#!/bin/bash # # Reproducer for BUG #19520: PANIC when concurrently manipulating # stored procedures with track_functions = all (or pl). # # On an unfixed build this PANICs. On a fixed build the server survives. set -e PGPORT="${1:-5432}" PGDATABASE="postgres" PGUSER="${USER:-postgres}" N_DDL=10 # number of DROP/CREATE/CALL workers N_CALL=20 # number of CALL-only workers ITERATIONS=3000 # iterations per worker export PGPORT PGDATABASE PGUSER echo "=== BUG #19520 reproducer ===" echo "Port: $PGPORT | DDL workers: $N_DDL | CALL workers: $N_CALL" echo "Iterations per worker: $ITERATIONS" echo "" # Verify the server is reachable if ! psql -Xc "SELECT 1" > /dev/null 2>&1; then echo "ERROR: Cannot connect to PostgreSQL on port $PGPORT." echo "Make sure the server is running with:" echo " track_functions = 'all' (or 'pl')" exit 1 fi # Check track_functions setting TF=$(psql -XtAc "SHOW track_functions") if [ "$TF" = "none" ]; then echo "ERROR: track_functions = 'none'. Must be 'pl' or 'all'." exit 1 fi echo "track_functions = '$TF'" # Create the initial procedure psql -Xc "CREATE OR REPLACE PROCEDURE proc_race_test() LANGUAGE plpgsql AS \$\$ BEGIN END; \$\$;" 2>/dev/null || true PIDS=() # Generate a SQL script for DDL workers (persistent connection, tight loop) DDL_SQL=$(mktemp) for j in $(seq 1 $ITERATIONS); do cat >> "$DDL_SQL" <<'EOF' DROP PROCEDURE IF EXISTS proc_race_test; CREATE OR REPLACE PROCEDURE proc_race_test() LANGUAGE plpgsql AS $$ BEGIN END; $$; CALL proc_race_test(); EOF done # Generate a SQL script for CALL workers (persistent connection, tight loop) CALL_SQL=$(mktemp) for j in $(seq 1 $ITERATIONS); do echo "CALL proc_race_test();" >> "$CALL_SQL" done # Launch DDL workers using persistent psql sessions for i in $(seq 1 $N_DDL); do psql -X -f "$DDL_SQL" > /dev/null 2>&1 & PIDS+=($!) done # Launch CALL-only workers using persistent psql sessions for i in $(seq 1 $N_CALL); do psql -X -f "$CALL_SQL" > /dev/null 2>&1 & PIDS+=($!) done echo "Launched ${#PIDS[@]} background workers (persistent connections). Waiting..." echo "(On an unfixed build the server will PANIC; on a fixed build it survives.)" echo "" # Wait for all workers for pid in "${PIDS[@]}"; do wait "$pid" 2>/dev/null || true done # Cleanup temp files rm -f "$DDL_SQL" "$CALL_SQL" echo "" echo "All workers finished." # Check if the server is still alive if psql -Xc "SELECT 1" > /dev/null 2>&1; then echo "PASS: Server is still running - no PANIC occurred." exit 0 else echo "FAIL: Server is down - likely hit the PANIC." echo "Check the server log for:" echo ' PANIC: cannot abort transaction xxx, it was already committed' exit 1 fi