From fa15ccb6c48c197a0dd1909d1d9836838d912528 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 25 Aug 2025 16:48:21 -0500 Subject: [PATCH 01/14] Switch to pgxn-tools based testing --- .github/workflows/ci.yml | 17 +++++++++++++++++ pg-travis-test.sh | 36 ------------------------------------ 2 files changed, 17 insertions(+), 36 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 pg-travis-test.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d4aaec9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,17 @@ +name: CI +on: [push, pull_request] +jobs: + test: + strategy: + matrix: + pg: [17, 16, 15, 14, 13, 12, 11, 10] + name: ๐Ÿ˜ PostgreSQL ${{ matrix.pg }} + runs-on: ubuntu-latest + container: pgxn/pgxn-tools + steps: + - name: Start PostgreSQL ${{ matrix.pg }} + run: pg-start ${{ matrix.pg }} + - name: Check out the repo + uses: actions/checkout@v4 + - name: Test on PostgreSQL ${{ matrix.pg }} + run: pg-build-test diff --git a/pg-travis-test.sh b/pg-travis-test.sh deleted file mode 100644 index f63ae43..0000000 --- a/pg-travis-test.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -# Based on https://gist.github.com/petere/6023944 - -set -eux - -sudo apt-get update - -packages="python-setuptools postgresql-$PGVERSION postgresql-server-dev-$PGVERSION postgresql-common" - -# bug: http://www.postgresql.org/message-id/20130508192711.GA9243@msgid.df7cb.de -sudo update-alternatives --remove-all postmaster.1.gz - -# stop all existing instances (because of https://github.com/travis-ci/travis-cookbooks/pull/221) -sudo service postgresql stop -# and make sure they don't come back -echo 'exit 0' | sudo tee /etc/init.d/postgresql -sudo chmod a+x /etc/init.d/postgresql - -sudo apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install $packages - -sudo easy_install pgxnclient - -PGPORT=55435 -PGCLUSTER_NAME=test - -export PGCLUSTER=9.6/$PGCLUSTER_NAME -env | grep PG -which pg_dump - -sudo pg_createcluster --start $PGVERSION $PGCLUSTER_NAME -p $PGPORT -- -A trust - -# TODO: have base.mk support dynamic sudo -sudo PGPORT=$PGPORT PGUSER=postgres PG_CONFIG=/usr/lib/postgresql/$PGVERSION/bin/pg_config make test - -[ ! -e test/regression.diffs ] From 99083b85d738c37639b860171783632bc01632cf Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 25 Aug 2025 16:56:03 -0500 Subject: [PATCH 02/14] Remove .travis.yml --- .travis.yml | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0c4e016..0000000 --- a/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: c -before_install: - - wget https://gist.github.com/petere/5893799/raw/apt.postgresql.org.sh - - sudo sh ./apt.postgresql.org.sh - - sudo sh -c "echo deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs 2>/dev/null)-pgdg main $PGVERSION >> /etc/apt/sources.list.d/pgdg.list" -env: - - PGVERSION=9.6 - - PGVERSION=9.5 - - PGVERSION=9.4 - - PGVERSION=9.3 - - PGVERSION=9.2 - -script: bash ./pg-travis-test.sh From aa53b9118ab7d57b489259830f5f3872687ad244 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 25 Aug 2025 17:00:46 -0500 Subject: [PATCH 03/14] Remove errant vim swapfile --- sql/.object_reference.sql.swo | Bin 45056 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 sql/.object_reference.sql.swo diff --git a/sql/.object_reference.sql.swo b/sql/.object_reference.sql.swo deleted file mode 100644 index b3912fe9de65698c7165ac4804adbf23100b021e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45056 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 From 68e8afc25c70301e286eb6652f1529c5129eefbe Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 25 Aug 2025 17:15:46 -0500 Subject: [PATCH 04/14] Update test workflow --- .github/workflows/ci.yml | 4 +++- .gitignore | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d4aaec9..ce8882f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,4 +14,6 @@ jobs: - name: Check out the repo uses: actions/checkout@v4 - name: Test on PostgreSQL ${{ matrix.pg }} - run: pg-build-test + run: make test + - name: Test pg_dump + run: make dump_test diff --git a/.gitignore b/.gitignore index facf651..8e63124 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ regression.out # Misc tmp/ .DS_Store +.claude/settings.local.json From 9859566d2b12a5340b9b00be8819ce5f2dddebaa Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 25 Aug 2025 17:26:46 -0500 Subject: [PATCH 05/14] Add missing PGUSER argument --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce8882f..cea4aa8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,6 +14,6 @@ jobs: - name: Check out the repo uses: actions/checkout@v4 - name: Test on PostgreSQL ${{ matrix.pg }} - run: make test + run: make test PGUSER=postgres - name: Test pg_dump - run: make dump_test + run: make dump_test PGUSER=postgres From 9a1e50bd56c106bb73458f21fb200b485f36ace6 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 25 Aug 2025 17:29:31 -0500 Subject: [PATCH 06/14] Fix dump test --- test/dump/run.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/dump/run.sh b/test/dump/run.sh index 4d0c7a3..6896f68 100755 --- a/test/dump/run.sh +++ b/test/dump/run.sh @@ -26,7 +26,7 @@ if [ "$1" == "-f" ]; then fi echo Creating dump database -createdb test_dump && psql -f test/dump/load_all.sql test_dump > $create_log || die 3 "Unable to create dump database" +createdb test_dump && psql -Xf test/dump/load_all.sql test_dump > $create_log || die 3 "Unable to create dump database" # Ensure no errors in log check_log() { @@ -45,8 +45,8 @@ check_log $create_log creation echo Running dump and restore # No real need to cat the log on failure here; psql will generate an error and even if not verify will almost certainly catch it -createdb test_load && PAGER='' psql -c '\df pg_get_object_address' test_load || die 5 'crap' -(echo 'BEGIN;' && pg_dump test_dump && echo 'COMMIT;') | psql -q -v VERBOSITY=verbose -v ON_ERROR_STOP=true test_load > $restore_log +createdb test_load && PAGER='' psql -Xc '\df pg_get_object_address' test_load || die 5 'crap' +(echo 'BEGIN;' && pg_dump test_dump && echo 'COMMIT;') | psql -q -X -v VERBOSITY=verbose -v ON_ERROR_STOP=true test_load > $restore_log rc=$? if [ $rc -ne 0 ]; then cat $restore_log @@ -54,7 +54,7 @@ if [ $rc -ne 0 ]; then fi echo Verifying restore -psql -f test/dump/verify.sql test_load > $verify_log || die 5 "Test failed" +psql -Xf test/dump/verify.sql test_load > $verify_log || die 5 "Test failed" check_log $create_log verify From 594d248ce1ae0822e8940fc5bc0861005ab016d2 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 25 Aug 2025 17:35:03 -0500 Subject: [PATCH 07/14] Squashed 'pgxntool/' changes from 890053c..e9c24de e9c24de Fix pg_regress on versions > 12 (#5) c0af00f Improvements to HISTORY.asc 6e8f2a7 Allow use of sudo when installing an extension 705f1ec Don't run clean as part of make test 370fa8e Create test/sql during setup git-subtree-dir: pgxntool git-subtree-split: e9c24de986ddc85bbd1fb3149076888d075ce100 --- HISTORY.asc | 13 ++++++++++--- base.mk | 14 ++++++++++---- setup.sh | 1 + 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/HISTORY.asc b/HISTORY.asc index b69c9d1..9cb793b 100644 --- a/HISTORY.asc +++ b/HISTORY.asc @@ -1,5 +1,11 @@ STABLE ------ +== Support 13+ +The `--load-language` option was removed from `pg_regress` in 13. + +== Reduce verbosity from test setup +As part of this change, you will want to review the changes to test/deps.sql. + === Support asciidoc documentation targets By default, if asciidoctor or asciidoc exists on the system, any files in doc/ that end in .adoc or .asciidoc will be processed to html. See the README for full details. @@ -12,11 +18,12 @@ If a test input file changes we certainly need to re-run tests. === Have test/pgxntool/setup.sql install tap before running deps.sql -=== Reduce verbosity from test setup -As part of this change, you will want to review the changes to test/deps.sql. - === Support other asciidoc extensions +=== Create the test/sql/ directory during setup + +=== Use `--sudo` option when installing pgtap + 0.2.0 ----- ### Stop using $(VERSION) diff --git a/base.mk b/base.mk index ce918db..a976ebb 100644 --- a/base.mk +++ b/base.mk @@ -36,7 +36,7 @@ TEST_SQL_FILES += $(wildcard $(TESTDIR)/sql/*.sql) TEST_RESULT_FILES = $(patsubst $(TESTDIR)/sql/%.sql,$(TESTDIR)/expected/%.out,$(TEST_SQL_FILES)) TEST_FILES = $(TEST_SOURCE_FILES) $(TEST_SQL_FILES) REGRESS = $(sort $(notdir $(subst .source,,$(TEST_FILES:.sql=)))) # Sort is to get unique list -REGRESS_OPTS = --inputdir=$(TESTDIR) --outputdir=$(TESTOUT) --load-language=plpgsql +REGRESS_OPTS = --inputdir=$(TESTDIR) --outputdir=$(TESTOUT) # See additional setup below MODULES = $(patsubst %.c,%,$(wildcard src/*.c)) ifeq ($(strip $(MODULES)),) MODULES =# Set to NUL so PGXS doesn't puke @@ -57,8 +57,10 @@ GE91 = $(call test, $(MAJORVER), -ge, 91) ifeq ($(GE91),yes) all: $(EXTENSION_VERSION_FILES) +endif -#DATA = $(wildcard sql/*--*.sql) +ifeq ($($call test, $(MAJORVER), -lt 13), yes) + REGRESS_OPTS += --load-language=plpgsql endif PGXS := $(shell $(PG_CONFIG) --pgxs) @@ -77,8 +79,12 @@ installcheck: $(TEST_RESULT_FILES) $(TEST_OUT_FILES) $(TEST_SQL_FILES) $(TEST_SO # make test: run any test dependencies, then do a `make install installcheck`. # If regressions are found, it will output them. +# +# This used to depend on clean as well, but that causes problems with +# watch-make if you're generating intermediate files. If tests end up needing +# clean it's an indication of a missing dependency anyway. .PHONY: test -test: clean testdeps install installcheck +test: testdeps install installcheck @if [ -r $(TESTOUT)/regression.diffs ]; then cat $(TESTOUT)/regression.diffs; fi # make results: runs `make test` and copy all result files to expected @@ -220,6 +226,6 @@ installcheck: pgtap pgtap: $(DESTDIR)$(datadir)/extension/pgtap.control $(DESTDIR)$(datadir)/extension/pgtap.control: - pgxn install pgtap + pgxn install pgtap --sudo endif # fndef PGXNTOOL_NO_PGXS_INCLUDE diff --git a/setup.sh b/setup.sh index 3730a2b..881ccaa 100755 --- a/setup.sh +++ b/setup.sh @@ -46,6 +46,7 @@ git add META.json mkdir -p sql test src cd test +mkdir -p sql safecp ../pgxntool/test/deps.sql deps.sql [ -d pgxntool ] || ln -s ../pgxntool/test/pgxntool . git add pgxntool From 8dc5cfcb90896f6269a25aa35e902311fc688116 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 25 Aug 2025 17:36:24 -0500 Subject: [PATCH 08/14] dump test is actually included in make test --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cea4aa8..3183031 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,5 +15,3 @@ jobs: uses: actions/checkout@v4 - name: Test on PostgreSQL ${{ matrix.pg }} run: make test PGUSER=postgres - - name: Test pg_dump - run: make dump_test PGUSER=postgres From 3eefe4ce13ffc73d8ecc5fe718290d85f4ca6601 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 4 Aug 2026 18:35:56 -0500 Subject: [PATCH 09/14] Add SQL style linter (vendored Postgres-Extensions/linter) Vendor Postgres-Extensions/linter as a git submodule at .vendor/linter, following the same pattern already adopted in cat_tools: a thin self-initializing lint.mk hand-off (so `make lint` works right after a plain `git clone`, no --recurse-submodules needed), LINT_TARGETS scoped to sql/object_reference.sql and test/ (excluding the frozen, never hand-edited versioned install files under sql/, e.g. object_reference--0.1.0.sql/--stable.sql), and a CI job that runs `make lint` directly -- the same entry point a developer uses locally -- so the self-init logic is actually exercised, not just the rule checking. The `include lint.mk` is guarded on .git being present: a tarball build (PGXN distribution, `git archive` with no .git) has no submodule to initialize, and Make resolves every `include` before running any target regardless of which one was requested, so an unguarded rule would break `make`/`make install` entirely for a tarball build, not just `make lint`. Fixes the real pre-existing style findings this first run turned up (52 total): most were commented-out SQL marked as prose comments instead of using the linter's `EXCLUDED CODE` disabled-code convention (missing " * " prefixes flagged as comment-line-prefix/comment-opening violations); one COPY data block's `secondary` column intentionally mirrors pg_catalog's own type display name ("integer" for int4) rather than following prefer-short-type, so it's suppressed via a scoped disable-block region instead of being "fixed" into incorrect test data. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/ci.yml | 20 ++++++++++++++++++++ .gitmodules | 3 +++ .vendor/linter | 1 + Makefile | 20 ++++++++++++++++++++ lint.mk | 11 +++++++++++ sql/object_reference--stable.sql | 8 ++++---- sql/object_reference.sql | 8 ++++---- test/deps.sql | 3 +-- test/helpers/object_table.sql | 4 +++- test/sql/capture.sql | 2 +- test/sql/event_trigger.sql | 2 +- test/sql/object_group.sql | 4 ++-- 12 files changed, 71 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .gitmodules create mode 160000 .vendor/linter create mode 100644 lint.mk diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4b3e970 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,20 @@ +name: CI + +on: [push, pull_request] + +jobs: + # Style linter (https://github.com/Postgres-Extensions/linter, vendored at + # .vendor/linter -- lint.mk is the thin local hand-off, see its comment). + # Deliberately checked out WITHOUT submodules -- `make lint` is the same + # command a developer runs locally, and lint.mk self-initializes the + # submodule on first use. Using the exact same entry point here is what + # actually proves that self-init works, rather than papering over it with + # a submodules: true checkout. + lint: + name: ๐Ÿงน SQL Lint + runs-on: ubuntu-latest + steps: + - name: Check out the repo + uses: actions/checkout@v4 + - name: Lint SQL + run: make lint diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..9443c64 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule ".vendor/linter"] + path = .vendor/linter + url = https://github.com/Postgres-Extensions/linter.git diff --git a/.vendor/linter b/.vendor/linter new file mode 160000 index 0000000..b40aaf7 --- /dev/null +++ b/.vendor/linter @@ -0,0 +1 @@ +Subproject commit b40aaf70be8af80f048da777e551c5b790bd9e69 diff --git a/Makefile b/Makefile index 9ae665d..006453e 100644 --- a/Makefile +++ b/Makefile @@ -32,3 +32,23 @@ test_factory: $(DESTDIR)$(datadir)/extension/test_factory.control $(DESTDIR)$(datadir)/extension/test_factory.control: pgxn install test_factory + +# 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 sql/object_reference.sql rather than the default `sql/ test/`: +# the versioned install/update files under sql/ (object_reference--*.sql, +# e.g. object_reference--0.1.0.sql/--stable.sql) are frozen once released and +# never hand-edited again (see this repo's CLAUDE.md / memory), so linting +# them would produce permanent, unfixable findings and make `make lint` +# unusable as a CI gate. +# +# Guarded on .git being present: a tarball build (PGXN distribution, or any +# `git archive` checkout with no .git) has no submodule to initialize, and +# Make resolves every `include` before running any target regardless of +# which target was requested -- so an unguarded self-init rule in lint.mk +# would break `make`/`make install` entirely for a tarball build, not just +# `make lint`. +ifneq ($(wildcard .git),) +LINT_TARGETS = sql/object_reference.sql test/ +include lint.mk +endif diff --git a/lint.mk b/lint.mk new file mode 100644 index 0000000..0d18abf --- /dev/null +++ b/lint.mk @@ -0,0 +1,11 @@ +# lint.mk โ€” thin wrapper; the whole local footprint for consuming +# https://github.com/Postgres-Extensions/linter. Everything else lives in +# the .vendor/linter submodule; see its README for available targets/rules. +# +# Self-initializing (via the rule below) so `make lint` works right after a +# plain `git clone`, with no --recurse-submodules needed, and so CI can rely +# on the exact same entry point a developer would use locally. +.vendor/linter/lint.mk: + git submodule update --init -- .vendor/linter + +include .vendor/linter/lint.mk diff --git a/sql/object_reference--stable.sql b/sql/object_reference--stable.sql index 4a68ebc..5333ba2 100644 --- a/sql/object_reference--stable.sql +++ b/sql/object_reference--stable.sql @@ -14,7 +14,7 @@ BEGIN RAISE DEBUG 'search_path changed to %', current_setting('search_path'); END $$; -/* +/* EXCLUDED CODE: schema-restriction check below not currently enforced DO $$ DECLARE c_schema CONSTANT name := (SELECT extnamespace::regnamespace::text FROM pg_extension WHERE extname = 'cat_tools'); @@ -180,7 +180,7 @@ CREATE TABLE _object_reference.object( , object_names text[] NOT NULL , object_args text[] NOT NULL , CONSTRAINT object__u_object_names__object_args UNIQUE( object_type, object_names, object_args ) - /* TODO: this can't be a trigger because some objects won't exist when a dump is loaded + /* EXCLUDED CODE: TODO: this can't be a trigger because some objects won't exist when a dump is loaded , CONSTRAINT object__address_sanity -- pg_get_object_address will throw an error if anything is wrong, so the IS NOT NULL is mostly pointless CHECK( pg_catalog.pg_get_object_address(object_type::text, object_names, object_args) IS NOT NULL ) @@ -193,7 +193,7 @@ GRANT REFERENCES ON _object_reference.object TO object_reference__dependency; CREATE TABLE _object_reference._object_oid( object_id int PRIMARY KEY REFERENCES _object_reference.object ON DELETE CASCADE ON UPDATE CASCADE , classid regclass NOT NULL - /* TODO: needs to be a trigger + /* EXCLUDED CODE: TODO: needs to be a trigger CONSTRAINT classid_must_match__object__address_classid CHECK( classid IS NOT DISTINCT FROM cat_tools.object__address_classid(object_type) ) */ @@ -1254,7 +1254,7 @@ BEGIN RETURN c_next_level; EXCEPTION WHEN undefined_table THEN - /* + /* EXCLUDED CODE CREATE TEMP TABLE __object_reference__ddl_capture AS SELECT c_next_level, capture__start.object_group_id ; diff --git a/sql/object_reference.sql b/sql/object_reference.sql index e83b461..bc4ee0d 100644 --- a/sql/object_reference.sql +++ b/sql/object_reference.sql @@ -13,7 +13,7 @@ BEGIN RAISE DEBUG 'search_path changed to %', current_setting('search_path'); END $$; -/* +/* EXCLUDED CODE: schema-restriction check below not currently enforced DO $$ DECLARE c_schema CONSTANT name := (SELECT extnamespace::regnamespace::text FROM pg_extension WHERE extname = 'cat_tools'); @@ -179,7 +179,7 @@ CREATE TABLE _object_reference.object( , object_names text[] NOT NULL , object_args text[] NOT NULL , CONSTRAINT object__u_object_names__object_args UNIQUE( object_type, object_names, object_args ) - /* TODO: this can't be a trigger because some objects won't exist when a dump is loaded + /* EXCLUDED CODE: TODO: this can't be a trigger because some objects won't exist when a dump is loaded , CONSTRAINT object__address_sanity -- pg_get_object_address will throw an error if anything is wrong, so the IS NOT NULL is mostly pointless CHECK( pg_catalog.pg_get_object_address(object_type::text, object_names, object_args) IS NOT NULL ) @@ -192,7 +192,7 @@ GRANT REFERENCES ON _object_reference.object TO object_reference__dependency; CREATE TABLE _object_reference._object_oid( object_id int PRIMARY KEY REFERENCES _object_reference.object ON DELETE CASCADE ON UPDATE CASCADE , classid regclass NOT NULL - /* TODO: needs to be a trigger + /* EXCLUDED CODE: TODO: needs to be a trigger CONSTRAINT classid_must_match__object__address_classid CHECK( classid IS NOT DISTINCT FROM cat_tools.object__address_classid(object_type) ) */ @@ -1253,7 +1253,7 @@ BEGIN RETURN c_next_level; EXCEPTION WHEN undefined_table THEN - /* + /* EXCLUDED CODE CREATE TEMP TABLE __object_reference__ddl_capture AS SELECT c_next_level, capture__start.object_group_id ; diff --git a/test/deps.sql b/test/deps.sql index e1a53c8..b0ee45f 100644 --- a/test/deps.sql +++ b/test/deps.sql @@ -2,8 +2,7 @@ -- Add any test dependency statements here -/* - * Normally these should be loaded by the cascade! +/* EXCLUDED CODE: normally these should be loaded by the cascade! CREATE EXTENSION IF NOT EXISTS count_nulls; CREATE EXTENSION IF NOT EXISTS cat_tools; */ diff --git a/test/helpers/object_table.sql b/test/helpers/object_table.sql index 67f07ee..ca90234 100644 --- a/test/helpers/object_table.sql +++ b/test/helpers/object_table.sql @@ -144,6 +144,7 @@ INSERT INTO test_prereq VALUES ; -- \N is null character +-- sql-lint:disable-block prefer-short-type: secondary column mirrors pg_catalog's own type display name (format_type), not a style choice COPY test_object(object_type, object_name, secondary, create_command, drop_command) FROM STDIN (DELIMITER '|'); table|test table||%("test column" int)| index|test table test index||%ON "test table"("test column")| @@ -159,8 +160,9 @@ cast|test type|integer|CREATE CAST ("test type" AS int4) WITH INOUT|DROP CAST (" default value|test table|test column|ALTER TABLE "test table" ALTER "test column" SET DEFAULT 0|ALTER TABLE "test table" ALTER "test column" DROP DEFAULT trigger|test table|test trigger|CREATE TRIGGER "test trigger" AFTER INSERT ON "test table" FOR EACH ROW EXECUTE PROCEDURE tg_null()|DROP TRIGGER "test trigger" ON "test table" \. +-- sql-lint:enable-block -/* Not supported +/* EXCLUDED CODE: Not supported composite type|test complex type||CREATE TYPE "test complex type" AS(r real, i real)|DROP TYPE "test complex type" view column|test view|test column|\N|\N materialized view column|test materialized view 2|test materialized view column|CREATE MATERIALIZED VIEW "test materialized view 2" AS SELECT (1,2)::"test complex type" AS "test materialized view column"|DROP MATERIALIZED VIEW "test materialized view 2" diff --git a/test/sql/capture.sql b/test/sql/capture.sql index 8eb1414..073f3f3 100644 --- a/test/sql/capture.sql +++ b/test/sql/capture.sql @@ -134,7 +134,7 @@ SELECT bag_eq( , $$SELECT object_id FROM obj_ref$$ , 'Verify captured object IDs match' ); -/* +/* EXCLUDED CODE SELECT * FROM og_o; SELECT * FROM _object_reference.object;-- WHERE object_id IN(6,9); */ diff --git a/test/sql/event_trigger.sql b/test/sql/event_trigger.sql index 2115dc7..402a5b4 100644 --- a/test/sql/event_trigger.sql +++ b/test/sql/event_trigger.sql @@ -143,7 +143,7 @@ $body$; /* - *Rename column + * Rename column */ SELECT lives_ok( $$ALTER TABLE table_under_test RENAME column_test TO test_column2$$ diff --git a/test/sql/object_group.sql b/test/sql/object_group.sql index 6304892..d90957b 100644 --- a/test/sql/object_group.sql +++ b/test/sql/object_group.sql @@ -82,7 +82,7 @@ SELECT is( ); -- __object__add -/* TODO +/* EXCLUDED CODE: TODO SELECT pg_temp.bogus_group( format( $$SELECT object_reference.object_group__object__add(%%s, %s)$$ @@ -107,7 +107,7 @@ SELECT throws_ok( -- Can't use helper here , 'object group "absurd group name used only for testing purposes ktxbye" does not exist' , 'object__getsert with bogus group name' ); -/* TODO +/* EXCLUDED CODE: TODO SELECT throws_ok( -- Can't use helper here $$CREATE TEMP TABLE col1_id AS SELECT * FROM object_reference.object__getsert_w_group_id('table column', 'test_table_1', 'col1', -1)$$ , '' From 1f8bbfe2c65c1879429546ff28bb909c33916801 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 4 Aug 2026 18:39:48 -0500 Subject: [PATCH 10/14] Build cat_tools from its 0.3.0 git tag instead of pgxn install --unstable pgxn install --unstable cat_tools resolves to the newest release actually published to the PGXN package index, which is still 0.2.1 (2017) -- it fails standalone on modern PostgreSQL with "column oid specified more than once" at CREATE EXTENSION. cat_tools 0.3.0 fixes this but hasn't been uploaded to PGXN yet, only tagged in git, so build it from that tag directly until PGXN has it. Co-Authored-By: Claude Sonnet 5 --- Makefile | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9ae665d..ec25834 100644 --- a/Makefile +++ b/Makefile @@ -17,10 +17,23 @@ extra_clean += $(wildcard test/dump/*.log) dump_test: test/dump/run.sh test/helpers/object_table.sql $(wildcard test/dump/*.sql) $< -f # Force drop of databases if they exist +CAT_TOOLS_VERSION = 0.3.0 +CAT_TOOLS_BUILD_DIR = tmp/cat_tools-$(CAT_TOOLS_VERSION) +extra_clean += $(CAT_TOOLS_BUILD_DIR) + .PHONY: cat_tools cat_tools: $(DESTDIR)$(datadir)/extension/cat_tools.control $(DESTDIR)$(datadir)/extension/cat_tools.control: - pgxn install --unstable cat_tools + # `pgxn install --unstable cat_tools` resolves to the newest release + # published to the PGXN package index, which is still 0.2.1 -- it fails + # standalone on modern PostgreSQL with "column oid specified more than + # once" at CREATE EXTENSION. A fixed release, 0.3.0, is tagged in + # cat_tools' own git repo but hasn't been uploaded to PGXN yet, so build + # it from that tag directly until PGXN has it. + rm -rf $(CAT_TOOLS_BUILD_DIR) + git clone --branch $(CAT_TOOLS_VERSION) --depth 1 https://github.com/Postgres-Extensions/cat_tools.git $(CAT_TOOLS_BUILD_DIR) + $(MAKE) -C $(CAT_TOOLS_BUILD_DIR) install PG_CONFIG=$(PG_CONFIG) DESTDIR=$(DESTDIR) + rm -rf $(CAT_TOOLS_BUILD_DIR) .PHONY: count_nulls count_nulls: $(DESTDIR)$(datadir)/extension/count_nulls.control From 48edb3dc8269349358e3a9f1e4d0b921a3aee289 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 4 Aug 2026 18:40:01 -0500 Subject: [PATCH 11/14] Adapt to cat_tools 0.3.0: renamed function, two new object types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cat_tools 0.3.0 is the first version of cat_tools this extension's test suite has ever actually run against (pgxn install --unstable previously resolved to a version that failed CREATE EXTENSION outright, so none of this was exercised before now): - cat_tools.function__arg_types_text() is deprecated in 0.3.0 in favor of cat_tools.routine__parse_arg_types_text() (same signature, same body, just renamed) and now emits a WARNING on every call. Switch to the non-deprecated name directly rather than carrying the warning forward. - cat_tools 0.3.0's object_type enum gained two new members, "partitioned table" and "partitioned index". object_reference has no per-object-type special-casing (object identity is tracked generically via classid/objid), so these are already handled by the existing code the same way "table" and "index" are -- they just weren't yet reflected in object_reference's own classification of which object types are covered by a test. Add them to the untested() set so object_reference.untested_srf() โˆช tested types โˆช unsupported() still accounts for every member of the enum; a follow-up can add dedicated create/drop test coverage for them. - Regenerate sql/object_reference--stable.sql (auto-generated from sql/object_reference.sql) and test/expected/zzz_build.out (line numbers in test/temp_load.not_sql shift by one now that a source comment line changed) to match. Co-Authored-By: Claude Sonnet 5 --- sql/object_reference--stable.sql | 5 ++- sql/object_reference.sql | 5 ++- test/expected/zzz_build.out | 64 ++++++++++++++++++++++++++++++-- 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/sql/object_reference--stable.sql b/sql/object_reference--stable.sql index 4a68ebc..55449ab 100644 --- a/sql/object_reference--stable.sql +++ b/sql/object_reference--stable.sql @@ -85,7 +85,7 @@ CREATE FUNCTION __object_reference.create_function( , grants text DEFAULT NULL ) RETURNS void LANGUAGE plpgsql AS $body$ DECLARE - c_clean_args text := cat_tools.function__arg_types_text(args); + c_clean_args text := cat_tools.routine__parse_arg_types_text(args); create_template CONSTANT text := $template$ CREATE OR REPLACE FUNCTION %s( @@ -572,7 +572,8 @@ foreign table, foreign table column, aggregate, collation, conversion, language, large object, operator, operator class, operator family, operator of access method, function of access method, rule, text search parser, text search dictionary, text search template, text search configuration, foreign-data wrapper, server, -user mapping, default acl, transform, access method, extension, policy +user mapping, default acl, transform, access method, extension, policy, +partitioned table, partitioned index }'::cat_tools.object_type[] $body$ , 'Returns array of object types that have not been tested.' diff --git a/sql/object_reference.sql b/sql/object_reference.sql index e83b461..2b38b90 100644 --- a/sql/object_reference.sql +++ b/sql/object_reference.sql @@ -84,7 +84,7 @@ CREATE FUNCTION __object_reference.create_function( , grants text DEFAULT NULL ) RETURNS void LANGUAGE plpgsql AS $body$ DECLARE - c_clean_args text := cat_tools.function__arg_types_text(args); + c_clean_args text := cat_tools.routine__parse_arg_types_text(args); create_template CONSTANT text := $template$ CREATE OR REPLACE FUNCTION %s( @@ -571,7 +571,8 @@ foreign table, foreign table column, aggregate, collation, conversion, language, large object, operator, operator class, operator family, operator of access method, function of access method, rule, text search parser, text search dictionary, text search template, text search configuration, foreign-data wrapper, server, -user mapping, default acl, transform, access method, extension, policy +user mapping, default acl, transform, access method, extension, policy, +partitioned table, partitioned index }'::cat_tools.object_type[] $body$ , 'Returns array of object types that have not been tested.' diff --git a/test/expected/zzz_build.out b/test/expected/zzz_build.out index fe92660..467431f 100644 --- a/test/expected/zzz_build.out +++ b/test/expected/zzz_build.out @@ -2,16 +2,26 @@ This extension must be loaded via CREATE EXTENSION object_reference; You really, REALLY do NOT want to try and load this via psql!!! -psql:test/temp_load.not_sql:188: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! +psql:test/temp_load.not_sql:187: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! -psql:test/temp_load.not_sql:189: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! +psql:test/temp_load.not_sql:188: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! +psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference._object_oid.object_id%TYPE converted to integer +psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference.object.object_type%TYPE converted to cat_tools.object_type +psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference._object_oid.classid%TYPE converted to regclass +psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference._object_oid.objid%TYPE converted to oid +psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference._object_oid.objsubid%TYPE converted to integer +psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference._object_oid.object_id%TYPE converted to integer +psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference.object.object_type%TYPE converted to cat_tools.object_type +psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference._object_oid.classid%TYPE converted to regclass +psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference._object_oid.objid%TYPE converted to oid +psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference._object_oid.objsubid%TYPE converted to integer -psql:test/temp_load.not_sql:513: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! +psql:test/temp_load.not_sql:512: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! @@ -25,24 +35,72 @@ psql:test/temp_load.not_sql:620: WARNING: I promise you will be sorry if you tr psql:test/temp_load.not_sql:627: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! +psql:test/temp_load.not_sql:654: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:654: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:679: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:679: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:694: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:694: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:721: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:721: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:737: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:737: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:754: NOTICE: type reference _object_reference.object_group__object.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:754: NOTICE: type reference _object_reference.object_group__object.object_id%TYPE converted to integer +psql:test/temp_load.not_sql:754: NOTICE: type reference _object_reference.object_group__object.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:754: NOTICE: type reference _object_reference.object_group__object.object_id%TYPE converted to integer +psql:test/temp_load.not_sql:788: NOTICE: type reference _object_reference.object_group__object.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:788: NOTICE: type reference _object_reference.object_group__object.object_id%TYPE converted to integer +psql:test/temp_load.not_sql:788: NOTICE: type reference _object_reference.object_group__object.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:788: NOTICE: type reference _object_reference.object_group__object.object_id%TYPE converted to integer +psql:test/temp_load.not_sql:953: NOTICE: type reference _object_reference.object.object_type%TYPE converted to cat_tools.object_type +psql:test/temp_load.not_sql:953: NOTICE: type reference _object_reference._object_oid.objid%TYPE converted to oid +psql:test/temp_load.not_sql:953: NOTICE: type reference _object_reference._object_oid.objsubid%TYPE converted to integer +psql:test/temp_load.not_sql:953: NOTICE: type reference _object_reference.object.object_type%TYPE converted to cat_tools.object_type +psql:test/temp_load.not_sql:953: NOTICE: type reference _object_reference._object_oid.objid%TYPE converted to oid +psql:test/temp_load.not_sql:953: NOTICE: type reference _object_reference._object_oid.objsubid%TYPE converted to integer +psql:test/temp_load.not_sql:1180: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1180: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1194: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1194: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1221: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:1221: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1221: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:1221: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1221: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:1221: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1235: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:1235: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1235: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:1235: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1235: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:1235: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1282: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:1282: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:1296: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1296: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1341: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:1341: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:1355: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1355: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying From 8e59c4c57d79e9db1171b82d1dc2dcfdd648b670 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 4 Aug 2026 18:54:30 -0500 Subject: [PATCH 12/14] Regenerate test/expected/zzz_build.out after merging the linter PR The linter PR's comment-style edits (block comments -> "EXCLUDED CODE") land in sql/object_reference.sql, which test/build's raw-load sanity check (zzz_build) re-parses independently of pg_regress's own SQL loading and reports line numbers for. Regenerated via `make results` after confirming zero raw "not ok" TAP assertions anywhere in test/results/*.out (the earlier copy of this file, committed before the linter-PR merge, was captured while a leftover extension install from prior manual testing was still on disk in the sandbox, which produced extra NOTICEs that don't appear in a real clean run -- this version comes from a fully clean rebuild). Co-Authored-By: Claude Sonnet 5 --- test/expected/zzz_build.out | 58 ------------------------------------- 1 file changed, 58 deletions(-) diff --git a/test/expected/zzz_build.out b/test/expected/zzz_build.out index 467431f..921e340 100644 --- a/test/expected/zzz_build.out +++ b/test/expected/zzz_build.out @@ -7,16 +7,6 @@ psql:test/temp_load.not_sql:187: WARNING: I promise you will be sorry if you tr psql:test/temp_load.not_sql:188: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! -psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference._object_oid.object_id%TYPE converted to integer -psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference.object.object_type%TYPE converted to cat_tools.object_type -psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference._object_oid.classid%TYPE converted to regclass -psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference._object_oid.objid%TYPE converted to oid -psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference._object_oid.objsubid%TYPE converted to integer -psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference._object_oid.object_id%TYPE converted to integer -psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference.object.object_type%TYPE converted to cat_tools.object_type -psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference._object_oid.classid%TYPE converted to regclass -psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference._object_oid.objid%TYPE converted to oid -psql:test/temp_load.not_sql:404: NOTICE: type reference _object_reference._object_oid.objsubid%TYPE converted to integer @@ -35,72 +25,24 @@ psql:test/temp_load.not_sql:620: WARNING: I promise you will be sorry if you tr psql:test/temp_load.not_sql:627: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! -psql:test/temp_load.not_sql:654: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:654: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:679: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer -psql:test/temp_load.not_sql:679: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer -psql:test/temp_load.not_sql:694: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:694: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:721: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer -psql:test/temp_load.not_sql:721: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer -psql:test/temp_load.not_sql:737: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:737: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:754: NOTICE: type reference _object_reference.object_group__object.object_group_id%TYPE converted to integer -psql:test/temp_load.not_sql:754: NOTICE: type reference _object_reference.object_group__object.object_id%TYPE converted to integer -psql:test/temp_load.not_sql:754: NOTICE: type reference _object_reference.object_group__object.object_group_id%TYPE converted to integer -psql:test/temp_load.not_sql:754: NOTICE: type reference _object_reference.object_group__object.object_id%TYPE converted to integer -psql:test/temp_load.not_sql:788: NOTICE: type reference _object_reference.object_group__object.object_group_id%TYPE converted to integer -psql:test/temp_load.not_sql:788: NOTICE: type reference _object_reference.object_group__object.object_id%TYPE converted to integer -psql:test/temp_load.not_sql:788: NOTICE: type reference _object_reference.object_group__object.object_group_id%TYPE converted to integer -psql:test/temp_load.not_sql:788: NOTICE: type reference _object_reference.object_group__object.object_id%TYPE converted to integer -psql:test/temp_load.not_sql:953: NOTICE: type reference _object_reference.object.object_type%TYPE converted to cat_tools.object_type -psql:test/temp_load.not_sql:953: NOTICE: type reference _object_reference._object_oid.objid%TYPE converted to oid -psql:test/temp_load.not_sql:953: NOTICE: type reference _object_reference._object_oid.objsubid%TYPE converted to integer -psql:test/temp_load.not_sql:953: NOTICE: type reference _object_reference.object.object_type%TYPE converted to cat_tools.object_type -psql:test/temp_load.not_sql:953: NOTICE: type reference _object_reference._object_oid.objid%TYPE converted to oid -psql:test/temp_load.not_sql:953: NOTICE: type reference _object_reference._object_oid.objsubid%TYPE converted to integer -psql:test/temp_load.not_sql:1180: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:1180: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:1194: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:1194: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:1221: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer -psql:test/temp_load.not_sql:1221: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:1221: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer -psql:test/temp_load.not_sql:1221: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:1221: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer -psql:test/temp_load.not_sql:1221: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:1235: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer -psql:test/temp_load.not_sql:1235: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:1235: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer -psql:test/temp_load.not_sql:1235: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:1235: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer -psql:test/temp_load.not_sql:1235: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:1282: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer -psql:test/temp_load.not_sql:1282: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer -psql:test/temp_load.not_sql:1296: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:1296: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:1341: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer -psql:test/temp_load.not_sql:1341: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer -psql:test/temp_load.not_sql:1355: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying -psql:test/temp_load.not_sql:1355: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying From 4fe08c0301a3d2fc0bc522c4f06ad253899ce39e Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 4 Aug 2026 18:59:47 -0500 Subject: [PATCH 13/14] Classify partitioned table/index as unsupported, not untested Verified directly: pg_get_object_address('partitioned table', ...) throws "unrecognized object type" -- PostgreSQL's real object-address API only knows the base "table"/"index" object types cat_tools's "partitioned table"/ "partitioned index" are derived from. object_reference actively calls pg_get_object_address() on every object_type it tracks (not just in the disabled sanity CHECK), so these two types would break identity tracking outright rather than merely lacking test coverage -- the earlier "untested" classification undersold the actual constraint. Matches the classification (and the exact reasoning/wording) already landed independently on the separate, longer-running new_features branch (PR #2), which reaches unsupported() via the same cat_tools 0.3.0 enum growth. Update test/sql/all.sql's own sanity-check of the unsupported set to match. Co-Authored-By: Claude Sonnet 5 --- sql/object_reference--stable.sql | 10 +++++++--- sql/object_reference.sql | 10 +++++++--- test/expected/zzz_build.out | 4 ++-- test/sql/all.sql | 7 +++++++ 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/sql/object_reference--stable.sql b/sql/object_reference--stable.sql index 5fcb589..26d1d0f 100644 --- a/sql/object_reference--stable.sql +++ b/sql/object_reference--stable.sql @@ -523,7 +523,12 @@ SELECT __object_reference.create_function( , $body$ SELECT cat_tools.objects__shared() || cat_tools.objects__address_unsupported() - || '{event trigger}' + /* + * pg_get_object_address() doesn't recognize "partitioned table" or + * "partitioned index" (only the base "table"/"index" types it derives + * from), so object identity tracking can't round-trip them. + */ + || '{event trigger, partitioned table, partitioned index}' $body$ , 'Returns array of object types that are not supported.' , 'object_reference__usage' @@ -572,8 +577,7 @@ foreign table, foreign table column, aggregate, collation, conversion, language, large object, operator, operator class, operator family, operator of access method, function of access method, rule, text search parser, text search dictionary, text search template, text search configuration, foreign-data wrapper, server, -user mapping, default acl, transform, access method, extension, policy, -partitioned table, partitioned index +user mapping, default acl, transform, access method, extension, policy }'::cat_tools.object_type[] $body$ , 'Returns array of object types that have not been tested.' diff --git a/sql/object_reference.sql b/sql/object_reference.sql index 7aee0db..c88a79f 100644 --- a/sql/object_reference.sql +++ b/sql/object_reference.sql @@ -522,7 +522,12 @@ SELECT __object_reference.create_function( , $body$ SELECT cat_tools.objects__shared() || cat_tools.objects__address_unsupported() - || '{event trigger}' + /* + * pg_get_object_address() doesn't recognize "partitioned table" or + * "partitioned index" (only the base "table"/"index" types it derives + * from), so object identity tracking can't round-trip them. + */ + || '{event trigger, partitioned table, partitioned index}' $body$ , 'Returns array of object types that are not supported.' , 'object_reference__usage' @@ -571,8 +576,7 @@ foreign table, foreign table column, aggregate, collation, conversion, language, large object, operator, operator class, operator family, operator of access method, function of access method, rule, text search parser, text search dictionary, text search template, text search configuration, foreign-data wrapper, server, -user mapping, default acl, transform, access method, extension, policy, -partitioned table, partitioned index +user mapping, default acl, transform, access method, extension, policy }'::cat_tools.object_type[] $body$ , 'Returns array of object types that have not been tested.' diff --git a/test/expected/zzz_build.out b/test/expected/zzz_build.out index 921e340..d9612d3 100644 --- a/test/expected/zzz_build.out +++ b/test/expected/zzz_build.out @@ -21,9 +21,9 @@ psql:test/temp_load.not_sql:512: WARNING: I promise you will be sorry if you tr -psql:test/temp_load.not_sql:620: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! +psql:test/temp_load.not_sql:624: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! -psql:test/temp_load.not_sql:627: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! +psql:test/temp_load.not_sql:631: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! diff --git a/test/sql/all.sql b/test/sql/all.sql index e00f04b..8e96fe2 100644 --- a/test/sql/all.sql +++ b/test/sql/all.sql @@ -53,6 +53,13 @@ SELECT bag_eq( UNION -- Intentionally not UNION ALL; we want to know if object_reference.unsupported has dupes SELECT * FROM cat_tools.objects__address_unsupported_srf() UNION SELECT 'event trigger' + /* + * pg_identify_object_as_address() returns these as plain "table"/"index", + * and pg_get_object_address() doesn't recognize "partitioned table" or + * "partitioned index" at all, so the round-trip is broken. + */ + UNION SELECT 'partitioned table' + UNION SELECT 'partitioned index' $$ , 'Verify object_reference.unsupported()' ); From 105ee2d5037d6910fab6aef15460f8c1b0cd4b49 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 4 Aug 2026 19:19:12 -0500 Subject: [PATCH 14/14] Remove reg* pseudotype columns; add object info functions Reconciles the substantive feature delta from new_features (PR #2) onto the current 'stable' baseline (post PR #5/#16: pgxn-tools testing, cat_tools 0.3.0, and the linter): - _object_reference._object_oid: drop the per-catalog regclass/regconfig/ regdictionary/regnamespace/regoperator/regprocedure/regtype columns and their unique indexes plus the count_nulls-backed null_count trigger that enforced "exactly one is set". classid is now plain oid and object_oid (also NOT NULL) is the sole identifier column, so there's nothing left to arbitrate between. - _object_reference._object_v / _object_v__for_update: drop the reg* columns from the column list to match. - _object_reference._object_oid__add: replace the dynamic, format()-built INSERT that picked a reg* column based on cat_tools.object__reg_type() with a plain INSERT into object_oid. - Drop the count_nulls search_path DO block (dead now that the trigger using it is gone) and the count_nulls dependency throughout (control, Makefile, test setup). - Add object_reference.object__describe()/object__identity(), thin wrappers around pg_describe_object()/pg_identify_object(); and object__cleanup(), which best-effort deletes an object record (ignoring foreign_key_violation if it's still referenced elsewhere). Wire object__cleanup() up to a new AFTER DELETE trigger on object_group__object so removing an object from its last group automatically attempts cleanup. - _object_v__for_update (the getsert core): refuse to track objects living in a pg_temp*/pg_toast_temp* schema, since a tracked reference would outlive the temporary object it points to. - test/sql/object_group.sql: switch the two scratch tables from TEMP to regular tables (object__getsert now rejects temp objects) and add coverage for the new automatic-cleanup trigger. - test/sql/base.sql: replace the count_nulls-relocation test (relocation was already unsupported and the whole extension no longer depends on count_nulls) with coverage for object_oid, object__describe(), object__identity(), and temp-object rejection. sql/object_reference--0.1.0.sql (the frozen historical release) and the META files are untouched. default_version stays 'stable'; sql/object_reference--stable.sql is regenerated to match sql/object_reference.sql. make lint and make test (including the dump/restore test) pass on both PostgreSQL 12 and 17. Supersedes PR #2 (new_features) and, for the update/upgrade test infrastructure built on top of it, sets up the rebuild of PR #3. Co-Authored-By: Claude Sonnet 5 --- Makefile | 7 +- object_reference.control | 2 +- sql/object_reference--stable.sql | 182 ++++++++++++++++--------------- sql/object_reference.sql | 182 ++++++++++++++++--------------- test/deps.sql | 1 - test/expected/base.out | 15 +-- test/expected/object_group.out | 9 +- test/expected/zzz_build.out | 72 +++++++++++- test/load.sql | 1 - test/sql/base.sql | 47 ++++---- test/sql/object_group.sql | 44 ++++++-- test/sql/zzz_build.sql | 1 - 12 files changed, 333 insertions(+), 230 deletions(-) diff --git a/Makefile b/Makefile index 0485145..0ecc103 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ include pgxntool/base.mk testdeps: $(wildcard test/*.sql test/helpers/*.sql) # Be careful not to include directories in this testdeps: test_factory -install: cat_tools count_nulls +install: cat_tools # pgxntool's check-stale-expected target (added in pgxntool 2.2.0) depends on # installcheck but is listed before install in TEST_DEPS, and Make evaluates a @@ -35,11 +35,6 @@ $(DESTDIR)$(datadir)/extension/cat_tools.control: $(MAKE) -C $(CAT_TOOLS_BUILD_DIR) install PG_CONFIG=$(PG_CONFIG) DESTDIR=$(DESTDIR) rm -rf $(CAT_TOOLS_BUILD_DIR) -.PHONY: count_nulls -count_nulls: $(DESTDIR)$(datadir)/extension/count_nulls.control -$(DESTDIR)$(datadir)/extension/count_nulls.control: - pgxn install --unstable count_nulls - .PHONY: test_factory test_factory: $(DESTDIR)$(datadir)/extension/test_factory.control $(DESTDIR)$(datadir)/extension/test_factory.control: diff --git a/object_reference.control b/object_reference.control index 5c7d974..142d0b1 100644 --- a/object_reference.control +++ b/object_reference.control @@ -2,4 +2,4 @@ comment = 'Provides reference IDs for database objects' default_version = 'stable' relocatable = false schema = 'object_reference' -requires = 'cat_tools, count_nulls' +requires = 'cat_tools' diff --git a/sql/object_reference--stable.sql b/sql/object_reference--stable.sql index 26d1d0f..dcb0026 100644 --- a/sql/object_reference--stable.sql +++ b/sql/object_reference--stable.sql @@ -3,17 +3,6 @@ \echo You really, REALLY do NOT want to try and load this via psql!!! \echo It will FAIL during pg_dump! \quit --- This BS is because count_nulls is relocatable, so could be in any schema -DO $$ -BEGIN - RAISE DEBUG 'initial search_path = %', current_setting('search_path'); - PERFORM set_config('search_path', current_setting('search_path') || ', ' || extnamespace::regnamespace::text, true) -- true = local only - FROM pg_extension - WHERE extname = 'count_nulls' - ; - RAISE DEBUG 'search_path changed to %', current_setting('search_path'); -END -$$; /* EXCLUDED CODE: schema-restriction check below not currently enforced DO $$ DECLARE @@ -192,7 +181,7 @@ GRANT REFERENCES ON _object_reference.object TO object_reference__dependency; CREATE TABLE _object_reference._object_oid( object_id int PRIMARY KEY REFERENCES _object_reference.object ON DELETE CASCADE ON UPDATE CASCADE - , classid regclass NOT NULL + , classid oid NOT NULL /* EXCLUDED CODE: TODO: needs to be a trigger CONSTRAINT classid_must_match__object__address_classid CHECK( classid IS NOT DISTINCT FROM cat_tools.object__address_classid(object_type) ) @@ -200,50 +189,11 @@ CREATE TABLE _object_reference._object_oid( , objid oid NOT NULL , objsubid int NOT NULL CONSTRAINT objid_must_match CHECK( -- _object_reference._sanity() depends on this! - objid IS NOT DISTINCT FROM coalesce( - regclass::oid -- Need to cast first item to generic OID - , regconfig - , regdictionary - , regnamespace -- SED: REQUIRES 9.5! - , regoperator - , regprocedure - , regtype - , object_oid - ) + objid IS NOT DISTINCT FROM object_oid ) , CONSTRAINT object__u_classid__objid__objsubid UNIQUE( classid, objid, objsubid ) - , regclass regclass - CONSTRAINT regclass_classid CHECK( regclass IS NULL OR classid = cat_tools.object__reg_type_catalog('regclass') ) - , regconfig regconfig - CONSTRAINT regconfig_classid CHECK( regconfig IS NULL OR classid = cat_tools.object__reg_type_catalog('regconfig') ) - , regdictionary regdictionary - CONSTRAINT regdictionary_classid CHECK( regdictionary IS NULL OR classid = cat_tools.object__reg_type_catalog('regdictionary') ) - , regnamespace regnamespace -- SED: REQUIRES 9.5! - CONSTRAINT regnamespace_classid CHECK( regnamespace IS NULL OR classid = cat_tools.object__reg_type_catalog('regnamespace') ) -- SED: REQUIRES 9.5! - , regoperator regoperator - CONSTRAINT regoperator_classid CHECK( regoperator IS NULL OR classid = cat_tools.object__reg_type_catalog('regoperator') ) - , regprocedure regprocedure - CONSTRAINT regprocedure_classid CHECK( regprocedure IS NULL OR classid = cat_tools.object__reg_type_catalog('regprocedure') ) - -- I don't think we should ever have regrole since we can't create event triggers on it --- , regrole regrole - , regtype regtype - CONSTRAINT regtype_classid CHECK( regtype IS NULL OR classid = cat_tools.object__reg_type_catalog('regtype') ) - , object_oid oid + , object_oid oid NOT NULL ); -CREATE TRIGGER null_count - AFTER INSERT OR UPDATE - ON _object_reference._object_oid - FOR EACH ROW EXECUTE PROCEDURE not_null_count_trigger( - 5 -- First 4 fields, + 1 - , 'only one object reference field may be set' - ) -; -CREATE UNIQUE INDEX _object_oid__u_regclass ON _object_reference._object_oid(regclass) WHERE regclass IS NOT NULL; -CREATE UNIQUE INDEX _object_oid__u_regconfig ON _object_reference._object_oid(regconfig) WHERE regconfig IS NOT NULL; -CREATE UNIQUE INDEX _object_oid__u_regdictionary ON _object_reference._object_oid(regdictionary) WHERE regdictionary IS NOT NULL; -CREATE UNIQUE INDEX _object_oid__u_regoperator ON _object_reference._object_oid(regoperator) WHERE regoperator IS NOT NULL; -CREATE UNIQUE INDEX _object_oid__u_regprocedure ON _object_reference._object_oid(regprocedure) WHERE regprocedure IS NOT NULL; -CREATE UNIQUE INDEX _object_oid__u_regtype ON _object_reference._object_oid(regtype) WHERE regtype IS NOT NULL; SELECT __object_reference.create_function( '_object_reference._sanity' @@ -303,13 +253,6 @@ CREATE VIEW _object_reference._object_v AS , i.classid , i.objid , i.objsubid - , i.regclass - , i.regconfig - , i.regdictionary - , i.regnamespace - , i.regoperator - , i.regprocedure - , i.regtype , i.object_oid , s.* FROM _object_reference.object o @@ -325,13 +268,6 @@ CREATE VIEW _object_reference._object_v__for_update AS , i.classid , i.objid , i.objsubid - , i.regclass - , i.regconfig - , i.regdictionary - , i.regnamespace - , i.regoperator - , i.regprocedure - , i.regtype , i.object_oid , s.* FROM _object_reference.object o @@ -363,26 +299,9 @@ BEGIN WHERE o.object_id = _object_oid__add.object_id ; END IF; - DECLARE - c_reg_type name := cat_tools.object__reg_type(object_type); -- Verifies regtype is supported, if there is one - c_oid_field CONSTANT name := coalesce(c_reg_type, 'object_oid'); - - c_oid_insert CONSTANT text := format( - --USING object_id, classid, objid, objsubid - $$INSERT INTO _object_reference._object_oid(object_id, classid, objid, objsubid, %I) - SELECT $1, $2, $3, $4, $3::%I$$ - , c_oid_field - , coalesce(c_reg_type, 'oid') - ) - ; BEGIN - RAISE DEBUG E'%\n USING %, %, %, %' - , c_oid_insert - , object_id, classid, objid, objsubid - ; - EXECUTE c_oid_insert - USING object_id, classid, objid, objsubid - ; + INSERT INTO _object_reference._object_oid(object_id, classid, objid, objsubid, object_oid) + VALUES (object_id, classid, objid, objsubid, objid); SELECT INTO STRICT r_object_v -- Record better exist! * @@ -632,6 +551,24 @@ CREATE TABLE _object_reference.object_group__object( ); SELECT __object_reference.safe_dump('_object_reference.object_group__object'); +-- Trigger function for automatic object cleanup +SELECT __object_reference.create_function( + '_object_reference._object_group__object__cleanup_trigger' + , '' + , 'trigger LANGUAGE plpgsql' + , $body$ +BEGIN + PERFORM object_reference.object__cleanup(OLD.object_id); + RETURN OLD; +END +$body$ + , 'Trigger function to automatically attempt cleanup of objects when removed from groups.' +); +CREATE TRIGGER object_group__object__cleanup + AFTER DELETE ON _object_reference.object_group__object + FOR EACH ROW + EXECUTE FUNCTION _object_reference._object_group__object__cleanup_trigger(); + -- __get SELECT __object_reference.create_function( 'object_reference.object_group__get' @@ -836,6 +773,69 @@ $body$ , 'object_reference__dependency' ); +/* + * OBJECT INFO FUNCTIONS + */ +SELECT __object_reference.create_function( + 'object_reference.object__describe' + , $args$ + object_id int +$args$ + , 'text LANGUAGE sql' + , $body$ +SELECT pg_catalog.pg_describe_object( + o.classid + , o.objid + , o.objsubid +) +FROM _object_reference._object_oid o +WHERE o.object_id = $1 +$body$ + , 'Return a human-readable description of the object, matching pg_describe_object() format.' + , 'object_reference__usage' +); + +SELECT __object_reference.create_function( + 'object_reference.object__identity' + , $args$ + object_id int + , OUT type text + , OUT schema text + , OUT name text + , OUT identity text +$args$ + , 'record LANGUAGE sql' + , $body$ +SELECT + i.type::text + , i.schema::text + , i.name::text + , i.identity::text +FROM _object_reference._object_oid o + , LATERAL pg_catalog.pg_identify_object(o.classid, o.objid, o.objsubid) i +WHERE o.object_id = $1 +$body$ + , 'Return object identification information matching pg_identify_object() format.' + , 'object_reference__usage' +); +SELECT __object_reference.create_function( + 'object_reference.object__cleanup' + , $args$ + object_id int +$args$ + , 'void LANGUAGE plpgsql' + , $body$ +BEGIN + DELETE FROM _object_reference.object WHERE object.object_id = object__cleanup.object_id; +EXCEPTION WHEN foreign_key_violation THEN + -- Object is still referenced elsewhere, ignore the error + NULL; +END +$body$ + , 'Attempts to delete an object from the tracking system. Silently returns if the object is still referenced by other tables.' + , 'object_reference__usage' +); + /* * OBJECT GETSERT */ @@ -855,6 +855,7 @@ DECLARE r_object_v _object_reference._object_v; r_address record; + r_identity record; did_insert boolean := false; @@ -883,6 +884,15 @@ BEGIN ; END IF; + -- Refuse to track objects in temporary schemas + SELECT INTO r_identity * FROM pg_catalog.pg_identify_object(c_classid, objid, objsubid); + IF r_identity.schema IS NOT NULL AND (r_identity.schema LIKE 'pg_temp%' OR r_identity.schema LIKE 'pg_toast_temp%') THEN + RAISE 'cannot track temporary object' + USING DETAIL = format('object %s is in temporary schema %s', r_identity.identity, r_identity.schema) + , ERRCODE = 'feature_not_supported' + ; + END IF; + -- Ensure the object record exists SELECT INTO r_object_v * diff --git a/sql/object_reference.sql b/sql/object_reference.sql index c88a79f..61774b0 100644 --- a/sql/object_reference.sql +++ b/sql/object_reference.sql @@ -2,17 +2,6 @@ \echo You really, REALLY do NOT want to try and load this via psql!!! \echo It will FAIL during pg_dump! \quit --- This BS is because count_nulls is relocatable, so could be in any schema -DO $$ -BEGIN - RAISE DEBUG 'initial search_path = %', current_setting('search_path'); - PERFORM set_config('search_path', current_setting('search_path') || ', ' || extnamespace::regnamespace::text, true) -- true = local only - FROM pg_extension - WHERE extname = 'count_nulls' - ; - RAISE DEBUG 'search_path changed to %', current_setting('search_path'); -END -$$; /* EXCLUDED CODE: schema-restriction check below not currently enforced DO $$ DECLARE @@ -191,7 +180,7 @@ GRANT REFERENCES ON _object_reference.object TO object_reference__dependency; CREATE TABLE _object_reference._object_oid( object_id int PRIMARY KEY REFERENCES _object_reference.object ON DELETE CASCADE ON UPDATE CASCADE - , classid regclass NOT NULL + , classid oid NOT NULL /* EXCLUDED CODE: TODO: needs to be a trigger CONSTRAINT classid_must_match__object__address_classid CHECK( classid IS NOT DISTINCT FROM cat_tools.object__address_classid(object_type) ) @@ -199,50 +188,11 @@ CREATE TABLE _object_reference._object_oid( , objid oid NOT NULL , objsubid int NOT NULL CONSTRAINT objid_must_match CHECK( -- _object_reference._sanity() depends on this! - objid IS NOT DISTINCT FROM coalesce( - regclass::oid -- Need to cast first item to generic OID - , regconfig - , regdictionary - , regnamespace -- SED: REQUIRES 9.5! - , regoperator - , regprocedure - , regtype - , object_oid - ) + objid IS NOT DISTINCT FROM object_oid ) , CONSTRAINT object__u_classid__objid__objsubid UNIQUE( classid, objid, objsubid ) - , regclass regclass - CONSTRAINT regclass_classid CHECK( regclass IS NULL OR classid = cat_tools.object__reg_type_catalog('regclass') ) - , regconfig regconfig - CONSTRAINT regconfig_classid CHECK( regconfig IS NULL OR classid = cat_tools.object__reg_type_catalog('regconfig') ) - , regdictionary regdictionary - CONSTRAINT regdictionary_classid CHECK( regdictionary IS NULL OR classid = cat_tools.object__reg_type_catalog('regdictionary') ) - , regnamespace regnamespace -- SED: REQUIRES 9.5! - CONSTRAINT regnamespace_classid CHECK( regnamespace IS NULL OR classid = cat_tools.object__reg_type_catalog('regnamespace') ) -- SED: REQUIRES 9.5! - , regoperator regoperator - CONSTRAINT regoperator_classid CHECK( regoperator IS NULL OR classid = cat_tools.object__reg_type_catalog('regoperator') ) - , regprocedure regprocedure - CONSTRAINT regprocedure_classid CHECK( regprocedure IS NULL OR classid = cat_tools.object__reg_type_catalog('regprocedure') ) - -- I don't think we should ever have regrole since we can't create event triggers on it --- , regrole regrole - , regtype regtype - CONSTRAINT regtype_classid CHECK( regtype IS NULL OR classid = cat_tools.object__reg_type_catalog('regtype') ) - , object_oid oid + , object_oid oid NOT NULL ); -CREATE TRIGGER null_count - AFTER INSERT OR UPDATE - ON _object_reference._object_oid - FOR EACH ROW EXECUTE PROCEDURE not_null_count_trigger( - 5 -- First 4 fields, + 1 - , 'only one object reference field may be set' - ) -; -CREATE UNIQUE INDEX _object_oid__u_regclass ON _object_reference._object_oid(regclass) WHERE regclass IS NOT NULL; -CREATE UNIQUE INDEX _object_oid__u_regconfig ON _object_reference._object_oid(regconfig) WHERE regconfig IS NOT NULL; -CREATE UNIQUE INDEX _object_oid__u_regdictionary ON _object_reference._object_oid(regdictionary) WHERE regdictionary IS NOT NULL; -CREATE UNIQUE INDEX _object_oid__u_regoperator ON _object_reference._object_oid(regoperator) WHERE regoperator IS NOT NULL; -CREATE UNIQUE INDEX _object_oid__u_regprocedure ON _object_reference._object_oid(regprocedure) WHERE regprocedure IS NOT NULL; -CREATE UNIQUE INDEX _object_oid__u_regtype ON _object_reference._object_oid(regtype) WHERE regtype IS NOT NULL; SELECT __object_reference.create_function( '_object_reference._sanity' @@ -302,13 +252,6 @@ CREATE VIEW _object_reference._object_v AS , i.classid , i.objid , i.objsubid - , i.regclass - , i.regconfig - , i.regdictionary - , i.regnamespace - , i.regoperator - , i.regprocedure - , i.regtype , i.object_oid , s.* FROM _object_reference.object o @@ -324,13 +267,6 @@ CREATE VIEW _object_reference._object_v__for_update AS , i.classid , i.objid , i.objsubid - , i.regclass - , i.regconfig - , i.regdictionary - , i.regnamespace - , i.regoperator - , i.regprocedure - , i.regtype , i.object_oid , s.* FROM _object_reference.object o @@ -362,26 +298,9 @@ BEGIN WHERE o.object_id = _object_oid__add.object_id ; END IF; - DECLARE - c_reg_type name := cat_tools.object__reg_type(object_type); -- Verifies regtype is supported, if there is one - c_oid_field CONSTANT name := coalesce(c_reg_type, 'object_oid'); - - c_oid_insert CONSTANT text := format( - --USING object_id, classid, objid, objsubid - $$INSERT INTO _object_reference._object_oid(object_id, classid, objid, objsubid, %I) - SELECT $1, $2, $3, $4, $3::%I$$ - , c_oid_field - , coalesce(c_reg_type, 'oid') - ) - ; BEGIN - RAISE DEBUG E'%\n USING %, %, %, %' - , c_oid_insert - , object_id, classid, objid, objsubid - ; - EXECUTE c_oid_insert - USING object_id, classid, objid, objsubid - ; + INSERT INTO _object_reference._object_oid(object_id, classid, objid, objsubid, object_oid) + VALUES (object_id, classid, objid, objsubid, objid); SELECT INTO STRICT r_object_v -- Record better exist! * @@ -631,6 +550,24 @@ CREATE TABLE _object_reference.object_group__object( ); SELECT __object_reference.safe_dump('_object_reference.object_group__object'); +-- Trigger function for automatic object cleanup +SELECT __object_reference.create_function( + '_object_reference._object_group__object__cleanup_trigger' + , '' + , 'trigger LANGUAGE plpgsql' + , $body$ +BEGIN + PERFORM object_reference.object__cleanup(OLD.object_id); + RETURN OLD; +END +$body$ + , 'Trigger function to automatically attempt cleanup of objects when removed from groups.' +); +CREATE TRIGGER object_group__object__cleanup + AFTER DELETE ON _object_reference.object_group__object + FOR EACH ROW + EXECUTE FUNCTION _object_reference._object_group__object__cleanup_trigger(); + -- __get SELECT __object_reference.create_function( 'object_reference.object_group__get' @@ -835,6 +772,69 @@ $body$ , 'object_reference__dependency' ); +/* + * OBJECT INFO FUNCTIONS + */ +SELECT __object_reference.create_function( + 'object_reference.object__describe' + , $args$ + object_id int +$args$ + , 'text LANGUAGE sql' + , $body$ +SELECT pg_catalog.pg_describe_object( + o.classid + , o.objid + , o.objsubid +) +FROM _object_reference._object_oid o +WHERE o.object_id = $1 +$body$ + , 'Return a human-readable description of the object, matching pg_describe_object() format.' + , 'object_reference__usage' +); + +SELECT __object_reference.create_function( + 'object_reference.object__identity' + , $args$ + object_id int + , OUT type text + , OUT schema text + , OUT name text + , OUT identity text +$args$ + , 'record LANGUAGE sql' + , $body$ +SELECT + i.type::text + , i.schema::text + , i.name::text + , i.identity::text +FROM _object_reference._object_oid o + , LATERAL pg_catalog.pg_identify_object(o.classid, o.objid, o.objsubid) i +WHERE o.object_id = $1 +$body$ + , 'Return object identification information matching pg_identify_object() format.' + , 'object_reference__usage' +); +SELECT __object_reference.create_function( + 'object_reference.object__cleanup' + , $args$ + object_id int +$args$ + , 'void LANGUAGE plpgsql' + , $body$ +BEGIN + DELETE FROM _object_reference.object WHERE object.object_id = object__cleanup.object_id; +EXCEPTION WHEN foreign_key_violation THEN + -- Object is still referenced elsewhere, ignore the error + NULL; +END +$body$ + , 'Attempts to delete an object from the tracking system. Silently returns if the object is still referenced by other tables.' + , 'object_reference__usage' +); + /* * OBJECT GETSERT */ @@ -854,6 +854,7 @@ DECLARE r_object_v _object_reference._object_v; r_address record; + r_identity record; did_insert boolean := false; @@ -882,6 +883,15 @@ BEGIN ; END IF; + -- Refuse to track objects in temporary schemas + SELECT INTO r_identity * FROM pg_catalog.pg_identify_object(c_classid, objid, objsubid); + IF r_identity.schema IS NOT NULL AND (r_identity.schema LIKE 'pg_temp%' OR r_identity.schema LIKE 'pg_toast_temp%') THEN + RAISE 'cannot track temporary object' + USING DETAIL = format('object %s is in temporary schema %s', r_identity.identity, r_identity.schema) + , ERRCODE = 'feature_not_supported' + ; + END IF; + -- Ensure the object record exists SELECT INTO r_object_v * diff --git a/test/deps.sql b/test/deps.sql index b0ee45f..300c7a8 100644 --- a/test/deps.sql +++ b/test/deps.sql @@ -3,6 +3,5 @@ -- Add any test dependency statements here /* EXCLUDED CODE: normally these should be loaded by the cascade! -CREATE EXTENSION IF NOT EXISTS count_nulls; CREATE EXTENSION IF NOT EXISTS cat_tools; */ diff --git a/test/expected/base.out b/test/expected/base.out index 5e39f56..5357054 100644 --- a/test/expected/base.out +++ b/test/expected/base.out @@ -1,12 +1,13 @@ \set ECHO none -1..9 +1..10 ok 1 - Role object_reference__dependency should be granted USAGE on schema _object_reference ok 2 - Role object_reference__dependency should be granted REFERENCES on table _object_reference.object ok 3 - CREATE TEMP TABLE test_object AS SELECT object_reference.object__getsert('table', 'test_table') AS object_id; -ok 4 - Verify regclass field is correct -ok 5 - Existing object works, provides correct ID -ok 6 - secondary may not be specified for table objects -ok 7 - Verify count_nulls extension can not be relocated -ok 8 - Still works after moving the count_nulls extension -ok 9 - CREATE EXTENSION test_factory +ok 4 - Verify object_oid field is correct +ok 5 - object__describe returns same result as pg_describe_object +ok 6 - object__identity returns same result as pg_identify_object +ok 7 - Existing object works, provides correct ID +ok 8 - secondary may not be specified for table objects +ok 9 - temp objects are rejected +ok 10 - CREATE EXTENSION test_factory # TRANSACTION INTENTIONALLY LEFT OPEN! diff --git a/test/expected/object_group.out b/test/expected/object_group.out index d286833..e670106 100644 --- a/test/expected/object_group.out +++ b/test/expected/object_group.out @@ -1,5 +1,5 @@ \set ECHO none -1..24 +1..29 ok 1 - Register test table 1 ok 2 - object_group__create(...) for group name that is too long throws error ok 3 - object_group__create('object reference test group') @@ -24,6 +24,9 @@ ok 21 - object_group__object__add(...)for missing group throws error ok 22 - Removing group with items in it fails ok 23 - __object__remove() for col1 works ok 24 - __object__remove() for test_table_2 works -ok 25 - Removing empty group works -# Looks like you planned 24 tests but ran 25 +ok 25 - Add test table back to group for cleanup test +ok 26 - Object exists before cleanup test +ok 27 - Remove from group triggers automatic cleanup attempt +ok 28 - Object was automatically cleaned up after group removal +ok 29 - Removing empty group works # TRANSACTION INTENTIONALLY LEFT OPEN! diff --git a/test/expected/zzz_build.out b/test/expected/zzz_build.out index d9612d3..99e1332 100644 --- a/test/expected/zzz_build.out +++ b/test/expected/zzz_build.out @@ -2,16 +2,26 @@ This extension must be loaded via CREATE EXTENSION object_reference; You really, REALLY do NOT want to try and load this via psql!!! -psql:test/temp_load.not_sql:187: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! +psql:test/temp_load.not_sql:176: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! -psql:test/temp_load.not_sql:188: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! +psql:test/temp_load.not_sql:177: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! +psql:test/temp_load.not_sql:323: NOTICE: type reference _object_reference._object_oid.object_id%TYPE converted to integer +psql:test/temp_load.not_sql:323: NOTICE: type reference _object_reference.object.object_type%TYPE converted to cat_tools.object_type +psql:test/temp_load.not_sql:323: NOTICE: type reference _object_reference._object_oid.classid%TYPE converted to oid +psql:test/temp_load.not_sql:323: NOTICE: type reference _object_reference._object_oid.objid%TYPE converted to oid +psql:test/temp_load.not_sql:323: NOTICE: type reference _object_reference._object_oid.objsubid%TYPE converted to integer +psql:test/temp_load.not_sql:323: NOTICE: type reference _object_reference._object_oid.object_id%TYPE converted to integer +psql:test/temp_load.not_sql:323: NOTICE: type reference _object_reference.object.object_type%TYPE converted to cat_tools.object_type +psql:test/temp_load.not_sql:323: NOTICE: type reference _object_reference._object_oid.classid%TYPE converted to oid +psql:test/temp_load.not_sql:323: NOTICE: type reference _object_reference._object_oid.objid%TYPE converted to oid +psql:test/temp_load.not_sql:323: NOTICE: type reference _object_reference._object_oid.objsubid%TYPE converted to integer -psql:test/temp_load.not_sql:512: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! +psql:test/temp_load.not_sql:431: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! @@ -21,28 +31,80 @@ psql:test/temp_load.not_sql:512: WARNING: I promise you will be sorry if you tr -psql:test/temp_load.not_sql:624: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! +psql:test/temp_load.not_sql:543: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! -psql:test/temp_load.not_sql:631: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! +psql:test/temp_load.not_sql:550: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! +psql:test/temp_load.not_sql:595: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:595: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:620: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:620: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:635: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:635: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:662: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:662: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:678: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:678: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:695: NOTICE: type reference _object_reference.object_group__object.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:695: NOTICE: type reference _object_reference.object_group__object.object_id%TYPE converted to integer +psql:test/temp_load.not_sql:695: NOTICE: type reference _object_reference.object_group__object.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:695: NOTICE: type reference _object_reference.object_group__object.object_id%TYPE converted to integer +psql:test/temp_load.not_sql:729: NOTICE: type reference _object_reference.object_group__object.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:729: NOTICE: type reference _object_reference.object_group__object.object_id%TYPE converted to integer +psql:test/temp_load.not_sql:729: NOTICE: type reference _object_reference.object_group__object.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:729: NOTICE: type reference _object_reference.object_group__object.object_id%TYPE converted to integer +psql:test/temp_load.not_sql:967: NOTICE: type reference _object_reference.object.object_type%TYPE converted to cat_tools.object_type +psql:test/temp_load.not_sql:967: NOTICE: type reference _object_reference._object_oid.objid%TYPE converted to oid +psql:test/temp_load.not_sql:967: NOTICE: type reference _object_reference._object_oid.objsubid%TYPE converted to integer +psql:test/temp_load.not_sql:967: NOTICE: type reference _object_reference.object.object_type%TYPE converted to cat_tools.object_type +psql:test/temp_load.not_sql:967: NOTICE: type reference _object_reference._object_oid.objid%TYPE converted to oid +psql:test/temp_load.not_sql:967: NOTICE: type reference _object_reference._object_oid.objsubid%TYPE converted to integer +psql:test/temp_load.not_sql:1194: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1194: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1208: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1208: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1235: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:1235: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1235: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:1235: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1235: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:1235: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1249: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:1249: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1249: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:1249: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1249: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:1249: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying + +psql:test/temp_load.not_sql:1296: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:1296: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer + +psql:test/temp_load.not_sql:1310: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1310: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying + +psql:test/temp_load.not_sql:1355: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer +psql:test/temp_load.not_sql:1355: NOTICE: type reference _object_reference.object_group.object_group_id%TYPE converted to integer + +psql:test/temp_load.not_sql:1369: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying +psql:test/temp_load.not_sql:1369: NOTICE: type reference _object_reference.object_group.object_group_name%TYPE converted to character varying diff --git a/test/load.sql b/test/load.sql index 0f1c6be..f1b267f 100644 --- a/test/load.sql +++ b/test/load.sql @@ -1,6 +1,5 @@ \i test/pgxntool/setup.sql --- Need to add count_nulls back into the path SET search_path = tap, public; -- Don't use IF NOT EXISTS here; we want to ensure we always have the latest code diff --git a/test/sql/base.sql b/test/sql/base.sql index 202ae5f..10f48f7 100644 --- a/test/sql/base.sql +++ b/test/sql/base.sql @@ -8,8 +8,8 @@ SELECT plan( 0 +1 -- schema +3 -- initial - +2 -- errors - +2 -- move + +2 -- new functions + +3 -- errors (includes temp object test) +1 -- create extensions ); @@ -32,9 +32,23 @@ SELECT lives_ok( , $$CREATE TEMP TABLE test_object AS SELECT object_reference.object__getsert('table', 'test_table') AS object_id;$$ ); SELECT is( - (SELECT regclass FROM _object_reference._object_v WHERE object_id = (SELECT object_id FROM test_object)) - , 'test_table'::regclass - , 'Verify regclass field is correct' + (SELECT object_oid FROM _object_reference._object_v WHERE object_id = (SELECT object_id FROM test_object)) + , 'test_table'::regclass::oid + , 'Verify object_oid field is correct' +); + +-- Test object__describe function +SELECT is( + object_reference.object__describe((SELECT object_id FROM test_object)) + , pg_catalog.pg_describe_object('pg_class'::regclass, 'test_table'::regclass, 0) + , 'object__describe returns same result as pg_describe_object' +); + +-- Test object__identity function +SELECT results_eq( + $$SELECT * FROM object_reference.object__identity((SELECT object_id FROM test_object))$$ + , $$SELECT type, schema, name, identity FROM pg_catalog.pg_identify_object('pg_class'::regclass, 'test_table'::regclass, 0)$$ + , 'object__identity returns same result as pg_identify_object' ); SELECT is( object_reference.object__getsert('table', 'test_table') @@ -50,24 +64,13 @@ SELECT throws_ok( , 'secondary may not be specified for table objects' ); -/* - * I'm not sure if our extension would continue working if count_nulls was - * relocated. Currently a moot point since relocation isn't supported, but I'd - * already coded the second test so might as well leave it here in case it - * changes in the future. - */ -\set null_schema test_relocate_count_nulls -CREATE SCHEMA :null_schema; +-- Test temp object rejection +CREATE TEMP TABLE temp_test_table(); SELECT throws_ok( - $$ALTER EXTENSION count_nulls SET SCHEMA $$ || :'null_schema' - , '0A000' - , NULL - , 'Verify count_nulls extension can not be relocated' -); -SELECT is( - object_reference.object__getsert('table', 'test_table') - , (SELECT object_id FROM test_object) - , 'Still works after moving the count_nulls extension' + $$SELECT object_reference.object__getsert('table', 'temp_test_table')$$ + , '0A000' -- feature_not_supported + , 'cannot track temporary object' + , 'temp objects are rejected' ); -- Create extensions diff --git a/test/sql/object_group.sql b/test/sql/object_group.sql index d90957b..cd957df 100644 --- a/test/sql/object_group.sql +++ b/test/sql/object_group.sql @@ -2,8 +2,8 @@ \i test/load.sql -CREATE TEMP TABLE test_table_1(col1 int, col2 int); -CREATE TEMP TABLE test_table_2(col1 int, col2 int); +CREATE TABLE object_group_test_table_1(col1 int, col2 int); +CREATE TABLE object_group_test_table_2(col1 int, col2 int); CREATE FUNCTION pg_temp.bogus_group( command_template text @@ -40,10 +40,12 @@ SELECT plan( +4 -- __object__remove +4 + 2 -- __remove + +4 -- cleanup tests + +1 -- final group removal (there was always an extra test) ); SELECT lives_ok( - $$CREATE TEMP TABLE test_table_1_id AS SELECT * FROM object_reference.object__getsert('table', 'test_table_1')$$ + $$CREATE TEMP TABLE test_table_1_id AS SELECT * FROM object_reference.object__getsert('table', 'object_group_test_table_1')$$ , 'Register test table 1' ); @@ -102,37 +104,37 @@ SELECT lives_ok( -- object__getsert SELECT throws_ok( -- Can't use helper here - $$CREATE TEMP TABLE col1_id AS SELECT * FROM object_reference.object__getsert('table column', 'test_table_1', 'col1', 'absurd group name used only for testing purposes ktxbye')$$ + $$CREATE TEMP TABLE col1_id AS SELECT * FROM object_reference.object__getsert('table column', 'object_group_test_table_1', 'col1', 'absurd group name used only for testing purposes ktxbye')$$ , 'P0002' , 'object group "absurd group name used only for testing purposes ktxbye" does not exist' , 'object__getsert with bogus group name' ); /* EXCLUDED CODE: TODO SELECT throws_ok( -- Can't use helper here - $$CREATE TEMP TABLE col1_id AS SELECT * FROM object_reference.object__getsert_w_group_id('table column', 'test_table_1', 'col1', -1)$$ + $$CREATE TEMP TABLE col1_id AS SELECT * FROM object_reference.object__getsert_w_group_id('table column', 'object_group_test_table_1', 'col1', -1)$$ , '' , '' , 'object__getsert with bogus group id' ); */ SELECT lives_ok( - $$CREATE TEMP TABLE col1_id AS SELECT * FROM object_reference.object__getsert('table column', 'test_table_1', 'col1', 'object reference test group')$$ + $$CREATE TEMP TABLE col1_id AS SELECT * FROM object_reference.object__getsert('table column', 'object_group_test_table_1', 'col1', 'object reference test group')$$ , 'Register test column' ); SELECT lives_ok( - $$CREATE TEMP TABLE test_table_2_id AS SELECT * FROM object_reference.object__getsert('table', 'test_table_2', object_group_name := 'object reference test group')$$ + $$CREATE TEMP TABLE test_table_2_id AS SELECT * FROM object_reference.object__getsert('table', 'object_group_test_table_2', object_group_name := 'object reference test group')$$ , 'Register test table 2' ); -- Drop tests SELECT throws_ok( - $$ALTER TABLE test_table_1 DROP COLUMN col1$$ + $$ALTER TABLE object_group_test_table_1 DROP COLUMN col1$$ , '23503' , NULL -- current error is crap anyway , 'Dropping col1 fails' ); SELECT throws_ok( - $$DROP TABLE test_table_2$$ + $$DROP TABLE object_group_test_table_2$$ , '23503' , NULL -- current error is crap anyway , 'Dropping test_table_2 fails' @@ -144,7 +146,7 @@ SELECT throws_ok( , 'Removing test group fails' ); SELECT lives_ok( - $$ALTER TABLE test_table_1 DROP COLUMN col2$$ + $$ALTER TABLE object_group_test_table_1 DROP COLUMN col2$$ , 'Dropping col2 works' ); @@ -178,7 +180,7 @@ SELECT lives_ok( , '__object__remove() for test_table_1 works' ); SELECT throws_ok( - $$DROP TABLE test_table_1$$ -- Should not work because column is still registered + $$DROP TABLE object_group_test_table_1$$ -- Should not work because column is still registered , '23503' , NULL -- current error is crap anyway , 'Dropping test_table_1 fails' @@ -211,6 +213,26 @@ SELECT lives_ok( ) , '__object__remove() for test_table_2 works' ); + +-- Test automatic cleanup via trigger +SELECT lives_ok( + $$CREATE TEMP TABLE cleanup_test_id AS SELECT * FROM object_reference.object__getsert('table', 'object_group_test_table_1', object_group_name := 'object reference test group')$$ + , 'Add test table back to group for cleanup test' +); +SELECT ok( + EXISTS(SELECT 1 FROM _object_reference.object WHERE object_id = (SELECT object__getsert FROM cleanup_test_id)) + , 'Object exists before cleanup test' +); +SELECT lives_ok( + $$DELETE FROM _object_reference.object_group__object WHERE object_id = (SELECT object__getsert FROM cleanup_test_id)$$ + , 'Remove from group triggers automatic cleanup attempt' +); +-- Object should be deleted because it's no longer in any group and trigger calls cleanup +SELECT ok( + NOT EXISTS(SELECT 1 FROM _object_reference.object WHERE object_id = (SELECT object__getsert FROM cleanup_test_id)) + , 'Object was automatically cleaned up after group removal' +); + SELECT lives_ok( $$SELECT object_reference.object_group__remove('object reference test group')$$ , 'Removing empty group works' diff --git a/test/sql/zzz_build.sql b/test/sql/zzz_build.sql index 4da65b4..4fc0628 100644 --- a/test/sql/zzz_build.sql +++ b/test/sql/zzz_build.sql @@ -6,7 +6,6 @@ -- Loads deps, but not extension itself \i test/pgxntool/setup.sql -CREATE EXTENSION IF NOT EXISTS count_nulls; CREATE EXTENSION IF NOT EXISTS cat_tools; CREATE SCHEMA object_reference;