From fa15ccb6c48c197a0dd1909d1d9836838d912528 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 25 Aug 2025 16:48:21 -0500 Subject: [PATCH 01/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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 c0325029502d22e29c61f27f52731ca838ecdfaf Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 25 Aug 2025 18:29:18 -0500 Subject: [PATCH 09/20] Stop using reg* pseudotypes in tables Use of those types is not supported by pg_upgrade --- sql/object_reference.sql | 80 +++---------------------------------- test/expected/base.out | 2 +- test/expected/zzz_build.out | 6 +-- test/sql/base.sql | 6 +-- 4 files changed, 12 insertions(+), 82 deletions(-) diff --git a/sql/object_reference.sql b/sql/object_reference.sql index 44dc1c6..fafb79a 100644 --- a/sql/object_reference.sql +++ b/sql/object_reference.sql @@ -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 + , classid oid NOT NULL /* 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 +200,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 +264,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 +279,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 +310,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! * diff --git a/test/expected/base.out b/test/expected/base.out index 5e39f56..8579c90 100644 --- a/test/expected/base.out +++ b/test/expected/base.out @@ -3,7 +3,7 @@ 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 4 - Verify object_oid 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 diff --git a/test/expected/zzz_build.out b/test/expected/zzz_build.out index fe92660..f3cfa9a 100644 --- a/test/expected/zzz_build.out +++ b/test/expected/zzz_build.out @@ -11,7 +11,7 @@ psql:test/temp_load.not_sql:189: WARNING: I promise you will be sorry if you tr -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:443: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! @@ -21,9 +21,9 @@ psql:test/temp_load.not_sql:513: 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: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: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:557: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! diff --git a/test/sql/base.sql b/test/sql/base.sql index 202ae5f..5b5ff27 100644 --- a/test/sql/base.sql +++ b/test/sql/base.sql @@ -32,9 +32,9 @@ 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' ); SELECT is( object_reference.object__getsert('table', 'test_table') From 7236cf3f6f62bffa74a166ef997f84b75f9ac8ad Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 26 Aug 2025 15:59:38 -0500 Subject: [PATCH 10/20] Add README; get rid of no longer needed code --- README.md | 313 +++++++++++++++++++++++++++++++++++++++ sql/object_reference.sql | 29 ---- 2 files changed, 313 insertions(+), 29 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..c20af2c --- /dev/null +++ b/README.md @@ -0,0 +1,313 @@ +# Object Reference Framework + +This framework provides tracking and management of references to database objects. It's designed to maintain referential integrity for objects that may be created, dropped, or renamed, and provides facilities for automatically capturing newly created objects into organized groups. + +Key capabilities: +- Track references to database objects that may be created, dropped, or renamed +- Group related objects for organization and DDL capture +- Automatically capture DDL operations to track new objects +- Manage dependencies between objects and external tables +- Support for object lifecycle management + +# A word on documentation... + +Good documentation should be like good code comments - explain things concisely without being overly verbose. Towards that end, this doc does *not* provide definition for things that should be inherently obvious, other than mentioning their existence. For example, we never define what is meant by `object_type`. The name itself should provide enough information. + +# Installation + +This extension depends on the `cat_tools` extension. + +```sql +CREATE EXTENSION object_reference CASCADE; +``` + +The extension creates two schemas: +- `object_reference` - Contains the public API functions +- `_object_reference` - Contains internal implementation details (do not use directly) + +To grant users access to the extension: +```sql +GRANT object_reference__usage TO role1, role2, role3; +``` + +# Security + +There are two roles associated with the extension: + +- `object_reference__usage` - Allows using the extension's public API functions. Grant this to users who need to track and manage object references. +- `object_reference__dependency` - Special role for creating foreign key dependencies to the internal object table. Only grant this to schemas/applications that need to create referential integrity constraints against the object tracking system. + +Most users will only need `object_reference__usage`. The `object_reference__dependency` role is only needed when using `object__dependency__add()` or `object_group__dependency__add()` functions. + +# Key Concepts + +## Objects vs OIDs + +The framework separates object metadata (names, types, arguments) from their actual database OIDs. This allows tracking objects that don't exist yet, or that may be recreated. OID resolution is performed lazily - only when actually needed. + +## Object Groups + +Objects can be organized into named groups for logical organization. This is particularly useful for tracking all objects created during a specific operation or time period, especially when combined with DDL capture. + +## DDL Capture + +The framework can automatically capture newly created objects during DDL operations and add them to a specified object group. This is implemented using PostgreSQL event triggers. + +# API + +Note that all API routines live in the `object_reference` schema. Objects in the `_object_reference` schema are considered internal-only and should not be accessed directly. + +Most routines work with the `cat_tools.object_type` enum for specifying object types. You can also pass object types as text strings which will be converted automatically. + +## Core Object Functions + +### `object__getsert(...) RETURNS int` + +```sql +object__getsert( + object_type text | cat_tools.object_type + , object_name text + , secondary text DEFAULT NULL + , object_group_name text DEFAULT NULL + , loose boolean DEFAULT false +) RETURNS int +``` + +Get or insert an object reference, returning the `object_id`. This is the primary function for tracking objects. + +Arguments: +- `object_type` - Type of object (table, function, index, etc.) +- `object_name` - Fully qualified name of the object +- `secondary` - Additional identifier for objects that need it (e.g., function arguments) +- `object_group_name` - Optional object group to add this object to +- `loose` - If true, allows creating references to objects that don't exist + +### `object__getsert_w_group_id(...) RETURNS int` + +```sql +object__getsert_w_group_id( + object_type cat_tools.object_type + , object_name text + , secondary text DEFAULT NULL + , object_group_id int DEFAULT NULL + , loose boolean DEFAULT false +) RETURNS int +``` + +Same as `object__getsert()` but accepts a numeric `object_group_id` instead of group name. + + +## Object Group Functions + +### `object_group__create(...) RETURNS int` + +```sql +object_group__create( + object_group_name text +) RETURNS int +``` + +Create a new object group and return its ID. + +### `object_group__get(...) RETURNS object_group` + +```sql +object_group__get( + object_group_name text | object_group_id int +) RETURNS _object_reference.object_group +``` + +Retrieve an object group by name or ID. Throws an error if the group doesn't exist. + +### `object_group__remove(...) RETURNS void` + +```sql +object_group__remove( + object_group_name text | object_group_id int + , force boolean DEFAULT false +) RETURNS void +``` + +Remove an object group. This does not delete the objects themselves, only the grouping. + +### `object_group__object__add(...) RETURNS void` + +```sql +object_group__object__add( + object_group_id int + , object_id int +) RETURNS void +``` + +Add an existing object to an object group. + +### `object_group__object__remove(...) RETURNS void` + +```sql +object_group__object__remove( + object_group_id int + , object_id int +) RETURNS void +``` + +Remove an object from an object group. + +## Dependency Functions + +These functions create foreign key dependencies to the object tracking system. They require the `object_reference__dependency` role. + +### `object__dependency__add(...) RETURNS void` + +```sql +object__dependency__add( + table_name text + , field_name name +) RETURNS void +``` + +Create a foreign key dependency from the specified table to the object tracking system. + +Arguments: +- `table_name` - Name of table to add dependency to +- `field_name` - Name of the field to create the foreign key on + +### `object_group__dependency__add(...) RETURNS void` + +```sql +object_group__dependency__add( + table_name text + , field_name name +) RETURNS void +``` + +Create a foreign key dependency from the specified table to the object group system. + +## DDL Capture Functions + +DDL capture allows you to automatically track objects created during DDL operations. + +### `capture__start(...) RETURNS int` + +```sql +capture__start( + object_group_name text | object_group_id int +) RETURNS int +``` + +Begin capturing newly created objects to the specified group. The group must +already exist. Returns the capture level (for nested captures). + +### `capture__stop(...) RETURNS void` + +```sql +capture__stop( + object_group_name text | object_group_id int +) RETURNS void +``` + +Stop capturing objects to the specified group. + +### `capture__get_current(...) RETURNS record` + +```sql +capture__get_current( + OUT capture_level int + , OUT object_group_id int +) RETURNS record +``` + +Get information about the current capture state. + +### `capture__get_all(...) RETURNS SETOF record` + +```sql +capture__get_all( + OUT capture_level int + , OUT object_group_id int +) RETURNS SETOF record +``` + +Get information about all active capture levels. + +## Utility Functions + +### `post_restore() RETURNS void` + +```sql +post_restore() RETURNS void +``` + +Ensures all object references are correct after a database restore. Run this after restoring from backup to fix any OID mismatches. + +### Object Type Information Functions + +**Get lists of unsupported/untested object types:** + +```sql +unsupported() RETURNS cat_tools.object_type[] +unsupported_srf() RETURNS SETOF cat_tools.object_type + +untested() RETURNS cat_tools.object_type[] +untested_srf() RETURNS SETOF cat_tools.object_type +``` + +**Check if specific object types are supported/tested:** + +```sql +unsupported(object_type text | cat_tools.object_type) RETURNS boolean +untested(object_type text | cat_tools.object_type) RETURNS boolean +``` + +These functions help determine which object types are supported by the framework. Unsupported types cannot be tracked, while untested types may work but haven't been fully validated. + +# Event Triggers + +The extension automatically installs several event triggers that: + +- Capture object creation when DDL capture is active +- Update object identity information when objects are renamed +- Clean up object references when objects are dropped + +These event triggers operate transparently and require no user intervention. However, be aware that they may add slight overhead to DDL operations. + +# Examples + +## Basic Object Tracking + +```sql +-- Track a table +SELECT object_reference.object__getsert('table', 'public.my_table'); + +-- Track a function with its signature +SELECT object_reference.object__getsert('function', 'public.my_func', 'integer, text'); +``` + +## Using Object Groups + +```sql +-- Create a group for related objects +SELECT object_reference.object_group__create('my_feature_objects'); + +-- Add objects to the group +SELECT object_reference.object__getsert('table', 'public.feature_table', NULL, 'my_feature_objects'); +SELECT object_reference.object__getsert('view', 'public.feature_view', NULL, 'my_feature_objects'); +``` + +## DDL Capture + +```sql +-- Create a group first +SELECT object_reference.object_group__create('migration_v2_objects'); + +-- Start capturing new objects to that group +SELECT object_reference.capture__start('migration_v2_objects'); + +-- Run your DDL commands +CREATE TABLE public.new_table (id int, name text); +CREATE INDEX idx_new_table_name ON public.new_table (name); + +-- Stop capturing +SELECT object_reference.capture__stop('migration_v2_objects'); + +-- All objects created between start/stop are now tracked in the 'migration_v2_objects' group +``` \ No newline at end of file diff --git a/sql/object_reference.sql b/sql/object_reference.sql index fafb79a..9b204e1 100644 --- a/sql/object_reference.sql +++ b/sql/object_reference.sql @@ -3,35 +3,6 @@ SET LOCAL client_min_messages = WARNING; \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 -$$; -/* -DO $$ -DECLARE - c_schema CONSTANT name := (SELECT extnamespace::regnamespace::text FROM pg_extension WHERE extname = 'cat_tools'); -BEGIN - IF c_schema IS NULL THEN - RAISE 'extension cat_tools is not installed'; - END IF; - - IF c_schema <> 'cat_tools' THEN - RAISE 'having the cat_tools extension installed anywhere but the "cat_tools" schema is not currently supported' - USING DETAIL = format('current schema for cat_tools is %s', c_schema) - ; - END IF; -END -$$; -*/ - DO $$ BEGIN CREATE ROLE object_reference__usage NOLOGIN; From d89e0fbd0561e29e67f3c9fb220836676c07fa3c Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 26 Aug 2025 16:24:37 -0500 Subject: [PATCH 11/20] minor test cleanup --- test/expected/base.out | 6 ++---- test/expected/zzz_build.out | 10 +++++----- test/sql/base.sql | 21 --------------------- 3 files changed, 7 insertions(+), 30 deletions(-) diff --git a/test/expected/base.out b/test/expected/base.out index 8579c90..9a52932 100644 --- a/test/expected/base.out +++ b/test/expected/base.out @@ -1,12 +1,10 @@ \set ECHO none -1..9 +1..7 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 object_oid 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 7 - CREATE EXTENSION test_factory # TRANSACTION INTENTIONALLY LEFT OPEN! diff --git a/test/expected/zzz_build.out b/test/expected/zzz_build.out index f3cfa9a..93431c5 100644 --- a/test/expected/zzz_build.out +++ b/test/expected/zzz_build.out @@ -2,16 +2,16 @@ 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:159: 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:160: 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:443: 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:414: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! @@ -21,9 +21,9 @@ psql:test/temp_load.not_sql:443: WARNING: I promise you will be sorry if you tr -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:521: 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:557: 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:528: WARNING: I promise you will be sorry if you try to use this as anything other than an extension! diff --git a/test/sql/base.sql b/test/sql/base.sql index 5b5ff27..07c57a5 100644 --- a/test/sql/base.sql +++ b/test/sql/base.sql @@ -9,7 +9,6 @@ SELECT plan( +1 -- schema +3 -- initial +2 -- errors - +2 -- move +1 -- create extensions ); @@ -50,26 +49,6 @@ 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; -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' -); - -- Create extensions SELECT lives_ok( $$CREATE EXTENSION test_factory$$ From fae8f7c7c95f0ac8df661cf40b30295a78c84b6b Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 26 Aug 2025 16:46:29 -0500 Subject: [PATCH 12/20] Add functions to retrieve object info --- README.md | 8 +++++++ sql/object_reference.sql | 44 +++++++++++++++++++++++++++++++++++++ test/expected/base.out | 10 +++++---- test/expected/zzz_build.out | 2 ++ test/sql/base.sql | 15 +++++++++++++ 5 files changed, 75 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c20af2c..01644fd 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,14 @@ object__getsert_w_group_id( Same as `object__getsert()` but accepts a numeric `object_group_id` instead of group name. +### `object__describe(object_id int) RETURNS text` + +Returns a human-readable description of the object, matching the format of PostgreSQL's `pg_describe_object()` function. + +### `object__identity(object_id int) RETURNS record` + +Returns object identification information matching the format of PostgreSQL's `pg_identify_object()` function. Returns a record with columns: `type`, `schema`, `name`, `identity`. + ## Object Group Functions diff --git a/sql/object_reference.sql b/sql/object_reference.sql index 9b204e1..03b449c 100644 --- a/sql/object_reference.sql +++ b/sql/object_reference.sql @@ -731,7 +731,51 @@ $body$ , 'Add a foreign key from . to the object table.' , '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' +); /* * OBJECT GETSERT */ diff --git a/test/expected/base.out b/test/expected/base.out index 9a52932..9e9af7a 100644 --- a/test/expected/base.out +++ b/test/expected/base.out @@ -1,10 +1,12 @@ \set ECHO none -1..7 +1..9 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 object_oid field is correct -ok 5 - Existing object works, provides correct ID -ok 6 - secondary may not be specified for table objects -ok 7 - CREATE EXTENSION test_factory +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 - CREATE EXTENSION test_factory # TRANSACTION INTENTIONALLY LEFT OPEN! diff --git a/test/expected/zzz_build.out b/test/expected/zzz_build.out index 93431c5..84aa402 100644 --- a/test/expected/zzz_build.out +++ b/test/expected/zzz_build.out @@ -47,6 +47,8 @@ psql:test/temp_load.not_sql:528: WARNING: I promise you will be sorry if you tr + + diff --git a/test/sql/base.sql b/test/sql/base.sql index 07c57a5..9652a4b 100644 --- a/test/sql/base.sql +++ b/test/sql/base.sql @@ -8,6 +8,7 @@ SELECT plan( 0 +1 -- schema +3 -- initial + +2 -- new functions +2 -- errors +1 -- create extensions ); @@ -35,6 +36,20 @@ SELECT is( , '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') , (SELECT object_id FROM test_object) From 96be1332b36787c85d88e9e67362069b12b6eced Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 26 Aug 2025 17:38:26 -0500 Subject: [PATCH 13/20] Disallow tracking objects in temp schemas --- sql/object_reference.sql | 10 ++++++++++ test/expected/base.out | 5 +++-- test/sql/base.sql | 11 ++++++++++- test/sql/object_group.sql | 22 +++++++++++----------- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/sql/object_reference.sql b/sql/object_reference.sql index 03b449c..878009d 100644 --- a/sql/object_reference.sql +++ b/sql/object_reference.sql @@ -795,6 +795,7 @@ DECLARE r_object_v _object_reference._object_v; r_address record; + r_identity record; did_insert boolean := false; @@ -823,6 +824,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/expected/base.out b/test/expected/base.out index 9e9af7a..5357054 100644 --- a/test/expected/base.out +++ b/test/expected/base.out @@ -1,5 +1,5 @@ \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; @@ -8,5 +8,6 @@ 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 - CREATE EXTENSION test_factory +ok 9 - temp objects are rejected +ok 10 - CREATE EXTENSION test_factory # TRANSACTION INTENTIONALLY LEFT OPEN! diff --git a/test/sql/base.sql b/test/sql/base.sql index 9652a4b..5fa9918 100644 --- a/test/sql/base.sql +++ b/test/sql/base.sql @@ -9,7 +9,7 @@ SELECT plan( +1 -- schema +3 -- initial +2 -- new functions - +2 -- errors + +3 -- errors (includes temp object test) +1 -- create extensions ); @@ -64,6 +64,15 @@ SELECT throws_ok( , 'secondary may not be specified for table objects' ); +-- Test temp object rejection +CREATE TEMP TABLE temp_test_table(); +SELECT throws_ok( + $$SELECT object_reference.object__getsert('table', 'temp_test_table')$$ + , '0A000' -- feature_not_supported + , 'cannot track temporary object' + , 'temp objects are rejected' +); + -- Create extensions SELECT lives_ok( $$CREATE EXTENSION test_factory$$ diff --git a/test/sql/object_group.sql b/test/sql/object_group.sql index 6304892..7ae5468 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 @@ -43,7 +43,7 @@ SELECT plan( ); 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 +102,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' ); /* 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 +144,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 +178,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' From bb40896086b86c8bb09c41dfdcc2eca8eb7c19d5 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Wed, 27 Aug 2025 15:37:04 -0500 Subject: [PATCH 14/20] Add object__cleanup() --- README.md | 14 +++++++++++++- sql/object_reference.sql | 34 ++++++++++++++++++++++++++++++++++ test/sql/object_group.sql | 22 ++++++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 01644fd..9bb1a6f 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ GRANT object_reference__usage TO role1, role2, role3; There are two roles associated with the extension: - `object_reference__usage` - Allows using the extension's public API functions. Grant this to users who need to track and manage object references. -- `object_reference__dependency` - Special role for creating foreign key dependencies to the internal object table. Only grant this to schemas/applications that need to create referential integrity constraints against the object tracking system. +- `object_reference__dependency` - Special role for creating foreign key dependencies to the internal object table. Only grant this to schemas/applications that need to create referential integrity constraints against the object tracking system. See [Referring to Objects](#referring-to-objects) below. Most users will only need `object_reference__usage`. The `object_reference__dependency` role is only needed when using `object__dependency__add()` or `object_group__dependency__add()` functions. @@ -53,6 +53,10 @@ Objects can be organized into named groups for logical organization. This is par The framework can automatically capture newly created objects during DDL operations and add them to a specified object group. This is implemented using PostgreSQL event triggers. +## Referring to Objects + +The framework supports removing objects that are no longer referenced. Because of this, *it is critical that any tables that store an `object_id` are registered with `object__dependency__add()`*. + # API Note that all API routines live in the `object_reference` schema. Objects in the `_object_reference` schema are considered internal-only and should not be accessed directly. @@ -247,6 +251,14 @@ post_restore() RETURNS void Ensures all object references are correct after a database restore. Run this after restoring from backup to fix any OID mismatches. +### `object__cleanup(object_id int) RETURNS void` + +```sql +object__cleanup(object_id int) RETURNS void +``` + +Attempts to delete an object from the tracking system. Silently returns if the object is still referenced by other tables (via foreign keys). This function is automatically called when objects are removed from object groups. + ### Object Type Information Functions **Get lists of unsupported/untested object types:** diff --git a/sql/object_reference.sql b/sql/object_reference.sql index 878009d..fcfc045 100644 --- a/sql/object_reference.sql +++ b/sql/object_reference.sql @@ -528,6 +528,23 @@ 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' @@ -776,6 +793,23 @@ $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 */ diff --git a/test/sql/object_group.sql b/test/sql/object_group.sql index 7ae5468..bef342a 100644 --- a/test/sql/object_group.sql +++ b/test/sql/object_group.sql @@ -40,6 +40,8 @@ SELECT plan( +4 -- __object__remove +4 + 2 -- __remove + +4 -- cleanup tests + +1 -- final group removal (there was always an extra test) ); SELECT lives_ok( @@ -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' From f50bbc677aeba936e6740f20ae5e1e733ce3930f Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Wed, 27 Aug 2025 15:40:00 -0500 Subject: [PATCH 15/20] Fix tests --- test/expected/object_group.out | 9 ++++++--- test/expected/zzz_build.out | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) 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 84aa402..ff07ade 100644 --- a/test/expected/zzz_build.out +++ b/test/expected/zzz_build.out @@ -49,6 +49,8 @@ psql:test/temp_load.not_sql:528: WARNING: I promise you will be sorry if you tr + + From f02670ec97e597697a5aa802b69f5fe46eebeaea Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Wed, 27 Aug 2025 16:44:52 -0500 Subject: [PATCH 16/20] Remove references to count_nulls Also, add missing cat_tools requirement to META.in --- META.in.json | 1 + Makefile | 6 +----- object_reference.control | 2 +- test/deps.sql | 1 - test/load.sql | 1 - test/sql/zzz_build.sql | 1 - 6 files changed, 3 insertions(+), 9 deletions(-) diff --git a/META.in.json b/META.in.json index d01dc70..9a541be 100644 --- a/META.in.json +++ b/META.in.json @@ -81,6 +81,7 @@ }, "runtime": { "requires": { + "cat_tools": 0, "plpgsql": 0 } }, diff --git a/Makefile b/Makefile index f5d2ff7..75543b6 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 test: dump_test extra_clean += $(wildcard test/dump/*.log) @@ -15,10 +15,6 @@ cat_tools: $(DESTDIR)$(datadir)/extension/cat_tools.control $(DESTDIR)$(datadir)/extension/cat_tools.control: pgxn install --unstable cat_tools -.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 diff --git a/object_reference.control b/object_reference.control index 8200390..c03010e 100644 --- a/object_reference.control +++ b/object_reference.control @@ -2,4 +2,4 @@ comment = 'Provides reference IDs for database objects' default_version = '0.1.0' relocatable = false schema = 'object_reference' -requires = 'cat_tools, count_nulls' +requires = 'cat_tools' diff --git a/test/deps.sql b/test/deps.sql index e1a53c8..d13a016 100644 --- a/test/deps.sql +++ b/test/deps.sql @@ -4,6 +4,5 @@ /* * 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/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/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; From 1d964c715030c791baf426a1f234e8792c4f3e34 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Wed, 27 Aug 2025 16:44:52 -0500 Subject: [PATCH 17/20] Remove references to count_nulls Also, add missing cat_tools requirement to META.in --- META.in.json | 1 + META.json | 1 + Makefile | 6 +----- object_reference.control | 2 +- sql/object_reference.sql | 2 +- test/deps.sql | 1 - test/load.sql | 1 - test/sql/zzz_build.sql | 1 - 8 files changed, 5 insertions(+), 10 deletions(-) diff --git a/META.in.json b/META.in.json index d01dc70..9a541be 100644 --- a/META.in.json +++ b/META.in.json @@ -81,6 +81,7 @@ }, "runtime": { "requires": { + "cat_tools": 0, "plpgsql": 0 } }, diff --git a/META.json b/META.json index 0512fbb..c56fae1 100644 --- a/META.json +++ b/META.json @@ -79,6 +79,7 @@ }, "runtime": { "requires": { + "cat_tools": 0, "plpgsql": 0 } }, diff --git a/Makefile b/Makefile index f5d2ff7..75543b6 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 test: dump_test extra_clean += $(wildcard test/dump/*.log) @@ -15,10 +15,6 @@ cat_tools: $(DESTDIR)$(datadir)/extension/cat_tools.control $(DESTDIR)$(datadir)/extension/cat_tools.control: pgxn install --unstable cat_tools -.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 diff --git a/object_reference.control b/object_reference.control index 8200390..c03010e 100644 --- a/object_reference.control +++ b/object_reference.control @@ -2,4 +2,4 @@ comment = 'Provides reference IDs for database objects' default_version = '0.1.0' relocatable = false schema = 'object_reference' -requires = 'cat_tools, count_nulls' +requires = 'cat_tools' diff --git a/sql/object_reference.sql b/sql/object_reference.sql index fcfc045..e381023 100644 --- a/sql/object_reference.sql +++ b/sql/object_reference.sql @@ -56,7 +56,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( diff --git a/test/deps.sql b/test/deps.sql index e1a53c8..d13a016 100644 --- a/test/deps.sql +++ b/test/deps.sql @@ -4,6 +4,5 @@ /* * 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/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/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; From 2fa541d5113cc1b2e033615ac58616b34afdb0c7 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 11 Nov 2025 16:02:54 -0600 Subject: [PATCH 18/20] Get more debug output on a test failure --- .github/workflows/ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3183031..bb674ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,3 +15,10 @@ jobs: uses: actions/checkout@v4 - name: Test on PostgreSQL ${{ matrix.pg }} run: make test PGUSER=postgres + - name: Output failed results + run: | + if [ -e test/regression.out ]; then + ls -la /etc/postgresql/${{ matrix.pg }}/ + ls -la /etc/postgresql/${{ matrix.pg }}/test/ + cat /etc/postgresql/${{ matrix.pg }}/test/log + fi From 23d3bf97e63fa72efc398a0328dc2bb6ae0c4a41 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 11 Nov 2025 16:07:01 -0600 Subject: [PATCH 19/20] Have test step continue on failure --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb674ff..50f52de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,10 +15,12 @@ jobs: uses: actions/checkout@v4 - name: Test on PostgreSQL ${{ matrix.pg }} run: make test PGUSER=postgres + continue-on-error: true - name: Output failed results run: | if [ -e test/regression.out ]; then ls -la /etc/postgresql/${{ matrix.pg }}/ ls -la /etc/postgresql/${{ matrix.pg }}/test/ cat /etc/postgresql/${{ matrix.pg }}/test/log + exit 1 fi From 40625c2a3552315a5f5e3ddbfc5a7ef47c08297b Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 11 Nov 2025 16:09:28 -0600 Subject: [PATCH 20/20] Try /var/log for logfile --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50f52de..9fb30d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,8 +19,8 @@ jobs: - name: Output failed results run: | if [ -e test/regression.out ]; then - ls -la /etc/postgresql/${{ matrix.pg }}/ - ls -la /etc/postgresql/${{ matrix.pg }}/test/ - cat /etc/postgresql/${{ matrix.pg }}/test/log + ls -la /var/log + ls -la /var/log/postgresql/ + cat /var/log/postgresql/postgresql-${{ matrix.pg }}-test.log exit 1 fi