Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion object_reference.control
Original file line number Diff line number Diff line change
Expand Up @@ -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'
182 changes: 96 additions & 86 deletions sql/object_reference--stable.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -192,58 +181,19 @@ 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) )
*/
, 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'
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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!
*
Expand Down Expand Up @@ -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'
Expand Down Expand Up @@ -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
*/
Expand All @@ -855,6 +855,7 @@ DECLARE

r_object_v _object_reference._object_v;
r_address record;
r_identity record;

did_insert boolean := false;

Expand Down Expand Up @@ -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
*
Expand Down
Loading
Loading