Hi hackers, Attached is a patch that adds --exclude-database (-D) to vacuumdb, allowing users to skip specific databases when using --all.
Motivation
----------
"vacuumdb --all" vacuums every connectable database without exception.
In production environments, operators often need to skip certain databases
during maintenance — for example, test databases, large inactive databases
with historical data.
The current workaround is to manually vacuum each database
individually or write wrapper scripts.
Usage
-----
vacuumdb --all --exclude-database=test_db
vacuumdb --all -D db1 -D db2 -D db3
The option requires --all
Testing
-------
The patch passes all existing vacuumdb TAP tests (100_vacuumdb,
101_vacuumdb_all, 102_vacuumdb_stages) and includes 4 new TAP tests
in 101_vacuumdb_all.pl covering exclusion, multiple exclusions, and
error cases.
I've also attached a standalone test script (test_exclude_database.sh)
that exercises the feature with 11 test scenarios:
1. Single database exclusion
2. Multiple database exclusions (-D db1 -D db2)
3. Exclude all databases
4. Exclude non-existent database (silently ignored)
5. Exclude maintenance database (postgres)
6. Case sensitivity (exact case excludes, wrong case does not)
7. --exclude-database without --all (error)
8. --exclude-database with -d (error)
9. SQL injection protection
10. --help output
11. -d with -D and --all (conflicting options error)
All tests pass. The test script is portable — it uses standard libpq
environment variables and auto-detects binaries. Test output is also
attached (test_exclude_database_results.txt).
--
Mohamed Ali
AWS RDS
============================================================
VACUUMDB --exclude-database FEATURE TEST SUITE
============================================================
Date: Thu May 14 22:48:56 PDT 2026
PostgreSQL: PostgreSQL 19devel on aarch64-darwin, compiled by clang-21.0.0,
64-bit
vacuumdb: vacuumdb (PostgreSQL) 19devel
Available databases:
postgres
template1
test_db1
test_db2
test_db3
================================================================
TEST 1: Single database exclusion
================================================================
Description: Exclude test_db1 from vacuum --all. Expected: exit 0, test_db1
skipped, other dbs vacuumed.
Command: /Users/mmohali/Kiro_projects/vacuumdb/pghome/bin/vacuumdb --all
--exclude-database=test_db1
Expected: pass
---
Exit Code: 0
Output:
vacuumdb: vacuuming database "postgres"
vacuumdb: vacuuming database "template1"
vacuumdb: vacuuming database "test_db2"
vacuumdb: vacuuming database "test_db3"
---
RESULT: ✅ PASS
✅ 'vacuuming database "test_db1"' correctly absent from output
✅ All other databases vacuumed (4/4)
================================================================
TEST 2: Multiple database exclusions (-D db1 -D db2)
================================================================
Description: Exclude test_db1 and test_db2. Expected: exit 0, both excluded,
test_db3 still vacuumed.
Command: /Users/mmohali/Kiro_projects/vacuumdb/pghome/bin/vacuumdb --all -D
test_db1 -D test_db2
Expected: pass
---
Exit Code: 0
Output:
vacuumdb: vacuuming database "postgres"
vacuumdb: vacuuming database "template1"
vacuumdb: vacuuming database "test_db3"
---
RESULT: ✅ PASS
✅ 'vacuuming database "test_db1"' correctly absent from output
✅ 'vacuuming database "test_db2"' correctly absent from output
✅ 'vacuuming database "test_db3"' found in output
================================================================
TEST 3: Exclude ALL databases (edge case)
================================================================
Description: Exclude every connectable database. Expected: exit 0, no vacuum
ops, graceful no-op.
Command: /Users/mmohali/Kiro_projects/vacuumdb/pghome/bin/vacuumdb --all -D
postgres -D test_db1 -D template1 -D test_db2 -D test_db3
Expected: pass
---
Exit Code: 0
Output:
---
RESULT: ✅ PASS
================================================================
TEST 4: Exclude non-existent database
================================================================
Description: Exclude a name that doesn't exist. Expected: exit 0, silently
ignored, all real dbs vacuumed.
Command: /Users/mmohali/Kiro_projects/vacuumdb/pghome/bin/vacuumdb --all
--exclude-database=this_db_does_not_exist_xyz
Expected: pass
---
Exit Code: 0
Output:
vacuumdb: vacuuming database "postgres"
vacuumdb: vacuuming database "template1"
vacuumdb: vacuuming database "test_db1"
vacuumdb: vacuuming database "test_db2"
vacuumdb: vacuuming database "test_db3"
---
RESULT: ✅ PASS
✅ 'vacuuming database "postgres"' found in output
================================================================
TEST 5: Exclude maintenance database (postgres)
================================================================
Description: Exclude postgres (used for listing). Expected: exit 0, postgres
skipped, others vacuumed.
Command: /Users/mmohali/Kiro_projects/vacuumdb/pghome/bin/vacuumdb --all
--exclude-database=postgres
Expected: pass
---
Exit Code: 0
Output:
vacuumdb: vacuuming database "template1"
vacuumdb: vacuuming database "test_db1"
vacuumdb: vacuuming database "test_db2"
vacuumdb: vacuuming database "test_db3"
---
RESULT: ✅ PASS
✅ 'vacuuming database "postgres"' correctly absent from output
✅ All other databases vacuumed (4/4)
================================================================
TEST 6: Case sensitivity - exact case excludes MixedCaseDB
================================================================
Description: TEST 6.1: Exclude MixedCaseDB with exact case. Expected: exit 0,
MixedCaseDB NOT vacuumed.
Command: /Users/mmohali/Kiro_projects/vacuumdb/pghome/bin/vacuumdb --all
--exclude-database=MixedCaseDB
Expected: pass
---
Exit Code: 0
Output:
vacuumdb: vacuuming database "postgres"
vacuumdb: vacuuming database "template1"
vacuumdb: vacuuming database "test_db1"
vacuumdb: vacuuming database "test_db2"
vacuumdb: vacuuming database "test_db3"
---
RESULT: ✅ PASS
✅ 'vacuuming database "MixedCaseDB"' correctly absent from output
----------------------------------------------------------------
TEST 6.2: Case sensitivity - wrong case does NOT exclude
----------------------------------------------------------------
Description: Exclude with wrong case 'mixedcasedb'. Expected: MixedCaseDB IS
vacuumed.
Command: /Users/mmohali/Kiro_projects/vacuumdb/pghome/bin/vacuumdb --all
--exclude-database=mixedcasedb
---
Exit Code: 0
Output:
vacuumdb: vacuuming database "MixedCaseDB"
vacuumdb: vacuuming database "postgres"
vacuumdb: vacuuming database "template1"
vacuumdb: vacuuming database "test_db1"
vacuumdb: vacuuming database "test_db2"
vacuumdb: vacuuming database "test_db3"
---
RESULT: ✅ PASS (MixedCaseDB was vacuumed — wrong case did not exclude it)
================================================================
TEST 7: --exclude-database without --all (must fail)
================================================================
Description: Use -D without --all. Expected: non-zero exit, error: cannot use
--exclude-database without --all.
Command: /Users/mmohali/Kiro_projects/vacuumdb/pghome/bin/vacuumdb -D test_db1
Expected: fail
---
Exit Code: 1
Output:
vacuumdb: error: cannot use --exclude-database without --all option
---
RESULT: ✅ PASS (correctly failed)
✅ Correct error message: 'cannot use --exclude-database without --all'
================================================================
TEST 8: --exclude-database with -d (must fail)
================================================================
Description: Use -D with -d. Expected: non-zero exit, -D requires --all but -d
conflicts with --all.
Command: /Users/mmohali/Kiro_projects/vacuumdb/pghome/bin/vacuumdb -d postgres
-D test_db1
Expected: fail
---
Exit Code: 1
Output:
vacuumdb: error: cannot use --exclude-database without --all option
---
RESULT: ✅ PASS (correctly failed)
================================================================
TEST 9: SQL injection attempt in database name
================================================================
Description: Inject SQL via -D value. Expected: exit 0, safely escaped, no
injection, all dbs vacuumed.
Command: /Users/mmohali/Kiro_projects/vacuumdb/pghome/bin/vacuumdb --all
--exclude-database="'; DROP TABLE pg_class; --"
Expected: pass
---
Exit Code: 0
Output:
vacuumdb: vacuuming database "MixedCaseDB"
vacuumdb: vacuuming database "postgres"
vacuumdb: vacuuming database "template1"
vacuumdb: vacuuming database "test_db1"
vacuumdb: vacuuming database "test_db2"
vacuumdb: vacuuming database "test_db3"
---
RESULT: ✅ PASS
================================================================
TEST 10: --help shows --exclude-database
================================================================
Description: Run vacuumdb --help and check output.
Expected: Output contains '-D, --exclude-database=DBNAME'
---
Output:
vacuumdb cleans and analyzes a PostgreSQL database.
Usage:
vacuumdb [OPTION]... [DBNAME]
Options:
-a, --all vacuum all databases
--buffer-usage-limit=SIZE size of ring buffer used for vacuum
-d, --dbname=DBNAME database to vacuum
-D, --exclude-database=DBNAME exclude database from --all operation
--disable-page-skipping disable all page-skipping behavior
--dry-run show the commands that would be sent to the
server
-e, --echo show the commands being sent to the server
-f, --full do full vacuuming
-F, --freeze freeze row transaction information
--force-index-cleanup always remove index entries that point to
dead tuples
-j, --jobs=NUM use this many concurrent connections to vacuum
--min-mxid-age=MXID_AGE minimum multixact ID age of tables to vacuum
--min-xid-age=XID_AGE minimum transaction ID age of tables to vacuum
--missing-stats-only only analyze relations with missing statistics
--no-index-cleanup don't remove index entries that point to dead
tuples
--no-process-main skip the main relation
--no-process-toast skip the TOAST table associated with the
table to vacuum
--no-truncate don't truncate empty pages at the end of the
table
-n, --schema=SCHEMA vacuum tables in the specified schema(s) only
-N, --exclude-schema=SCHEMA do not vacuum tables in the specified
schema(s)
-P, --parallel=PARALLEL_WORKERS use this many background workers for vacuum,
if available
-q, --quiet don't write any messages
--skip-locked skip relations that cannot be immediately
locked
-t, --table='TABLE[(COLUMNS)]' vacuum specific table(s) only
-v, --verbose write a lot of output
-V, --version output version information, then exit
-z, --analyze update optimizer statistics
-Z, --analyze-only only update optimizer statistics; no vacuum
--analyze-in-stages only update optimizer statistics, in multiple
stages for faster results; no vacuum
-?, --help show this help, then exit
Connection options:
-h, --host=HOSTNAME database server host or socket directory
-p, --port=PORT database server port
-U, --username=USERNAME user name to connect as
-w, --no-password never prompt for password
-W, --password force password prompt
--maintenance-db=DBNAME alternate maintenance database
Read the description of the SQL command VACUUM for details.
Report bugs to <[email protected]>.
PostgreSQL home page: <https://www.postgresql.org/>
---
RESULT: ✅ PASS
================================================================
TEST 11: -d with -D and --all (must fail)
================================================================
Description: Use -d postgres -D test_db1 --all. Expected: non-zero exit, -d and
--all conflict.
Command: /Users/mmohali/Kiro_projects/vacuumdb/pghome/bin/vacuumdb -d postgres
-D test_db1 --all
Expected: fail
---
Exit Code: 1
Output:
vacuumdb: error: cannot vacuum all databases and a specific one at the same time
---
RESULT: ✅ PASS (correctly failed)
============================================================
TEST SUMMARY
============================================================
Total checks: 22
Passed: 22
Failed: 0
ALL TESTS PASSED
Results saved to: ./test_exclude_database_results.txt
#!/bin/bash
#
# Test script for vacuumdb --exclude-database feature
# Patch: "Add --exclude-database option to vacuumdb"
#
# Prerequisites:
# - PostgreSQL built with the --exclude-database patch applied
# - A running PostgreSQL instance (initdb + pg_ctl start)
# - vacuumdb and psql in PATH (or specify with PGBIN)
#
# Usage:
# ./test_exclude_database.sh # uses standard PG env vars
# PGBIN=/path/to/bin ./test_exclude_database.sh # custom binary path
#
# The script uses standard libpq environment variables (PGPORT, PGUSER,
# PGHOST, etc.) — same as psql, vacuumdb, and other PG tools.
# Set them before running if your instance uses non-default values.
#
# Optional:
# PGBIN - Path to PostgreSQL bin directory (default: uses PATH)
# OUTFILE - Output file path (default: ./test_exclude_database_results.txt)
#
# The script will:
# 1. Create test databases (test_db1, test_db2, test_db3) if they don't exist
# 2. Run 11 tests covering the --exclude-database feature
# 3. Clean up (drops MixedCaseDB if created, keeps test_db1/2/3)
# 4. Write detailed results to OUTFILE
#
# ============================================================
# TEST PLAN — Description & Expected Results
# ============================================================
#
# TEST 1: Single database exclusion
# Description: Run "vacuumdb --all --exclude-database=test_db1".
# Verifies the basic functionality of excluding one
# database from a vacuum --all operation.
# Expected: Exit code 0. test_db1 is NOT vacuumed.
# All other connectable databases ARE vacuumed.
#
# TEST 2: Multiple database exclusions
# Description: Run "vacuumdb --all -D test_db1 -D test_db2".
# Verifies that the -D option can be specified multiple
# times to exclude more than one database.
# Expected: Exit code 0. test_db1 and test_db2 are NOT vacuumed.
# test_db3 and other databases ARE vacuumed.
#
# TEST 3: Exclude ALL databases (edge case)
# Description: Run "vacuumdb --all -D <every connectable database>".
# Tests the edge case where every database is excluded,
# leaving nothing to vacuum.
# Expected: Exit code 0. No vacuum operations occur.
# The command handles this gracefully without crashing.
#
# TEST 4: Exclude non-existent database
# Description: Run "vacuumdb --all --exclude-database=nonexistent_db".
# Tests that specifying a database name that doesn't exist
# in pg_database is silently ignored.
# Expected: Exit code 0. All real databases are vacuumed normally.
#
# TEST 5: Exclude maintenance database (postgres)
# Description: Run "vacuumdb --all --exclude-database=postgres".
# Tests that the maintenance database itself can be excluded.
# vacuumdb connects to postgres to retrieve the database list,
# but should then skip it during the vacuum phase.
# Expected: Exit code 0. postgres is NOT vacuumed.
# Other databases ARE vacuumed.
#
# TEST 6.1: Case sensitivity - exact case excludes
# Description: Create "MixedCaseDB", then exclude with exact case.
# Expected: Exit code 0. MixedCaseDB is NOT vacuumed.
#
# TEST 6.2: Case sensitivity - wrong case does NOT exclude
# Description: Exclude with wrong case "mixedcasedb".
# Expected: Exit code 0. MixedCaseDB IS vacuumed (case mismatch).
#
# TEST 7: --exclude-database without --all (error case)
# Description: Run "vacuumdb -D test_db1" without --all.
# Expected: Non-zero exit code. Error message:
# "cannot use --exclude-database without --all option"
#
# TEST 8: --exclude-database with -d (error case)
# Description: Run "vacuumdb -d postgres -D test_db1".
# Expected: Non-zero exit code (conflicting options).
#
# TEST 9: SQL injection protection
# Description: Pass a SQL injection attempt as the database name.
# Expected: Exit code 0. Safely escaped, all databases vacuumed.
#
# TEST 10: --help shows the new option
# Description: Run "vacuumdb --help" and check the output.
# Expected: Output contains "-D, --exclude-database=DBNAME".
#
# TEST 11: -d with -D and --all (conflicting options)
# Description: Run "vacuumdb -d postgres -D test_db1 --all".
# Expected: Non-zero exit code (-d and --all conflict).
#
# ============================================================
set -o pipefail
# ============================================================
# Configuration
# ============================================================
OUTFILE="${OUTFILE:-./test_exclude_database_results.txt}"
# Determine binary paths
if [ -n "$PGBIN" ]; then
VACUUMDB="$PGBIN/vacuumdb"
PSQL="$PGBIN/psql"
else
VACUUMDB="$(command -v vacuumdb)"
PSQL="$(command -v psql)"
fi
# Validate binaries exist
if [ ! -x "$VACUUMDB" ]; then
echo "ERROR: vacuumdb not found. Set PGBIN or add to PATH."
echo " PGBIN=/path/to/pg/bin ./test_exclude_database.sh"
exit 1
fi
if [ ! -x "$PSQL" ]; then
echo "ERROR: psql not found. Set PGBIN or add to PATH."
exit 1
fi
# Verify connection works
if ! $PSQL -d postgres -c "SELECT 1" >/dev/null 2>&1; then
echo "ERROR: Cannot connect to PostgreSQL."
echo " Make sure PostgreSQL is running and standard PG env vars are set."
echo " Example: PGPORT=5433 PGUSER=myuser ./test_exclude_database.sh"
exit 1
fi
# Verify --exclude-database option exists
if ! $VACUUMDB --help 2>&1 | grep -q "exclude-database"; then
echo "ERROR: vacuumdb does not support --exclude-database."
echo " Make sure the patch is applied and vacuumdb is rebuilt."
exit 1
fi
# ============================================================
# Test framework
# ============================================================
PASS_COUNT=0
FAIL_COUNT=0
TOTAL_COUNT=0
TEST_NUM=0
log() {
echo "$1" | tee -a "$OUTFILE"
}
run_test() {
local test_name="$1"
local expected_result="$2" # "pass" or "fail"
local description="$3"
shift 3
local cmd="$@"
TEST_NUM=$((TEST_NUM + 1))
TOTAL_COUNT=$((TOTAL_COUNT + 1))
log ""
log "================================================================"
log "TEST $TEST_NUM: $test_name"
log "================================================================"
log "Description: $description"
log "Command: $cmd"
log "Expected: $expected_result"
log "---"
LAST_OUTPUT=$(eval "$cmd" 2>&1)
LAST_EXIT_CODE=$?
log "Exit Code: $LAST_EXIT_CODE"
log "Output:"
log "$LAST_OUTPUT"
log "---"
if [ "$expected_result" = "pass" ]; then
if [ $LAST_EXIT_CODE -eq 0 ]; then
log "RESULT: ✅ PASS"
PASS_COUNT=$((PASS_COUNT + 1))
echo -e "${GREEN}✅ PASS${NC}: $test_name"
else
log "RESULT: ❌ FAIL (expected exit 0, got $LAST_EXIT_CODE)"
FAIL_COUNT=$((FAIL_COUNT + 1))
echo -e "${RED}❌ FAIL${NC}: $test_name"
fi
elif [ "$expected_result" = "fail" ]; then
if [ $LAST_EXIT_CODE -ne 0 ]; then
log "RESULT: ✅ PASS (correctly failed)"
PASS_COUNT=$((PASS_COUNT + 1))
echo -e "${GREEN}✅ PASS${NC}: $test_name"
else
log "RESULT: ❌ FAIL (expected non-zero exit, got 0)"
FAIL_COUNT=$((FAIL_COUNT + 1))
echo -e "${RED}❌ FAIL${NC}: $test_name"
fi
fi
}
check_output_contains() {
local test_name="$1"
local pattern="$2"
local output="$3"
TOTAL_COUNT=$((TOTAL_COUNT + 1))
if echo "$output" | grep -q "$pattern"; then
log " ✅ '$pattern' found in output"
PASS_COUNT=$((PASS_COUNT + 1))
echo -e "${GREEN} ✅${NC}: $test_name"
else
log " ❌ '$pattern' NOT found in output"
FAIL_COUNT=$((FAIL_COUNT + 1))
echo -e "${RED} ❌${NC}: $test_name"
fi
}
check_output_not_contains() {
local test_name="$1"
local pattern="$2"
local output="$3"
TOTAL_COUNT=$((TOTAL_COUNT + 1))
if echo "$output" | grep -q "$pattern"; then
log " ❌ '$pattern' found in output (should NOT be)"
FAIL_COUNT=$((FAIL_COUNT + 1))
echo -e "${RED} ❌${NC}: $test_name"
else
log " ✅ '$pattern' correctly absent from output"
PASS_COUNT=$((PASS_COUNT + 1))
echo -e "${GREEN} ✅${NC}: $test_name"
fi
}
# Colors (disabled if not a terminal)
if [ -t 1 ]; then
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
else
RED=''
GREEN=''
YELLOW=''
NC=''
fi
# ============================================================
# SETUP
# ============================================================
> "$OUTFILE"
log "============================================================"
log "VACUUMDB --exclude-database FEATURE TEST SUITE"
log "============================================================"
log "Date: $(date)"
log "PostgreSQL: $($PSQL -d postgres -t -c 'SELECT version();' | head -1 | xargs)"
log "vacuumdb: $($VACUUMDB --version)"
log ""
# Create test databases if they don't exist
for db in test_db1 test_db2 test_db3; do
$PSQL -d postgres -t -c \
"SELECT 1 FROM pg_database WHERE datname='$db'" | grep -q 1 || \
$PSQL -d postgres -c "CREATE DATABASE $db;" 2>/dev/null
done
log "Available databases:"
$PSQL -d postgres -t -c \
"SELECT datname FROM pg_database WHERE datallowconn AND datconnlimit <> -2 ORDER BY 1;" | tee -a "$OUTFILE"
log ""
# ============================================================
# TEST 1: Single database exclusion
# ============================================================
run_test "Single database exclusion" "pass" \
"Exclude test_db1 from vacuum --all. Expected: exit 0, test_db1 skipped, other dbs vacuumed." \
"$VACUUMDB --all --exclude-database=test_db1"
check_output_not_contains "1.1: test_db1 NOT vacuumed" 'vacuuming database "test_db1"' "$LAST_OUTPUT"
# Verify all other databases were vacuumed
TOTAL_COUNT=$((TOTAL_COUNT + 1))
VACUUMED_COUNT=$(echo "$LAST_OUTPUT" | grep -c 'vacuuming database' || true)
TOTAL_DBS=$($PSQL -d postgres -t -c \
"SELECT count(*) FROM pg_database WHERE datallowconn AND datconnlimit <> -2;" | tr -d ' ')
EXPECTED_COUNT=$((TOTAL_DBS - 1))
if [ "$VACUUMED_COUNT" -eq "$EXPECTED_COUNT" ]; then
log " ✅ All other databases vacuumed ($VACUUMED_COUNT/$EXPECTED_COUNT)"
PASS_COUNT=$((PASS_COUNT + 1))
echo -e "${GREEN} ✅${NC}: 1.2: All other databases vacuumed ($VACUUMED_COUNT/$EXPECTED_COUNT)"
else
log " ❌ Expected $EXPECTED_COUNT databases vacuumed, got $VACUUMED_COUNT"
FAIL_COUNT=$((FAIL_COUNT + 1))
echo -e "${RED} ❌${NC}: 1.2: Expected $EXPECTED_COUNT databases vacuumed, got $VACUUMED_COUNT"
fi
# ============================================================
# TEST 2: Multiple database exclusions
# ============================================================
run_test "Multiple database exclusions (-D db1 -D db2)" "pass" \
"Exclude test_db1 and test_db2. Expected: exit 0, both excluded, test_db3 still vacuumed." \
"$VACUUMDB --all -D test_db1 -D test_db2"
check_output_not_contains "2.1: test_db1 excluded" 'vacuuming database "test_db1"' "$LAST_OUTPUT"
check_output_not_contains "2.2: test_db2 excluded" 'vacuuming database "test_db2"' "$LAST_OUTPUT"
check_output_contains "2.3: test_db3 still vacuumed" 'vacuuming database "test_db3"' "$LAST_OUTPUT"
# ============================================================
# TEST 3: Exclude all databases (edge case)
# ============================================================
ALL_DBS=$($PSQL -d postgres -t -c \
"SELECT datname FROM pg_database WHERE datallowconn AND datconnlimit <> -2;" | tr -d ' ' | grep -v '^$')
EXCLUDE_ARGS=""
for db in $ALL_DBS; do
EXCLUDE_ARGS="$EXCLUDE_ARGS -D $db"
done
run_test "Exclude ALL databases (edge case)" "pass" \
"Exclude every connectable database. Expected: exit 0, no vacuum ops, graceful no-op." \
"$VACUUMDB --all $EXCLUDE_ARGS"
# ============================================================
# TEST 4: Exclude non-existent database
# ============================================================
run_test "Exclude non-existent database" "pass" \
"Exclude a name that doesn't exist. Expected: exit 0, silently ignored, all real dbs vacuumed." \
"$VACUUMDB --all --exclude-database=this_db_does_not_exist_xyz"
check_output_contains "4.1: postgres still vacuumed" 'vacuuming database "postgres"' "$LAST_OUTPUT"
# ============================================================
# TEST 5: Exclude maintenance database (postgres)
# ============================================================
run_test "Exclude maintenance database (postgres)" "pass" \
"Exclude postgres (used for listing). Expected: exit 0, postgres skipped, others vacuumed." \
"$VACUUMDB --all --exclude-database=postgres"
check_output_not_contains "5.1: postgres NOT vacuumed" 'vacuuming database "postgres"' "$LAST_OUTPUT"
# Verify all other databases were vacuumed
TOTAL_COUNT=$((TOTAL_COUNT + 1))
VACUUMED_COUNT=$(echo "$LAST_OUTPUT" | grep -c 'vacuuming database' || true)
EXPECTED_COUNT=$((TOTAL_DBS - 1))
if [ "$VACUUMED_COUNT" -eq "$EXPECTED_COUNT" ]; then
log " ✅ All other databases vacuumed ($VACUUMED_COUNT/$EXPECTED_COUNT)"
PASS_COUNT=$((PASS_COUNT + 1))
echo -e "${GREEN} ✅${NC}: 5.2: All other databases vacuumed ($VACUUMED_COUNT/$EXPECTED_COUNT)"
else
log " ❌ Expected $EXPECTED_COUNT databases vacuumed, got $VACUUMED_COUNT"
FAIL_COUNT=$((FAIL_COUNT + 1))
echo -e "${RED} ❌${NC}: 5.2: Expected $EXPECTED_COUNT databases vacuumed, got $VACUUMED_COUNT"
fi
# ============================================================
# TEST 6: Case sensitivity
# ============================================================
$PSQL -d postgres -c 'CREATE DATABASE "MixedCaseDB";' 2>/dev/null
# --- TEST 6.1: Exact case should exclude ---
run_test "Case sensitivity - exact case excludes MixedCaseDB" "pass" \
"TEST 6.1: Exclude MixedCaseDB with exact case. Expected: exit 0, MixedCaseDB NOT vacuumed." \
"$VACUUMDB --all --exclude-database=MixedCaseDB"
check_output_not_contains "6.1: MixedCaseDB excluded (exact case)" 'vacuuming database "MixedCaseDB"' "$LAST_OUTPUT"
# --- TEST 6.2: Wrong case should NOT exclude ---
log ""
log "----------------------------------------------------------------"
log "TEST 6.2: Case sensitivity - wrong case does NOT exclude"
log "----------------------------------------------------------------"
log "Description: Exclude with wrong case 'mixedcasedb'. Expected: MixedCaseDB IS vacuumed."
log "Command: $VACUUMDB --all --exclude-database=mixedcasedb"
log "---"
OUTPUT=$($VACUUMDB --all --exclude-database=mixedcasedb 2>&1)
log "Exit Code: $?"
log "Output:"
log "$OUTPUT"
log "---"
TOTAL_COUNT=$((TOTAL_COUNT + 1))
if echo "$OUTPUT" | grep -q 'vacuuming database "MixedCaseDB"'; then
log "RESULT: ✅ PASS (MixedCaseDB was vacuumed — wrong case did not exclude it)"
PASS_COUNT=$((PASS_COUNT + 1))
echo -e "${GREEN}✅ PASS${NC}: 6.2: MixedCaseDB IS vacuumed (wrong case doesn't match)"
else
log "RESULT: ❌ FAIL (MixedCaseDB was excluded by wrong case — should not happen)"
FAIL_COUNT=$((FAIL_COUNT + 1))
echo -e "${RED}❌ FAIL${NC}: 6.2: MixedCaseDB was incorrectly excluded by wrong case"
fi
# ============================================================
# TEST 7: --exclude-database without --all (error case)
# ============================================================
run_test "--exclude-database without --all (must fail)" "fail" \
"Use -D without --all. Expected: non-zero exit, error: cannot use --exclude-database without --all." \
"$VACUUMDB -D test_db1"
# Verify error message
TOTAL_COUNT=$((TOTAL_COUNT + 1))
if echo "$LAST_OUTPUT" | grep -q "cannot use --exclude-database without --all"; then
log " ✅ Correct error message: 'cannot use --exclude-database without --all'"
PASS_COUNT=$((PASS_COUNT + 1))
echo -e "${GREEN} ✅${NC}: 7.1: Correct error message"
else
log " ❌ Error message missing or wrong"
log " Got: $LAST_OUTPUT"
FAIL_COUNT=$((FAIL_COUNT + 1))
echo -e "${RED} ❌${NC}: 7.1: Error message missing or wrong"
fi
# ============================================================
# TEST 8: --exclude-database with -d (error case)
# ============================================================
run_test "--exclude-database with -d (must fail)" "fail" \
"Use -D with -d. Expected: non-zero exit, -D requires --all but -d conflicts with --all." \
"$VACUUMDB -d postgres -D test_db1"
# ============================================================
# TEST 9: SQL injection protection
# ============================================================
run_test "SQL injection attempt in database name" "pass" \
"Inject SQL via -D value. Expected: exit 0, safely escaped, no injection, all dbs vacuumed." \
"$VACUUMDB --all --exclude-database=\"'; DROP TABLE pg_class; --\""
# ============================================================
# TEST 10: --help shows the new option
# ============================================================
OUTPUT=$($VACUUMDB --help 2>&1)
TEST_NUM=$((TEST_NUM + 1))
TOTAL_COUNT=$((TOTAL_COUNT + 1))
log ""
log "================================================================"
log "TEST $TEST_NUM: --help shows --exclude-database"
log "================================================================"
log "Description: Run vacuumdb --help and check output."
log "Expected: Output contains '-D, --exclude-database=DBNAME'"
log "---"
log "Output:"
log "$OUTPUT"
log "---"
if echo "$OUTPUT" | grep -q "\-D.*--exclude-database"; then
log "RESULT: ✅ PASS"
PASS_COUNT=$((PASS_COUNT + 1))
echo -e "${GREEN}✅ PASS${NC}: --help shows --exclude-database"
else
log "RESULT: ❌ FAIL"
FAIL_COUNT=$((FAIL_COUNT + 1))
echo -e "${RED}❌ FAIL${NC}: --help shows --exclude-database"
fi
# ============================================================
# TEST 11: -d with -D and --all (conflicting options)
# ============================================================
run_test "-d with -D and --all (must fail)" "fail" \
"Use -d postgres -D test_db1 --all. Expected: non-zero exit, -d and --all conflict." \
"$VACUUMDB -d postgres -D test_db1 --all"
# ============================================================
# CLEANUP
# ============================================================
$PSQL -d postgres -c 'DROP DATABASE IF EXISTS "MixedCaseDB";' 2>/dev/null
# ============================================================
# SUMMARY
# ============================================================
log ""
log "============================================================"
log "TEST SUMMARY"
log "============================================================"
log "Total checks: $TOTAL_COUNT"
log "Passed: $PASS_COUNT"
log "Failed: $FAIL_COUNT"
log ""
if [ $FAIL_COUNT -eq 0 ]; then
log "ALL TESTS PASSED"
echo -e "\n${GREEN}ALL TESTS PASSED ($PASS_COUNT/$TOTAL_COUNT)${NC}"
else
log "SOME TESTS FAILED"
echo -e "\n${YELLOW}$FAIL_COUNT TESTS FAILED ($PASS_COUNT/$TOTAL_COUNT passed)${NC}"
fi
log ""
log "Results saved to: $OUTFILE"
echo ""
echo "Full results saved to: $OUTFILE"
v1-0001-vacuumdb-Add-exclude-database-option-to-skip-data.patch
Description: Binary data
