How to create a PL/pgSQL function in a database using a bash script?

Diogo dos Santos 30 Reputation points
2025-08-25T13:02:09.84+00:00

I have tried to install two PL/pgSQL functions, run the second of them, save the output of the function in a variable, export it to an SQL file and run the exported file, using a bash script:

#!/bin/bash

# function to install pg functions into the database
run_sql_commands() {
    local user=$1
    local pass=$2
    local id=$3
    local host=$4
    local port=$5
    local login=$6
    local password=$7
    PGPASSWORD="$pass" /usr/bin/psql -P pager=off -q -t -h "$host" -p "$port" -U "$user" -d postgres -AqtX -f /appl/mydir/first_function.sql >> "$LOG_OK"  2>> "$LOG_ERR"
    PGPASSWORD="$pass" /usr/bin/psql -P pager=off -q -t -h "$host" -p "$port" -U "$user" -d postgres -AqtX -f /appl/mydir/second_function.sql >> "$LOG_OK"  2>> "$LOG_ERR"
    update_var=$(PGPASSWORD="$pass" /usr/bin/psql -P pager=off -q -t -h "$host" -p "$port" -U "$user" -d postgres -AXqtc "SELECT F_PG_CHANGE_PASSWORD($id, '$login', '$password');")
    echo "$update_var" >> /appl/mydir/update_string.sql
    chmod 777 "/appl/mydir/update_string.sql"
}
# Paths to log files
LOG_OK="/appl/mydir/logs/success_change_password.log"
LOG_ERR="/appl/mydir/logs/error_change_password.log"

# Clear log files at the beginning of the script and add a timestamp
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "### SCRIPT EXECUTION LOG FOR PASSWORD CHANGE FROM $timestamp" > "$LOG_OK"
echo "### ERROR LOG FOR SCRIPT EXECUTION OF PASSWORD CHANGE FROM $timestamp" > "$LOG_ERR"

# read arguments
while read -r i j k l m; do
    id="$i"
    host="$j"
    port="$k"
    login="$l"
    password="$m"
    # load user info and password for DB connection
    while IFS='=' read -r key value; do
        case "$key" in
            "USER2") user="$value" ;;
            "PASSWORD") pass="$value" ;;
            "USER4") user2="$value" ;;
            "PASSWORD4") pass2="$value" ;;
        esac
    done < /appl/mydir2/.env
    # use on-prem or Azure user and password
    if [ -n "$user" ] && [ -n "$pass" ]; then
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] Connecting to host: $host, port: $port" >> "$LOG_OK"
        run_sql_commands "$user" "$pass" "$id" "$host" "$port" "$login" "$password" 2>> "$LOG_ERR"
        if [ $? -eq 0 ]; then
            echo "[$(date '+%Y-%m-%d %H:%M:%S')] Connection to host: $host, port: $port was successful" >> "$LOG_OK"
        else
            echo "[$(date '+%Y-%m-%d %H:%M:%S')] Error connecting to host: $host, port: $port" >> "$LOG_ERR"
        fi
    elif [ -n "$user2" ] && [ -n "$pass2" ]; then
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] Not an on-prem user. Using Azure user." >> "$LOG_OK"
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] Connecting to host: $host, port: $port" >> "$LOG_OK"
        run_sql_commands "$user2" "$pass2" "$id" "$host" "$port" "$login" "$password" 2>> "$LOG_ERR"
        if [ $? -eq 0 ]; then
            echo "[$(date '+%Y-%m-%d %H:%M:%S')] Connection to host: $host, port: $port was successful" >> "$LOG_OK"
        else
            echo "[$(date '+%Y-%m-%d %H:%M:%S')] Error connecting to host: $host, port: $port" >> "$LOG_ERR"
        fi
    else
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] User or password not found in .env file" >> "$LOG_ERR"
    fi
done < /appl/mydir/var_select.txt

# sql update
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Connecting to localhost:5432 to update table mytable" >> "$LOG_OK"
/usr/bin/psql -P pager=off -q -t -h localhost -p 5432 -U postgres -d end_db -AqtX -f /appl/mydir/update_string.sql 2>> "$LOG_ERR"
if [ $? -eq 0 ]; then
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] Connection to host and SQL script execution completed successfully" >> "$LOG_OK"
else
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] Error connecting or executing sql file update_string.sql" >> "$LOG_ERR"
fi

# remove files
rm "/appl/mydir/var_select.txt" 2>> "$LOG_ERR"
rm "/appl/mydir/update_string.sql" 2>> "$LOG_ERR"

I have already tested if the code can connect to the database, and it can. However, it is not installing the functions. They are not in the database. I have already tried to install the functions manually and it works, so it is not a matter of right. I cannot identify the error. Has anyone ever had this problem before?

Is it possible that it has something to do with the fact that the database, where I have tried to install the functions is an Azure database for Postgres? When I try to do the installation manually, it works. So may it be something related to the right to install the functions remotely? That is my only guess, but I have never had this problem before.

