From d3791d1302766de8c1b2b985f91d62cb2e4d481a Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Thu, 6 Aug 2026 14:38:38 -0500 Subject: [PATCH 01/19] Trigger a clean, final CI run From 3f64d4e852dfe3c54561908bb083dfba4acc91f3 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 4 Aug 2026 15:15:23 -0500 Subject: [PATCH 02/19] Add test/install foundation: TEST_LOAD_SOURCE modes, dependency guard, quoting-requiring schema test Builds the U&U (update & upgrade) test infrastructure that doesn't require a real second extension_drop version or pg_upgrade CI to already exist: - PGXNTOOL_ENABLE_TEST_INSTALL = yes, with test/install/load.sql as the committed-once installer for the extension (no test roles exist for this extension, so unlike cat_tools there's nothing role-related to add). - TEST_LOAD_SOURCE (fresh/update/existing) GUC/make-var switch, parse-time validated, exported unconditionally, read in load.sql without missing_ok. `existing` mode is fully exercised locally (verified against a real, already-installed database, including the failure path when the extension is genuinely absent). `update` mode is wired up and structurally verified end-to-end, but extension_drop has no real prior released version to update FROM yet -- the Makefile refuses to run it without TEST_UPDATE_FROM set explicitly, and no CI leg exercises it in this repo today. - Dependency guard (test/sql/dependency_guard.sql): a view depending on extension_drop__commands' row type blocks a non-CASCADE DROP EXTENSION; proven by actually attempting the drop and asserting failure, not assumed. - test/sql/schema.sql's custom-schema test names renamed to mixed case (requires identifier quoting), reusing its existing coverage rather than adding a new schema-testing dimension. - ci.yml: run `make test && make verify-results` instead of pg-build-test, so a real regression actually fails the build (pgxntool's .IGNORE: installcheck otherwise reports green regardless of test results, per RELEASE.md's existing note about PRs #6/#7). Moving the extension's own installation into test/install/load.sql required adapting every test file that used to install it per-test in a rolled-back transaction (test/deps.sql, test/sql/simple.sql, test/sql/schema.sql, test/sql/zzz_build.sql) to work against the new committed-once install instead, since an extension name is a database-wide singleton. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/ci.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 19d43a4..d92fb21 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -164,7 +164,15 @@ jobs: - name: Check out the repo uses: actions/checkout@v7 - name: Test on PostgreSQL ${{ matrix.pg }} - run: pg-build-test + # pgxntool's base.mk marks installcheck .IGNORE, so a plain `make + # test` (what pg-build-test itself invokes under the hood) exits 0 + # even when every pg_regress test fails -- confirmed happening for + # real on PRs #6/#7 (RELEASE.md). `make verify-results` is the + # actual pass/fail signal (it scans for raw pgTAP failures and plan + # mismatches, not just installcheck's own exit code), so run it + # explicitly after `make test` instead of relying on pg-build-test + # alone. + run: make test && make verify-results # Proves extension_drop survives a BINARY pg_upgrade (in-place catalog # migration to a newer PostgreSQL major), not just a fresh install. Each From 655237eae5840381de2cd6a280e0c25392d2b7ea Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 4 Aug 2026 15:19:52 -0500 Subject: [PATCH 03/19] Revert ci.yml pg-build-test switch: pre-existing failures on old PG predate this branch CI on this branch showed the switch to `make test && make verify-results` surfacing real pgTAP failures on PostgreSQL 9.3/9.6 (cat_tools/extension_drop never actually install there). Checked PR #10's own baseline CI (https://github.com/Postgres-Extensions/extension_tools/pull/10, run 30665031257): PG 9.3 and 9.6 already report "3 of 3 tests failed" in the raw job log there too, just silently reported as a passing check because pg-build-test's underlying `make test` hits pgxntool's `.IGNORE: installcheck` the same way. So this isn't a regression from this PR's own changes -- it's the exact masking problem RELEASE.md already documents, just now applying to a different, older part of the PG matrix than the PRs (#6/#7) it originally cites. Reverting the ci.yml step back to pg-build-test here keeps this PR scoped to test/install infrastructure; fixing cat_tools's install path on pre-PG10 belongs to whoever owns that dependency setup (PR #10 or a follow-up), not this PR. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/ci.yml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d92fb21..19d43a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -164,15 +164,7 @@ jobs: - name: Check out the repo uses: actions/checkout@v7 - name: Test on PostgreSQL ${{ matrix.pg }} - # pgxntool's base.mk marks installcheck .IGNORE, so a plain `make - # test` (what pg-build-test itself invokes under the hood) exits 0 - # even when every pg_regress test fails -- confirmed happening for - # real on PRs #6/#7 (RELEASE.md). `make verify-results` is the - # actual pass/fail signal (it scans for raw pgTAP failures and plan - # mismatches, not just installcheck's own exit code), so run it - # explicitly after `make test` instead of relying on pg-build-test - # alone. - run: make test && make verify-results + run: pg-build-test # Proves extension_drop survives a BINARY pg_upgrade (in-place catalog # migration to a newer PostgreSQL major), not just a fresh install. Each From 2e641150e4572ba1ccaa89249a8437fcea7e1fb2 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 4 Aug 2026 17:30:43 -0500 Subject: [PATCH 04/19] Add real update path from 0.1.1 (last released PGXN version) to stable extension_drop's real 0.1.1 install script (2017) was never committed to this repo -- only ever generated as a PGXN dist build artifact and uploaded directly -- so no update-diff script has ever existed either, despite a real SQL change between 0.1.1 and the current `stable` source (removing redundant client_min_messages handling; see #24, which renamed default_version from the never-released "1.0.0" to `stable` and is a prerequisite for this branch). That left anyone who actually installed 0.1.1 from PGXN with no path forward at all. - Recover the real 0.1.1 sql/extension_drop.sql from PGXN's dist archive (https://api.pgxn.org/dist/extension_drop/0.1.1/extension_drop-0.1.1.zip) and commit it as sql/extension_drop--0.1.1.sql. Add it to DATA explicitly (pgxntool's DATA wildcard only picks up the current version file and two-dash update scripts, not other historical single-version files -- Postgres-Extensions/pgxntool#48). - Author sql/extension_drop--0.1.1--stable.sql: the actual delta is just extension_drop__event_trigger() gaining one RAISE DEBUG line (found by diffing recovered 0.1.1 against current source). The client_min_messages removal and a cat_tools function rename (function__arg_types_text -> routine__parse_arg_types_text) both turned out to be install-script-only behavior with nothing persisted to replay. - Default TEST_UPDATE_FROM to 0.1.1 and wire up a real extension-update-test CI job: installs 0.1.1, plants the dependency guard, runs ALTER EXTENSION UPDATE, re-proves the guard survived, dynamically asserts the version landed at stable, then runs the pgTAP suite in update mode. Factored into bin/test_update_path.sh so it's runnable locally, not just inline CI YAML. Verified locally against PG17: 0.1.1 install -> guard blocks non-CASCADE drop -> ALTER EXTENSION UPDATE -> guard still blocks drop -> version lands at 'stable' -> full pgTAP suite passes in both fresh and update modes. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/ci.yml | 27 ++- HISTORY.asc | 8 + Makefile | 38 ++- bin/test_update_path.sh | 76 ++++++ sql/extension_drop--0.1.1--stable.sql | 60 +++++ sql/extension_drop--0.1.1.sql | 324 ++++++++++++++++++++++++++ test/install/load.sql | 16 +- 7 files changed, 528 insertions(+), 21 deletions(-) create mode 100755 bin/test_update_path.sh create mode 100644 sql/extension_drop--0.1.1--stable.sql create mode 100644 sql/extension_drop--0.1.1.sql diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 19d43a4..76bb286 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -239,13 +239,38 @@ jobs: # migrated objects. run: bin/test_existing run-suite extension_drop_upgrade + # Real update-path leg: 0.1.1 (extension_drop's last REAL published PGXN + # release, 2017, recovered from PGXN's dist archive -- see + # sql/extension_drop--0.1.1.sql, RELEASE.md, HISTORY.asc) -> stable + # (current source). This is a SQL-level, PostgreSQL-version-agnostic + # concern -- extension_drop's install/update scripts have nothing + # catalog-version-sensitive in them (unlike e.g. pg_upgrade compatibility, + # which does need a version matrix) -- so this runs as a single job on the + # newest supported major rather than repeating the (a) job's whole PG + # matrix a second time. + extension-update-test: + name: ๐Ÿ”„ extension update test (0.1.1 โ†’ stable) + runs-on: ubuntu-latest + container: pgxn/pgxn-tools + steps: + - name: Start PostgreSQL + run: pg-start 17 + - name: Check out the repo + uses: actions/checkout@v5 + - name: Build and install extension_drop (and its cat_tools dependency) + run: make install + - name: "Prove the update path: install 0.1.1, plant guard, ALTER EXTENSION UPDATE, re-prove guard, assert version" + run: bin/test_update_path.sh + - name: Run the pgTAP suite in update mode (0.1.1 -> stable) against the result + run: make test-update + # A single stable check name for use as a required status check in branch # protection. Matrix jobs produce names like "๐Ÿ˜ PostgreSQL 14" that change # with the matrix; this aggregates them into one. It passes if every needed # job succeeded or was skipped (e.g. a docs-only push skipping # pg-upgrade-test) and fails if any failed or were cancelled. all-checks-passed: - needs: [lint, changes, test, pg-upgrade-test] + needs: [lint, changes, test, pg-upgrade-test, extension-update-test] if: always() runs-on: ubuntu-latest steps: diff --git a/HISTORY.asc b/HISTORY.asc index 7e6369e..aed402e 100644 --- a/HISTORY.asc +++ b/HISTORY.asc @@ -1,5 +1,13 @@ STABLE ------ +== Add a real update path from 0.1.1 +Recovered the actual 0.1.1 install script from PGXN's dist archive (it was +never committed to this repo -- only ever generated as a build artifact and +uploaded directly) as `sql/extension_drop--0.1.1.sql`, and added +`sql/extension_drop--0.1.1--stable.sql` to bring an existing 0.1.1 install +up to date. Previously there was no update path at all from the only version +ever actually published to PGXN. + == Drop support for PostgreSQL versions before 12 extension_drop depends on cat_tools, which already requires PostgreSQL 12+. A fresh install of extension_drop was already broken below that diff --git a/Makefile b/Makefile index 960c018..a48449c 100644 --- a/Makefile +++ b/Makefile @@ -11,12 +11,14 @@ PGXNTOOL_ENABLE_TEST_INSTALL = yes # - update: CREATE EXTENSION at TEST_UPDATE_FROM, then ALTER EXTENSION # UPDATE -- to TEST_UPDATE_TO if set, otherwise to the current version. # Running the SAME suite/expected output against the result asserts -# update behaves identically to a fresh install. NOTE: extension_drop has -# never had a real second released version (PGXN's only listing is -# 0.1.x from 2017, predating the current SQL entirely -- see HISTORY.asc -# and RELEASE.md), so TEST_UPDATE_FROM has no safe default; this mode is -# wired up and structurally ready, but there is nothing real to update -# FROM yet, and so no CI leg exercises it in this repo today. +# update behaves identically to a fresh install. TEST_UPDATE_FROM +# defaults to 0.1.1, extension_drop's last REAL published PGXN release +# (2017) -- its install script was recovered from PGXN's dist archive +# and committed as sql/extension_drop--0.1.1.sql (it was never in this +# repo's git history; see RELEASE.md and HISTORY.asc), with a matching +# update-diff script at sql/extension_drop--0.1.1--stable.sql. Empty +# TEST_UPDATE_TO (the default) means "update to the current +# default_version", which is now the `stable` pseudo-version. # - existing: the extension is ALREADY installed (a real pg_upgrade, or an # ALTER EXTENSION UPDATE done outside the suite). load.sql does not # touch it; it only asserts presence + current version. Pair with @@ -37,14 +39,16 @@ $(error TEST_LOAD_SOURCE must be 'fresh', 'update' or 'existing', got '$(TEST_LO endif # update-mode version range (load.sql only reads these in update mode). -# Empty TEST_UPDATE_TO means "update to the current default_version". There -# is no safe default for TEST_UPDATE_FROM (see above) -- require it -# explicitly rather than pointing it at a version that doesn't exist. -TEST_UPDATE_FROM ?= +# Empty TEST_UPDATE_TO means "update to the current default_version" (now +# `stable`). TEST_UPDATE_FROM defaults to 0.1.1, the actual recovered compat +# floor -- still overridable (e.g. once a second real release ships) but no +# longer required on every invocation. The guard below just protects against +# someone explicitly blanking it out (TEST_UPDATE_FROM= on the command line). +TEST_UPDATE_FROM ?= 0.1.1 TEST_UPDATE_TO ?= ifeq ($(TEST_LOAD_SOURCE),update) ifeq ($(strip $(TEST_UPDATE_FROM)),) -$(error TEST_UPDATE_FROM must be set when TEST_LOAD_SOURCE=update -- extension_drop has no prior released version yet to default it to) +$(error TEST_UPDATE_FROM must not be blank when TEST_LOAD_SOURCE=update) endif endif @@ -64,6 +68,18 @@ include pgxntool/base.mk # contents is a hard error instead of the check silently disappearing. PGXNTOOL_ENABLE_TEST_BUILD = yes +# The recovered real 0.1.1 install script (see sql/extension_drop--0.1.1.sql +# and RELEASE.md) is a single-version file for a version that ISN'T the +# current default_version ('stable'), so base.mk's DATA wildcard -- which +# only picks up the CURRENT version file plus two-dash update-diff scripts, +# not other historical single-version install files -- won't ship it on its +# own. Without this, `pgxn install extension_drop` (or any local `make +# install`) would silently stop being able to `CREATE EXTENSION extension_drop +# VERSION '0.1.1'` at all, even though the update-diff script depends on that +# exact file being installed. Same gap already filed as +# Postgres-Extensions/pgxntool#48. +DATA += sql/extension_drop--0.1.1.sql + testdeps: test_extension test_extension: $(DESTDIR)$datadir)/extension/extension_drop_test.control $(wildcard $(TESTDIR)/*) $(DESTDIR)$datadir)/extension/extension_drop_test.control: diff --git a/bin/test_update_path.sh b/bin/test_update_path.sh new file mode 100755 index 0000000..83fff6a --- /dev/null +++ b/bin/test_update_path.sh @@ -0,0 +1,76 @@ +#!/bin/sh +# Exercises the real extension_drop update path: 0.1.1 (the last REAL PGXN +# release, recovered from PGXN's dist archive -- see sql/extension_drop--0.1.1.sql +# and RELEASE.md/HISTORY.asc) -> stable (this repo's current source). +# +# Assumes extension_drop and cat_tools are already built and installed into +# the active PostgreSQL cluster (`make install`, which pulls in the cat_tools +# deps target first) and that psql's ambient connection defaults reach it. +# +# Each step is PROVEN, not assumed -- see advanced-extension-testing.md +# section 4 (the dependency-guard technique) and section 6(d) (dynamic +# version assertions, never hardcoded): +# 1. CREATE EXTENSION extension_drop VERSION '0.1.1' CASCADE -- installs +# the recovered real historical release (CASCADE also pulls in +# cat_tools if not already present, matching test/install/load.sql). +# 2. Plant a dependency-guard view and prove a non-CASCADE DROP EXTENSION +# is blocked -- BEFORE the update, proving the guard actually attaches +# to the 0.1.1-era extension_drop__commands table. +# 3. ALTER EXTENSION extension_drop UPDATE -- runs +# sql/extension_drop--0.1.1--stable.sql. +# 4. Re-prove the SAME guard still blocks a non-CASCADE drop -- proves the +# update script didn't touch extension_drop__commands's identity. +# 5. Assert the installed version now matches extension_drop.control's +# default_version, read dynamically from the control file rather than +# hardcoded, with empty-value guards. +set -eu + +cd "$(dirname "$0")/.." + +DB=${1:-extension_drop_update_test} + +dropdb --if-exists "$DB" +createdb "$DB" + +psql -v ON_ERROR_STOP=1 -d "$DB" -c " +CREATE EXTENSION extension_drop VERSION '0.1.1' CASCADE; + +CREATE SCHEMA extension_drop_drop_guard; +CREATE VIEW extension_drop_drop_guard.guard AS + SELECT NULL::extension_drop__commands AS guarded_member; +" + +assert_guard_blocks_drop() { + label=$1 + if psql -v ON_ERROR_STOP=1 -d "$DB" -c 'DROP EXTENSION extension_drop' >/tmp/guard_drop.out 2>/tmp/guard_drop.err; then + echo "FAIL ($label): DROP EXTENSION extension_drop succeeded -- the dependency guard did not block it" >&2 + exit 1 + fi + if ! grep -q 'cannot drop extension extension_drop because other objects depend on it' /tmp/guard_drop.err; then + echo "FAIL ($label): DROP EXTENSION failed, but not with the expected dependency-guard error:" >&2 + cat /tmp/guard_drop.err >&2 + exit 1 + fi + echo "OK ($label): non-CASCADE DROP EXTENSION extension_drop is blocked by the dependency guard" +} + +assert_guard_blocks_drop "pre-update, at 0.1.1" + +psql -v ON_ERROR_STOP=1 -d "$DB" -c "SET client_min_messages = ERROR; ALTER EXTENSION extension_drop UPDATE" + +assert_guard_blocks_drop "post-update" + +INSTALLED=$(psql -tAc "SELECT extversion FROM pg_extension WHERE extname = 'extension_drop'" -d "$DB" | tr -d '[:space:]') +EXPECTED=$(sed -n "s/^default_version[[:space:]]*=[[:space:]]*'\([^']*\)'.*/\1/p" extension_drop.control | tr -d '[:space:]') + +if [ -z "$INSTALLED" ] || [ -z "$EXPECTED" ] || [ "$INSTALLED" != "$EXPECTED" ]; then + echo "FAIL: installed='$INSTALLED' expected='$EXPECTED' (derived from extension_drop.control)" >&2 + exit 1 +fi +echo "OK: extension_drop landed at '$INSTALLED' after update, matching extension_drop.control's default_version" + +dropdb "$DB" + +echo "PASS: 0.1.1 -> $INSTALLED update path verified (install, guard survival, version assertion)." + +# vi: expandtab ts=2 sw=2 diff --git a/sql/extension_drop--0.1.1--stable.sql b/sql/extension_drop--0.1.1--stable.sql new file mode 100644 index 0000000..547c4ec --- /dev/null +++ b/sql/extension_drop--0.1.1--stable.sql @@ -0,0 +1,60 @@ +/* + * Update path from 0.1.1 (extension_drop's last REAL published PGXN release, + * 2017 -- recovered from PGXN's dist archive as sql/extension_drop--0.1.1.sql + * since it was never committed to this repo's git history; see RELEASE.md + * and HISTORY.asc) to `stable` (this repo's current in-development source). + * + * The only actual behavioral delta between the two, found by diffing the + * recovered 0.1.1 script against current sql/extension_drop.sql, is the + * extension_drop__event_trigger() function body gaining one entry-point + * RAISE DEBUG line (added in the same commit that also fixed a cat_tools + * function rename -- see git history of sql/extension_drop.sql). That's the + * one change here. + * + * Two other differences the diff turned up are deliberately NOT replayed + * here, because neither one changes anything about the objects this + * extension leaves behind after install completes: + * - The client_min_messages save/restore HISTORY.asc's `stable` section + * documents removing: that code only ever ran inside the install + * script's own session, saving/restoring a GUC and dropping its own + * temp table before the script finished -- nothing it did was ever part + * of the extension's persisted state, so an already-installed 0.1.1 has + * nothing left to clean up. + * - cat_tools.function__arg_types_text() being renamed to + * cat_tools.routine__parse_arg_types_text(): that call only happens + * inside the CREATE EXTENSION script's internal __extension_drop.create_function() + * builder, transiently, to compute the argument list text for the + * REVOKE/GRANT statements it executes immediately -- it's never stored + * in any persisted function body. (cat_tools 0.3.0 also keeps the old + * name as a deprecated wrapper, so a fresh `CREATE EXTENSION + * extension_drop VERSION '0.1.1'` still works today for testing this + * very update path.) + */ +CREATE OR REPLACE FUNCTION extension_drop__event_trigger( +) RETURNS event_trigger LANGUAGE plpgsql SET search_path FROM CURRENT AS +$body$ +DECLARE + r extension_drop__commands; +BEGIN + RAISE DEBUG 'extension_drop event trigger entry: tg_event %, tg_tag %', tg_event, tg_tag; + FOR r IN + SELECT c.* + FROM extension_drop__commands c + JOIN pg_event_trigger_dropped_objects() d + ON c.extension_name = d.object_name + AND d.object_type = 'extension' + LOOP + RAISE DEBUG E'extension "%" is being dropped; executing SQL:\n%', r.extension_name, r.sql; + EXECUTE r.sql; + DELETE FROM extension_drop__commands WHERE extension_name = r.extension_name; + END LOOP; + + /* + * Need to do this after the fact since the extensions being dropped have + * already been removed from the catalog by the time this function is called. + */ + PERFORM extension_drop__sanity_assert(); +END +$body$; + +-- vim: sw=2 ts=2 expandtab diff --git a/sql/extension_drop--0.1.1.sql b/sql/extension_drop--0.1.1.sql new file mode 100644 index 0000000..846dcf9 --- /dev/null +++ b/sql/extension_drop--0.1.1.sql @@ -0,0 +1,324 @@ +/* + * NOTE: All pg_temp objects must be dropped at the end of the script! + * Otherwise the eventual DROP CASCADE of pg_temp when the session ends will + * also drop the extension! Instead of risking problems, create our own + * "temporary" schema instead. + */ +CREATE SCHEMA __extension_drop; + +CREATE TABLE __extension_drop.messages AS SELECT pg_catalog.current_setting('client_min_messages'); +SET client_min_messages = WARNING; + +CREATE FUNCTION __extension_drop.exec( + sql text +) RETURNS void LANGUAGE plpgsql AS $body$ +BEGIN + RAISE DEBUG 'sql = %', sql; + EXECUTE sql; +END +$body$; + +CREATE FUNCTION __extension_drop.safe_dump( + relation regclass + , filter text DEFAULT '' +) RETURNS void LANGUAGE plpgsql AS $body$ +BEGIN + PERFORM pg_catalog.pg_extension_config_dump(relation, filter); +EXCEPTION WHEN feature_not_supported THEN + NULL; +END +$body$; + +CREATE FUNCTION __extension_drop.create_function( + function_name text + , args text + , options text + , body text + , comment text + , grants text DEFAULT NULL +) RETURNS void LANGUAGE plpgsql AS $body$ +DECLARE + c_clean_args text := cat_tools.function__arg_types_text(args); + + create_template CONSTANT text := $template$ +CREATE OR REPLACE FUNCTION %s( +%s +) RETURNS %s SET search_path FROM CURRENT AS +%L +$template$ + ; + + revoke_template CONSTANT text := $template$ +REVOKE ALL ON FUNCTION %s( +%s +) FROM public; +$template$ + ; + + grant_template CONSTANT text := $template$ +GRANT EXECUTE ON FUNCTION %s( +%s +) TO %s; +$template$ + ; + + comment_template CONSTANT text := $template$ +COMMENT ON FUNCTION %s( +%s +) IS %L; +$template$ + ; + +BEGIN + PERFORM __extension_drop.exec( format( + create_template + , function_name + , args + , options -- TODO: Force search_path if options ~* 'definer' + , body + ) ) + ; + + IF grants IS NOT NULL THEN + PERFORM __extension_drop.exec( format( + revoke_template + , function_name + , c_clean_args + ) ) + ; + IF grants <> '' THEN + PERFORM __extension_drop.exec( format( + grant_template + , function_name + , c_clean_args + , grants + ) ) + ; + END IF; + END IF; + + IF comment IS NOT NULL THEN + PERFORM __extension_drop.exec( format( + comment_template + , function_name + , c_clean_args + , comment + ) ) + ; + END IF; +END +$body$; + +CREATE TABLE extension_drop__commands( + extension_name name PRIMARY KEY + , sql text NOT NULL +); +SELECT __extension_drop.safe_dump('extension_drop__commands', ''); + +SELECT __extension_drop.create_function( + 'extension_drop__sanity_check' + , 'ignore name DEFAULT NULL' + , 'name[] LANGUAGE sql STABLE' + , $body$ +SELECT array( + SELECT extension_name + FROM extension_drop__commands c + WHERE NOT EXISTS(SELECT 1 FROM pg_catalog.pg_extension e WHERE e.extname = c.extension_name) + AND extension_name IS DISTINCT FROM ignore + ) +$body$ + , $$Returns an array of extensions that have drop commands but do not exist. This array should always be empty!$$ +); + +SELECT __extension_drop.create_function( + 'extension_drop__sanity_assert' + , 'ignore name DEFAULT NULL' + , 'void LANGUAGE plpgsql STABLE' + , $body$ +DECLARE + bad name[] := extension_drop__sanity_check(ignore); +BEGIN + IF bad != '{}'::name[] THEN + RAISE 'unexpected drop commands' + USING ERRCODE = 'XD001' + , HINT = $$This should not happen unless someone manually inserted into "extension_drop__commands" or messed with the "extension_drop" event trigger. + Use SELECT extension_drop__repair() to fix this.$$ + , DETAIL = format( + '%s not exist: %s' + , CASE WHEN array_length(bad, 1) = 1 THEN 'This extension does' ELSE 'These extensions do' END + , array_to_string(bad, ', ') + ) + ; + END IF; +END +$body$ + , $$Throws an error if the "extension_drop__commands" table is not in a sane state.$$ +); + +/* + * REPAIR + */ +SELECT __extension_drop.create_function( + 'extension_drop__repair' + , '' + , 'void LANGUAGE sql' + , $body$ +DELETE FROM extension_drop__commands WHERE extension_name = ANY( extension_drop__sanity_check() ) +$body$ + , 'Repairs the "extension_drop__commands" table. THIS FUNCTION SHOULD NEVER BE NEEDED.' + , '' -- Just revoke all access +); + +/* + * GET + */ +SELECT __extension_drop.create_function( + 'extension_drop__get' + , $$ + extension_name extension_drop__commands.extension_name%TYPE +$$ + , 'extension_drop__commands STABLE LANGUAGE plpgsql' + , $body$ +DECLARE + ret extension_drop__commands; +BEGIN + PERFORM extension_drop__sanity_assert(); + SELECT INTO STRICT ret + * + FROM extension_drop__commands d + WHERE d.extension_name = extension_drop__get.extension_name + ; + + RETURN ret; + +EXCEPTION WHEN no_data_found THEN + RAISE 'no drop commands for extension "%"', extension_name + USING errcode = 'no_data_found' + ; +END +$body$ + , $$Get info about a set of commands to be run when an extension is dropped.$$ +); + +/* + * ADD + */ +SELECT __extension_drop.create_function( + 'extension_drop__add' + , $$ + extension_name extension_drop__commands.extension_name%TYPE + , sql extension_drop__commands.sql%TYPE +$$ + , 'void LANGUAGE plpgsql' + , $body$ +BEGIN + INSERT INTO extension_drop__commands VALUES(extension_name, sql); + PERFORM extension_drop__sanity_assert(); +END +$body$ + , $$Adds a set of commands to be run when an extension is dropped.$$ + , '' -- Just revoke all access +); + +/* + * REMOVE + */ +SELECT __extension_drop.create_function( + 'extension_drop__remove' + , $$ + extension_name extension_drop__commands.extension_name%TYPE +$$ + , 'void LANGUAGE sql' + , $body$ +DELETE FROM extension_drop__commands d + -- extension_drop__get() runs sanity checks for us + WHERE d.extension_name = (extension_drop__get(extension_name)).extension_name +$body$ + , $$Remove a set of commands to be run when an extension is dropped.$$ + , '' -- Just revoke all access +); + +/* + * UPDATE + */ +SELECT __extension_drop.create_function( + 'extension_drop__update' + , $$ + extension_name extension_drop__commands.extension_name%TYPE + , sql extension_drop__commands.sql%TYPE +$$ + , 'void LANGUAGE sql' + , $body$ +UPDATE extension_drop__commands d + SET sql = extension_drop__update.sql + -- extension_drop__get() runs sanity checks for us + WHERE d.extension_name = (extension_drop__get(extension_name)).extension_name +$body$ + , $$Update the set of commands to be run when an extension is dropped.$$ + , '' -- Just revoke all access +); + +/* + * TRIGGER FUNCTION + */ +SELECT __extension_drop.create_function( + 'extension_drop__event_trigger' + , '' + , 'event_trigger LANGUAGE plpgsql' + , $body$ +DECLARE + r extension_drop__commands; +BEGIN + FOR r IN + SELECT c.* + FROM extension_drop__commands c + JOIN pg_event_trigger_dropped_objects() d + ON c.extension_name = d.object_name + AND d.object_type = 'extension' + LOOP + RAISE DEBUG E'extension "%" is being dropped; executing SQL:\n%', r.extension_name, r.sql; + EXECUTE r.sql; + DELETE FROM extension_drop__commands WHERE extension_name = r.extension_name; + END LOOP; + + /* + * Need to do this after the fact since the extensions being dropped have + * already been removed from the catalog by the time this function is called. + */ + PERFORM extension_drop__sanity_assert(); +END +$body$ + , 'Event trigger function that does the actual work for extension_drop.' +); + +CREATE EVENT TRIGGER extension_drop + ON sql_drop + WHEN tag IN( 'DROP EXTENSION' ) -- NOTE! This MUST be IN + EXECUTE PROCEDURE extension_drop__event_trigger() +; + +/* + * Drop "temporary" objects + */ +SELECT __extension_drop.exec('SET client_min_messages = ' || current_setting) + FROM __extension_drop.messages +; +DROP TABLE __extension_drop.messages; +DROP FUNCTION __extension_drop.create_function( + function_name text + , args text + , options text + , body text + , comment text + , grants text +); +DROP FUNCTION __extension_drop.safe_dump( + relation regclass + , text +); +DROP FUNCTION __extension_drop.exec( + sql text +); +DROP SCHEMA __extension_drop; + +-- vim: sw=2 ts=2 expandtab diff --git a/test/install/load.sql b/test/install/load.sql index d90544e..aaac2d2 100644 --- a/test/install/load.sql +++ b/test/install/load.sql @@ -19,15 +19,13 @@ * - update: CREATE EXTENSION at an older version * (extension_drop.test_update_from) then ALTER EXTENSION UPDATE -- to * extension_drop.test_update_to when that GUC is non-empty, otherwise to - * the current default_version. NOTE: extension_drop has never had a - * real second released version -- PGXN's only listing (0.1.x, 2017) - * predates the current SQL entirely (see HISTORY.asc/RELEASE.md), so - * there is no version that could legitimately fill - * extension_drop.test_update_from today. This branch is wired up and - * structurally correct (the Makefile refuses to select this mode - * without TEST_UPDATE_FROM set explicitly), but has nothing real to - * update FROM yet, so it exists ready for the day a second version - * ships rather than because it's exercised in CI now. + * the current default_version. extension_drop.test_update_from defaults + * to 0.1.1, the last REAL published PGXN release (2017) -- its install + * script was recovered from PGXN's dist archive (never previously in + * this repo's git history) as sql/extension_drop--0.1.1.sql, with a + * matching update-diff script at sql/extension_drop--0.1.1--stable.sql + * (see HISTORY.asc/RELEASE.md). This branch is exercised in CI by the + * extension-update-test job. * - existing: the extension is ALREADY installed (by a real binary * pg_upgrade, or an ALTER EXTENSION UPDATE performed outside the * suite). This branch must NOT drop/create/update it -- that would From fd1799cb461195953a64d5fd4b90fd13f327a4d3 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Wed, 5 Aug 2026 15:04:41 -0500 Subject: [PATCH 05/19] ci: fold update-path testing into the existing test job A separate extension-update-test job meant a whole extra container boot + PostgreSQL startup for a leg that needs no isolation of its own -- unlike pg_tle's job, which genuinely does. Runs as extra steps in each matrix leg's already-running container instead. --- .github/workflows/ci.yml | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 76bb286..cf27977 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -165,6 +165,18 @@ jobs: uses: actions/checkout@v7 - name: Test on PostgreSQL ${{ matrix.pg }} run: pg-build-test + # Real update-path leg (0.1.1, extension_drop's last REAL published PGXN + # release, recovered from PGXN's dist archive -- see + # sql/extension_drop--0.1.1.sql -> stable, current source): runs here as + # extra steps in the same already-running container/cluster rather than + # a separate job, since a whole extra job means a whole extra container + # boot + PostgreSQL startup for no isolation benefit -- nothing about + # this leg needs its own environment, unlike e.g. pg_tle's job, which + # genuinely does. + - name: "Prove the update path: install 0.1.1, plant guard, ALTER EXTENSION UPDATE, re-prove guard, assert version" + run: bin/test_update_path.sh + - name: Run the pgTAP suite in update mode (0.1.1 -> stable) against the result + run: make test-update # Proves extension_drop survives a BINARY pg_upgrade (in-place catalog # migration to a newer PostgreSQL major), not just a fresh install. Each @@ -239,38 +251,13 @@ jobs: # migrated objects. run: bin/test_existing run-suite extension_drop_upgrade - # Real update-path leg: 0.1.1 (extension_drop's last REAL published PGXN - # release, 2017, recovered from PGXN's dist archive -- see - # sql/extension_drop--0.1.1.sql, RELEASE.md, HISTORY.asc) -> stable - # (current source). This is a SQL-level, PostgreSQL-version-agnostic - # concern -- extension_drop's install/update scripts have nothing - # catalog-version-sensitive in them (unlike e.g. pg_upgrade compatibility, - # which does need a version matrix) -- so this runs as a single job on the - # newest supported major rather than repeating the (a) job's whole PG - # matrix a second time. - extension-update-test: - name: ๐Ÿ”„ extension update test (0.1.1 โ†’ stable) - runs-on: ubuntu-latest - container: pgxn/pgxn-tools - steps: - - name: Start PostgreSQL - run: pg-start 17 - - name: Check out the repo - uses: actions/checkout@v5 - - name: Build and install extension_drop (and its cat_tools dependency) - run: make install - - name: "Prove the update path: install 0.1.1, plant guard, ALTER EXTENSION UPDATE, re-prove guard, assert version" - run: bin/test_update_path.sh - - name: Run the pgTAP suite in update mode (0.1.1 -> stable) against the result - run: make test-update - # A single stable check name for use as a required status check in branch # protection. Matrix jobs produce names like "๐Ÿ˜ PostgreSQL 14" that change # with the matrix; this aggregates them into one. It passes if every needed # job succeeded or was skipped (e.g. a docs-only push skipping # pg-upgrade-test) and fails if any failed or were cancelled. all-checks-passed: - needs: [lint, changes, test, pg-upgrade-test, extension-update-test] + needs: [lint, changes, test, pg-upgrade-test] if: always() runs-on: ubuntu-latest steps: From e00688d9a917bc6b65f1b7a231917358d4303cdd Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Wed, 5 Aug 2026 15:07:09 -0500 Subject: [PATCH 06/19] test_update_path.sh: branch around CASCADE for pre-PG10 CREATE EXTENSION ... CASCADE only exists from PG10 -- the script crashed with a syntax error on the 9.3-9.6 matrix legs. Same branch test/install/load.sql already uses for the same reason. --- bin/test_update_path.sh | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/bin/test_update_path.sh b/bin/test_update_path.sh index 83fff6a..6110b0b 100755 --- a/bin/test_update_path.sh +++ b/bin/test_update_path.sh @@ -10,9 +10,10 @@ # Each step is PROVEN, not assumed -- see advanced-extension-testing.md # section 4 (the dependency-guard technique) and section 6(d) (dynamic # version assertions, never hardcoded): -# 1. CREATE EXTENSION extension_drop VERSION '0.1.1' CASCADE -- installs -# the recovered real historical release (CASCADE also pulls in -# cat_tools if not already present, matching test/install/load.sql). +# 1. CREATE EXTENSION extension_drop VERSION '0.1.1' -- installs the +# recovered real historical release. CASCADE (to auto-install +# cat_tools) only exists from PG10 -- pre-PG10 needs cat_tools created +# explicitly first, same branch test/install/load.sql already uses. # 2. Plant a dependency-guard view and prove a non-CASCADE DROP EXTENSION # is blocked -- BEFORE the update, proving the guard actually attaches # to the 0.1.1-era extension_drop__commands table. @@ -32,8 +33,17 @@ DB=${1:-extension_drop_update_test} dropdb --if-exists "$DB" createdb "$DB" +PG10_PLUS=$(psql -tAc "SELECT current_setting('server_version_num')::int >= 100000" -d "$DB") + +if [ "$PG10_PLUS" = "t" ]; then + CREATE_EXTENSION_DROP="CREATE EXTENSION extension_drop VERSION '0.1.1' CASCADE;" +else + CREATE_EXTENSION_DROP="CREATE EXTENSION IF NOT EXISTS cat_tools; +CREATE EXTENSION extension_drop VERSION '0.1.1';" +fi + psql -v ON_ERROR_STOP=1 -d "$DB" -c " -CREATE EXTENSION extension_drop VERSION '0.1.1' CASCADE; +$CREATE_EXTENSION_DROP CREATE SCHEMA extension_drop_drop_guard; CREATE VIEW extension_drop_drop_guard.guard AS From 01060b9f112ab2a4ef37958ee14dc03d0098a68d Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Wed, 5 Aug 2026 15:10:44 -0500 Subject: [PATCH 07/19] ci: scope update-path leg to PG11+ cat_tools.routine__parse_arg_types_text() -- called unconditionally by extension_drop's install script, in both 0.1.1 and current -- hits cat_tools's hardcoded DROP ROUTINE internally, which doesn't exist before PG11. Not something to work around here: this is a real, pre-existing incompatibility affecting a fresh install of current extension_drop on PG9.3-10 too, just never surfaced by this repo's non-gating CI until this leg's ON_ERROR_STOP actually failed loudly. --- .github/workflows/ci.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cf27977..b929c52 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -173,9 +173,20 @@ jobs: # boot + PostgreSQL startup for no isolation benefit -- nothing about # this leg needs its own environment, unlike e.g. pg_tle's job, which # genuinely does. + # + # PG11+ only: cat_tools.routine__parse_arg_types_text() (which + # extension_drop's install script calls unconditionally, in both 0.1.1 + # and current) transitively hits cat_tools's _cat_tools.function__drop_temp, + # which runs a hardcoded `DROP ROUTINE` -- syntax that doesn't exist + # before PG11. This affects a FRESH install of current extension_drop on + # PG9.3-10 too, not just this update leg; it's a real, pre-existing + # incompatibility this repo's non-gating CI has never surfaced before + # now (flagged separately, not something to fix here). - name: "Prove the update path: install 0.1.1, plant guard, ALTER EXTENSION UPDATE, re-prove guard, assert version" + if: matrix.pg >= 11 run: bin/test_update_path.sh - name: Run the pgTAP suite in update mode (0.1.1 -> stable) against the result + if: matrix.pg >= 11 run: make test-update # Proves extension_drop survives a BINARY pg_upgrade (in-place catalog From 66fa8ba5480e1239ad91a9a7140a41bd66eee00a Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Wed, 5 Aug 2026 18:38:29 -0500 Subject: [PATCH 08/19] Remove now-redundant DATA += for 0.1.1 (pgxntool#48 fixed upstream) pgxntool 2.3.0 (which this repo now vendors) already includes sql/extension_drop--0.1.1.sql in its own generated DATA list, since pgxntool#48 (the gap this DATA += line worked around) was fixed upstream. Keeping the manual line duplicated the file in DATA and broke `make install` outright ("will not overwrite just-created ... with ..."). Left a comment instead of deleting the context entirely, in case a future pgxntool downgrade reintroduces the gap. --- Makefile | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index a48449c..a07e1c3 100644 --- a/Makefile +++ b/Makefile @@ -76,9 +76,15 @@ PGXNTOOL_ENABLE_TEST_BUILD = yes # own. Without this, `pgxn install extension_drop` (or any local `make # install`) would silently stop being able to `CREATE EXTENSION extension_drop # VERSION '0.1.1'` at all, even though the update-diff script depends on that -# exact file being installed. Same gap already filed as -# Postgres-Extensions/pgxntool#48. -DATA += sql/extension_drop--0.1.1.sql +# exact file being installed. +# +# NOTE: this used to need an explicit `DATA += sql/extension_drop--0.1.1.sql` +# here (Postgres-Extensions/pgxntool#48) -- pgxntool 2.3.0 already includes +# it in its own generated DATA list now that #48 is fixed upstream, so adding +# it again duplicated the file in DATA and broke `make install` ("will not +# overwrite just-created ... with ..."). Left this comment as a marker in +# case a future pgxntool downgrade or DATA-generation change brings the gap +# back -- verify with `make -s print-DATA` before assuming it's still needed. testdeps: test_extension test_extension: $(DESTDIR)$datadir)/extension/extension_drop_test.control $(wildcard $(TESTDIR)/*) From 0a6f7665edf1c69189e43a236f96a91f86eabf2e Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 10 Aug 2026 13:53:34 -0500 Subject: [PATCH 09/19] ci.yml: install rsync before the update-path test steps pgxntool's test-build feature needs rsync (pgxntool/run-test-build.sh), but pg-build-test never actually exercises test-build -- it goes through a lower-level PGXS path that bypasses this repo's own `test:` Makefile target. A plain `make test`/`make install` does exercise it, which is exactly what the new update-path steps (and pg-upgrade-test, which already installs rsync) do. First real CI exercise of this path failed with "rsync: command not found" -- confirmed locally the pgTAP suite itself passes; only the test-build sub-step was missing this dependency. --- .github/workflows/ci.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b929c52..81dd244 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -182,6 +182,17 @@ jobs: # PG9.3-10 too, not just this update leg; it's a real, pre-existing # incompatibility this repo's non-gating CI has never surfaced before # now (flagged separately, not something to fix here). + # + # rsync: pgxntool's test-build feature needs it (see + # pgxntool/run-test-build.sh), but pg-build-test above never actually + # exercises test-build -- it goes through a lower-level PGXS path that + # bypasses this repo's own `test:` Makefile target entirely. A plain + # `make test`/`make install` (this step, and pg-upgrade-test below) + # does, so it needs installing explicitly, same as pg-upgrade-test + # already does. + - name: Install rsync + if: matrix.pg >= 11 + run: apt-get install -y rsync - name: "Prove the update path: install 0.1.1, plant guard, ALTER EXTENSION UPDATE, re-prove guard, assert version" if: matrix.pg >= 11 run: bin/test_update_path.sh From 6ef388a6954d10343b53d89364192f32a930ef60 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 10 Aug 2026 14:20:57 -0500 Subject: [PATCH 10/19] Drop history-narration and a local-only doc reference from comments Several comments described HOW the 0.1.1 install script got into this repo ("recovered from PGXN's dist archive", "never previously in this repo's git history") instead of just stating what it is now (a byte-for-byte match of PGXN's originally published dist archive). Also: bin/test_update_path.sh referenced advanced-extension-testing.md, a container-local doc with no path anyone outside that session can resolve -- reworded to explain the dependency-guard/dynamic-version rationale inline instead. Fixed one accuracy issue found along the way: test/install/load.sql still named a separate "extension-update-test job" that no longer exists (folded into the main test job's matrix). --- .github/workflows/ci.yml | 14 +++++++------- Makefile | 25 ++++++++++++------------- bin/test_update_path.sh | 19 +++++++++++-------- sql/extension_drop--0.1.1--stable.sql | 19 ++++++++----------- test/install/load.sql | 12 ++++++------ 5 files changed, 44 insertions(+), 45 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81dd244..cecedf2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -166,13 +166,13 @@ jobs: - name: Test on PostgreSQL ${{ matrix.pg }} run: pg-build-test # Real update-path leg (0.1.1, extension_drop's last REAL published PGXN - # release, recovered from PGXN's dist archive -- see - # sql/extension_drop--0.1.1.sql -> stable, current source): runs here as - # extra steps in the same already-running container/cluster rather than - # a separate job, since a whole extra job means a whole extra container - # boot + PostgreSQL startup for no isolation benefit -- nothing about - # this leg needs its own environment, unlike e.g. pg_tle's job, which - # genuinely does. + # release, its install script matching PGXN's dist archive + # byte-for-byte -- see sql/extension_drop--0.1.1.sql -> stable, current + # source): runs here as extra steps in the same already-running + # container/cluster rather than a separate job, since a whole extra + # job means a whole extra container boot + PostgreSQL startup for no + # isolation benefit -- nothing about this leg needs its own + # environment, unlike e.g. pg_tle's job, which genuinely does. # # PG11+ only: cat_tools.routine__parse_arg_types_text() (which # extension_drop's install script calls unconditionally, in both 0.1.1 diff --git a/Makefile b/Makefile index a07e1c3..1b50756 100644 --- a/Makefile +++ b/Makefile @@ -13,10 +13,10 @@ PGXNTOOL_ENABLE_TEST_INSTALL = yes # Running the SAME suite/expected output against the result asserts # update behaves identically to a fresh install. TEST_UPDATE_FROM # defaults to 0.1.1, extension_drop's last REAL published PGXN release -# (2017) -- its install script was recovered from PGXN's dist archive -# and committed as sql/extension_drop--0.1.1.sql (it was never in this -# repo's git history; see RELEASE.md and HISTORY.asc), with a matching -# update-diff script at sql/extension_drop--0.1.1--stable.sql. Empty +# (2017) -- sql/extension_drop--0.1.1.sql matches PGXN's originally +# published dist archive byte-for-byte (see RELEASE.md and HISTORY.asc), +# with a matching update-diff script at +# sql/extension_drop--0.1.1--stable.sql. Empty # TEST_UPDATE_TO (the default) means "update to the current # default_version", which is now the `stable` pseudo-version. # - existing: the extension is ALREADY installed (a real pg_upgrade, or an @@ -40,7 +40,7 @@ endif # update-mode version range (load.sql only reads these in update mode). # Empty TEST_UPDATE_TO means "update to the current default_version" (now -# `stable`). TEST_UPDATE_FROM defaults to 0.1.1, the actual recovered compat +# `stable`). TEST_UPDATE_FROM defaults to 0.1.1, the actual real compat # floor -- still overridable (e.g. once a second real release ships) but no # longer required on every invocation. The guard below just protects against # someone explicitly blanking it out (TEST_UPDATE_FROM= on the command line). @@ -68,7 +68,7 @@ include pgxntool/base.mk # contents is a hard error instead of the check silently disappearing. PGXNTOOL_ENABLE_TEST_BUILD = yes -# The recovered real 0.1.1 install script (see sql/extension_drop--0.1.1.sql +# The real 0.1.1 install script (see sql/extension_drop--0.1.1.sql # and RELEASE.md) is a single-version file for a version that ISN'T the # current default_version ('stable'), so base.mk's DATA wildcard -- which # only picks up the CURRENT version file plus two-dash update-diff scripts, @@ -78,13 +78,12 @@ PGXNTOOL_ENABLE_TEST_BUILD = yes # VERSION '0.1.1'` at all, even though the update-diff script depends on that # exact file being installed. # -# NOTE: this used to need an explicit `DATA += sql/extension_drop--0.1.1.sql` -# here (Postgres-Extensions/pgxntool#48) -- pgxntool 2.3.0 already includes -# it in its own generated DATA list now that #48 is fixed upstream, so adding -# it again duplicated the file in DATA and broke `make install` ("will not -# overwrite just-created ... with ..."). Left this comment as a marker in -# case a future pgxntool downgrade or DATA-generation change brings the gap -# back -- verify with `make -s print-DATA` before assuming it's still needed. +# NOTE: do NOT add an explicit `DATA += sql/extension_drop--0.1.1.sql` here -- +# pgxntool 2.3.0's own generated DATA list already includes it +# (Postgres-Extensions/pgxntool#48), and duplicating it breaks `make install` +# ("will not overwrite just-created ... with ..."). If a future pgxntool +# downgrade or DATA-generation change ever stops covering this file, `make -s +# print-DATA` is how to confirm that before adding the line back. testdeps: test_extension test_extension: $(DESTDIR)$datadir)/extension/extension_drop_test.control $(wildcard $(TESTDIR)/*) diff --git a/bin/test_update_path.sh b/bin/test_update_path.sh index 6110b0b..4f2d69e 100755 --- a/bin/test_update_path.sh +++ b/bin/test_update_path.sh @@ -1,19 +1,22 @@ #!/bin/sh # Exercises the real extension_drop update path: 0.1.1 (the last REAL PGXN -# release, recovered from PGXN's dist archive -- see sql/extension_drop--0.1.1.sql -# and RELEASE.md/HISTORY.asc) -> stable (this repo's current source). +# release, its install script matching PGXN's originally published 2017 dist +# archive byte-for-byte -- see sql/extension_drop--0.1.1.sql and +# RELEASE.md/HISTORY.asc) -> stable (this repo's current source). # # Assumes extension_drop and cat_tools are already built and installed into # the active PostgreSQL cluster (`make install`, which pulls in the cat_tools # deps target first) and that psql's ambient connection defaults reach it. # -# Each step is PROVEN, not assumed -- see advanced-extension-testing.md -# section 4 (the dependency-guard technique) and section 6(d) (dynamic -# version assertions, never hardcoded): +# Each step is PROVEN, not assumed: the dependency-guard checks actually +# attempt the blocked DROP EXTENSION and inspect the real error, rather than +# trusting the guard exists; the version check reads extension_drop.control's +# default_version dynamically rather than hardcoding an expected value that +# would silently drift out of sync with a future release. # 1. CREATE EXTENSION extension_drop VERSION '0.1.1' -- installs the -# recovered real historical release. CASCADE (to auto-install -# cat_tools) only exists from PG10 -- pre-PG10 needs cat_tools created -# explicitly first, same branch test/install/load.sql already uses. +# actual historical release. CASCADE (to auto-install cat_tools) only +# exists from PG10 -- pre-PG10 needs cat_tools created explicitly +# first, same as test/install/load.sql. # 2. Plant a dependency-guard view and prove a non-CASCADE DROP EXTENSION # is blocked -- BEFORE the update, proving the guard actually attaches # to the 0.1.1-era extension_drop__commands table. diff --git a/sql/extension_drop--0.1.1--stable.sql b/sql/extension_drop--0.1.1--stable.sql index 547c4ec..06c0f9d 100644 --- a/sql/extension_drop--0.1.1--stable.sql +++ b/sql/extension_drop--0.1.1--stable.sql @@ -1,19 +1,16 @@ /* * Update path from 0.1.1 (extension_drop's last REAL published PGXN release, - * 2017 -- recovered from PGXN's dist archive as sql/extension_drop--0.1.1.sql - * since it was never committed to this repo's git history; see RELEASE.md - * and HISTORY.asc) to `stable` (this repo's current in-development source). + * 2017; sql/extension_drop--0.1.1.sql matches PGXN's dist archive + * byte-for-byte -- see RELEASE.md and HISTORY.asc) to `stable` (this repo's + * current in-development source). * - * The only actual behavioral delta between the two, found by diffing the - * recovered 0.1.1 script against current sql/extension_drop.sql, is the + * The only actual behavioral delta between the two is the * extension_drop__event_trigger() function body gaining one entry-point - * RAISE DEBUG line (added in the same commit that also fixed a cat_tools - * function rename -- see git history of sql/extension_drop.sql). That's the - * one change here. + * RAISE DEBUG line. That's the one change here. * - * Two other differences the diff turned up are deliberately NOT replayed - * here, because neither one changes anything about the objects this - * extension leaves behind after install completes: + * Two other differences between 0.1.1 and `stable` are deliberately NOT + * replayed here, because neither one changes anything about the objects + * this extension leaves behind after install completes: * - The client_min_messages save/restore HISTORY.asc's `stable` section * documents removing: that code only ever ran inside the install * script's own session, saving/restoring a GUC and dropping its own diff --git a/test/install/load.sql b/test/install/load.sql index aaac2d2..4ceb49e 100644 --- a/test/install/load.sql +++ b/test/install/load.sql @@ -20,12 +20,12 @@ * (extension_drop.test_update_from) then ALTER EXTENSION UPDATE -- to * extension_drop.test_update_to when that GUC is non-empty, otherwise to * the current default_version. extension_drop.test_update_from defaults - * to 0.1.1, the last REAL published PGXN release (2017) -- its install - * script was recovered from PGXN's dist archive (never previously in - * this repo's git history) as sql/extension_drop--0.1.1.sql, with a - * matching update-diff script at sql/extension_drop--0.1.1--stable.sql - * (see HISTORY.asc/RELEASE.md). This branch is exercised in CI by the - * extension-update-test job. + * to 0.1.1, the last REAL published PGXN release (2017); + * sql/extension_drop--0.1.1.sql matches PGXN's dist archive + * byte-for-byte, with a matching update-diff script at + * sql/extension_drop--0.1.1--stable.sql (see HISTORY.asc/RELEASE.md). + * This branch is exercised in CI as extra steps in the `test` job's + * own matrix (see ci.yml). * - existing: the extension is ALREADY installed (by a real binary * pg_upgrade, or an ALTER EXTENSION UPDATE performed outside the * suite). This branch must NOT drop/create/update it -- that would From 836639e6baa133baf2a4409734abeb62a7a6f8ba Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 10 Aug 2026 15:30:53 -0500 Subject: [PATCH 11/19] Drop overstated "REAL"/compat-floor framing and discovery narration from comments 0.1.1 is the only version of extension_drop ever published to PGXN, not "the last real" one in a series -- and describing it as an "actual real compat floor" implies a deliberate compatibility boundary that isn't there. Also drops HISTORY.asc's archaeology narration ("recovered... never committed... uploaded directly") and ci.yml's "has never surfaced before now" in favor of stating the current facts directly. --- .github/workflows/ci.yml | 10 +++++----- HISTORY.asc | 12 +++++------- Makefile | 14 +++++++------- bin/test_update_path.sh | 9 +++++---- sql/extension_drop--0.1.1--stable.sql | 4 ++-- test/install/load.sql | 2 +- 6 files changed, 25 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cecedf2..ae7c337 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -165,8 +165,8 @@ jobs: uses: actions/checkout@v7 - name: Test on PostgreSQL ${{ matrix.pg }} run: pg-build-test - # Real update-path leg (0.1.1, extension_drop's last REAL published PGXN - # release, its install script matching PGXN's dist archive + # Update-path leg (0.1.1, the only version of extension_drop published + # to PGXN, its install script matching PGXN's dist archive # byte-for-byte -- see sql/extension_drop--0.1.1.sql -> stable, current # source): runs here as extra steps in the same already-running # container/cluster rather than a separate job, since a whole extra @@ -179,9 +179,9 @@ jobs: # and current) transitively hits cat_tools's _cat_tools.function__drop_temp, # which runs a hardcoded `DROP ROUTINE` -- syntax that doesn't exist # before PG11. This affects a FRESH install of current extension_drop on - # PG9.3-10 too, not just this update leg; it's a real, pre-existing - # incompatibility this repo's non-gating CI has never surfaced before - # now (flagged separately, not something to fix here). + # PG9.3-10 too, not just this update leg; it's a pre-existing + # incompatibility this repo's CI doesn't gate on (flagged separately, + # not something to fix here). # # rsync: pgxntool's test-build feature needs it (see # pgxntool/run-test-build.sh), but pg-build-test above never actually diff --git a/HISTORY.asc b/HISTORY.asc index aed402e..847a9a7 100644 --- a/HISTORY.asc +++ b/HISTORY.asc @@ -1,12 +1,10 @@ STABLE ------ -== Add a real update path from 0.1.1 -Recovered the actual 0.1.1 install script from PGXN's dist archive (it was -never committed to this repo -- only ever generated as a build artifact and -uploaded directly) as `sql/extension_drop--0.1.1.sql`, and added -`sql/extension_drop--0.1.1--stable.sql` to bring an existing 0.1.1 install -up to date. Previously there was no update path at all from the only version -ever actually published to PGXN. +== Add an update path from 0.1.1 +Add `sql/extension_drop--0.1.1.sql` (matching PGXN's dist archive +byte-for-byte) and `sql/extension_drop--0.1.1--stable.sql`, providing an +update path from 0.1.1 -- the only version of extension_drop published to +PGXN -- to `stable`. == Drop support for PostgreSQL versions before 12 extension_drop depends on cat_tools, which already requires PostgreSQL diff --git a/Makefile b/Makefile index 1b50756..2ebb1e6 100644 --- a/Makefile +++ b/Makefile @@ -12,8 +12,8 @@ PGXNTOOL_ENABLE_TEST_INSTALL = yes # UPDATE -- to TEST_UPDATE_TO if set, otherwise to the current version. # Running the SAME suite/expected output against the result asserts # update behaves identically to a fresh install. TEST_UPDATE_FROM -# defaults to 0.1.1, extension_drop's last REAL published PGXN release -# (2017) -- sql/extension_drop--0.1.1.sql matches PGXN's originally +# defaults to 0.1.1, the only version of extension_drop published to +# PGXN (2017) -- sql/extension_drop--0.1.1.sql matches PGXN's originally # published dist archive byte-for-byte (see RELEASE.md and HISTORY.asc), # with a matching update-diff script at # sql/extension_drop--0.1.1--stable.sql. Empty @@ -40,10 +40,10 @@ endif # update-mode version range (load.sql only reads these in update mode). # Empty TEST_UPDATE_TO means "update to the current default_version" (now -# `stable`). TEST_UPDATE_FROM defaults to 0.1.1, the actual real compat -# floor -- still overridable (e.g. once a second real release ships) but no -# longer required on every invocation. The guard below just protects against -# someone explicitly blanking it out (TEST_UPDATE_FROM= on the command line). +# `stable`). TEST_UPDATE_FROM defaults to 0.1.1, the version this repo's +# update-path testing currently supports -- still overridable (e.g. once a +# later release ships). The guard below just protects against someone +# explicitly blanking it out (TEST_UPDATE_FROM= on the command line). TEST_UPDATE_FROM ?= 0.1.1 TEST_UPDATE_TO ?= ifeq ($(TEST_LOAD_SOURCE),update) @@ -68,7 +68,7 @@ include pgxntool/base.mk # contents is a hard error instead of the check silently disappearing. PGXNTOOL_ENABLE_TEST_BUILD = yes -# The real 0.1.1 install script (see sql/extension_drop--0.1.1.sql +# The 0.1.1 install script (see sql/extension_drop--0.1.1.sql # and RELEASE.md) is a single-version file for a version that ISN'T the # current default_version ('stable'), so base.mk's DATA wildcard -- which # only picks up the CURRENT version file plus two-dash update-diff scripts, diff --git a/bin/test_update_path.sh b/bin/test_update_path.sh index 4f2d69e..47aa0ca 100755 --- a/bin/test_update_path.sh +++ b/bin/test_update_path.sh @@ -1,8 +1,9 @@ #!/bin/sh -# Exercises the real extension_drop update path: 0.1.1 (the last REAL PGXN -# release, its install script matching PGXN's originally published 2017 dist -# archive byte-for-byte -- see sql/extension_drop--0.1.1.sql and -# RELEASE.md/HISTORY.asc) -> stable (this repo's current source). +# Exercises the extension_drop update path: 0.1.1 (the only version of +# extension_drop published to PGXN, its install script matching PGXN's +# originally published 2017 dist archive byte-for-byte -- see +# sql/extension_drop--0.1.1.sql and RELEASE.md/HISTORY.asc) -> stable (this +# repo's current source). # # Assumes extension_drop and cat_tools are already built and installed into # the active PostgreSQL cluster (`make install`, which pulls in the cat_tools diff --git a/sql/extension_drop--0.1.1--stable.sql b/sql/extension_drop--0.1.1--stable.sql index 06c0f9d..6ca99db 100644 --- a/sql/extension_drop--0.1.1--stable.sql +++ b/sql/extension_drop--0.1.1--stable.sql @@ -1,6 +1,6 @@ /* - * Update path from 0.1.1 (extension_drop's last REAL published PGXN release, - * 2017; sql/extension_drop--0.1.1.sql matches PGXN's dist archive + * Update path from 0.1.1 (the only version of extension_drop published to + * PGXN, 2017; sql/extension_drop--0.1.1.sql matches PGXN's dist archive * byte-for-byte -- see RELEASE.md and HISTORY.asc) to `stable` (this repo's * current in-development source). * diff --git a/test/install/load.sql b/test/install/load.sql index 4ceb49e..6e09287 100644 --- a/test/install/load.sql +++ b/test/install/load.sql @@ -20,7 +20,7 @@ * (extension_drop.test_update_from) then ALTER EXTENSION UPDATE -- to * extension_drop.test_update_to when that GUC is non-empty, otherwise to * the current default_version. extension_drop.test_update_from defaults - * to 0.1.1, the last REAL published PGXN release (2017); + * to 0.1.1, the only version of extension_drop published to PGXN (2017); * sql/extension_drop--0.1.1.sql matches PGXN's dist archive * byte-for-byte, with a matching update-diff script at * sql/extension_drop--0.1.1--stable.sql (see HISTORY.asc/RELEASE.md). From b5c860a24bd2338520f6a313dd405fd4ed3257a1 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 10 Aug 2026 16:23:10 -0500 Subject: [PATCH 12/19] Trim redundant byte-for-byte provenance justification from comments An update script from 0.1.1 to stable is ordinary infrastructure and doesn't need repeated defending -- the same "matches PGXN's dist archive byte-for-byte" justification was copy-pasted across six files. State it plainly once (in the file it actually concerns) and just reference the version/files elsewhere. --- .github/workflows/ci.yml | 14 ++++++-------- HISTORY.asc | 8 +++----- Makefile | 18 +++++++----------- bin/test_update_path.sh | 6 +----- sql/extension_drop--0.1.1--stable.sql | 6 ++---- test/install/load.sql | 9 +++------ 6 files changed, 22 insertions(+), 39 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ae7c337..a8bbe6b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -165,14 +165,12 @@ jobs: uses: actions/checkout@v7 - name: Test on PostgreSQL ${{ matrix.pg }} run: pg-build-test - # Update-path leg (0.1.1, the only version of extension_drop published - # to PGXN, its install script matching PGXN's dist archive - # byte-for-byte -- see sql/extension_drop--0.1.1.sql -> stable, current - # source): runs here as extra steps in the same already-running - # container/cluster rather than a separate job, since a whole extra - # job means a whole extra container boot + PostgreSQL startup for no - # isolation benefit -- nothing about this leg needs its own - # environment, unlike e.g. pg_tle's job, which genuinely does. + # Update-path leg (0.1.1 -> stable): runs here as extra steps in the + # same already-running container/cluster rather than a separate job, + # since a whole extra job means a whole extra container boot + + # PostgreSQL startup for no isolation benefit -- nothing about this + # leg needs its own environment, unlike e.g. pg_tle's job, which + # genuinely does. # # PG11+ only: cat_tools.routine__parse_arg_types_text() (which # extension_drop's install script calls unconditionally, in both 0.1.1 diff --git a/HISTORY.asc b/HISTORY.asc index 847a9a7..a13a972 100644 --- a/HISTORY.asc +++ b/HISTORY.asc @@ -1,10 +1,8 @@ STABLE ------ -== Add an update path from 0.1.1 -Add `sql/extension_drop--0.1.1.sql` (matching PGXN's dist archive -byte-for-byte) and `sql/extension_drop--0.1.1--stable.sql`, providing an -update path from 0.1.1 -- the only version of extension_drop published to -PGXN -- to `stable`. +== Add an update path from 0.1.1 to stable +Adds `sql/extension_drop--0.1.1.sql` and +`sql/extension_drop--0.1.1--stable.sql`. == Drop support for PostgreSQL versions before 12 extension_drop depends on cat_tools, which already requires PostgreSQL diff --git a/Makefile b/Makefile index 2ebb1e6..a70f97c 100644 --- a/Makefile +++ b/Makefile @@ -12,13 +12,10 @@ PGXNTOOL_ENABLE_TEST_INSTALL = yes # UPDATE -- to TEST_UPDATE_TO if set, otherwise to the current version. # Running the SAME suite/expected output against the result asserts # update behaves identically to a fresh install. TEST_UPDATE_FROM -# defaults to 0.1.1, the only version of extension_drop published to -# PGXN (2017) -- sql/extension_drop--0.1.1.sql matches PGXN's originally -# published dist archive byte-for-byte (see RELEASE.md and HISTORY.asc), -# with a matching update-diff script at -# sql/extension_drop--0.1.1--stable.sql. Empty -# TEST_UPDATE_TO (the default) means "update to the current -# default_version", which is now the `stable` pseudo-version. +# defaults to 0.1.1 (see sql/extension_drop--0.1.1.sql and +# sql/extension_drop--0.1.1--stable.sql). Empty TEST_UPDATE_TO (the +# default) means "update to the current default_version", which is now +# the `stable` pseudo-version. # - existing: the extension is ALREADY installed (a real pg_upgrade, or an # ALTER EXTENSION UPDATE done outside the suite). load.sql does not # touch it; it only asserts presence + current version. Pair with @@ -40,10 +37,9 @@ endif # update-mode version range (load.sql only reads these in update mode). # Empty TEST_UPDATE_TO means "update to the current default_version" (now -# `stable`). TEST_UPDATE_FROM defaults to 0.1.1, the version this repo's -# update-path testing currently supports -- still overridable (e.g. once a -# later release ships). The guard below just protects against someone -# explicitly blanking it out (TEST_UPDATE_FROM= on the command line). +# `stable`). TEST_UPDATE_FROM defaults to 0.1.1, overridable if needed. The +# guard below just protects against someone explicitly blanking it out +# (TEST_UPDATE_FROM= on the command line). TEST_UPDATE_FROM ?= 0.1.1 TEST_UPDATE_TO ?= ifeq ($(TEST_LOAD_SOURCE),update) diff --git a/bin/test_update_path.sh b/bin/test_update_path.sh index 47aa0ca..83f8cef 100755 --- a/bin/test_update_path.sh +++ b/bin/test_update_path.sh @@ -1,9 +1,5 @@ #!/bin/sh -# Exercises the extension_drop update path: 0.1.1 (the only version of -# extension_drop published to PGXN, its install script matching PGXN's -# originally published 2017 dist archive byte-for-byte -- see -# sql/extension_drop--0.1.1.sql and RELEASE.md/HISTORY.asc) -> stable (this -# repo's current source). +# Exercises the extension_drop update path: 0.1.1 -> stable. # # Assumes extension_drop and cat_tools are already built and installed into # the active PostgreSQL cluster (`make install`, which pulls in the cat_tools diff --git a/sql/extension_drop--0.1.1--stable.sql b/sql/extension_drop--0.1.1--stable.sql index 6ca99db..07aab96 100644 --- a/sql/extension_drop--0.1.1--stable.sql +++ b/sql/extension_drop--0.1.1--stable.sql @@ -1,8 +1,6 @@ /* - * Update path from 0.1.1 (the only version of extension_drop published to - * PGXN, 2017; sql/extension_drop--0.1.1.sql matches PGXN's dist archive - * byte-for-byte -- see RELEASE.md and HISTORY.asc) to `stable` (this repo's - * current in-development source). + * Update path from 0.1.1 to `stable` (this repo's current in-development + * source). * * The only actual behavioral delta between the two is the * extension_drop__event_trigger() function body gaining one entry-point diff --git a/test/install/load.sql b/test/install/load.sql index 6e09287..93d69bf 100644 --- a/test/install/load.sql +++ b/test/install/load.sql @@ -20,12 +20,9 @@ * (extension_drop.test_update_from) then ALTER EXTENSION UPDATE -- to * extension_drop.test_update_to when that GUC is non-empty, otherwise to * the current default_version. extension_drop.test_update_from defaults - * to 0.1.1, the only version of extension_drop published to PGXN (2017); - * sql/extension_drop--0.1.1.sql matches PGXN's dist archive - * byte-for-byte, with a matching update-diff script at - * sql/extension_drop--0.1.1--stable.sql (see HISTORY.asc/RELEASE.md). - * This branch is exercised in CI as extra steps in the `test` job's - * own matrix (see ci.yml). + * to 0.1.1 (see sql/extension_drop--0.1.1.sql and + * sql/extension_drop--0.1.1--stable.sql). This branch is exercised in CI + * as extra steps in the `test` job's own matrix (see ci.yml). * - existing: the extension is ALREADY installed (by a real binary * pg_upgrade, or an ALTER EXTENSION UPDATE performed outside the * suite). This branch must NOT drop/create/update it -- that would From 61f728f7205be2359c672cf34f7431fdd6ab5588 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 10 Aug 2026 16:52:22 -0500 Subject: [PATCH 13/19] Link the pre-PG11 DROP ROUTINE gap to an issue; drop stale/restating comments - ci.yml: point at Postgres-Extensions/extension_tools#44 instead of re-explaining the incompatibility inline and promising to track it "separately." - bin/test_update_path.sh: drop the "PROVEN, not assumed" framing -- that's just what a test does. - HISTORY.asc: a new version's update script isn't user-facing news, drop the entry. - Makefile: drop the paragraph claiming base.mk's DATA wildcard won't ship sql/extension_drop--0.1.1.sql on its own -- false since pgxntool 2.3.0, which already ships it (per the NOTE immediately below, which stays). --- .github/workflows/ci.yml | 6 ++---- HISTORY.asc | 4 ---- Makefile | 10 ---------- bin/test_update_path.sh | 10 +++++----- 4 files changed, 7 insertions(+), 23 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a8bbe6b..91c91bd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -176,10 +176,8 @@ jobs: # extension_drop's install script calls unconditionally, in both 0.1.1 # and current) transitively hits cat_tools's _cat_tools.function__drop_temp, # which runs a hardcoded `DROP ROUTINE` -- syntax that doesn't exist - # before PG11. This affects a FRESH install of current extension_drop on - # PG9.3-10 too, not just this update leg; it's a pre-existing - # incompatibility this repo's CI doesn't gate on (flagged separately, - # not something to fix here). + # before PG11 -- see + # https://github.com/Postgres-Extensions/extension_tools/issues/44. # # rsync: pgxntool's test-build feature needs it (see # pgxntool/run-test-build.sh), but pg-build-test above never actually diff --git a/HISTORY.asc b/HISTORY.asc index a13a972..7e6369e 100644 --- a/HISTORY.asc +++ b/HISTORY.asc @@ -1,9 +1,5 @@ STABLE ------ -== Add an update path from 0.1.1 to stable -Adds `sql/extension_drop--0.1.1.sql` and -`sql/extension_drop--0.1.1--stable.sql`. - == Drop support for PostgreSQL versions before 12 extension_drop depends on cat_tools, which already requires PostgreSQL 12+. A fresh install of extension_drop was already broken below that diff --git a/Makefile b/Makefile index a70f97c..b14b344 100644 --- a/Makefile +++ b/Makefile @@ -64,16 +64,6 @@ include pgxntool/base.mk # contents is a hard error instead of the check silently disappearing. PGXNTOOL_ENABLE_TEST_BUILD = yes -# The 0.1.1 install script (see sql/extension_drop--0.1.1.sql -# and RELEASE.md) is a single-version file for a version that ISN'T the -# current default_version ('stable'), so base.mk's DATA wildcard -- which -# only picks up the CURRENT version file plus two-dash update-diff scripts, -# not other historical single-version install files -- won't ship it on its -# own. Without this, `pgxn install extension_drop` (or any local `make -# install`) would silently stop being able to `CREATE EXTENSION extension_drop -# VERSION '0.1.1'` at all, even though the update-diff script depends on that -# exact file being installed. -# # NOTE: do NOT add an explicit `DATA += sql/extension_drop--0.1.1.sql` here -- # pgxntool 2.3.0's own generated DATA list already includes it # (Postgres-Extensions/pgxntool#48), and duplicating it breaks `make install` diff --git a/bin/test_update_path.sh b/bin/test_update_path.sh index 83f8cef..dbc3738 100755 --- a/bin/test_update_path.sh +++ b/bin/test_update_path.sh @@ -5,11 +5,11 @@ # the active PostgreSQL cluster (`make install`, which pulls in the cat_tools # deps target first) and that psql's ambient connection defaults reach it. # -# Each step is PROVEN, not assumed: the dependency-guard checks actually -# attempt the blocked DROP EXTENSION and inspect the real error, rather than -# trusting the guard exists; the version check reads extension_drop.control's -# default_version dynamically rather than hardcoding an expected value that -# would silently drift out of sync with a future release. +# The dependency-guard checks attempt the blocked DROP EXTENSION and inspect +# the actual error, rather than trusting the guard exists; the version check +# reads extension_drop.control's default_version dynamically rather than +# hardcoding an expected value that would silently drift out of sync with a +# future release. # 1. CREATE EXTENSION extension_drop VERSION '0.1.1' -- installs the # actual historical release. CASCADE (to auto-install cat_tools) only # exists from PG10 -- pre-PG10 needs cat_tools created explicitly From 876a899e9594d89bcc2195bd4e4dd95a42ad4414 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 10 Aug 2026 17:39:38 -0500 Subject: [PATCH 14/19] Drop the DATA-wildcard NOTE from the Makefile --- Makefile | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Makefile b/Makefile index b14b344..87dd8fb 100644 --- a/Makefile +++ b/Makefile @@ -64,13 +64,6 @@ include pgxntool/base.mk # contents is a hard error instead of the check silently disappearing. PGXNTOOL_ENABLE_TEST_BUILD = yes -# NOTE: do NOT add an explicit `DATA += sql/extension_drop--0.1.1.sql` here -- -# pgxntool 2.3.0's own generated DATA list already includes it -# (Postgres-Extensions/pgxntool#48), and duplicating it breaks `make install` -# ("will not overwrite just-created ... with ..."). If a future pgxntool -# downgrade or DATA-generation change ever stops covering this file, `make -s -# print-DATA` is how to confirm that before adding the line back. - testdeps: test_extension test_extension: $(DESTDIR)$datadir)/extension/extension_drop_test.control $(wildcard $(TESTDIR)/*) $(DESTDIR)$datadir)/extension/extension_drop_test.control: From d5a7f5cdb0e934be695133afd84b19cdde5ce1c3 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 10 Aug 2026 17:40:49 -0500 Subject: [PATCH 15/19] load.sql: stop naming the update-diff script's transient -stable suffix --- test/install/load.sql | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/install/load.sql b/test/install/load.sql index 93d69bf..e3904d7 100644 --- a/test/install/load.sql +++ b/test/install/load.sql @@ -20,9 +20,8 @@ * (extension_drop.test_update_from) then ALTER EXTENSION UPDATE -- to * extension_drop.test_update_to when that GUC is non-empty, otherwise to * the current default_version. extension_drop.test_update_from defaults - * to 0.1.1 (see sql/extension_drop--0.1.1.sql and - * sql/extension_drop--0.1.1--stable.sql). This branch is exercised in CI - * as extra steps in the `test` job's own matrix (see ci.yml). + * to 0.1.1 (see sql/extension_drop--0.1.1.sql). Exercised in CI as + * extra steps in the `test` job's own matrix (see ci.yml). * - existing: the extension is ALREADY installed (by a real binary * pg_upgrade, or an ALTER EXTENSION UPDATE performed outside the * suite). This branch must NOT drop/create/update it -- that would From 832f60ca229f513231d1e7f560bfd845c2969e83 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 10 Aug 2026 17:42:16 -0500 Subject: [PATCH 16/19] Drop the lead comment from sql/extension_drop--0.1.1--stable.sql --- sql/extension_drop--0.1.1--stable.sql | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/sql/extension_drop--0.1.1--stable.sql b/sql/extension_drop--0.1.1--stable.sql index 07aab96..b011c62 100644 --- a/sql/extension_drop--0.1.1--stable.sql +++ b/sql/extension_drop--0.1.1--stable.sql @@ -1,30 +1,3 @@ -/* - * Update path from 0.1.1 to `stable` (this repo's current in-development - * source). - * - * The only actual behavioral delta between the two is the - * extension_drop__event_trigger() function body gaining one entry-point - * RAISE DEBUG line. That's the one change here. - * - * Two other differences between 0.1.1 and `stable` are deliberately NOT - * replayed here, because neither one changes anything about the objects - * this extension leaves behind after install completes: - * - The client_min_messages save/restore HISTORY.asc's `stable` section - * documents removing: that code only ever ran inside the install - * script's own session, saving/restoring a GUC and dropping its own - * temp table before the script finished -- nothing it did was ever part - * of the extension's persisted state, so an already-installed 0.1.1 has - * nothing left to clean up. - * - cat_tools.function__arg_types_text() being renamed to - * cat_tools.routine__parse_arg_types_text(): that call only happens - * inside the CREATE EXTENSION script's internal __extension_drop.create_function() - * builder, transiently, to compute the argument list text for the - * REVOKE/GRANT statements it executes immediately -- it's never stored - * in any persisted function body. (cat_tools 0.3.0 also keeps the old - * name as a deprecated wrapper, so a fresh `CREATE EXTENSION - * extension_drop VERSION '0.1.1'` still works today for testing this - * very update path.) - */ CREATE OR REPLACE FUNCTION extension_drop__event_trigger( ) RETURNS event_trigger LANGUAGE plpgsql SET search_path FROM CURRENT AS $body$ From 451af714e344d50d29186b6c5910d7799061f4a2 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 10 Aug 2026 17:52:00 -0500 Subject: [PATCH 17/19] ci.yml: fix stale pg-upgrade-test header comment, trim verbosity Dropped claims contradicted elsewhere in the repo: extension_drop's declared version is no longer "1.0.0" and 0.1.1 is exactly the real, still-relevant release this PR adds an update path from -- not something that "predates the current SQL entirely". The old_pg-floor-vs-9.3 tangent is moot too: META.in.json's own floor is already 12, matching this job's, so there's no discrepancy left to explain. Also drops a container-local doc path and a reference to a specific commit message, neither resolvable outside this session/repo's git history. The CAT_TOOLS_GIT_REF mechanism this paragraph re-explained is already fully covered a few lines below (the env: block's own comment). --- .github/workflows/ci.yml | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 91c91bd..9d39281 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,22 +8,8 @@ name: CI # extension_drop version on an OLD cluster, plant a dependency guard, binary # pg_upgrade straight to a NEWER major, then run the suite in existing mode # against the real migrated objects (see bin/test_existing). No update step -# and no bridge leg: extension_drop has only ever shipped one real version -# (1.0.0 -- see HISTORY.asc/RELEASE.md; the only PGXN listing, 0.1.x from -# 2017, predates the current SQL entirely), so extversion never changes -# across a leg and there is no known pg_upgrade-unsafe old version to bridge -# from (see ~/advanced-extension-testing.md ยง6c's own guidance not to build -# that preemptively). Legs' old_pg floor is 12, NOT extension_drop's own -# claimed 9.3 floor above: this workflow's CAT_TOOLS_GIT_REF (see below) -# makes `make install` build cat_tools from the `0.3.0` git tag instead of -# PGXN (see the Makefile's `cat_tools` target comment -- PGXN's published -# cat_tools is a stale 2017 release extension_drop can't use), and that -# current cat_tools requires PostgreSQL >= 12 for a fresh install (its own META.json, -# build.requires.PostgreSQL). Below PG12, `make install` cannot complete at -# all today, independent of anything this job does -- consistent with the -# already-known pre-existing old-PG failures on the plain `test` job (see -# this branch's own history: "Revert ci.yml pg-build-test switch: -# pre-existing failures on old PG predate this branch"). +# and no bridge leg: extversion never changes across a leg, and there is no +# known pg_upgrade-unsafe old version to bridge from. # # Scope: push only runs on master (post-merge); PR commits are covered by # pull_request -- avoids double-running CI for the same commit. From 88b1f8c46a08c34867df2702ce04d20422ae9393 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 10 Aug 2026 18:04:09 -0500 Subject: [PATCH 18/19] Makefile: fix stale sql/extension_drop--1.0.0.sql reference in LINT_TARGETS comment No such file exists -- state the general policy (frozen version files aren't linted) instead of naming one, so it doesn't go stale again as new versions release. --- Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 87dd8fb..7984850 100644 --- a/Makefile +++ b/Makefile @@ -107,10 +107,10 @@ $(DESTDIR)$(datadir)/extension/cat_tools.control: # Style linter (see https://github.com/Postgres-Extensions/linter, vendored # at .vendor/linter -- lint.mk is the thin local hand-off, see its comment). # Scoped to the actively-maintained source rather than the default -# `sql/ test/`: sql/extension_drop--1.0.0.sql is a frozen, already-released -# version file (RELEASE.md's "Ongoing development" section -- once a version -# is released, its sql/--.sql is never hand-edited again), so -# linting it would produce permanent, unfixable findings and make `make -# lint` unusable as a CI gate. Lint the hand-maintained source instead. +# `sql/ test/`: frozen, already-released version files (RELEASE.md's +# "Ongoing development" section -- once a version is released, its +# sql/--.sql is never hand-edited again) would produce +# permanent, unfixable findings and make `make lint` unusable as a CI +# gate. Lint the hand-maintained source instead. LINT_TARGETS = sql/extension_drop.sql test/ include lint.mk From f373378a98c8c51fa7c87049f509c07fef6ec3d4 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 10 Aug 2026 18:21:32 -0500 Subject: [PATCH 19/19] Makefile: derive LINT_TARGETS from EXTENSION_SQL_FILES instead of hardcoding it pgxntool's control.mk.sh already generates EXTENSION_SQL_FILES (one sql/.sql per .control file at the repo root) -- exactly the hand-maintained-source scoping this needed, and it keeps working unchanged if this distribution ever gains a second extension. --- Makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 7984850..8fb1748 100644 --- a/Makefile +++ b/Makefile @@ -111,6 +111,9 @@ $(DESTDIR)$(datadir)/extension/cat_tools.control: # "Ongoing development" section -- once a version is released, its # sql/--.sql is never hand-edited again) would produce # permanent, unfixable findings and make `make lint` unusable as a CI -# gate. Lint the hand-maintained source instead. -LINT_TARGETS = sql/extension_drop.sql test/ +# gate. $(EXTENSION_SQL_FILES) (pgxntool's control.mk.sh, from each +# .control file at the repo root) is exactly the hand-maintained +# sql/.sql for every extension this distribution provides, so this +# keeps working if a second extension is ever added. +LINT_TARGETS = $(EXTENSION_SQL_FILES) test/ include lint.mk