Find if a PostgreSQL database exists with bash - 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.

Related

Check if a role exists in PostgreSQL using psql

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.

Error when trying to insert values in Postgres query inside Bash script

I'm executing the query as follows:
ssh user#XX.XX.1XX.XX "PGPASSWORD=myPassword psql -U psqlUser -h XX.XX.XX.XX -p 5432 -d myDB -c
'INSERT INTO table(\"CPU_IDLE_TIME\",\"TOTAL_SIZE\",\"USED_SIZE\",\"USED_STORAGE_P\") VALUES ($idlecputime,$totalSize,$usedSize,$usedStoragePercentage)';"
I obtain the values previous to this query doing snmpwalks. In order for the query to work the values have to be surrounded by single quotes (' '). I tried putting single quotes around the variable but everytime I get an error because the query is already surroundes by " ' ' ". I can't seem to find the configuration of quotes, or scaping quotes to make it work.
The variables are of type var char, integer and float.
One of the errores I get:
ERROR: syntax error at or near ","
Thanks in advance for your help.
Use printf to format the string for you
ssh user#XX.XX.1XX.XX "PGPASSWORD=myPassword psql -U psqlUser -h XX.XX.XX.XX -p 5432 -d myDB -c ""$(printf 'INSERT INTO table("CPU_IDLE_TIME","TOTAL_SIZE","USED_SIZE","USED_STORAGE_P") VALUES (%d, %d, %d, %d);' $idlecputime $totalSize $usedSize $usedStoragePercentage)"
The $( ) construct executes printf in a subshell.

bash scripting - function outputs results to empty file

I have a function that reads a list of names and uses that as input into another command like so:
runMain() {
getName=$(PGPASSWORD=$_clpw1 psql -h myendpoint.com -U ops_readonly -d dev -p 5439 -t -c "select datname from pg_database where datname not like 'template%' and datname not like 'tealium%' and datname not like 'padb%' and datname not like 'services%' and datname not like 'sales%' and datname not like 'dev%' and datname not like 'demo_%' and datname not like '%_demo' and datname not like 'nt_%';")
echo "${getName}" >> "${_file}"
for db in $(cat "${_file}");
do
getSchema=$(PGPASSWORD=$_clpw2 psql -h myendpoint.com -U masteruser -d "${db}" -p 5439 -t -c "select distinct 'GRANT SELECT ON ALL TABLES IN SCHEMA ' || table_schema ||' TO ops_readonly;' FROM information_schema.tables where table_catalog='%${db}%' and table_schema not in ('pg_catalog','information_schema');")
echo "${getSchema}" >> "${_script}"
done
}
I do an echo "${getSchema}" >> "${_script}" so I can output my query findings to a file.
I can see the output file has been touched and its like 32k, however the file its empty.
I've tested the command line string separately and it works and i'm getting the output I expect.
Is there a better way to capture the output to a file? What am I missing? Thank you.
Your file is empty (filled with 32k of blank lines) because ${getName} and ${getSchema} are both empty. Therefore, the problem is in those psql commands.
It's okay to put one level of double quotes inside a "$(…)" (never mind that SO's highlighting messes it up), so you can do this:
runMain() {
getName="$(PGPASSWORD="$_clpw1" psql -h myendpoint.com -U ops_readonly -d dev -p 5439 -t -c "select datname from pg_database where datname not like 'template%' and datname not like 'tealium%' and datname not like 'padb%' and datname not like 'services%' and datname not like 'sales%' and datname not like 'dev%' and datname not like 'demo_%' and datname not like '%_demo' and datname not like 'nt_%';" 2>&1)"
echo "${getName}" >> "${_file}"
for db in $(grep -o '[[:alnum:].-][[:alnum:].-]*' "${_file}");
do
getSchema="$(PGPASSWORD="$_clpw2" psql -h myendpoint.com -U masteruser -d "${db}" -p 5439 -t -c "select distinct 'GRANT SELECT ON ALL TABLES IN SCHEMA ' || table_schema ||' TO ops_readonly;' FROM information_schema.tables where table_catalog='%${db}%' and table_schema not in ('pg_catalog','information_schema');" 2>&1)"
echo "${getSchema}" >> "${_script}"
done
}
In addition to quoting your command substitution, I also quoted your passwords (which matters tremendously if you have spaces or other non-word characters in them!). Finally, I gave your commands 2>&1 to convert standard error into standard output so it can be captured in your output files, which might reveal other problems (like a bad password or bad connection).
The grep command makes the for loop safe to execute, ensuring the inputs are restricted to one or more alphanumeric characters, dots, and hyphens.
An output file was created. I was just getting 0 results. The root of my issue was in the plsql query. Running it via command line, my use of '%${db}%' is valid if running queries for postgres using like and since I am not using like, removing the surrounding % to '${db}' produced my output.

Bash script - cycle through MySQL records and update record based on user select

I'm a bit stuck, I need to loop through all of my mysql records and update one of the fields based on user input.
I was going to use the following to do the loop:
mysql -uuser -ppassword -s -e "SELECT company,product,category FROM MyTable"|while read varcomp varprod varcat;do
..and then use a PS3 select to provide the option:
PS3 "Please select new category: "
select opt1 in "Blocks" "Dolls" "Puzzles"
...before using, the following to update:
mysql -uuser -ppassword -s -e "UPDATE MyTable SET Category='$opt1' WHERE company='$varcomp' AND product='$varprod'"
...and then closing the loop.
I just can't seem to get all of the components to work together. I think it's because I'm using a while loop? Any advice on the best way to do this would be appreciated...
This should work:
while read -u 4 varcomp varprod varcat; do
echo "Company: $varcomp - Product: $varprod - Category: $varcat"
PS3="Please select new category: "
select opt in "Blocks" "Dolls" "Puzzles"; do
mysql -uuser -ppassword -s -e "UPDATE MyTable SET Category='$opt' WHERE company='$varcomp' AND product='$varprod';"
break
done
done 4< <(mysql -uuser -ppassword -s --skip-column-names -e "SELECT company,product,category FROM MyTable;")
You had the right idea, but the issue with using select inside a while read loop is that select and read both read input from stdin, so select would read all the SQL lines instead of prompting for user input. Instead, we redirect the mysql results to file descriptor 4, then tell read to use that instead of stdin, while select still reads from stdin as usual.
Note that if a user puts in a different value for select (eg 8 instead of 1, 2 or 3) then $opt will be null. You could replace the lines inside the select with:
[[ -n "$opt" ]] && mysql -uuser -ppassword -s -e "UPDATE MyTable SET Category='$opt' WHERE company='$varcomp' AND product='$varprod';" && break
This will keep prompting the user for input until they give a valid response.

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