Azure Database for PostgreSQL
{count} votes

1 answer

Sort by: Most helpful
  1. Kalyani Kondavaradala 1,015 Reputation points Microsoft External Staff Moderator
    2025-08-27T13:36:06.5333333+00:00

    Hello Diogo dos Santos,

    Thank you so much for your patience and for sharing the details, really appreciate it. I’m glad to hear your issue has been resolved. I am adding the steps that you have followed to resolve your issue.

    Here's a corrected Bash script:

    • Explicitly uses the right database (change DB to actual DB if required).
    • Enforces sslmode=require (mandatory on Azure).
    • Surfaces errors by removing quiet flags when installing functions.
    • Logs properly, with least-privilege file permissions
    #!/bin/bash
    # Paths to log files
    LOG_OK="/appl/mydir/logs/success_change_password.log"
    LOG_ERR="/appl/mydir/logs/error_change_password.log"
    # Clear log files at the beginning of the script and add a timestamp
    timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo "### SCRIPT EXECUTION LOG FOR PASSWORD CHANGE FROM $timestamp" > "$LOG_OK"
    echo "### ERROR LOG FOR SCRIPT EXECUTION OF PASSWORD CHANGE FROM $timestamp" > "$LOG_ERR"
    # Function to install pg functions into the database
    run_sql_commands() {
        local user=$1
        local pass=$2
        local id=$3
        local host=$4
        local port=$5
        local login=$6
        local password=$7
        local dbname="postgres"   
        # Install first function
        PGPASSWORD="$pass" /usr/bin/psql "host=$host port=$port user=$user dbname=$dbname sslmode=require" \
            -v ON_ERROR_STOP=1 -f /appl/mydir/first_function.sql >> "$LOG_OK" 2>> "$LOG_ERR" || return 1
        # Install second function
        PGPASSWORD="$pass" /usr/bin/psql "host=$host port=$port user=$user dbname=$dbname sslmode=require" \
            -v ON_ERROR_STOP=1 -f /appl/mydir/second_function.sql >> "$LOG_OK" 2>> "$LOG_ERR" || return 1
        # Call function and capture output
        update_sql="SELECT second_function($id, '$login', '$password');"
        update_var=$(PGPASSWORD="$pass" /usr/bin/psql "host=$host port=$port user=$user dbname=$dbname sslmode=require" \
            -AXqtc "$update_sql" 2>> "$LOG_ERR") || return 1
        echo "$update_var" > /appl/mydir/update_string.sql
        chmod 640 /appl/mydir/update_string.sql
        return 0
    }
    # Read input arguments line by line
    while read -r i j k l m; do 
    id="$i"
     host="$j"
     port="$k"
     login="$l" 
    password="$m"
        # Load user info and password for DB connection from .env
        while IFS='=' read -r key value; do
            case "$key" in
                "USER2") user="$value" ;;
                "PASSWORD") pass="$value" ;;
                "USER4") user2="$value" ;;
                "PASSWORD4") pass2="$value" ;;
            esac
        done < /appl/mydir2/.env
        if [ -n "$user" ] && [ -n "$pass" ]; then
            echo "[$(date '+%Y-%m-%d %H:%M:%S')] Connecting to host: $host, port: $port with USER2" >> "$LOG_OK"
            if run_sql_commands "$user" "$pass" "$id" "$host" "$port" "$login" "$password"; then
                echo "[$(date '+%Y-%m-%d %H:%M:%S')] Connection to host: $host, port: $port with USER2 was successful" >> "$LOG_OK"
            elif [ -n "$user2" ] && [ -n "$pass2" ]; then
                echo "[$(date '+%Y-%m-%d %H:%M:%S')] Connecting to host: $host, port: $port with USER4" >> "$LOG_OK"
                run_sql_commands "$user2" "$pass2" "$id" "$host" "$port" "$login" "$password"
            else
                echo "[$(date '+%Y-%m-%d %H:%M:%S')] Failure to connect to host: $host, port: $port" >> "$LOG_ERR"
            fi
        else
            echo "[$(date '+%Y-%m-%d %H:%M:%S')] User or password not found in .env file" >> "$LOG_ERR"
        fi
    done < /appl/mydir/var_select.txt
    # Clean up
    rm -f "/appl/mydir/var_select.txt" 2>> "$LOG_ERR"
    rm -f "/appl/mydir/update_string.sql" 2>> "$LOG_ERR"
    

    Connect manually to the target database:

       psql -h <host> -U <user> -d <Target db>
    
    1. Check if functions are installed
    2. Review $LOG_ERR for any suppressed errors.

    Could you please try running the script once and let me know if you still face any issues? I’ll be happy to help further. If you find this information helpful, kindly consider clicking Upvote so it can assist others as well.

    Thanks,

    Kalyani

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.