42

I have a .sql file, which is a bunch of oracle pl/sql commands and I want to create a shell script to run these commands.

Suppose that user/pass@server is my credentials. What will be the shell script to do such a task?

8 Answers 8

47

For example:

sqlplus -s admin/password << EOF
whenever sqlerror exit sql.sqlcode;
set echo off 
set heading off

@pl_script_1.sql
@pl_script_2.sql

exit;
EOF
Sign up to request clarification or add additional context in comments.

5 Comments

This is horribly insecure, as anyone can see the password while "sqlplus" is running by using the "ps" command.
Hi @NetBear, I think you need to do sqlplus -s admin/password@server (the @server part was the deal breaker in my case).
use sqlplus -s <username>/<password>@<db_ip>:<db_port>/<db_name> << EOF in the first line for the remote db
@NetBear where do you put the database name when using this method?
See my expanded answer below for an alternative, storing the database password as a shell variable, as well as tricks for keeping the variable assignment itself out of your shell history file.
37

Wouldn't something akin to this be better, security-wise?:

sqlplus -S /nolog << EOF
CONNECT admin/password;

whenever sqlerror exit sql.sqlcode;

@pl_script_1.sql
@pl_script_2.sql

exit;
EOF 

Feeding the SQL statements to sqlplus on its standard input (via a here doc in this example) prevents the password from appearing in the process list.

If you need to specify a different host or service name, e.g. one defined in your tnsnames.ora, append @service_name to the CONNECT statement above.

6 Comments

What is this more secure than? What makes it more secure? Try editing your post and adding this information. Or are you asking a question?
It's more secure because username/password doesn't show up in ps -ea
Chaos, thanks for adding that - yeah, that was my intent, and I didn't see keith's reply, so thanks for catching this!
For posterity: if you use Bash variables, do not surround them by double quotes after CONNECT. So CONNECT "$ORCL_CREDS" won't work.
@BlaineDeLancey where do you put the database name when using this method?
|
6

If you want to redirect the output to a log file to look for errors or something. You can do something like this.

sqlplus -s <<EOF>> LOG_FILE_NAME user/passwd@host/db
#Your SQL code
EOF

Comments

4

This should handle issue:

  1. WHENEVER SQLERROR EXIT SQL.SQLCODE
  2. SPOOL ${SPOOL_FILE}
  3. $RC returns oracle's exit code
  4. cat from $SPOOL_FILE explains error
SPOOL_FILE=${LOG_DIR}/${LOG_FILE_NAME}.spool 

SQLPLUS_OUTPUT=`sqlplus -s  "$SFDC_WE_CORE" <<EOF 
        SET HEAD OFF
        SET AUTOPRINT OFF
        SET TERMOUT OFF
        SET SERVEROUTPUT ON

        SPOOL  ${SPOOL_FILE} 

        WHENEVER SQLERROR EXIT SQL.SQLCODE
        DECLARE 

        BEGIN
           foooo 
        --rollback; 
        END;
    /
    EOF` 

RC=$?

if [[ $RC != 0 ]] ; then

    echo " RDBMS exit code : $RC  "     | tee -a ${LOG_FILE}
    cat ${SPOOL_FILE}                   | tee -a ${LOG_FILE}

    cat ${LOG_FILE} | mail -s "Script ${INIT_EXE} failed on $SFDC_ENV" $SUPPORT_LIST

    exit 3

fi

Comments

1

If you are logging into sqlplus from a script, I would recommend setting up a wallet to store the username/password and tns

--create a wallet subdir
cd /myscriptloc/wallet
$ORACLE_HOME/client/bin/mkstore -wrl . -create
$ORACLE_HOME/client/bin/mkstore -wrl . -createCredential tnsname username pw

You will need the filessqlnet.ora and tnsnames.ora in this directory for the tns:

--sqlnet.ora
WALLET_LOCATION =
   (SOURCE =
      (METHOD = FILE)
         (METHOD_DATA=
           (DIRECTORY=/myscriptloc/wallet)
         )
    )

SQLNET.WALLET_OVERRIDE=TRUE
SSL_CLIENT_AUTHENTICATION=FALSE
--end of sqlnet.ora

-- Script
TNS_ADMIN=/myscriptloc/wallet
tnsname=tnsname_from_wallet

sqlplus -S  /nolog <<stop
  connect /@${tnsname}
  @@${scriptname}
exit

1 Comment

This is the most secure; the answer stackoverflow.com/a/16108372/4178262 is almost as good, but leaves the possible issues if the file permissions on the script are not 600 and if the root user is not trustworthy.
1

Here's an answer that doesn't expose the logon credentials on the command line. It expands a bit on this answer above.

Of course, this script's file permissions should be set to only allow you to view and execute it, and keep in mind the root user can see your script.

#!/bin/bash

# set up any session parms
export SID=tradewinds

# logon information
export USER="scott"
export PW='tiger'

sqlplus /nolog  << EOF
connect $USER/$PW@$SID
@@disp_space.sql
exit
EOF
SQLPLUS_RC=$?

echo Sql Plus return code: $SQLPLUS_RC

Recent Oracle versions clear out any connect information on the command line, but there could be a brief moment where it is visible to all.

See this answer for using the wallet, which is more secure than this.

Comments

0

Some of the other answers here inspired me to write a script for automating the mixed sequential execution of SQL tasks using SQLPLUS along with shell commands for a project, a process that was previously manually done. Maybe this (highly sanitized) example will be useful to someone else:

#!/bin/bash
acreds="user_a/supergreatpassword"
bcreds="user_b/anothergreatpassword"
hoststring='fancyoraclehoststring'

runsql () {
  # param 1 is $1
sqlplus -S /nolog << EOF
CONNECT $1@$hoststring;
whenever sqlerror exit sql.sqlcode;
set echo off
set heading off
$2
exit;
EOF
}

echo "TS::$(date): Starting SCHEM_A.PROC_YOU_NEED()..."
runsql "$acreds" "execute SCHEM_A.PROC_YOU_NEED();"

echo "TS::$(date): Starting superusefuljob..."
/var/scripts/superusefuljob.sh

echo "TS::$(date): Starting SCHEM_B.SECRET_B_PROC()..."
runsql "$bcreds" "execute SCHEM_B.SECRET_B_PROC();"

echo "TS::$(date): DONE"

runsql allows you to pass a credential string as the first argument, and any SQL you need as the second argument. The variables containing the credentials are included for illustration, but for security I actually source them from another file. If you wanted to handle multiple database connections, you could easily modify the function to accept the hoststring as an additional parameter.

1 Comment

Is you pass credentials on cmmand line, they are exposed to all users and processes in the system via the /proc filesystem. Same if you store them in environment variables (but not bash variables). so -1 for the insecure approach.
0

echo "exit" | echo "SELECT table_name FROM all_tables FETCH FIRST 10 ROWS ONLY;" | sqlplus admin/password > outputFile.log

1 Comment

Just FYI, the echo "exit" at the front doesn't do anything. The second echo command doesn't read from standard input, so the output of the first echo is ignored. I know, it's tricky shell scripting stuff, but I want to point this out for anyone else scratching their head about that. Just omit the first echo up to and including the pipe character.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.