Postgres comparing two databases - postgresql

We running two database servers with around 10 databases and multiple schemas in it (production and test). Every night we restore some of the prod to the test. The backup we do with pg_dump and restore with pg_restore. Now the size of the production and the restored database differnces from a few kb up to 700mb.
Now I want to ensure that the restored data is the same as on the production. I already saw that this is usual to postgres but we have to proof this to our manager. What would be the easiest to proof that the database servers are the same after the restore?

Let me suggest you another approach. You can use pg_restore with single transaction. Quote from de docs:
1
--single-transaction Execute the restore as a single transaction (that is, wrap the emitted commands in BEGIN/COMMIT). This ensures that
either all the commands complete successfully, or no changes are
applied. This option implies --exit-on-error.
In this case you don't need to compare a COUNT on all tables from both sides just because if pg_restore returned 0 (zero) then everything went well.

just solved the provide our solution for the moment.
#!/bin/bash
#
#change to the dir this script is located in (just to be sure)
cd "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# CONFIGURATION
remoteHost=stackoverflow.com
remotePort=5432
remoteUser=postgres
logfile=00comparsion.txt
#######################
cat "" > $logfile
databases=$(psql -U postgres -t -c "SELECT datname FROM pg_database WHERE datistemplate = false")
for database in $databases; do
echo ------------------------------------------------------------------------------- >> $logfile
echo $database >> $logfile
echo -------------------------------------------------------------------------------
echo $database
if [ "$(psql -U $remoteUser -h $remoteHost -p $remotePort -tAc "SELECT datname FROM pg_database WHERE datname='$database'" )" = '' ]
then
echo "Database '$database' does not exist on remote host! I quit now!" >> $logfile
exit 3
fi
schemas=$(psql -U postgres -d $database -t -c "SELECT SCHEMA_NAME FROM information_schema.schemata
WHERE SCHEMA_NAME NOT IN ('pg_toast',
'pg_temp_1',
'pg_toast_temp_1',
'pg_catalog',
'information_schema')")
for schema in $schemas; do
echo --$schema >> $logfile
if [ "$(psql -U $remoteUser -h $remoteHost -p $remotePort -tAc "SELECT SCHEMA_NAME FROM information_schema.schemata
WHERE SCHEMA_NAME='$schema'" )" = '' ]
then
echo "Schema '$schema' does not exist on remote host! I quit now!" >> $logfile
exit 3
fi
tables=$(psql -U postgres -d $database -t -c "SELECT TABLE_NAME FROM information_schema.tables
WHERE table_schema = '$schema'")
for table in $tables; do
if [ "$(psql -U $remoteUser -h $remoteHost -p $remotePort -tAc "SELECT TABLE_NAME FROM information_schema.tables
WHERE table_name = '$table'" )" = '' ]
then
echo "table '$table' does not exist on remote host! I quit now!" >> $logfile
exit 3
fi
orderField=$(psql -U postgres -d $database -t -c "SELECT column_name FROM information_schema.columns
WHERE table_schema = '$schema'
AND table_name = '$table' LIMIT 1")
#psql -U postgres -d $database -t -c "SELECT * FROM $table order by $orderField" > l.txt
#fetch same table data on remote instance
#psql -U $remoteUser -h $remoteHost -p $remotePort -d $database -t -c "SELECT * FROM $table order by $orderField" > r.txt
#if !(cmp --print-chars "l.txt" "r.txt")
lcl=$(psql -U postgres -d $database -t -c "SELECT * FROM $table order by $orderField")
rmt=$(psql -U $remoteUser -h $remoteHost -p $remotePort -d $database -t -c "SELECT * FROM $table order by $orderField")
if !("$lcl"="$rmt")
then
echo ---$table ✘ >> $logfile
exit 3
else
echo ---$table ✔ >> $logfile
fi
done
done
done
rm l.txt r.txt
echo ------------------------------------------------------------------------------- >> $logfile
echo comparsion finished, sir! >> $logfile
exit 0

Related

Ouput PostgreSQL query into INT powershell variable

I am quite new in using Powershell and try to output the result of a PostgreSQL query into a Powershell variable in order to use as a trigger for sending emails.
The returned value is a numeric value = 1 but it is considered as a system.Object and thus not recognised as INT.
See my code below (all email related code removed, no issue on that part)
# QUERY FOR EMAIL TRIGGER
Set-Location "C:\Program Files\pgAdmin 4\v4\runtime\";
$sql_trigger = $(.\psql -h $Server -p $DBPort -U $User -d $Database -w -v ON_ERROR_STOP=1 -c "select trigger_value from my_table ;" -t)
$trigger = $sql_trigger
Write-Host "trigger is "$trigger
[int]$_trig_false = 0
[int]$_trig_true = 1
IF ($trigger -as [int] -eq $_trig_false) {
Write-Host "Trigger value is 0 and will trigger an ERROR email"
}
ELSEIF ($trigger -as [int] -eq $_trig_true) {
write-host "Trigger value is 1 and will send email with file attached"
}
ELSE {
Write-Host "TRIGGER NOT READY"
#exit
}
here is the result.
trigger is 1
TRIGGER NOT READY
Many thanks in advance for the support

how to insert error returned from copy command from .bat file into table

batch-file:
cd C:\Program Files\pgAdmin 4\v5\runtime
psql -h "Hostname" -p "5432" -U "user_name" -d "dbname" -c "\COPY (SELECT * FROM schema_name.table_name) TO "C:\ExportFromStaging\outputfile.csv" WITH (FORMAT CSV, HEADER TRUE, FORCE_QUOTE *, QUOTE '\"', ESCAPE '''',DELIMITER ';')
Expectation :
If any error occurs in copy command, I want to catch error rerturned from Database eighter in local variable or in table
Example batch file:
cd C:\Program Files\pgAdmin 4\v5\runtime
psql -h "Hostname" -p "5432" -U "user_name" -d "dbname" -c "\COPY (SELECT * FROM schema_name.table_name) TO "C:\ExportFromStaging\outputfile.csv" WITH (FORMAT CSV, HEADER TRUE, FORCE_QUOTE *, QUOTE '\"', ESCAPE '''',DELIMITER ';')
if error
then
insert into error_log (error_message,error_time)
values (#ERRROR_RETURNED_FROM_DATABASE_IFCOPPYING_WENT_WRONG,timestamp);
echo #ERRROR_RETURNED_FROM_DATABASE_IF_COPPYING_WENT_WRONG
```
i don't know postgress but i can hazard a solution. From the psql manual:
psql returns 0 to the shell if it finished normally, 1 if a fatal
error of its own occurs (e.g. out of memory, file not found), 2 if the
connection to the server went bad and the session was not interactive,
and 3 if an error occurred in a script and the variable ON_ERROR_STOP
was set.
you can try:
setlocal EnableDelayedExpansion
rem use double quote if there is space in filename.
cd "C:\Program Files\pgAdmin 4\v5\runtime"
rem psql command.
psql -h "Hostname" -p "5432" -U "user_name" -d "dbname" -c "\COPY (SELECT * FROM schema_name.table_name) TO "C:\ExportFromStaging\outputfile.csv" WITH (FORMAT CSV, HEADER TRUE, FORCE_QUOTE *, QUOTE '\"', ESCAPE '''',DELIMITER ';')
if %ERRORLEVEL% GEQ 1 (
IF %ERRORLEVEL% EQU 1 set "result=psql fatal error."
IF %ERRORLEVEL% EQU 2 set "result=psql connection to the server went bad."
IF %ERRORLEVEL% EQU 3 set "result=psql error occurred in a script: '%ON_ERROR_STOP%'"
echo psql error: [!date! !time!] !result!
:: you can change "timestamp" with variable !date! !time!
:: pseudocode:
:: insert into error_log (error_message,error_time) values ("!result!","!date! !time!");
) else (
IF %ERRORLEVEL% EQU 0 echo psql finished normally.
)

The reason why the script written in centos does not work in crontab

I registered the script to crontab to run every 10 minutes. When I run the script, the log is printed, but if I put it on the cron tab and wait, the log does not appear, so it seems that it does not work. If you have anything I need to add or edit, please let me know :(
my sh script
#!/bin/sh
pslist=`ps -ef | grep ffprobe | awk '{print $2}'`
pscount=`ps -ef | grep ffprobe | wc -l`
logs='/apps/kMobile/kEncoderPy/batch/kill_ffprobe.log'
timestamp=`date +%Y%m%d--%H:%M`
echo "[$timestamp] Kill the Batch process Start :: "$timestamp >> $logs
echo "[$timestamp] process ffprobe running count :: "$pscount >> $logs
for pid in $pslist
do
rtime=`ps -p $pid -o etime | tail -1`
rtime=$rtime | tr -d ' '
minutes=${rtime:6:2}
if [$rtime != "ELAPSED" ]; then
if [ $minutes -gt 10 ]; then
`kill -9 $pid`
echo "[$timestamp] passed 10 minute kill process id : "$pid >> $logs
echo "[$timestamp] process kill after ffprobe running count : "$psount >> $logs
fi
fi
done
my crontab -e
*/10 * * * * /apps/kMobile/batch/kill_ffprobe.sh

Can function get empty arguments?

My code
function foo
argparse -n foo 'u/user=' 'g/group=' 's/shell=' -- $argv
bar $_flag_u $_flag_g $_flag_s
end
function bar -a user group shell
echo $user
echo $group
echo $shell
end
foo $argv
Execute and Result
> fish test.fish -u user_name -g group_name -s shell_name
user_name
group_name
shell_name
> fish test.fish -g group_name -s shell_name
group_name
shell_name
> fish test.fish -u user_name -s shell_name
user_name
shell_name
>
Expectation I want
> fish test.fish -u user_name -g group_name -s shell_name
user_name
group_name
shell_name
> fish test.fish -g group_name -s shell_name
group_name
shell_name
> fish test.fish -u user_name -s shell_name
user_name
shell_name
>
Can I get the expectation?
If -u option is not used, my expectation is that $user in bar function is empty.
(it means that result of "echo $status" is 1 after "set -q user".)
If I have no choice, I'll do bellow:
(Reference: https://github.com/fish-shell/fish-shell/issues/3926)
function foo
argparse -n foo 'u/user=' 'g/group=' 's/shell=' -- $argv
set -q _flag_u; or set _flag_u ''
set -q _flag_g; or set _flag_g ''
set -q _flag_s; or set _flag_s ''
bar $_flag_u $_flag_g $_flag_s
end
function bar -a user group shell
if test -n $user
# do something
end
if test -n $group
# do something
end
if test -n $shell
# do something
end
end
foo $argv
Your issue is this:
function bar -a user group shell
This means bar calls its first argument "user", the second "group" and the third "shell".
When you then run
bar $u $g $s
fish expands the variables. If they are set, they'll expand to as many arguments as they have elements (in fish, all variables are lists!).
So you'll get $u into $user, $g into $group and $s into $shell.
However, if one isn't set (because the option wasn't given in the call to foo), then the variable will expand to nothing, so if e.g. --group wasn't given, this works like
bar $u $s
which will assign the contents of $u to $user and $s to $group - because it is the second argument that bar sees.
To inhibit this, either use set -q or double-quote the variable:
bar "$_flag_u" "$_flag_g" "$_flag_s"

Executing a command within powershell with newlines in arguments

Below is a powershell script I am trying to get working. Its designed to run with GitHub for Windows git shell and I have am trying to call "Hub" (https://github.com/github/hub), but thats not relevant. I can call it fine except in one of the command line parameters I want to have some newlines. Is there some way to do this? The new lines are being interpreted as the end of the command.
The newlines are the $msg variable. So the (abbreviated) output is something like:
hub pull-request -m "PFR-1
https://linktoitem/PFR-1
"
But the command line just sees: hub pull-request -m "PFR-1
$branch = $Global:GitStatus.branch
$segments = $branch.split("/")
iex "git push -u origin $branch"
if ($segments.Length -eq 2 -and $segments[1] -match "^\w+\-\d+$")
{
$jiraItem = $segments[1].ToUpper()
$msg = "$jiraItem`r`n``r`nnhttps://someurl.atlassian.net/browse/$jiraItem"
echo "hub pull-request -m ""$msg"" -b kiandra-projects:develop -h kiandra-projects:$branch"
iex "& hub pull-request -m ""$msg"" -b kiandra-projects:develop -h kiandra-projects:$branch"
}
else
{
iex "hub pull-request -b kiandra-projects:develop -h kiandra-projects:$branch"
}
Have you tried a here-string?
$MultilineString = #"
Stuff
More stuff
"#
# in your case:
$msg = #"
$jiraItem
https://someurl.atlassian.net/browse/$jiraItem
"#
Note: The closing "# must be on its own line
Also, check http://chocolatey.org/packages/Posh-GitHub, it may do what you need