From 7d5300853b402bb1f50ba1d8ea95f39f7057b989 Mon Sep 17 00:00:00 2001 From: yukkop Date: Thu, 30 Apr 2026 12:16:09 +0000 Subject: [PATCH] fix(`db-tool`): `postgres-init`: createdb on reuse when target DB missing Previously when PG_REUSE=1 and PG_VERSION existed but the target database had never been successfully created (e.g. devshell exited mid-init in a prior run), postgres-init skipped createdb and the subsequent psql connection failed with 'database "" does not exist'. Now on reuse path we probe pg_database and create the target DB if missing, making postgres-init fully idempotent across stale-state recovery. Adds postgres-init-reuse-missing-db test. --- package/db-tool/postgres-init.sh | 8 +++- .../postgres-init-reuse-missing-db/run.sh | 45 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 test/package/db-tool/test/postgresql/postgres-init-reuse-missing-db/run.sh diff --git a/package/db-tool/postgres-init.sh b/package/db-tool/postgres-init.sh index f47a84a..d0074b9 100644 --- a/package/db-tool/postgres-init.sh +++ b/package/db-tool/postgres-init.sh @@ -39,7 +39,13 @@ postgres_init_main() { pg_ctl -D "$data" -o "-F" -w start || return 2 user="$(id -un)" || return 1 - if [ "$PG_REUSE" -eq 0 ]; then createdb -h "$sockdir" -U "$user" "$db" || return 1; fi + if [ "$PG_REUSE" -eq 0 ]; then + createdb -h "$sockdir" -U "$user" "$db" || return 1 + else + if ! psql -h "$sockdir" -p "$PG_PORT" -U "$user" -d postgres -tAc "select 1 from pg_database where datname = '$db'" 2>/dev/null | grep -q '^1$'; then + createdb -h "$sockdir" -U "$user" "$db" || return 1 + fi + fi psql -h "$sockdir" -p "$PG_PORT" -d "$db" -v ON_ERROR_STOP=1 -c 'select 1;' || return 1 export POSTGRESQL_HOST="$sockdir" POSTGRESQL_PORT="$PG_PORT" POSTGRESQL_USER="$user" POSTGRESQL_DATABASE="$db" diff --git a/test/package/db-tool/test/postgresql/postgres-init-reuse-missing-db/run.sh b/test/package/db-tool/test/postgresql/postgres-init-reuse-missing-db/run.sh new file mode 100644 index 0000000..1a41986 --- /dev/null +++ b/test/package/db-tool/test/postgresql/postgres-init-reuse-missing-db/run.sh @@ -0,0 +1,45 @@ +# shellcheck shell=dash + +HECTIC_NAMESPACE=test-db-tool-postgres-init-reuse-missing-db + +PG_WORKING_DIR=$(mktemp -d) +export PG_WORKING_DIR PG_DATABASE=testdb PG_PORT=5432 PG_SHARED_PRELOAD_LIBRARIES='' + +cleanup() { + postgres-cleanup >/dev/null 2>&1 || : + rm -rf "$PG_WORKING_DIR" +} +trap 'cleanup' EXIT INT TERM + +log notice "step 1: fresh init creates testdb" +if ! postgres-init; then + log error "initial postgres-init failed" + exit 1 +fi + +log notice "step 2: drop testdb to simulate stale-state cluster" +sockdir="$PG_WORKING_DIR/sock" +if ! dropdb -h "$sockdir" -p "$PG_PORT" -U "$(id -un)" testdb; then + log error "dropdb failed" + exit 1 +fi + +log notice "step 3: stop cluster (simulate prior devshell exit)" +postgres-cleanup >/dev/null 2>&1 || : + +log notice "step 4: re-init with PG_REUSE=1 must recreate missing testdb" +export PG_REUSE=1 +if ! postgres-init; then + log error "postgres-init with PG_REUSE=1 and missing DB failed" + exit 1 +fi +unset PG_REUSE + +log notice "step 5: verify testdb is reachable" +pgurl="postgresql://$(id -un)@/testdb?host=${sockdir}&port=5432" +if ! psql "$pgurl" -c 'SELECT 1;' >/dev/null 2>&1; then + log error "testdb not reachable after reuse-create" + exit 1 +fi + +log notice "test passed"