Check if a role exists in PostgreSQL using psql - bash

I need in a bash script a IF condition on the existence of a role in a PostgreSQL database. I have found solutions in SQL code [1, 2], but I need something I can use directly in bash, I assume with the help of psql. In [2] there are also psql solutions, but I don't manage to adapt it in a IF statement.
I have tried this unsuccessfully (I am a PostgreSQL and bash newbie):
psql_USER=my
if [ "$( psql -h db -U postgres --no-psqlrc --single-transaction --pset=pager=off --tuples-only --set=ON_ERROR_STOP=1 -tc "SELECT 1 FROM pg_user WHERE usename = $psql_USER" | grep -q 1 )" == '1' ] > /dev/null 2> /dev/null; then
echo "HOURRA !"
fi;
Result is:
Password for user postgres:
ERROR: column « my » does not exist
LINE 1: SELECT 1 FROM pg_user WHERE usename = my
^

I would avoid the quoting problem like this:
if psql -Atq -c "SELECT '#' || usename || '#' FROM pg_user" | grep -q '#'"$psql_USER"'#'
then
echo yes
fi
The psql invocation selects a list of all usernames, prefixed and suffixed with #. The grep has return code 0 if psql_USER contains one of these user names, else 1. The then branch of if is only taken if the return code of the pipeline is 0, that is, if the user exists in the database.

Related

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.

Find if a PostgreSQL database exists with bash

I have a bash function where I check if a PostgreSQL database already exists.
I capture the output. If database exist PostgreSQL returns the database name as response.
function is_database() {
local database=$1
local output=$(sudo -u postgres psql -c "SELECT datname FROM pg_catalog.pg_database WHERE datname=\"$database\";")
if [[ $output = *"${1}"* ]]
then
return 0
else
return 1
fi
}
is_database test
I get the following error:
column "test" does not exist
I am not searching for a table, but a database.
Use single quotes for string literals:
sudo -u postgres psql \
-c "SELECT datname FROM pg_catalog.pg_database WHERE datname='$database'"
Your code as it is won't work for database names like has spaces or has'quotes.

From a shell script, how can I check whether a table in db2 database exists or not?

I am trying to write a script which allows to check if the db2 table exists or not. If it exists I will continue to touch a file if not exists then it has to wait for 30 min and try to check the same after 30 min. How might I achieve this?
#!/bin/sh
db2 "connect to <database> user <username> using <password>"
Variable=`db2 -x "SELECT COUNT(1) FROM SCHEMA.TABLEA WHERE 1=2"`
while read Variable ;
do
if $Variable=0
then touch triggerfile.txt
else
sleep 30
fi
done
You want to continually poll (without limitation on time) for a table to exist? Might be more readable to use bash or korn syntax, and avoid backticks but that's your choice.
Usual caveats apply, don't hardcode the password.
Apart from the looping logic, you might try this inside the loop (bash or ksh syntax shown below), initialising the variables to suit yourself:
db2 "connect to $dbname user $username using $passwd"
(( $? > 0 )) && print "Failed to connect to database " && exit 1
db2 -o- "select 1 from syscat.tables where tabschema=$schema and tabname=$tabname with ur"
rc=$?
# rc = 0 : the table exists in that schema
# rc= 1 : the table does not exist
(( rc == 1 )) && touch triggerfile.txt
# rc >= 2 : some warning or error, need to investigate and correct
(( rc >= 2)) && print "problems querying syscat.tables" && exit 1
db2 -o- connect reset

Execute psql query in bash

I have a problem with executing a psql-query in a bash script.
Below is my code.
run_sql(){
sql_sel="$1;";#sql select
table=$2;#table name
for i in "${!GP_SERVER_NAMES[#]}"
do
logmsg "Executing [$sql_sel] on "${GP_SERVER_NAMES[$i]}": " $loglvl;
result_host[$i]=`${PSQL_HOST[$i]}${sql_sel}`;
#result_host[$i]=cleanresult "`$(${PSQL_HOST[$i]} "$tx_fix $sql_sel" 2>&1`");
if [[ `checkresult "${result_host[$i]}"` != 'true' ]]; then
logmsg "Error occured during sql select: Result for "${GP_SERVER_NAMES[$i]}" '${table}': ${result_host[$i]};" '1' '1';
raise_alarm "${GP_SYNC_SQL_ERR}" "${i}" "${table}" "${result_host}";
fi
logmsg "Result for" ${GP_SERVER_NAMES[$i]} " '${table}': ${result_host[$i]}";
done
final_result='true';
for i in "${!result_host[#]}"
do
if [[ `checkresult "${result_host[$i]}"` = 'true' ]]; then
final_result='false';
I am trying to executing the query on many different servers, with the following command
result_host[$i]=${PSQL_HOST[$i]}${sql_sel};
The above variables have the following meaning:
1. result_host[$i] : is an array that holds the i-th result of the sql query.
2. PSQL_HOST[$i] : is the command line psql-statement, including the IP address which is of the form
psql -t -q -h -U password -d database -c
3. $sql_sel : is the sql_statement
When I run the script, I get the following output.
scriptname.sh: line 168: SELECT: command not found
ERROR: syntax error at end of input
LINE 1: SELECT
^
Why is that? Any help, comments or suggestions would be appreciated.

Bash script makes connection using FreeTDS, interacts, doesn't exit (just hangs)

I'm using FreeTDS in a script to insert records into a MSSQL database. TheUSEandINSERTcommands work, but theexitcommand doesn't and it hangs. I've tried redirectingstdoutbutcatcomplains. I suppose I will use Expect otherwise. Meh. Thanks.
echo -e "USE db\nGO\nINSERT INTO db_table (id, data, meta)\nVALUES (1, 'data', 'meta')\nGO\nexit" > tempfile
cat tempfile - | tsql -H 10.10.10.10 -p 1433 -U user -P pass
Did you mean to do this: cat tempfile -? It means that it will wait for you to press Ctrl+D, because it is trying to read from standard input as well.
If not, remove the -.
Also, as Ignacio suggests, you could write it more cleanly as a heredoc:
tsql -H 10.10.10.10 -p 1433 -U user -P pass <<EOF
USE db
GO
INSERT INTO db_table (id, data, meta)
VALUES (1, 'data', 'meta')
GO
exit
EOF
Or just do the echo with literal newlines rather than \n:
echo "
USE db
GO
INSERT INTO db_table (id, data, meta)
VALUES (1, 'data', 'meta')
GO
exit
" > tempfile
and then run it by using standard input redirection (<) like this:
tsql -H 10.10.10.10 -p 1433 -U user -P pass < tempfile

Resources