mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
feat(self-hosted): change the default db version to postgres 17 (#46981)
This commit is contained in:
1 parent
c9b8768940
commit
6cf174b925
6 files changed
+204
-37
No files matched your search
@@ -0,0 +1,18 @@
|
||||
# Postgres 15 override for self-hosted Supabase.
|
||||
#
|
||||
# Postgres 17 is now the default in docker-compose.yml. Use this override to pin
|
||||
# Postgres 15, for two cases:
|
||||
# 1. An existing Postgres 15 deployment that has not been upgraded yet.
|
||||
# 2. As the rollback target for utils/upgrade-pg17.sh (PG 15 and PG 17 use
|
||||
# different postgres UIDs, so rollback must start with the PG 15 image).
|
||||
#
|
||||
# Usage:
|
||||
# docker compose -f docker-compose.yml -f docker-compose.pg15.yml up -d
|
||||
#
|
||||
# To upgrade an existing Postgres 15 database to Postgres 17 in place, see:
|
||||
# - https://supabase.com/docs/guides/self-hosting/postgres-upgrade-17
|
||||
# - utils/upgrade-pg17.sh
|
||||
|
||||
services:
|
||||
db:
|
||||
image: supabase/postgres:15.8.1.085
|
||||
@@ -1,5 +1,9 @@
|
||||
# Postgres 17 override for self-hosted Supabase.
|
||||
#
|
||||
# NOTE: Postgres 17 is now the default in docker-compose.yml, so this override
|
||||
# is redundant for new installs (kept for explicitness / backwards compatibility).
|
||||
# Keep the image tag here in sync with the db image in docker-compose.yml.
|
||||
#
|
||||
# Usage (new install or after upgrade):
|
||||
# docker compose -f docker-compose.yml -f docker-compose.pg17.yml up -d
|
||||
#
|
||||
@@ -12,4 +16,4 @@
|
||||
|
||||
services:
|
||||
db:
|
||||
image: supabase/postgres:17.6.1.084
|
||||
image: supabase/postgres:17.6.1.136
|
||||
@@ -474,7 +474,8 @@ services:
|
||||
# Comment out everything below this point if you are using an external Postgres database
|
||||
db:
|
||||
container_name: supabase-db
|
||||
image: supabase/postgres:15.8.1.085
|
||||
# To upgrade an existing Postgres 15 database in place, see utils/upgrade-pg17.sh.
|
||||
image: supabase/postgres:17.6.1.136
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./volumes/db/realtime.sql:/docker-entrypoint-initdb.d/migrations/99-realtime.sql:Z
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
# sudo bash tests/test-pg17-upgrade.sh
|
||||
#
|
||||
# Prerequisites:
|
||||
# - Running self-hosted Supabase with a clean, tests-only Postgres 15:
|
||||
# docker compose up -d
|
||||
# - Running self-hosted Supabase with a clean, tests-only Postgres 15.
|
||||
# Postgres 17 is now the default, so start PG 15 explicitly via the override:
|
||||
# docker compose -f docker-compose.yml -f docker-compose.pg15.yml up -d
|
||||
# - .env file with POSTGRES_PASSWORD, ANON_KEY
|
||||
#
|
||||
|
||||
@@ -48,7 +49,7 @@ echo ""
|
||||
current_version=$(run_sql -A -t -c "SHOW server_version;" | head -1)
|
||||
case "$current_version" in
|
||||
15.*) echo "Starting version: PostgreSQL $current_version" ;;
|
||||
17.*) echo "Error: Already on Postgres 17. Start with a PG15 stack."; exit 1 ;;
|
||||
17.*) echo "Error: Already on Postgres 17. Start with a PG 15 stack."; exit 1 ;;
|
||||
*) echo "Error: Unexpected version: $current_version"; exit 1 ;;
|
||||
esac
|
||||
|
||||
@@ -88,6 +89,21 @@ $$;
|
||||
|
||||
-- Grant access so PostgREST can read it
|
||||
GRANT SELECT ON public._upgrade_test TO anon, authenticated;
|
||||
|
||||
-- pg_cron: created here as supabase_admin (the common manually-enabled case),
|
||||
-- so the extension is owned by supabase_admin, NOT postgres. complete.sh's
|
||||
-- drop+recreate only fires for postgres-owned pg_cron, so this exercises the
|
||||
-- version reconcile in the upgrade script: Supabase PG 15 registers pg_cron
|
||||
-- as '1.6', while the target image packages it as '1.6.4' with no update
|
||||
-- path between them.
|
||||
CREATE EXTENSION IF NOT EXISTS pg_cron;
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM cron.job WHERE jobname = 'upgrade_test_job') THEN
|
||||
PERFORM cron.unschedule('upgrade_test_job');
|
||||
END IF;
|
||||
END $$;
|
||||
SELECT cron.schedule('upgrade_test_job', '5 4 * * *', 'SELECT 1');
|
||||
EOSQL
|
||||
|
||||
pre_count=$(run_sql -A -t -c "SELECT count(*) FROM public._upgrade_test;" | tr -d '[:space:]')
|
||||
@@ -115,7 +131,7 @@ echo ""
|
||||
run_sql <<EOSQL
|
||||
CREATE EXTENSION IF NOT EXISTS pgtap;
|
||||
|
||||
SELECT plan(11);
|
||||
SELECT plan(16);
|
||||
|
||||
-- Version
|
||||
SELECT ok(version() LIKE 'PostgreSQL 17%', 'Running Postgres 17');
|
||||
@@ -169,6 +185,37 @@ SELECT ok(
|
||||
'postgres role is not superuser'
|
||||
);
|
||||
|
||||
-- pg_cron: registered as 1.6 on PG 15; the upgrade must reconcile the version
|
||||
-- label to the target's packaged 1.6.4 and preserve scheduled jobs.
|
||||
SELECT ok(
|
||||
EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'pg_cron'),
|
||||
'pg_cron extension exists'
|
||||
);
|
||||
SELECT is(
|
||||
(SELECT extversion FROM pg_extension WHERE extname = 'pg_cron'),
|
||||
'1.6.4',
|
||||
'pg_cron version label reconciled to 1.6.4'
|
||||
);
|
||||
SELECT ok(
|
||||
EXISTS (SELECT 1 FROM cron.job WHERE jobname = 'upgrade_test_job'),
|
||||
'pg_cron scheduled job survived the upgrade'
|
||||
);
|
||||
|
||||
-- New predefined role (initdb-only migration; the target image's supautils.conf
|
||||
-- references it, so it must exist on an upgraded instance).
|
||||
SELECT ok(
|
||||
EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'supabase_privileged_role'),
|
||||
'supabase_privileged_role exists'
|
||||
);
|
||||
|
||||
-- Extension version reconcile: complete.sh ran with .063 binaries, so the
|
||||
-- catalog should be reconciled to the target image's default version.
|
||||
SELECT is(
|
||||
(SELECT extversion FROM pg_extension WHERE extname = 'pg_net'),
|
||||
(SELECT default_version FROM pg_available_extensions WHERE name = 'pg_net'),
|
||||
'pg_net version reconciled to image default'
|
||||
);
|
||||
|
||||
SELECT * FROM finish(true);
|
||||
EOSQL
|
||||
|
||||
@@ -222,6 +269,12 @@ run_sql <<'EOSQL' || true
|
||||
DROP FUNCTION IF EXISTS public._upgrade_test_fn(int);
|
||||
DROP TABLE IF EXISTS public._upgrade_test;
|
||||
DROP EXTENSION IF EXISTS pgtap;
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM cron.job WHERE jobname = 'upgrade_test_job') THEN
|
||||
PERFORM cron.unschedule('upgrade_test_job');
|
||||
END IF;
|
||||
END $$;
|
||||
EOSQL
|
||||
|
||||
# --- Summary --------------------------------------------------------------
|
||||
|
||||
@@ -206,13 +206,36 @@ check "REST API query" "200" \
|
||||
# ---------------------------------------------
|
||||
|
||||
echo ""
|
||||
echo "--- GraphQL ---"
|
||||
gql_resp=$(http_body "$BASE_URL/graphql/v1" \
|
||||
echo "--- GraphQL (optional; off by default) ---"
|
||||
# pg_graphql is OFF by default since the PG17 image (the image drops the extension
|
||||
# on init, matching platform behavior for new projects), but users may enable it
|
||||
# (Studio extensions UI / CREATE EXTENSION pg_graphql). Both are valid states. A
|
||||
# healthy endpoint returns HTTP 200 either way:
|
||||
# enabled => {"data": ...}
|
||||
# disabled => {"errors":[{"message":"pg_graphql extension is not enabled."}]}
|
||||
# Assert the status AND the response shape, so a non-200, non-JSON, or empty body
|
||||
# (a real gateway/runtime failure) is not silently classified as "disabled".
|
||||
gql_status=$(http_status "$BASE_URL/graphql/v1" \
|
||||
-H "apikey: $ANON_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"query":"{ __typename }"}')
|
||||
gql_has_data=$(echo "$gql_resp" | jq -r 'if .data then "true" else "false" end' 2>/dev/null)
|
||||
check "GraphQL introspection" "true" "$gql_has_data"
|
||||
gql_body=$(http_body "$BASE_URL/graphql/v1" \
|
||||
-H "apikey: $ANON_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"query":"{ __typename }"}')
|
||||
if [ "$gql_status" = "200" ] && echo "$gql_body" | jq -e '.data' >/dev/null 2>&1; then
|
||||
gql_state="enabled"
|
||||
elif [ "$gql_status" = "200" ] && echo "$gql_body" | jq -e '.errors' >/dev/null 2>&1; then
|
||||
gql_state="disabled"
|
||||
else
|
||||
gql_state="unhealthy (HTTP $gql_status)"
|
||||
fi
|
||||
case "$gql_state" in
|
||||
enabled | disabled) gql_health="healthy" ;;
|
||||
*) gql_health="unhealthy" ;;
|
||||
esac
|
||||
check "GraphQL endpoint healthy" "healthy" "$gql_health"
|
||||
echo " (GraphQL is $gql_state)"
|
||||
|
||||
# ---------------------------------------------
|
||||
# 6. Storage: create bucket, upload >6MB file, download, cleanup
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# Upgrade self-hosted Supabase Postgres from 15 to 17.
|
||||
#
|
||||
# Uses Supabase's pg_upgrade scripts (initiate.sh + complete.sh) inside a
|
||||
# temporary PG15 container, then swaps data directories and starts Postgres 17.
|
||||
# temporary PG 15 container, then swaps data directories and starts Postgres 17.
|
||||
#
|
||||
# Usage (must be run as root or with sudo):
|
||||
# cd docker/
|
||||
@@ -27,8 +27,8 @@
|
||||
# 1. docker compose -f docker-compose.yml -f docker-compose.pg17.yml down
|
||||
# 2. rm -rf ./volumes/db/data
|
||||
# 3. mv ./volumes/db/data.bak.pg15 ./volumes/db/data
|
||||
# 4. docker compose run --rm db chown -R postgres:postgres /etc/postgresql-custom/
|
||||
# 5. docker compose up -d
|
||||
# 4. docker compose -f docker-compose.yml -f docker-compose.pg15.yml run --rm db chown -R postgres:postgres /etc/postgresql-custom/
|
||||
# 5. docker compose -f docker-compose.yml -f docker-compose.pg15.yml up -d
|
||||
#
|
||||
|
||||
# Ensure we're running under bash (not sh/zsh/dash).
|
||||
@@ -50,10 +50,18 @@ done
|
||||
# --- Configuration ----------------------------------------------------------
|
||||
|
||||
# Image used for the upgrade tarball + complete.sh container.
|
||||
# Must share glibc with PG15 (the extracted ELF binaries run inside PG15).
|
||||
# Must share glibc with PG 15 (the extracted ELF binaries run inside PG15).
|
||||
# Pinned to .063: later images bumped glibc, which breaks the ELF extraction.
|
||||
PG17_UPGRADE_IMAGE="supabase/postgres:17.6.1.063"
|
||||
# Tag in supabase/postgres repo matching the upgrade image (for downloading scripts)
|
||||
PG17_SCRIPTS_REF="17.6.1.063"
|
||||
|
||||
# Final Postgres 17 image that runs after the upgrade. Pinned here (not read from
|
||||
# the compose files). Keep in sync with the db image in docker-compose.yml (and
|
||||
# docker-compose.pg17.yml). Used for pulling, chowning data/db-config to the
|
||||
# target's postgres UID, and running the post-upgrade migrations.
|
||||
PG17_TARGET_IMAGE="supabase/postgres:17.6.1.136"
|
||||
|
||||
DB_CONTAINER="supabase-db"
|
||||
UPGRADE_CONTAINER="supabase-pg-upgrade"
|
||||
COMPLETE_CONTAINER="supabase-pg-complete"
|
||||
@@ -96,7 +104,7 @@ trap cleanup EXIT
|
||||
on_interrupt() {
|
||||
echo ""
|
||||
warn "Interrupted. Cleaning up..."
|
||||
# If db-config was chowned to PG17, restore for PG15 rollback
|
||||
# If db-config was chowned to PG17, restore for PG 15 rollback
|
||||
if [ -n "$db_config_vol" ] && [ -n "$current_image" ]; then
|
||||
docker run --rm -v "${db_config_vol}:/vol" "$current_image" \
|
||||
chown -R postgres:postgres /vol/ 2>/dev/null || true
|
||||
@@ -158,10 +166,6 @@ preflight() {
|
||||
| grep -E '^db-config$|_db-config$' | head -n 1)
|
||||
[ -n "$db_config_vol" ] || die "Could not find db-config volume. Is Supabase running?"
|
||||
|
||||
# Read the target PG17 image from the compose override (what the user will run)
|
||||
PG17_TARGET_IMAGE=$(grep 'image:.*postgres' docker-compose.pg17.yml | awk '{print $2}' | head -n 1)
|
||||
[ -n "$PG17_TARGET_IMAGE" ] || die "Could not read image from docker-compose.pg17.yml."
|
||||
|
||||
pg_password=$(grep '^POSTGRES_PASSWORD=' .env | cut -d '=' -f 2- | sed "s/^['\"]//;s/['\"]$//" | head -n 1)
|
||||
[ -n "$pg_password" ] || die "POSTGRES_PASSWORD not set in .env."
|
||||
|
||||
@@ -187,8 +191,8 @@ preflight() {
|
||||
warn " 1. docker compose -f docker-compose.yml -f docker-compose.pg17.yml down"
|
||||
warn " 2. rm -rf $DATA_DIR"
|
||||
warn " 3. mv $BACKUP_DIR $DATA_DIR"
|
||||
warn " 4. docker compose run --rm db chown -R postgres:postgres /etc/postgresql-custom/"
|
||||
warn " 5. docker compose up -d"
|
||||
warn " 4. docker compose -f docker-compose.yml -f docker-compose.pg15.yml run --rm db chown -R postgres:postgres /etc/postgresql-custom/"
|
||||
warn " 5. docker compose -f docker-compose.yml -f docker-compose.pg15.yml up -d"
|
||||
echo ""
|
||||
warn "Continuing will DELETE the existing backup permanently."
|
||||
confirm "Delete $BACKUP_DIR and start a fresh upgrade?"
|
||||
@@ -265,8 +269,8 @@ pull_image() {
|
||||
|
||||
# --- Step 2: Build upgrade tarball -----------------------------------------
|
||||
#
|
||||
# Extracts PG17 binaries, libraries, share data, and upgrade scripts from
|
||||
# the PG17 Docker image into a tarball that initiate.sh can consume.
|
||||
# Extracts PG 17 binaries, libraries, share data, and upgrade scripts from
|
||||
# the PG 17 Docker image into a tarball that initiate.sh can consume.
|
||||
#
|
||||
# The tarball uses the "non-nix" layout (17/bin, 17/lib, 17/share - no
|
||||
# nix_flake_version file), so initiate.sh sets LD_LIBRARY_PATH to find
|
||||
@@ -281,7 +285,7 @@ build_tarball() {
|
||||
echo " Staging directory: $staging_dir"
|
||||
|
||||
# Download upgrade scripts from the supabase/postgres repo (pinned to PG17_SCRIPTS_REF).
|
||||
# These are no longer bundled in the latest PG17 Docker images.
|
||||
# These are no longer bundled in the latest PG 17 Docker images.
|
||||
info "Downloading upgrade scripts (ref: $PG17_SCRIPTS_REF)"
|
||||
local scripts_base="https://raw.githubusercontent.com/supabase/postgres/${PG17_SCRIPTS_REF}/ansible/files/admin_api_scripts/pg_upgrade_scripts"
|
||||
mkdir -p "$staging_dir/scripts"
|
||||
@@ -470,7 +474,7 @@ run_upgrade() {
|
||||
'
|
||||
wait_for_healthy "$UPGRADE_CONTAINER"
|
||||
|
||||
# initiate.sh expects the PG17 binaries tarball at /tmp/persistent/pg_upgrade_bin.tar.gz
|
||||
# initiate.sh expects the PG 17 binaries tarball at /tmp/persistent/pg_upgrade_bin.tar.gz
|
||||
# (hardcoded path - copied there during container setup above).
|
||||
#
|
||||
# Env vars for the unwrapped nix ELF binaries in the tarball:
|
||||
@@ -502,7 +506,7 @@ run_upgrade() {
|
||||
docker rm -f "$UPGRADE_CONTAINER" >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
# --- Step 6: Run complete.sh in a native PG17 container -------------------
|
||||
# --- Step 6: Run complete.sh in a native PG 17 container -------------------
|
||||
#
|
||||
# complete.sh applies post-upgrade patches (pg_net grants, vault re-encryption,
|
||||
# pg_cron, predefined roles, vacuumdb, etc.). We run it in a PG17 container
|
||||
@@ -525,8 +529,8 @@ run_complete() {
|
||||
|
||||
info "Preparing complete.sh environment"
|
||||
# Save original db-config ownership so we can restore it if complete.sh fails.
|
||||
# complete.sh needs PG17 ownership to start postgres, but if it fails the
|
||||
# user needs to fall back to PG15 which uses a different uid.
|
||||
# complete.sh needs PG 17 ownership to start postgres, but if it fails the
|
||||
# user needs to fall back to PG 15 which uses a different uid.
|
||||
docker exec "$COMPLETE_CONTAINER" bash -c '
|
||||
stat -c "%u:%g" /etc/postgresql-custom/pgsodium_root.key 2>/dev/null > /tmp/dbconfig_owner || true
|
||||
'
|
||||
@@ -570,7 +574,7 @@ run_complete() {
|
||||
warn "complete.sh failed. Postgres log:"
|
||||
docker exec "$COMPLETE_CONTAINER" cat /tmp/postgres.log 2>/dev/null || true
|
||||
echo ""
|
||||
# Restore db-config ownership so PG15 can start for rollback
|
||||
# Restore db-config ownership so PG 15 can start for rollback
|
||||
warn "Restoring db-config ownership for PG15..."
|
||||
local orig_owner
|
||||
orig_owner=$(docker exec "$COMPLETE_CONTAINER" cat /tmp/dbconfig_owner 2>/dev/null || true)
|
||||
@@ -582,7 +586,7 @@ run_complete() {
|
||||
echo " Your Postgres 15 data is unchanged (data swap has not happened yet)."
|
||||
echo " To restart Postgres 15:"
|
||||
echo " rm -rf $MIGRATION_DIR"
|
||||
echo " docker compose up -d"
|
||||
echo " docker compose -f docker-compose.yml -f docker-compose.pg15.yml up -d"
|
||||
echo ""
|
||||
die "complete.sh failed (status: $status)"
|
||||
fi
|
||||
@@ -609,7 +613,7 @@ swap_data() {
|
||||
start_pg17() {
|
||||
info "Starting Supabase with Postgres 17"
|
||||
|
||||
# Ensure db-config volume has correct ownership and structure for PG17.
|
||||
# Ensure db-config volume has correct ownership and structure for PG 17.
|
||||
# complete.sh does this too, but just in case of partial
|
||||
# failures from previous runs.
|
||||
docker run --rm -v "${db_config_vol}:/vol" "$PG17_TARGET_IMAGE" sh -c '
|
||||
@@ -641,15 +645,28 @@ start_pg17() {
|
||||
|
||||
# --- Step 9: Apply migrations not covered by complete.sh -------------------
|
||||
#
|
||||
# These PG17 migrations run on fresh installs via initdb but not after
|
||||
# These PG 17 migrations run on fresh installs via initdb but not after
|
||||
# pg_upgrade (init scripts don't rerun when PG_VERSION already exists).
|
||||
# complete.sh doesn't cover them either.
|
||||
# complete.sh doesn't cover them either. On the platform a tracked migration
|
||||
# runner (dbmate) applies them; self-hosted has no such tracking, so we apply
|
||||
# the idempotent, safe-on-an-existing-DB ones directly here.
|
||||
#
|
||||
# Source: postgres/migrations/db/migrations/
|
||||
# - 20250710151649_supabase_read_only_user_default_transaction_read_only.sql
|
||||
# - 20251001204436_predefined_role_grants.sql (supabase_etl_admin + pg_monitor)
|
||||
# - 20251105172723_grant_pg_reload_conf_to_postgres.sql
|
||||
# - 20251121132723_correct_search_path_pgbouncer.sql
|
||||
# - 20260211120934_supabase_privileged_role.sql (target image's supautils.conf
|
||||
# references this role; it must exist or supautils config is broken)
|
||||
# - 20260413000000_fix-authenticator-session-preload-libraries.sql
|
||||
# - 20260421000001_rescope_pg_graphql_access_trigger.sql
|
||||
#
|
||||
# NOT applied:
|
||||
# - 20260421000000_pg_graphql-off-by-default.sql: drops pg_graphql. Safe on a
|
||||
# fresh install, but destructive on an existing DB that uses pg_graphql.
|
||||
#
|
||||
# This step also reconciles extension versions (complete.sh ran with the .063
|
||||
# binaries) and the pg_cron 1.6 -> 1.6.4 version label. See below.
|
||||
|
||||
apply_role_migrations() {
|
||||
info "Applying Postgres 17 migrations"
|
||||
@@ -663,7 +680,7 @@ apply_role_migrations() {
|
||||
-c "ALTER DATABASE \"$db\" REFRESH COLLATION VERSION;" || true
|
||||
done
|
||||
|
||||
# Create supabase_etl_admin role (doesn't exist in PG15 images).
|
||||
# Create supabase_etl_admin role (doesn't exist in PG 15 images).
|
||||
# Must be created before running predefined_role_grants.sql which
|
||||
# assumes it exists.
|
||||
run_sql_on "$DB_CONTAINER" -c "
|
||||
@@ -677,7 +694,7 @@ apply_role_migrations() {
|
||||
END
|
||||
\$\$;" || true
|
||||
|
||||
# Run the migration files directly from the PG17 container image.
|
||||
# Run the migration files directly from the PG 17 container image.
|
||||
# They're idempotent (IF EXISTS / IF NOT EXISTS guards).
|
||||
local migration_dir="/docker-entrypoint-initdb.d/migrations"
|
||||
local migrations="
|
||||
@@ -685,6 +702,9 @@ apply_role_migrations() {
|
||||
20251001204436_predefined_role_grants.sql
|
||||
20251105172723_grant_pg_reload_conf_to_postgres.sql
|
||||
20251121132723_correct_search_path_pgbouncer.sql
|
||||
20260211120934_supabase_privileged_role.sql
|
||||
20260413000000_fix-authenticator-session-preload-libraries.sql
|
||||
20260421000001_rescope_pg_graphql_access_trigger.sql
|
||||
"
|
||||
|
||||
for m in $migrations; do
|
||||
@@ -695,6 +715,54 @@ apply_role_migrations() {
|
||||
psql -h localhost -U supabase_admin -d postgres -v ON_ERROR_STOP=1 \
|
||||
-f "${migration_dir}/${m}" || warn " $m failed (non-fatal)"
|
||||
done
|
||||
|
||||
# Reconcile extension versions to the target image. pg_upgrade generates
|
||||
# update_extensions.sql, but complete.sh runs it inside the .063 container, so
|
||||
# extensions only get updated to .063's versions. The final image ships newer
|
||||
# .so files, leaving the catalog version behind what's loaded.
|
||||
#
|
||||
# Mirror what update_extensions.sql does, but against the running target image
|
||||
# and for every installed extension: ALTER EXTENSION ... UPDATE brings each one
|
||||
# up to the image's default version. This is generic on purpose - it tracks the
|
||||
# image (matching platform behavior) and stays correct across future image
|
||||
# bumps without maintaining a hardcoded list. ALTER ... UPDATE is a no-op when
|
||||
# already at the default. Per-extension exceptions are caught so one extension
|
||||
# with no update path (e.g. pg_cron 1.6 -> 1.6.4, handled below) does not abort
|
||||
# the rest.
|
||||
info "Reconciling extension versions to the target image"
|
||||
run_sql_on "$DB_CONTAINER" -c "
|
||||
DO \$\$
|
||||
DECLARE r record;
|
||||
BEGIN
|
||||
FOR r IN SELECT extname FROM pg_extension LOOP
|
||||
BEGIN
|
||||
EXECUTE format('ALTER EXTENSION %I UPDATE', r.extname);
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RAISE NOTICE 'skipped extension %: %', r.extname, SQLERRM;
|
||||
END;
|
||||
END LOOP;
|
||||
END
|
||||
\$\$;" || warn "extension version reconcile had errors (non-fatal)"
|
||||
|
||||
# pg_cron: PG 15 registers the extension as '1.6'; PG 17 images package it as
|
||||
# '1.6.4' with no '1.6' -> '1.6.4' update path, so ALTER EXTENSION ... UPDATE
|
||||
# has no path to follow. complete.sh only fixes this when pg_cron is owned by
|
||||
# 'postgres' (it drops + recreates). Manually-enabled instances are often
|
||||
# owned by supabase_admin, where that path is skipped. Reconcile the catalog
|
||||
# label directly: the loaded .so and the SQL objects are already
|
||||
# 1.6.4-equivalent (no SQL delta between 1.6 and 1.6.4). No DROP, so any
|
||||
# scheduled jobs are untouched.
|
||||
run_sql_on "$DB_CONTAINER" -c "
|
||||
DO \$\$
|
||||
DECLARE want text;
|
||||
BEGIN
|
||||
SELECT default_version INTO want FROM pg_available_extensions WHERE name = 'pg_cron';
|
||||
IF want IS NOT NULL
|
||||
AND EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'pg_cron' AND extversion <> want) THEN
|
||||
UPDATE pg_extension SET extversion = want WHERE extname = 'pg_cron';
|
||||
END IF;
|
||||
END
|
||||
\$\$;" || warn "pg_cron version reconcile had errors (non-fatal)"
|
||||
}
|
||||
|
||||
# --- Step 10: Verify ------------------------------------------------------
|
||||
@@ -726,8 +794,8 @@ verify() {
|
||||
echo " 1. docker compose -f docker-compose.yml -f docker-compose.pg17.yml down"
|
||||
echo " 2. rm -rf $DATA_DIR"
|
||||
echo " 3. mv $BACKUP_DIR $DATA_DIR"
|
||||
echo " 4. docker compose run --rm db chown -R postgres:postgres /etc/postgresql-custom/"
|
||||
echo " 5. docker compose up -d"
|
||||
echo " 4. docker compose -f docker-compose.yml -f docker-compose.pg15.yml run --rm db chown -R postgres:postgres /etc/postgresql-custom/"
|
||||
echo " 5. docker compose -f docker-compose.yml -f docker-compose.pg15.yml up -d"
|
||||
echo ""
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user