Redirecting PostgreSQL Notices to a Bash Array - bash

I have a PostgreSQL statement which raises notices. I wish to redirect this output into a bash array. I have tried the following:
declare -a MYARRAY
MYARRAY=( `psql -U $db_username -h $DATABASE_HOST $DATABASE_NAME -c \
"DO \\$\\$ DECLARE
mySite varchar;
myResult RECORD;
BEGIN
RAISE NOTICE 'current_site, folder, path';
FOR mySite IN SELECT name from public.app_info
LOOP
{Confidential Data here!}
LOOP
RAISE NOTICE '%,%,%', myResult.current_site, myResult.folder, myResult.path;
END LOOP;
END LOOP;
END\\$\\$"` )
echo "These are the files"
for i in ${MYARRAY[#]}; do
echo $i
done
When I run my script my notices from the query are printed to my window but they are not added into the array. I have also tried this with a variable instead of an array, with no luck.

Notices are printed into stderr so change
END\\$\\$"` ) to END\\$\\$" 2>&1` )
but array will contain also texts like NOTICE: and DO so you have to filter them out

Related

why result set value not stored in arraylist in shell script

sample code below
psql -h $host -U postgres -d postgres -At -c "select partner_country_id as country , case when (threshold is null) then global_threshold else threshold end as threshold from ra_country_day_threshold " \
| while read -a Record
do
arrIN=(${Record[0]//|/ })
col1=${arrIN[0]}
col2=${arrIN[1]}
country_array["$col1"]="$col2"
echo "Col1:$col1 Col2:$col2"
done
echo "Elements:${country_array[#]}"
echo "length: ${#country_array[#]}"
Result
empty elements and length 0
The answer is simple, while command create a subprocess with its own context, if you create a new variable in that context, it will not be accessible outside of it.
Meaning the variable will not be accessible when you are outside the loop.
My suggestion is that you store the result inside a temporary file that will be available within all your script, then outside your loop, read that file.

How can I disable * expansion in a script?

I have a strange problem - possibly I'm just going blind. I have this short script, which replaces the string #qry# in the here-document with a select statement in a file and then pipes it to mysql:
#!/bin/bash
if [[ "$1" == "-h" ]]
then
echo "sqljob [sqlfile] [procnm] [host] [database] [config file]"
echo " sqlfile: text file containing an SQL statement"
echo " procnm: name that will given to the new, stored procedure"
echo " host: hostname of IP address of the database server"
echo " database: the procedure will be created here"
echo " config file: default configuration file with username and password"
exit
fi
infile=$1
procnm=$2
hn=$3
pn=$4
db=$5
mycfg=$6
{
set -o noglob
sed -e "s/#qry#/$(echo $(cat $infile))/g" <<!
drop procedure if exists $procnm;
delete from jobs where jobname="$procnm";
insert into jobs
set
notes="SQL job $procnm",
jobname="$procnm",
parm_tmpl='int';
delimiter //
create procedure $procnm(vqid int)
begin
call joblogmsg(vqid,0,"$procnm","","Executing #qry#");
drop table if exists ${procnm}_res;
create table ${procnm}_res as
#qry#
end//
delimiter ;
!
} | mysql --defaults-file=$mycfg -h $hn -P $pn $db
However, when the select contains *, it expands to whatever is in the directory even though I use noglob. However, it works from the command line:
$ set -o noglob
$ ls *
What am I doing wrong?
Edit
Block Comments in a Shell Script has been suggested as a duplicate, but as you will notice, I need to expand ${procnm} in the here-doc; I just need to avoid the same happening to select *.
I suspect it is because the construct echo (cat). The echo command gets the * from the cat command and the shell in which it runs expands it. In that shell set noglob is not active.
Try leaving the echo away: /$(cat $infile)/, in the end that is the data you need; then there is no extra glob expansion by a shell.

Shell Script piping

#!/bin/sh
output=ANIL;
#
# Ask user for database inputs
#
echo -n "Enter Database Server Hostname: "
read dba_host
echo -n "Enter Database SID: "
read dba_sid
echo -n "Enter DBA User: "
read dba_usr
echo -n "Enter DBA password: "
read dba_pwd
echo -n "What daemon are we using: "
read daemon_str
#
# Loop to connect to database and exit if something is found
#
while :
do
output=`sqlplus $dba_usr/$dba_pwd#$dba_sid <<+ | grep '^-' | sed 's/-//'
set serveroutput on
DECLARE
command VARCHAR2(50);
return_name VARCHAR2(30);
value VARCHAR2(10000);
status INT;
system_time TIMESTAMP := SYSTIMESTAMP;
WHILE TRUE
BEGIN
status := DBMS_PIPE.RECEIVE_MESSAGE($daemon_str);
IF status = 0 THEN
DMS_PIPE.UNPACK_MESSAGE(command);
END IF;
IF command = "STOP" THEN
DBMS_OUTPUT.PUT_LINE('STOP was encountered') >> file.log;
DBMS_OUTPUT.PUT_LINE(system_time) >> file.log;
BREAK
ELSIF command = "SYSTEM" THEN
DBMS_PIPE.UNPACK_MESSAGE(return_name);
DBMS_PIPE.UNPACK_MESSAGE(value);
EXIT
$value
ELSIF command = "SQL"
DBMS_PIPE.UNPACK_MESSAGE(return_name);
DBMS_PIPE.UNPACK_MESSAGE(value);
EXECUTE IMMEDIATE value;
ELSE
nap(10)
EXCEPTION
WHEN OTHERS THEN
dbms_ouput.put_line('Unknown Input Error') >> file.log;
DBMS_OUTPUT.PUT_LINE(system_time) >> file.log;
DBMS_PIPE.PACK_MESSAGE('done');
DBMS_PIPE.PACK_MESSAGE(status);
status := DBMS_PIPE.SEND_MESSAGE(return_name,10);
END;
dbms_output.put_line(chr(10) || '-' || command);
END;
/
exit
+`
echo $output
done
I am trying to convert a c code block to what you see now a shell script block. I am just a beginner in this coding language and was wanting to know if anyone is seeing something I am not. To sum up what I am trying to accomplish is ask user for the oracle database they want to connect to then keep connection and receive things through pipe. Then the usual of unpacking, outputting errors and such. Then sending it back through same pipe. Any input on possible syntax or anything at all that could be causing this to constantly echo out nothing but blank lines from while loop.

How to fetch more than one column value from oracle select query to shell variable

I am trying to fetch a row with more than one column value to different shell variables. Infact I found that at a time all the column values can be stored to single shell variable. But how can I put those column values to seperate shell variables. Below is an example I am trying for time being
function sqlQuery {
sqlplus -S shiyas/********* <<'EOF'
set heading OFF termout ON trimout ON feedback OFF
set pagesize 0
SELECT name,open_mode from v$database;
EOF
}
OUTPUT="$( sqlQuery )"
echo $OUTPUT
Here I am getting the output as
ORCL READ WRITE
But my requirement is column values ORCL, READ WRITE should get assigned to different shell variable.
I tried the below of parsing.
echo "$OUTPUT" | while read name open_mode
but it was throwing unexpected end of file error.
-bash-3.2$ sh call_sql_col_val_1.sh
ORCL READ WRITE
call_sql_col_val_1.sh: line 18: syntax error: unexpected end of file
Please let me know what concept I can use to fetch a single row column values to different shell variables.
I do this via eval myself:
oracle#******:/*****> cat test.sh
#!/bin/bash
function sqlQuery {
sqlplus -S / as sysdba <<'EOF'
set heading OFF termout ON trimout ON feedback OFF
set pagesize 0
SELECT name,open_mode from v$database;
EOF
}
eval x=(`sqlQuery`)
NAME=${x[0]}
OPEN_MODE="${x[1]} ${x[2]}"
echo NAME IS $NAME
echo OPEN_MODE IS $OPEN_MODE
So we are running the same function you have above, passing it into x and running it through eval to handle the delimitation. Then you have an array and call call is as such: x[0] for the first item, for example.
Output is:
oracle#******:/******> sh test.sh
NAME IS ******
OPEN_MODE IS READ WRITE

Ksh function to query Oracle with return values

Some time ago I wrote a small routine to run some quick n' dirty queries (and with that I mean it is not used for large queries) against an Oracle DB, but also wanted to do it a bit easier to parse errors. Follows:
# Executes the query
#
# Will execute a query contained in the variable named
# in the parameter $4 and store the result in the variable
# named in $5.
# In case of errors (even SQL related) the function should
# exit with status 1, making it possible to "if execQuery".
#
# #param $1 = User
# $2 = Pasword
# $3 = Tns Alias
# $4 = Name of the variable containing the query
# $5 = Name of the variable to hold the result
#
# #return query execution status
function execQuery {
typeset eSQLU=$1
typeset eSQLP=$2
typeset eSQLS=$3
typeset etQUERY=$4
eval typeset eQUERY=\$$etQUERY
typeset eQRES=$5
logMessageFile "DEBUG" "Query: $eQUERY"
typeset res=$(sqlplus -s $eSQLU/$eSQLP#$eSQLS <<EOF
set echo off newpage 0 space 0 pagesize 0 feed off head off verify off lines 999
WHENEVER SQLERROR EXIT 1
$eQUERY
exit;
EOF
)
[[ $? -gt 0 ]] && return 1 || eval "$eQRES=\"$res\""
}
The idea of this function is that later I could do something like:
query="select sysdate from dual;"
if execQuery $RAID_APP_PI_USR $RAID_APP_PI_PWD $RAID_APP_PI_SID query result ; then
echo $result
logMessageFile "INFO" "Inserts into XX successful."
else
logMessageFile "ERROR" "Error insertando XXX."
fi
It kinda works... A properly written query will do it fine, and the result variable is all correctly evaluated and all. The problem are the errors. If the query in that example was something like select * potato potato;, It'd still not yield the correct return value thus missing the error test.
I'm not particularly good with sqlplus nor ksh, probably just missing something obvious... Could someone lend me a hand here?
Thanks!
I believe $? is returning the exit status of the typeset command, not the sqlplus command.
It may be easier to output the results of your SQLPLUS statement to a file instead of into a variable. Then you could either read that file with grep, looking for an "ORA-" message, or check the exit status variable.
sqlplus -s $eSQLU/$eSQLP#$eSQLS > querylog.tmp <<EOF
set echo off newpage 0 space 0 pagesize 0 feed off head off verify off lines 999
WHENEVER SQLERROR EXIT 1
$eQUERY
exit;
EOF
echo $?

Resources