From 645a89bda16f3d62fd83f0659349ad506636d229 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 14 Apr 2026 15:03:40 -0500 Subject: [PATCH 1/4] Add historical install scripts from PGXN distributions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each file is the canonical install script as published to PGXN: - 0.1.0–0.1.4: extracted directly from PGXN zip (pre-built) - 0.1.5–0.2.1: built from PGXN source for PG >= 9.5 (REQUIRES 9.5 features enabled, PRIOR TO 9.5 alternatives commented out) Also update .gitignore to allow tracking version-specific SQL files. These are needed as starting points for upgrade path testing. Co-Authored-By: Claude Sonnet 4.6 --- sql/cat_tools--0.1.0.sql | 340 +++++++++ sql/cat_tools--0.1.3.sql | 486 +++++++++++++ sql/cat_tools--0.1.4.sql | 489 +++++++++++++ sql/cat_tools--0.1.5.sql | 525 ++++++++++++++ sql/cat_tools--0.2.0.sql | 1285 +++++++++++++++++++++++++++++++++ sql/cat_tools--0.2.1.sql | 1472 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 4597 insertions(+) create mode 100644 sql/cat_tools--0.1.0.sql create mode 100644 sql/cat_tools--0.1.3.sql create mode 100644 sql/cat_tools--0.1.4.sql create mode 100644 sql/cat_tools--0.1.5.sql create mode 100644 sql/cat_tools--0.2.0.sql create mode 100644 sql/cat_tools--0.2.1.sql diff --git a/sql/cat_tools--0.1.0.sql b/sql/cat_tools--0.1.0.sql new file mode 100644 index 0000000..b53df42 --- /dev/null +++ b/sql/cat_tools--0.1.0.sql @@ -0,0 +1,340 @@ +CREATE SCHEMA cat_tools; +CREATE SCHEMA _cat_tools; + +CREATE OR REPLACE VIEW _cat_tools.pg_class_v AS + SELECT c.oid AS reloid, c.*, n.nspname AS relschema + FROM pg_class c + LEFT JOIN pg_namespace n ON( n.oid = c.relnamespace ) +; +REVOKE ALL ON _cat_tools.pg_class_v FROM public; + +CREATE OR REPLACE VIEW cat_tools.pg_class_v AS + SELECT * + FROM _cat_tools.pg_class_v + + /* + * Oddly, there's no security associated with schema or table visibility. + * Be a bit paranoid though. + */ + WHERE NOT pg_is_other_temp_schema(relnamespace) + AND relkind IN( 'r', 'v', 'f' ) +; + +CREATE OR REPLACE VIEW _cat_tools.pg_attribute_v AS + SELECT a.* + , c.* + , t.oid AS typoid + , t.* + FROM pg_attribute a + LEFT JOIN _cat_tools.pg_class_v c ON ( c.reloid = a.attrelid ) + LEFT JOIN pg_type t ON ( t.oid = a.atttypid ) +; +REVOKE ALL ON _cat_tools.pg_attribute_v FROM public; + +CREATE OR REPLACE VIEW _cat_tools.column AS + SELECT * + , pg_catalog.format_type(typoid, atttypmod) AS column_type + , CASE typtype + -- domain + WHEN 'd' THEN pg_catalog.format_type(typbasetype, typtypmod) + -- enum + WHEN 'e' THEN 'text' + ELSE pg_catalog.format_type(typoid, atttypmod) + END AS base_type + , pk.conkey AS pk_columns + , ARRAY[attnum] <@ pk.conkey AS is_pk_member + , (SELECT pg_catalog.pg_get_expr(d.adbin, d.adrelid) + FROM pg_catalog.pg_attrdef d + WHERE d.adrelid = a.attrelid + AND d.adnum = a.attnum + AND a.atthasdef + ) AS column_default + FROM _cat_tools.pg_attribute_v a + LEFT JOIN pg_constraint pk + ON ( reloid = pk.conrelid ) + AND pk.contype = 'p' +; +REVOKE ALL ON _cat_tools.column FROM public; + +CREATE OR REPLACE VIEW cat_tools.column AS + SELECT * + FROM _cat_tools.column + -- SECURITY + WHERE NOT pg_is_other_temp_schema(relnamespace) + AND attnum > 0 + AND NOT attisdropped + AND relkind IN( 'r', 'v', 'f' ) + AND ( + pg_has_role(SESSION_USER, relowner, 'USAGE'::text) + OR has_column_privilege(SESSION_USER, reloid, attnum, 'SELECT, INSERT, UPDATE, REFERENCES'::text) + ) + ORDER BY relschema, relname, attnum +; + +-- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ +CREATE OR REPLACE FUNCTION _cat_tools._pg_sv_column_array( OID, SMALLINT[] ) +RETURNS NAME[] AS $$ + SELECT ARRAY( + SELECT a.attname + FROM pg_catalog.pg_attribute a + JOIN generate_series(1, array_upper($2, 1)) s(i) ON a.attnum = $2[i] + WHERE attrelid = $1 + ORDER BY i + ) +$$ LANGUAGE SQL stable; + +-- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ +CREATE OR REPLACE FUNCTION _cat_tools._pg_sv_table_accessible( OID, OID ) +RETURNS BOOLEAN AS $$ + SELECT CASE WHEN has_schema_privilege($1, 'USAGE') THEN ( + has_table_privilege($2, 'SELECT') + OR has_table_privilege($2, 'INSERT') + or has_table_privilege($2, 'UPDATE') + OR has_table_privilege($2, 'DELETE') + OR has_table_privilege($2, 'RULE') + OR has_table_privilege($2, 'REFERENCES') + OR has_table_privilege($2, 'TRIGGER') + ) ELSE FALSE + END; +$$ LANGUAGE SQL immutable strict; + +-- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ +CREATE OR REPLACE VIEW cat_tools.pg_all_foreign_keys +AS + SELECT n1.nspname AS fk_schema_name, + c1.relname AS fk_table_name, + k1.conname AS fk_constraint_name, + c1.oid AS fk_table_oid, + _cat_tools._pg_sv_column_array(k1.conrelid,k1.conkey) AS fk_columns, + n2.nspname AS pk_schema_name, + c2.relname AS pk_table_name, + k2.conname AS pk_constraint_name, + c2.oid AS pk_table_oid, + ci.relname AS pk_index_name, + _cat_tools._pg_sv_column_array(k1.confrelid,k1.confkey) AS pk_columns, + CASE k1.confmatchtype WHEN 'f' THEN 'FULL' + WHEN 'p' THEN 'PARTIAL' + WHEN 'u' THEN 'NONE' + else null + END AS match_type, + CASE k1.confdeltype WHEN 'a' THEN 'NO ACTION' + WHEN 'c' THEN 'CASCADE' + WHEN 'd' THEN 'SET DEFAULT' + WHEN 'n' THEN 'SET NULL' + WHEN 'r' THEN 'RESTRICT' + else null + END AS on_delete, + CASE k1.confupdtype WHEN 'a' THEN 'NO ACTION' + WHEN 'c' THEN 'CASCADE' + WHEN 'd' THEN 'SET DEFAULT' + WHEN 'n' THEN 'SET NULL' + WHEN 'r' THEN 'RESTRICT' + ELSE NULL + END AS on_update, + k1.condeferrable AS is_deferrable, + k1.condeferred AS is_deferred + FROM pg_catalog.pg_constraint k1 + JOIN pg_catalog.pg_namespace n1 ON (n1.oid = k1.connamespace) + JOIN pg_catalog.pg_class c1 ON (c1.oid = k1.conrelid) + JOIN pg_catalog.pg_class c2 ON (c2.oid = k1.confrelid) + JOIN pg_catalog.pg_namespace n2 ON (n2.oid = c2.relnamespace) + JOIN pg_catalog.pg_depend d ON ( + d.classid = 'pg_constraint'::regclass + AND d.objid = k1.oid + AND d.objsubid = 0 + AND d.deptype = 'n' + AND d.refclassid = 'pg_class'::regclass + AND d.refobjsubid=0 + ) + JOIN pg_catalog.pg_class ci ON (ci.oid = d.refobjid AND ci.relkind = 'i') + LEFT JOIN pg_depend d2 ON ( + d2.classid = 'pg_class'::regclass + AND d2.objid = ci.oid + AND d2.objsubid = 0 + AND d2.deptype = 'i' + AND d2.refclassid = 'pg_constraint'::regclass + AND d2.refobjsubid = 0 + ) + LEFT JOIN pg_catalog.pg_constraint k2 ON ( + k2.oid = d2.refobjid + AND k2.contype IN ('p', 'u') + ) + WHERE k1.conrelid != 0 + AND k1.confrelid != 0 + AND k1.contype = 'f' + AND _cat_tools._pg_sv_table_accessible(n1.oid, c1.oid) +; + +CREATE OR REPLACE FUNCTION cat_tools.currval( + table_name text + , column_name text +) RETURNS bigint LANGUAGE plpgsql AS $body$ +DECLARE + seq regclass; +BEGIN + -- Note: the function will throw an error if table or column doesn't exist + seq := pg_get_serial_sequence( table_name, column_name ); + + IF seq IS NULL THEN + RAISE EXCEPTION '"%" is not a serial column', column_name + USING ERRCODE = 'wrong_object_type' + -- TODO: SCHEMA and COLUMN + , COLUMN = column_name + ; + END IF; + + RETURN currval(seq); +END +$body$; + +CREATE OR REPLACE FUNCTION cat_tools.enum_range( + enum regtype +) RETURNS text[] LANGUAGE plpgsql STABLE AS $body$ +DECLARE + ret text[]; +BEGIN + EXECUTE format('SELECT pg_catalog.enum_range( NULL::%s )', enum) INTO ret; + RETURN ret; +END +$body$; + +CREATE OR REPLACE FUNCTION cat_tools.enum_range_srf( + enum regtype +) RETURNS SETOF text LANGUAGE sql AS $body$ +SELECT * FROM unnest( cat_tools.enum_range($1) ) AS r(enum_label) +$body$; + +CREATE OR REPLACE FUNCTION cat_tools.pg_class( + rel regclass +) RETURNS cat_tools.pg_class_v LANGUAGE sql STABLE AS $body$ +SELECT * FROM cat_tools.pg_class_v WHERE reloid = rel +$body$; + +CREATE OR REPLACE FUNCTION cat_tools.name__check( + name_to_check text +) RETURNS void LANGUAGE plpgsql AS $body$ +BEGIN + IF name_to_check IS DISTINCT FROM name_to_check::name THEN + RAISE '"%" becomes "%" when cast to name', name_to_check, name_to_check::name; + END IF; +END +$body$; + +CREATE OR REPLACE FUNCTION cat_tools.trigger__parse( + trigger_oid oid + , OUT timing text + , OUT events text[] + , OUT defer text + , OUT row_statement text + , OUT when_clause text + , OUT function_arguments text +) RETURNS record LANGUAGE plpgsql AS $body$ +DECLARE + r_trigger pg_catalog.pg_trigger; + v_triggerdef text; + v_create_stanza text; + v_on_clause text; + v_execute_clause text; + + v_work text; + v_array text[]; +BEGIN + -- Do this first to make sure trigger exists + v_triggerdef := pg_catalog.pg_get_triggerdef(trigger_oid, true); + SELECT * INTO STRICT r_trigger FROM pg_catalog.pg_trigger WHERE oid = trigger_oid; + + v_create_stanza := format( + 'CREATE %sTRIGGER %I ' + , CASE WHEN r_trigger.tgconstraint=0 THEN '' ELSE 'CONSTRAINT ' END + , r_trigger.tgname + ); + -- Strip CREATE [CONSTRAINT] TRIGGER ... off + v_work := replace( v_triggerdef, v_create_stanza, '' ); + + -- Get BEFORE | AFTER | INSTEAD OF + timing := split_part( v_work, ' ', 1 ); + timing := timing || CASE timing WHEN 'INSTEAD' THEN ' OF' ELSE '' END; + + -- Strip off timing clause + v_work := replace( v_work, timing || ' ', '' ); + + -- Get array of events (INSERT, UPDATE [OF column, column], DELETE, TRUNCATE) + v_on_clause := ' ON ' || r_trigger.tgrelid::regclass || ' '; + v_array := regexp_split_to_array( v_work, v_on_clause ); + events := string_to_array( v_array[1], ' OR ' ); + -- Get everything after ON table_name + v_work := v_array[2]; + RAISE DEBUG 'v_work "%"', v_work; + + -- Strip off FROM referenced_table if we have it + IF r_trigger.tgconstrrelid<>0 THEN + v_work := replace( + v_work + , 'FROM ' || r_trigger.tgconstrrelid::regclass || ' ' + , '' + ); + END IF; + RAISE DEBUG 'v_work "%"', v_work; + + -- Get function arguments + v_execute_clause := ' EXECUTE PROCEDURE ' || r_trigger.tgfoid::regproc || E'\\('; + v_array := regexp_split_to_array( v_work, v_execute_clause ); + function_arguments := rtrim( v_array[2], ')' ); -- Yank trailing ) + -- Get everything prior to EXECUTE PROCEDURE ... + v_work := v_array[1]; + RAISE DEBUG 'v_work "%"', v_work; + + row_statement := (regexp_matches( v_work, 'FOR EACH (ROW|STATEMENT)' ))[1]; + + -- Get [ NOT DEFERRABLE | [ DEFERRABLE ] { INITIALLY IMMEDIATE | INITIALLY DEFERRED } ] + v_array := regexp_split_to_array( v_work, 'FOR EACH (ROW|STATEMENT)' ); + RAISE DEBUG 'v_work = "%", v_array = "%"', v_work, v_array; + defer := rtrim(v_array[1]); + + IF r_trigger.tgqual IS NOT NULL THEN + when_clause := rtrim( + (regexp_split_to_array( v_array[2], E' WHEN \\(' ))[2] + , ')' + ); + END IF; + + RAISE DEBUG +$$v_create_stanza = "%" + v_on_clause = "%" + v_execute_clause = "%"$$ + , v_create_stanza + , v_on_clause + , v_execute_clause + ; + + RETURN; +END +$body$; + +CREATE OR REPLACE FUNCTION cat_tools.trigger__get_oid__loose( + trigger_table regclass + , trigger_name text +) RETURNS oid LANGUAGE sql AS $body$ + SELECT oid + FROM pg_trigger + WHERE tgrelid = trigger_table + AND tgname = trigger_name + ; +$body$; + +CREATE OR REPLACE FUNCTION cat_tools.trigger__get_oid( + trigger_table regclass + , trigger_name text +) RETURNS oid LANGUAGE plpgsql AS $body$ +DECLARE + v_oid oid; +BEGIN + SELECT cat_tools.crigger__get_oid__loose( trigger_table, trigger_name ) + INTO STRICT v_oid + ; + + RETURN v_oid; +END +$body$; + +-- vi: expandtab ts=2 sw=2 diff --git a/sql/cat_tools--0.1.3.sql b/sql/cat_tools--0.1.3.sql new file mode 100644 index 0000000..af0879b --- /dev/null +++ b/sql/cat_tools--0.1.3.sql @@ -0,0 +1,486 @@ +DO $$ +BEGIN + CREATE ROLE cat_tools__usage NOLOGIN; +EXCEPTION WHEN duplicate_object THEN + NULL; +END +$$; + +/* + * NOTE: All pg_temp objects must be dropped at the end of the script! + * Otherwise the eventual DROP CASCADE of pg_temp when the session ends will + * also drop the extension! Instead of risking problems, create our own + * "temporary" schema instead. + */ +CREATE SCHEMA __cat_tools; +CREATE FUNCTION __cat_tools.exec( + sql text +) RETURNS void LANGUAGE plpgsql AS $body$ +BEGIN + RAISE DEBUG 'sql = %', sql; + EXECUTE sql; +END +$body$; +CREATE FUNCTION __cat_tools.create_function( + function_name text + , args text + , options text + , body text + , grants text DEFAULT NULL +) RETURNS void LANGUAGE plpgsql AS $body$ +DECLARE + + create_template CONSTANT text := $template$ +CREATE OR REPLACE FUNCTION %s( +%s +) RETURNS %s AS +%L +$template$ + ; + + revoke_template CONSTANT text := $template$ +REVOKE ALL ON FUNCTION %s( +%s +) FROM public; +$template$ + ; + + grant_template CONSTANT text := $template$ +GRANT EXECUTE ON FUNCTION %s( +%s +) TO %s; +$template$ + ; + +BEGIN + PERFORM __cat_tools.exec( format( + create_template + , function_name + , args + , options + , body + ) ) + ; + PERFORM __cat_tools.exec( format( + revoke_template + , function_name + , args + ) ) + ; + + IF grants IS NOT NULL THEN + PERFORM __cat_tools.exec( format( + grant_template + , function_name + , args + , grants + ) ) + ; + END IF; +END +$body$; + +CREATE SCHEMA cat_tools; +GRANT USAGE ON SCHEMA cat_tools TO cat_tools__usage; +CREATE SCHEMA _cat_tools; + +CREATE OR REPLACE VIEW _cat_tools.pg_class_v AS + SELECT c.oid AS reloid, c.*, n.nspname AS relschema + FROM pg_class c + LEFT JOIN pg_namespace n ON( n.oid = c.relnamespace ) +; +REVOKE ALL ON _cat_tools.pg_class_v FROM public; + +CREATE OR REPLACE VIEW cat_tools.pg_class_v AS + SELECT * + FROM _cat_tools.pg_class_v + + /* + * Oddly, there's no security associated with schema or table visibility. + * Be a bit paranoid though. + */ + WHERE NOT pg_is_other_temp_schema(relnamespace) + AND relkind IN( 'r', 'v', 'f' ) +; +GRANT SELECT ON cat_tools.pg_class_v TO cat_tools__usage; + +CREATE OR REPLACE VIEW _cat_tools.pg_attribute_v AS + SELECT a.* + , c.* + , t.oid AS typoid + , t.* + FROM pg_attribute a + LEFT JOIN _cat_tools.pg_class_v c ON ( c.reloid = a.attrelid ) + LEFT JOIN pg_type t ON ( t.oid = a.atttypid ) +; +REVOKE ALL ON _cat_tools.pg_attribute_v FROM public; + +CREATE OR REPLACE VIEW _cat_tools.column AS + SELECT * + , pg_catalog.format_type(typoid, atttypmod) AS column_type + , CASE typtype + -- domain + WHEN 'd' THEN pg_catalog.format_type(typbasetype, typtypmod) + -- enum + WHEN 'e' THEN 'text' + ELSE pg_catalog.format_type(typoid, atttypmod) + END AS base_type + , pk.conkey AS pk_columns + , ARRAY[attnum] <@ pk.conkey AS is_pk_member + , (SELECT pg_catalog.pg_get_expr(d.adbin, d.adrelid) + FROM pg_catalog.pg_attrdef d + WHERE d.adrelid = a.attrelid + AND d.adnum = a.attnum + AND a.atthasdef + ) AS column_default + FROM _cat_tools.pg_attribute_v a + LEFT JOIN pg_constraint pk + ON ( reloid = pk.conrelid ) + AND pk.contype = 'p' +; +REVOKE ALL ON _cat_tools.column FROM public; + +CREATE OR REPLACE VIEW cat_tools.column AS + SELECT * + FROM _cat_tools.column + -- SECURITY + WHERE NOT pg_is_other_temp_schema(relnamespace) + AND attnum > 0 + AND NOT attisdropped + AND relkind IN( 'r', 'v', 'f' ) + AND ( + pg_has_role(SESSION_USER, relowner, 'USAGE'::text) + OR has_column_privilege(SESSION_USER, reloid, attnum, 'SELECT, INSERT, UPDATE, REFERENCES'::text) + ) + ORDER BY relschema, relname, attnum +; +GRANT SELECT ON cat_tools.column TO cat_tools__usage; + +-- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ +SELECT __cat_tools.create_function( + '_cat_tools._pg_sv_column_array' + , 'OID, SMALLINT[]' + , 'NAME[] LANGUAGE sql STABLE' + , $$ + SELECT ARRAY( + SELECT a.attname + FROM pg_catalog.pg_attribute a + JOIN generate_series(1, array_upper($2, 1)) s(i) ON a.attnum = $2[i] + WHERE attrelid = $1 + ORDER BY i + ) +$$ +); + +-- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ +SELECT __cat_tools.create_function( + '_cat_tools._pg_sv_table_accessible' + , 'OID, OID' + , 'boolean LANGUAGE sql STABLE' + , $$ + SELECT CASE WHEN has_schema_privilege($1, 'USAGE') THEN ( + has_table_privilege($2, 'SELECT') + OR has_table_privilege($2, 'INSERT') + or has_table_privilege($2, 'UPDATE') + OR has_table_privilege($2, 'DELETE') + OR has_table_privilege($2, 'RULE') + OR has_table_privilege($2, 'REFERENCES') + OR has_table_privilege($2, 'TRIGGER') + ) ELSE FALSE + END; +$$ +); + +-- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ +CREATE OR REPLACE VIEW cat_tools.pg_all_foreign_keys +AS + SELECT n1.nspname AS fk_schema_name, + c1.relname AS fk_table_name, + k1.conname AS fk_constraint_name, + c1.oid AS fk_table_oid, + _cat_tools._pg_sv_column_array(k1.conrelid,k1.conkey) AS fk_columns, + n2.nspname AS pk_schema_name, + c2.relname AS pk_table_name, + k2.conname AS pk_constraint_name, + c2.oid AS pk_table_oid, + ci.relname AS pk_index_name, + _cat_tools._pg_sv_column_array(k1.confrelid,k1.confkey) AS pk_columns, + CASE k1.confmatchtype WHEN 'f' THEN 'FULL' + WHEN 'p' THEN 'PARTIAL' + WHEN 'u' THEN 'NONE' + else null + END AS match_type, + CASE k1.confdeltype WHEN 'a' THEN 'NO ACTION' + WHEN 'c' THEN 'CASCADE' + WHEN 'd' THEN 'SET DEFAULT' + WHEN 'n' THEN 'SET NULL' + WHEN 'r' THEN 'RESTRICT' + else null + END AS on_delete, + CASE k1.confupdtype WHEN 'a' THEN 'NO ACTION' + WHEN 'c' THEN 'CASCADE' + WHEN 'd' THEN 'SET DEFAULT' + WHEN 'n' THEN 'SET NULL' + WHEN 'r' THEN 'RESTRICT' + ELSE NULL + END AS on_update, + k1.condeferrable AS is_deferrable, + k1.condeferred AS is_deferred + FROM pg_catalog.pg_constraint k1 + JOIN pg_catalog.pg_namespace n1 ON (n1.oid = k1.connamespace) + JOIN pg_catalog.pg_class c1 ON (c1.oid = k1.conrelid) + JOIN pg_catalog.pg_class c2 ON (c2.oid = k1.confrelid) + JOIN pg_catalog.pg_namespace n2 ON (n2.oid = c2.relnamespace) + JOIN pg_catalog.pg_depend d ON ( + d.classid = 'pg_constraint'::regclass + AND d.objid = k1.oid + AND d.objsubid = 0 + AND d.deptype = 'n' + AND d.refclassid = 'pg_class'::regclass + AND d.refobjsubid=0 + ) + JOIN pg_catalog.pg_class ci ON (ci.oid = d.refobjid AND ci.relkind = 'i') + LEFT JOIN pg_depend d2 ON ( + d2.classid = 'pg_class'::regclass + AND d2.objid = ci.oid + AND d2.objsubid = 0 + AND d2.deptype = 'i' + AND d2.refclassid = 'pg_constraint'::regclass + AND d2.refobjsubid = 0 + ) + LEFT JOIN pg_catalog.pg_constraint k2 ON ( + k2.oid = d2.refobjid + AND k2.contype IN ('p', 'u') + ) + WHERE k1.conrelid != 0 + AND k1.confrelid != 0 + AND k1.contype = 'f' + AND _cat_tools._pg_sv_table_accessible(n1.oid, c1.oid) +; +GRANT SELECT ON cat_tools.pg_all_foreign_keys TO cat_tools__usage; + +SELECT __cat_tools.create_function( + 'cat_tools.currval' + , $$ + table_name text + , column_name text +$$ + , $$bigint LANGUAGE plpgsql$$ + , $body$ +DECLARE + seq regclass; +BEGIN + -- Note: the function will throw an error if table or column doesn't exist + seq := pg_get_serial_sequence( table_name, column_name ); + + IF seq IS NULL THEN + RAISE EXCEPTION '"%" is not a serial column', column_name + USING ERRCODE = 'wrong_object_type' + -- TODO: SCHEMA and COLUMN + , COLUMN = column_name + ; + END IF; + + RETURN currval(seq); +END +$body$ + , 'cat_tools__usage' +); + +SELECT __cat_tools.create_function( + 'cat_tools.enum_range' + , 'enum regtype' + , $$text[] LANGUAGE plpgsql STABLE$$ + , $body$ +DECLARE + ret text[]; +BEGIN + EXECUTE format('SELECT pg_catalog.enum_range( NULL::%s )', enum) INTO ret; + RETURN ret; +END +$body$ + , 'cat_tools__usage' +); + +SELECT __cat_tools.create_function( + 'cat_tools.enum_range_srf' + , 'enum regtype' + , $$SETOF text LANGUAGE sql$$ + , $body$ +SELECT * FROM unnest( cat_tools.enum_range($1) ) AS r(enum_label) +$body$ + , 'cat_tools__usage' +); + +SELECT __cat_tools.create_function( + 'cat_tools.pg_class' + , 'rel regclass' + , $$cat_tools.pg_class_v LANGUAGE sql STABLE$$ + , $body$ +SELECT * FROM cat_tools.pg_class_v WHERE reloid = rel +$body$ + , 'cat_tools__usage' +); + +SELECT __cat_tools.create_function( + 'cat_tools.name__check' + , 'name_to_check text' + , $$void LANGUAGE plpgsql$$ + , $body$ +BEGIN + IF name_to_check IS DISTINCT FROM name_to_check::name THEN + RAISE '"%" becomes "%" when cast to name', name_to_check, name_to_check::name; + END IF; +END +$body$ + , 'cat_tools__usage' +); + +SELECT __cat_tools.create_function( + 'cat_tools.trigger__parse' + , $$ + trigger_oid oid + , OUT timing text + , OUT events text[] + , OUT defer text + , OUT row_statement text + , OUT when_clause text + , OUT function_arguments text +$$ + , $$record LANGUAGE plpgsql$$ + , $body$ +DECLARE + r_trigger pg_catalog.pg_trigger; + v_triggerdef text; + v_create_stanza text; + v_on_clause text; + v_execute_clause text; + + v_work text; + v_array text[]; +BEGIN + -- Do this first to make sure trigger exists + v_triggerdef := pg_catalog.pg_get_triggerdef(trigger_oid, true); + SELECT * INTO STRICT r_trigger FROM pg_catalog.pg_trigger WHERE oid = trigger_oid; + + v_create_stanza := format( + 'CREATE %sTRIGGER %I ' + , CASE WHEN r_trigger.tgconstraint=0 THEN '' ELSE 'CONSTRAINT ' END + , r_trigger.tgname + ); + -- Strip CREATE [CONSTRAINT] TRIGGER ... off + v_work := replace( v_triggerdef, v_create_stanza, '' ); + + -- Get BEFORE | AFTER | INSTEAD OF + timing := split_part( v_work, ' ', 1 ); + timing := timing || CASE timing WHEN 'INSTEAD' THEN ' OF' ELSE '' END; + + -- Strip off timing clause + v_work := replace( v_work, timing || ' ', '' ); + + -- Get array of events (INSERT, UPDATE [OF column, column], DELETE, TRUNCATE) + v_on_clause := ' ON ' || r_trigger.tgrelid::regclass || ' '; + v_array := regexp_split_to_array( v_work, v_on_clause ); + events := string_to_array( v_array[1], ' OR ' ); + -- Get everything after ON table_name + v_work := v_array[2]; + RAISE DEBUG 'v_work "%"', v_work; + + -- Strip off FROM referenced_table if we have it + IF r_trigger.tgconstrrelid<>0 THEN + v_work := replace( + v_work + , 'FROM ' || r_trigger.tgconstrrelid::regclass || ' ' + , '' + ); + END IF; + RAISE DEBUG 'v_work "%"', v_work; + + -- Get function arguments + v_execute_clause := ' EXECUTE PROCEDURE ' || r_trigger.tgfoid::regproc || E'\\('; + v_array := regexp_split_to_array( v_work, v_execute_clause ); + function_arguments := rtrim( v_array[2], ')' ); -- Yank trailing ) + -- Get everything prior to EXECUTE PROCEDURE ... + v_work := v_array[1]; + RAISE DEBUG 'v_work "%"', v_work; + + row_statement := (regexp_matches( v_work, 'FOR EACH (ROW|STATEMENT)' ))[1]; + + -- Get [ NOT DEFERRABLE | [ DEFERRABLE ] { INITIALLY IMMEDIATE | INITIALLY DEFERRED } ] + v_array := regexp_split_to_array( v_work, 'FOR EACH (ROW|STATEMENT)' ); + RAISE DEBUG 'v_work = "%", v_array = "%"', v_work, v_array; + defer := rtrim(v_array[1]); + + IF r_trigger.tgqual IS NOT NULL THEN + when_clause := rtrim( + (regexp_split_to_array( v_array[2], E' WHEN \\(' ))[2] + , ')' + ); + END IF; + + RAISE DEBUG +$$v_create_stanza = "%" + v_on_clause = "%" + v_execute_clause = "%"$$ + , v_create_stanza + , v_on_clause + , v_execute_clause + ; + + RETURN; +END +$body$ + , 'cat_tools__usage' +); + +SELECT __cat_tools.create_function( + 'cat_tools.trigger__get_oid__loose' + , $$ + trigger_table regclass + , trigger_name text +$$ + , $$oid LANGUAGE sql$$ + , $body$ + SELECT oid + FROM pg_trigger + WHERE tgrelid = trigger_table + AND tgname = trigger_name + ; +$body$ + , 'cat_tools__usage' +); + +SELECT __cat_tools.create_function( + 'cat_tools.trigger__get_oid' + , $$ + trigger_table regclass + , trigger_name text +$$ + , $$oid LANGUAGE plpgsql$$ + , $body$ +DECLARE + v_oid oid; +BEGIN + SELECT cat_tools.crigger__get_oid__loose( trigger_table, trigger_name ) + INTO STRICT v_oid + ; + + RETURN v_oid; +END +$body$ + , 'cat_tools__usage' +); + +DROP FUNCTION __cat_tools.exec( + sql text +); +DROP FUNCTION __cat_tools.create_function( + function_name text + , args text + , options text + , body text + , grants text +); +DROP SCHEMA __cat_tools; + +-- vi: expandtab ts=2 sw=2 diff --git a/sql/cat_tools--0.1.4.sql b/sql/cat_tools--0.1.4.sql new file mode 100644 index 0000000..47547db --- /dev/null +++ b/sql/cat_tools--0.1.4.sql @@ -0,0 +1,489 @@ +DO $$ +BEGIN + CREATE ROLE cat_tools__usage NOLOGIN; +EXCEPTION WHEN duplicate_object THEN + NULL; +END +$$; + +/* + * NOTE: All pg_temp objects must be dropped at the end of the script! + * Otherwise the eventual DROP CASCADE of pg_temp when the session ends will + * also drop the extension! Instead of risking problems, create our own + * "temporary" schema instead. + */ +CREATE SCHEMA __cat_tools; +CREATE FUNCTION __cat_tools.exec( + sql text +) RETURNS void LANGUAGE plpgsql AS $body$ +BEGIN + RAISE DEBUG 'sql = %', sql; + EXECUTE sql; +END +$body$; +CREATE FUNCTION __cat_tools.create_function( + function_name text + , args text + , options text + , body text + , grants text DEFAULT NULL +) RETURNS void LANGUAGE plpgsql AS $body$ +DECLARE + + create_template CONSTANT text := $template$ +CREATE OR REPLACE FUNCTION %s( +%s +) RETURNS %s AS +%L +$template$ + ; + + revoke_template CONSTANT text := $template$ +REVOKE ALL ON FUNCTION %s( +%s +) FROM public; +$template$ + ; + + grant_template CONSTANT text := $template$ +GRANT EXECUTE ON FUNCTION %s( +%s +) TO %s; +$template$ + ; + +BEGIN + PERFORM __cat_tools.exec( format( + create_template + , function_name + , args + , options + , body + ) ) + ; + PERFORM __cat_tools.exec( format( + revoke_template + , function_name + , args + ) ) + ; + + IF grants IS NOT NULL THEN + PERFORM __cat_tools.exec( format( + grant_template + , function_name + , args + , grants + ) ) + ; + END IF; +END +$body$; + +CREATE SCHEMA cat_tools; +GRANT USAGE ON SCHEMA cat_tools TO cat_tools__usage; +CREATE SCHEMA _cat_tools; + +CREATE OR REPLACE VIEW _cat_tools.pg_class_v AS + SELECT c.oid AS reloid, c.*, n.nspname AS relschema + FROM pg_class c + LEFT JOIN pg_namespace n ON( n.oid = c.relnamespace ) +; +REVOKE ALL ON _cat_tools.pg_class_v FROM public; + +CREATE OR REPLACE VIEW cat_tools.pg_class_v AS + SELECT * + FROM _cat_tools.pg_class_v + + /* + * Oddly, there's no security associated with schema or table visibility. + * Be a bit paranoid though. + */ + WHERE NOT pg_is_other_temp_schema(relnamespace) + AND relkind IN( 'r', 'v', 'f' ) +; +GRANT SELECT ON cat_tools.pg_class_v TO cat_tools__usage; + +CREATE OR REPLACE VIEW _cat_tools.pg_attribute_v AS + SELECT a.* + , c.* + , t.oid AS typoid + , t.* + FROM pg_attribute a + LEFT JOIN _cat_tools.pg_class_v c ON ( c.reloid = a.attrelid ) + LEFT JOIN pg_type t ON ( t.oid = a.atttypid ) +; +REVOKE ALL ON _cat_tools.pg_attribute_v FROM public; + +CREATE OR REPLACE VIEW _cat_tools.column AS + SELECT * + , pg_catalog.format_type(typoid, atttypmod) AS column_type + , CASE typtype + -- domain + WHEN 'd' THEN pg_catalog.format_type(typbasetype, typtypmod) + -- enum + WHEN 'e' THEN 'text' + ELSE pg_catalog.format_type(typoid, atttypmod) + END AS base_type + , pk.conkey AS pk_columns + , ARRAY[attnum] <@ pk.conkey AS is_pk_member + , (SELECT pg_catalog.pg_get_expr(d.adbin, d.adrelid) + FROM pg_catalog.pg_attrdef d + WHERE d.adrelid = a.attrelid + AND d.adnum = a.attnum + AND a.atthasdef + ) AS column_default + FROM _cat_tools.pg_attribute_v a + LEFT JOIN pg_constraint pk + ON ( reloid = pk.conrelid ) + AND pk.contype = 'p' +; +REVOKE ALL ON _cat_tools.column FROM public; + +CREATE OR REPLACE VIEW cat_tools.column AS + SELECT * + FROM _cat_tools.column + -- SECURITY + WHERE NOT pg_is_other_temp_schema(relnamespace) + AND attnum > 0 + AND NOT attisdropped + AND relkind IN( 'r', 'v', 'f' ) + AND ( + pg_has_role(SESSION_USER, relowner, 'USAGE'::text) + OR has_column_privilege(SESSION_USER, reloid, attnum, 'SELECT, INSERT, UPDATE, REFERENCES'::text) + ) + ORDER BY relschema, relname, attnum +; +GRANT SELECT ON cat_tools.column TO cat_tools__usage; + +-- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ +SELECT __cat_tools.create_function( + '_cat_tools._pg_sv_column_array' + , 'OID, SMALLINT[]' + , 'NAME[] LANGUAGE sql STABLE' + , $$ + SELECT ARRAY( + SELECT a.attname + FROM pg_catalog.pg_attribute a + JOIN generate_series(1, array_upper($2, 1)) s(i) ON a.attnum = $2[i] + WHERE attrelid = $1 + ORDER BY i + ) +$$ +); + +-- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ +SELECT __cat_tools.create_function( + '_cat_tools._pg_sv_table_accessible' + , 'OID, OID' + , 'boolean LANGUAGE sql STABLE' + , $$ + SELECT CASE WHEN has_schema_privilege($1, 'USAGE') THEN ( + has_table_privilege($2, 'SELECT') + OR has_table_privilege($2, 'INSERT') + or has_table_privilege($2, 'UPDATE') + OR has_table_privilege($2, 'DELETE') + OR has_table_privilege($2, 'RULE') + OR has_table_privilege($2, 'REFERENCES') + OR has_table_privilege($2, 'TRIGGER') + ) ELSE FALSE + END; +$$ +); + +-- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ +CREATE OR REPLACE VIEW cat_tools.pg_all_foreign_keys +AS + SELECT n1.nspname AS fk_schema_name, + c1.relname AS fk_table_name, + k1.conname AS fk_constraint_name, + c1.oid AS fk_table_oid, + _cat_tools._pg_sv_column_array(k1.conrelid,k1.conkey) AS fk_columns, + n2.nspname AS pk_schema_name, + c2.relname AS pk_table_name, + k2.conname AS pk_constraint_name, + c2.oid AS pk_table_oid, + ci.relname AS pk_index_name, + _cat_tools._pg_sv_column_array(k1.confrelid,k1.confkey) AS pk_columns, + CASE k1.confmatchtype WHEN 'f' THEN 'FULL' + WHEN 'p' THEN 'PARTIAL' + WHEN 'u' THEN 'NONE' + else null + END AS match_type, + CASE k1.confdeltype WHEN 'a' THEN 'NO ACTION' + WHEN 'c' THEN 'CASCADE' + WHEN 'd' THEN 'SET DEFAULT' + WHEN 'n' THEN 'SET NULL' + WHEN 'r' THEN 'RESTRICT' + else null + END AS on_delete, + CASE k1.confupdtype WHEN 'a' THEN 'NO ACTION' + WHEN 'c' THEN 'CASCADE' + WHEN 'd' THEN 'SET DEFAULT' + WHEN 'n' THEN 'SET NULL' + WHEN 'r' THEN 'RESTRICT' + ELSE NULL + END AS on_update, + k1.condeferrable AS is_deferrable, + k1.condeferred AS is_deferred + FROM pg_catalog.pg_constraint k1 + JOIN pg_catalog.pg_namespace n1 ON (n1.oid = k1.connamespace) + JOIN pg_catalog.pg_class c1 ON (c1.oid = k1.conrelid) + JOIN pg_catalog.pg_class c2 ON (c2.oid = k1.confrelid) + JOIN pg_catalog.pg_namespace n2 ON (n2.oid = c2.relnamespace) + JOIN pg_catalog.pg_depend d ON ( + d.classid = 'pg_constraint'::regclass + AND d.objid = k1.oid + AND d.objsubid = 0 + AND d.deptype = 'n' + AND d.refclassid = 'pg_class'::regclass + AND d.refobjsubid=0 + ) + JOIN pg_catalog.pg_class ci ON (ci.oid = d.refobjid AND ci.relkind = 'i') + LEFT JOIN pg_depend d2 ON ( + d2.classid = 'pg_class'::regclass + AND d2.objid = ci.oid + AND d2.objsubid = 0 + AND d2.deptype = 'i' + AND d2.refclassid = 'pg_constraint'::regclass + AND d2.refobjsubid = 0 + ) + LEFT JOIN pg_catalog.pg_constraint k2 ON ( + k2.oid = d2.refobjid + AND k2.contype IN ('p', 'u') + ) + WHERE k1.conrelid != 0 + AND k1.confrelid != 0 + AND k1.contype = 'f' + AND _cat_tools._pg_sv_table_accessible(n1.oid, c1.oid) +; +GRANT SELECT ON cat_tools.pg_all_foreign_keys TO cat_tools__usage; + +SELECT __cat_tools.create_function( + 'cat_tools.currval' + , $$ + table_name text + , column_name text +$$ + , $$bigint LANGUAGE plpgsql$$ + , $body$ +DECLARE + seq regclass; +BEGIN + -- Note: the function will throw an error if table or column doesn't exist + seq := pg_get_serial_sequence( table_name, column_name ); + + IF seq IS NULL THEN + RAISE EXCEPTION '"%" is not a serial column', column_name + USING ERRCODE = 'wrong_object_type' + -- TODO: SCHEMA and COLUMN + , COLUMN = column_name + ; + END IF; + + RETURN currval(seq); +END +$body$ + , 'cat_tools__usage' +); + +SELECT __cat_tools.create_function( + 'cat_tools.enum_range' + , 'enum regtype' + , $$text[] LANGUAGE plpgsql STABLE$$ + , $body$ +DECLARE + ret text[]; +BEGIN + EXECUTE format('SELECT pg_catalog.enum_range( NULL::%s )', enum) INTO ret; + RETURN ret; +END +$body$ + , 'cat_tools__usage' +); + +SELECT __cat_tools.create_function( + 'cat_tools.enum_range_srf' + , 'enum regtype' + , $$SETOF text LANGUAGE sql$$ + , $body$ +SELECT * FROM unnest( cat_tools.enum_range($1) ) AS r(enum_label) +$body$ + , 'cat_tools__usage' +); + +SELECT __cat_tools.create_function( + 'cat_tools.pg_class' + , 'rel regclass' + , $$cat_tools.pg_class_v LANGUAGE sql STABLE$$ + , $body$ +SELECT * FROM cat_tools.pg_class_v WHERE reloid = rel +$body$ + , 'cat_tools__usage' +); + +SELECT __cat_tools.create_function( + 'cat_tools.name__check' + , 'name_to_check text' + , $$void LANGUAGE plpgsql$$ + , $body$ +BEGIN + IF name_to_check IS DISTINCT FROM name_to_check::name THEN + RAISE '"%" becomes "%" when cast to name', name_to_check, name_to_check::name; + END IF; +END +$body$ + , 'cat_tools__usage' +); + +SELECT __cat_tools.create_function( + 'cat_tools.trigger__parse' + , $$ + trigger_oid oid + , OUT timing text + , OUT events text[] + , OUT defer text + , OUT row_statement text + , OUT when_clause text + , OUT function_arguments text +$$ + , $$record LANGUAGE plpgsql$$ + , $body$ +DECLARE + r_trigger pg_catalog.pg_trigger; + v_triggerdef text; + v_create_stanza text; + v_on_clause text; + v_execute_clause text; + + v_work text; + v_array text[]; +BEGIN + -- Do this first to make sure trigger exists + v_triggerdef := pg_catalog.pg_get_triggerdef(trigger_oid, true); + SELECT * INTO STRICT r_trigger FROM pg_catalog.pg_trigger WHERE oid = trigger_oid; + + v_create_stanza := format( + 'CREATE %sTRIGGER %I ' + , CASE WHEN r_trigger.tgconstraint=0 THEN '' ELSE 'CONSTRAINT ' END + , r_trigger.tgname + ); + -- Strip CREATE [CONSTRAINT] TRIGGER ... off + v_work := replace( v_triggerdef, v_create_stanza, '' ); + + -- Get BEFORE | AFTER | INSTEAD OF + timing := split_part( v_work, ' ', 1 ); + timing := timing || CASE timing WHEN 'INSTEAD' THEN ' OF' ELSE '' END; + + -- Strip off timing clause + v_work := replace( v_work, timing || ' ', '' ); + + -- Get array of events (INSERT, UPDATE [OF column, column], DELETE, TRUNCATE) + v_on_clause := ' ON ' || r_trigger.tgrelid::regclass || ' '; + v_array := regexp_split_to_array( v_work, v_on_clause ); + events := string_to_array( v_array[1], ' OR ' ); + -- Get everything after ON table_name + v_work := v_array[2]; + RAISE DEBUG 'v_work "%"', v_work; + + -- Strip off FROM referenced_table if we have it + IF r_trigger.tgconstrrelid<>0 THEN + v_work := replace( + v_work + , 'FROM ' || r_trigger.tgconstrrelid::regclass || ' ' + , '' + ); + END IF; + RAISE DEBUG 'v_work "%"', v_work; + + -- Get function arguments + v_execute_clause := ' EXECUTE PROCEDURE ' || r_trigger.tgfoid::regproc || E'\\('; + v_array := regexp_split_to_array( v_work, v_execute_clause ); + function_arguments := rtrim( v_array[2], ')' ); -- Yank trailing ) + -- Get everything prior to EXECUTE PROCEDURE ... + v_work := v_array[1]; + RAISE DEBUG 'v_work "%"', v_work; + + row_statement := (regexp_matches( v_work, 'FOR EACH (ROW|STATEMENT)' ))[1]; + + -- Get [ NOT DEFERRABLE | [ DEFERRABLE ] { INITIALLY IMMEDIATE | INITIALLY DEFERRED } ] + v_array := regexp_split_to_array( v_work, 'FOR EACH (ROW|STATEMENT)' ); + RAISE DEBUG 'v_work = "%", v_array = "%"', v_work, v_array; + defer := rtrim(v_array[1]); + + IF r_trigger.tgqual IS NOT NULL THEN + when_clause := rtrim( + (regexp_split_to_array( v_array[2], E' WHEN \\(' ))[2] + , ')' + ); + END IF; + + RAISE DEBUG +$$v_create_stanza = "%" + v_on_clause = "%" + v_execute_clause = "%"$$ + , v_create_stanza + , v_on_clause + , v_execute_clause + ; + + RETURN; +END +$body$ + , 'cat_tools__usage' +); + +SELECT __cat_tools.create_function( + 'cat_tools.trigger__get_oid__loose' + , $$ + trigger_table regclass + , trigger_name text +$$ + , $$oid LANGUAGE sql$$ + , $body$ + SELECT oid + FROM pg_trigger + WHERE tgrelid = trigger_table + AND tgname = trigger_name + ; +$body$ + , 'cat_tools__usage' +); + +SELECT __cat_tools.create_function( + 'cat_tools.trigger__get_oid' + , $$ + trigger_table regclass + , trigger_name text +$$ + , $$oid LANGUAGE plpgsql$$ + , $body$ +DECLARE + v_oid oid; +BEGIN + -- Note that because __loose isn't an SRF it'll always return a value + v_oid := cat_tools.trigger__get_oid__loose( trigger_table, trigger_name ) ; + + IF v_oid IS NULL THEN + RAISE EXCEPTION 'trigger % on table % does not exist', trigger_name, trigger_table; + END IF; + + RETURN v_oid; +END +$body$ + , 'cat_tools__usage' +); + +DROP FUNCTION __cat_tools.exec( + sql text +); +DROP FUNCTION __cat_tools.create_function( + function_name text + , args text + , options text + , body text + , grants text +); +DROP SCHEMA __cat_tools; + +-- vi: expandtab ts=2 sw=2 diff --git a/sql/cat_tools--0.1.5.sql b/sql/cat_tools--0.1.5.sql new file mode 100644 index 0000000..1760e3b --- /dev/null +++ b/sql/cat_tools--0.1.5.sql @@ -0,0 +1,525 @@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +DO $$ +BEGIN + CREATE ROLE cat_tools__usage NOLOGIN; +EXCEPTION WHEN duplicate_object THEN + NULL; +END +$$; + +/* + * NOTE: All pg_temp objects must be dropped at the end of the script! + * Otherwise the eventual DROP CASCADE of pg_temp when the session ends will + * also drop the extension! Instead of risking problems, create our own + * "temporary" schema instead. + */ +CREATE SCHEMA __cat_tools; +CREATE FUNCTION __cat_tools.exec( + sql text +) RETURNS void LANGUAGE plpgsql AS $body$ +BEGIN + RAISE DEBUG 'sql = %', sql; + EXECUTE sql; +END +$body$; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +CREATE FUNCTION __cat_tools.create_function( + function_name text + , args text + , options text + , body text + , grants text DEFAULT NULL +) RETURNS void LANGUAGE plpgsql AS $body$ +DECLARE + + create_template CONSTANT text := $template$ +CREATE OR REPLACE FUNCTION %s( +%s +) RETURNS %s AS +%L +$template$ + ; + + revoke_template CONSTANT text := $template$ +REVOKE ALL ON FUNCTION %s( +%s +) FROM public; +$template$ + ; + + grant_template CONSTANT text := $template$ +GRANT EXECUTE ON FUNCTION %s( +%s +) TO %s; +$template$ + ; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +BEGIN + PERFORM __cat_tools.exec( format( + create_template + , function_name + , args + , options + , body + ) ) + ; + PERFORM __cat_tools.exec( format( + revoke_template + , function_name + , args + ) ) + ; + + IF grants IS NOT NULL THEN + PERFORM __cat_tools.exec( format( + grant_template + , function_name + , args + , grants + ) ) + ; + END IF; +END +$body$; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +CREATE SCHEMA cat_tools; +GRANT USAGE ON SCHEMA cat_tools TO cat_tools__usage; +CREATE SCHEMA _cat_tools; + +CREATE OR REPLACE VIEW _cat_tools.pg_class_v AS + SELECT c.oid AS reloid, c.*, n.nspname AS relschema + FROM pg_class c + LEFT JOIN pg_namespace n ON( n.oid = c.relnamespace ) +; +REVOKE ALL ON _cat_tools.pg_class_v FROM public; + +CREATE OR REPLACE VIEW cat_tools.pg_class_v AS + SELECT * + FROM _cat_tools.pg_class_v + + /* + * Oddly, there's no security associated with schema or table visibility. + * Be a bit paranoid though. + */ + WHERE NOT pg_is_other_temp_schema(relnamespace) + AND relkind IN( 'r', 'v', 'f' ) +; +GRANT SELECT ON cat_tools.pg_class_v TO cat_tools__usage; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +CREATE OR REPLACE VIEW _cat_tools.pg_attribute_v AS + SELECT a.* + , c.* + , t.oid AS typoid + , t.* + FROM pg_attribute a + LEFT JOIN _cat_tools.pg_class_v c ON ( c.reloid = a.attrelid ) + LEFT JOIN pg_type t ON ( t.oid = a.atttypid ) +; +REVOKE ALL ON _cat_tools.pg_attribute_v FROM public; + +CREATE OR REPLACE VIEW _cat_tools.column AS + SELECT * + , pg_catalog.format_type(typoid, atttypmod) AS column_type + , CASE typtype + -- domain + WHEN 'd' THEN pg_catalog.format_type(typbasetype, typtypmod) + -- enum + WHEN 'e' THEN 'text' + ELSE pg_catalog.format_type(typoid, atttypmod) + END AS base_type + , pk.conkey AS pk_columns + , ARRAY[attnum] <@ pk.conkey AS is_pk_member + , (SELECT pg_catalog.pg_get_expr(d.adbin, d.adrelid) + FROM pg_catalog.pg_attrdef d + WHERE d.adrelid = a.attrelid + AND d.adnum = a.attnum + AND a.atthasdef + ) AS column_default + FROM _cat_tools.pg_attribute_v a + LEFT JOIN pg_constraint pk + ON ( reloid = pk.conrelid ) + AND pk.contype = 'p' +; +REVOKE ALL ON _cat_tools.column FROM public; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +CREATE OR REPLACE VIEW cat_tools.column AS + SELECT * + FROM _cat_tools.column + -- SECURITY + WHERE NOT pg_is_other_temp_schema(relnamespace) + AND attnum > 0 + AND NOT attisdropped + AND relkind IN( 'r', 'v', 'f' ) + AND ( + pg_has_role(SESSION_USER, relowner, 'USAGE'::text) + OR has_column_privilege(SESSION_USER, reloid, attnum, 'SELECT, INSERT, UPDATE, REFERENCES'::text) + ) + ORDER BY relschema, relname, attnum +; +GRANT SELECT ON cat_tools.column TO cat_tools__usage; + +-- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ +SELECT __cat_tools.create_function( + '_cat_tools._pg_sv_column_array' + , 'OID, SMALLINT[]' + , 'NAME[] LANGUAGE sql STABLE' + , $$ + SELECT ARRAY( + SELECT a.attname + FROM pg_catalog.pg_attribute a + JOIN generate_series(1, array_upper($2, 1)) s(i) ON a.attnum = $2[i] + WHERE attrelid = $1 + ORDER BY i + ) +$$ +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +-- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ +SELECT __cat_tools.create_function( + '_cat_tools._pg_sv_table_accessible' + , 'OID, OID' + , 'boolean LANGUAGE sql STABLE' + , $$ + SELECT CASE WHEN has_schema_privilege($1, 'USAGE') THEN ( + has_table_privilege($2, 'SELECT') + OR has_table_privilege($2, 'INSERT') + or has_table_privilege($2, 'UPDATE') + OR has_table_privilege($2, 'DELETE') + OR has_table_privilege($2, 'RULE') + OR has_table_privilege($2, 'REFERENCES') + OR has_table_privilege($2, 'TRIGGER') + ) ELSE FALSE + END; +$$ +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +-- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ +CREATE OR REPLACE VIEW cat_tools.pg_all_foreign_keys +AS + SELECT n1.nspname AS fk_schema_name, + c1.relname AS fk_table_name, + k1.conname AS fk_constraint_name, + c1.oid AS fk_table_oid, + _cat_tools._pg_sv_column_array(k1.conrelid,k1.conkey) AS fk_columns, + n2.nspname AS pk_schema_name, + c2.relname AS pk_table_name, + k2.conname AS pk_constraint_name, + c2.oid AS pk_table_oid, + ci.relname AS pk_index_name, + _cat_tools._pg_sv_column_array(k1.confrelid,k1.confkey) AS pk_columns, + CASE k1.confmatchtype WHEN 'f' THEN 'FULL' + WHEN 'p' THEN 'PARTIAL' + WHEN 'u' THEN 'NONE' + else null + END AS match_type, + CASE k1.confdeltype WHEN 'a' THEN 'NO ACTION' -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + WHEN 'c' THEN 'CASCADE' + WHEN 'd' THEN 'SET DEFAULT' + WHEN 'n' THEN 'SET NULL' + WHEN 'r' THEN 'RESTRICT' + else null + END AS on_delete, + CASE k1.confupdtype WHEN 'a' THEN 'NO ACTION' + WHEN 'c' THEN 'CASCADE' + WHEN 'd' THEN 'SET DEFAULT' + WHEN 'n' THEN 'SET NULL' + WHEN 'r' THEN 'RESTRICT' + ELSE NULL + END AS on_update, + k1.condeferrable AS is_deferrable, -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + k1.condeferred AS is_deferred + FROM pg_catalog.pg_constraint k1 + JOIN pg_catalog.pg_namespace n1 ON (n1.oid = k1.connamespace) + JOIN pg_catalog.pg_class c1 ON (c1.oid = k1.conrelid) + JOIN pg_catalog.pg_class c2 ON (c2.oid = k1.confrelid) + JOIN pg_catalog.pg_namespace n2 ON (n2.oid = c2.relnamespace) + JOIN pg_catalog.pg_depend d ON ( + d.classid = 'pg_constraint'::regclass -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + AND d.objid = k1.oid + AND d.objsubid = 0 + AND d.deptype = 'n' + AND d.refclassid = 'pg_class'::regclass + AND d.refobjsubid=0 + ) + JOIN pg_catalog.pg_class ci ON (ci.oid = d.refobjid AND ci.relkind = 'i') + LEFT JOIN pg_depend d2 ON ( + d2.classid = 'pg_class'::regclass -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + AND d2.objid = ci.oid + AND d2.objsubid = 0 + AND d2.deptype = 'i' + AND d2.refclassid = 'pg_constraint'::regclass + AND d2.refobjsubid = 0 + ) + LEFT JOIN pg_catalog.pg_constraint k2 ON ( -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + k2.oid = d2.refobjid + AND k2.contype IN ('p', 'u') + ) + WHERE k1.conrelid != 0 + AND k1.confrelid != 0 + AND k1.contype = 'f' + AND _cat_tools._pg_sv_table_accessible(n1.oid, c1.oid) +; +GRANT SELECT ON cat_tools.pg_all_foreign_keys TO cat_tools__usage; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.currval' + , $$ + table_name text + , column_name text +$$ + , $$bigint LANGUAGE plpgsql$$ + , $body$ +DECLARE + seq regclass; +BEGIN + -- Note: the function will throw an error if table or column doesn't exist + seq := pg_get_serial_sequence( table_name, column_name ); + + IF seq IS NULL THEN + RAISE EXCEPTION '"%" is not a serial column', column_name + USING ERRCODE = 'wrong_object_type' + -- TODO: SCHEMA and COLUMN + , COLUMN = column_name + ; + END IF; + + RETURN currval(seq); +END +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.enum_range' + , 'enum regtype' + , $$text[] LANGUAGE plpgsql STABLE$$ + , $body$ +DECLARE + ret text[]; +BEGIN + EXECUTE format('SELECT pg_catalog.enum_range( NULL::%s )', enum) INTO ret; + RETURN ret; +END +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.enum_range_srf' + , 'enum regtype' + , $$SETOF text LANGUAGE sql$$ + , $body$ +SELECT * FROM unnest( cat_tools.enum_range($1) ) AS r(enum_label) +$body$ + , 'cat_tools__usage' +); + +SELECT __cat_tools.create_function( + 'cat_tools.pg_class' + , 'rel regclass' + , $$cat_tools.pg_class_v LANGUAGE sql STABLE$$ + , $body$ +SELECT * FROM cat_tools.pg_class_v WHERE reloid = $1 +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.name__check' + , 'name_to_check text' + , $$void LANGUAGE plpgsql$$ + , $body$ +BEGIN + IF name_to_check IS DISTINCT FROM name_to_check::name THEN + RAISE '"%" becomes "%" when cast to name', name_to_check, name_to_check::name; + END IF; +END +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.trigger__parse' + , $$ + trigger_oid oid + , OUT timing text + , OUT events text[] + , OUT defer text + , OUT row_statement text + , OUT when_clause text + , OUT function_arguments text +$$ + , $$record LANGUAGE plpgsql$$ + , $body$ +DECLARE + r_trigger pg_catalog.pg_trigger; + v_triggerdef text; + v_create_stanza text; + v_on_clause text; + v_execute_clause text; + + v_work text; + v_array text[]; +BEGIN + -- Do this first to make sure trigger exists + v_triggerdef := pg_catalog.pg_get_triggerdef(trigger_oid, true); + SELECT * INTO STRICT r_trigger FROM pg_catalog.pg_trigger WHERE oid = trigger_oid; + + v_create_stanza := format( + 'CREATE %sTRIGGER %I ' + , CASE WHEN r_trigger.tgconstraint=0 THEN '' ELSE 'CONSTRAINT ' END + , r_trigger.tgname + ); + -- Strip CREATE [CONSTRAINT] TRIGGER ... off + v_work := replace( v_triggerdef, v_create_stanza, '' ); + + -- Get BEFORE | AFTER | INSTEAD OF + timing := split_part( v_work, ' ', 1 ); + timing := timing || CASE timing WHEN 'INSTEAD' THEN ' OF' ELSE '' END; + + -- Strip off timing clause + v_work := replace( v_work, timing || ' ', '' ); + + -- Get array of events (INSERT, UPDATE [OF column, column], DELETE, TRUNCATE) + v_on_clause := ' ON ' || r_trigger.tgrelid::regclass || ' '; + v_array := regexp_split_to_array( v_work, v_on_clause ); + events := string_to_array( v_array[1], ' OR ' ); + -- Get everything after ON table_name + v_work := v_array[2]; + RAISE DEBUG 'v_work "%"', v_work; + + -- Strip off FROM referenced_table if we have it + IF r_trigger.tgconstrrelid<>0 THEN + v_work := replace( + v_work + , 'FROM ' || r_trigger.tgconstrrelid::regclass || ' ' + , '' + ); + END IF; + RAISE DEBUG 'v_work "%"', v_work; + + -- Get function arguments + v_execute_clause := ' EXECUTE PROCEDURE ' || r_trigger.tgfoid::regproc || E'\\('; + v_array := regexp_split_to_array( v_work, v_execute_clause ); + function_arguments := rtrim( v_array[2], ')' ); -- Yank trailing ) + -- Get everything prior to EXECUTE PROCEDURE ... + v_work := v_array[1]; + RAISE DEBUG 'v_work "%"', v_work; + + row_statement := (regexp_matches( v_work, 'FOR EACH (ROW|STATEMENT)' ))[1]; + + -- Get [ NOT DEFERRABLE | [ DEFERRABLE ] { INITIALLY IMMEDIATE | INITIALLY DEFERRED } ] + v_array := regexp_split_to_array( v_work, 'FOR EACH (ROW|STATEMENT)' ); + RAISE DEBUG 'v_work = "%", v_array = "%"', v_work, v_array; + defer := rtrim(v_array[1]); + + IF r_trigger.tgqual IS NOT NULL THEN + when_clause := rtrim( + (regexp_split_to_array( v_array[2], E' WHEN \\(' ))[2] + , ')' + ); + END IF; + + RAISE DEBUG +$$v_create_stanza = "%" + v_on_clause = "%" + v_execute_clause = "%"$$ + , v_create_stanza + , v_on_clause + , v_execute_clause + ; + + RETURN; +END +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.trigger__get_oid__loose' + , $$ + trigger_table regclass + , trigger_name text +$$ + , $$oid LANGUAGE sql$$ + , $body$ + SELECT oid + FROM pg_trigger + WHERE tgrelid = $1 --trigger_table + AND tgname = $2 --trigger_name + ; +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.trigger__get_oid' + , $$ + trigger_table regclass + , trigger_name text +$$ + , $$oid LANGUAGE plpgsql$$ + , $body$ +DECLARE + v_oid oid; +BEGIN + -- Note that because __loose isn't an SRF it'll always return a value + v_oid := cat_tools.trigger__get_oid__loose( trigger_table, trigger_name ) ; + + IF v_oid IS NULL THEN + RAISE EXCEPTION 'trigger % on table % does not exist', trigger_name, trigger_table; + END IF; + + RETURN v_oid; +END +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +/* + * Drop "temporary" objects + */ +DROP FUNCTION __cat_tools.exec( + sql text +); +DROP FUNCTION __cat_tools.create_function( + function_name text + , args text + , options text + , body text + , grants text +); +DROP SCHEMA __cat_tools; + +-- vi: expandtab ts=2 sw=2 +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql diff --git a/sql/cat_tools--0.2.0.sql b/sql/cat_tools--0.2.0.sql new file mode 100644 index 0000000..92dc797 --- /dev/null +++ b/sql/cat_tools--0.2.0.sql @@ -0,0 +1,1285 @@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SET LOCAL client_min_messages = WARNING; + +DO $$ +BEGIN + CREATE ROLE cat_tools__usage NOLOGIN; +EXCEPTION WHEN duplicate_object THEN + NULL; +END +$$; + +/* + * NOTE: All pg_temp objects must be dropped at the end of the script! + * Otherwise the eventual DROP CASCADE of pg_temp when the session ends will + * also drop the extension! Instead of risking problems, create our own + * "temporary" schema instead. + */ +CREATE SCHEMA __cat_tools; + +-- Schema already created via CREATE EXTENSION +GRANT USAGE ON SCHEMA cat_tools TO cat_tools__usage; +CREATE SCHEMA _cat_tools; + +CREATE OR REPLACE VIEW _cat_tools.pg_class_v AS + SELECT c.oid AS reloid, c.*, n.nspname AS relschema + FROM pg_class c + LEFT JOIN pg_namespace n ON( n.oid = c.relnamespace ) +; +REVOKE ALL ON _cat_tools.pg_class_v FROM public; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +CREATE FUNCTION __cat_tools.exec( + sql text +) RETURNS void LANGUAGE plpgsql AS $body$ +BEGIN + RAISE DEBUG 'sql = %', sql; + EXECUTE sql; +END +$body$; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +/* + * Temporary stub function. We do this so we can use the nice create_function + * function that we're about to create to create the real version of this + * function. + */ +CREATE FUNCTION cat_tools.function__arg_types_text(text +) RETURNS text LANGUAGE sql AS 'SELECT $1'; + +CREATE FUNCTION __cat_tools.create_function( + function_name text + , args text + , options text + , body text + , grants text DEFAULT NULL + , comment text DEFAULT NULL +) RETURNS void LANGUAGE plpgsql AS $body$ +DECLARE + c_simple_args CONSTANT text := cat_tools.function__arg_types_text(args); + + create_template CONSTANT text := $template$ +CREATE OR REPLACE FUNCTION %s( +%s +) RETURNS %s AS +%L +$template$ + ; + + revoke_template CONSTANT text := $template$ +REVOKE ALL ON FUNCTION %s( +%s +) FROM public; +$template$ + ; + + grant_template CONSTANT text := $template$ +GRANT EXECUTE ON FUNCTION %s( +%s +) TO %s; +$template$ + ; + + comment_template CONSTANT text := $template$ +COMMENT ON FUNCTION %s( +%s +) IS %L; +$template$ + ; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +BEGIN + PERFORM __cat_tools.exec( format( + create_template + , function_name + , args + , options -- TODO: Force search_path if options ~* 'definer' + , body + ) ) + ; + PERFORM __cat_tools.exec( format( + revoke_template + , function_name + , c_simple_args + ) ) + ; + + IF grants IS NOT NULL THEN + PERFORM __cat_tools.exec( format( + grant_template + , function_name + , c_simple_args + , grants + ) ) + ; + END IF; + + IF comment IS NOT NULL THEN + PERFORM __cat_tools.exec( format( + comment_template + , function_name + , c_simple_args + , comment + ) ) + ; + END IF; +END +$body$; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.function__arg_types' + , $$arguments text$$ + , $$pg_catalog.regtype[] LANGUAGE plpgsql$$ + , $body$ +DECLARE + input_arg_types pg_catalog.regtype[]; + + c_template CONSTANT text := $fmt$CREATE FUNCTION pg_temp.cat_tools__function__arg_types__temp_function( + %s + ) RETURNS %s LANGUAGE plpgsql AS 'BEGIN NULL; END' + $fmt$; + + temp_proc pg_catalog.regprocedure; + sql text; +BEGIN + sql := format( + c_template + , arguments + , 'void' + ); + --RAISE DEBUG 'Executing SQL %', sql; + DECLARE + v_type pg_catalog.regtype; + BEGIN + EXECUTE sql; + EXCEPTION WHEN invalid_function_definition THEN + v_type := (regexp_matches( SQLERRM, 'function result type must be ([^ ]+) because of' ))[1]; + sql := format( + c_template + , arguments + , v_type + ); + EXECUTE sql; + END; + + /* + * Get new OID. *This must be done dynamically!* Otherwise we get stuck + * with a CONST oid after first compilation. The regproc cast ensures there's + * only one function with this name. The cast to regprocedure is for the sake + * of the DROP down below. + */ + EXECUTE $$SELECT 'pg_temp.cat_tools__function__arg_types__temp_function'::pg_catalog.regproc::pg_catalog.regprocedure$$ INTO temp_proc; + SELECT INTO STRICT input_arg_types + -- This is here to re-cast the array as 1-based instead of 0 based (better solutions welcome!) + string_to_array(proargtypes::text,' ')::pg_catalog.regtype[] + FROM pg_proc + WHERE oid = temp_proc + ; + -- NOTE: DROP may not accept all the argument options that CREATE does, so use temp_proc + EXECUTE format( + $fmt$DROP FUNCTION %s$fmt$ + , temp_proc + ); + + RETURN input_arg_types; +END +$body$ + , 'cat_tools__usage' + , 'Returns argument types for a function argument body as an array. Unlike a + normal regprocedure cast, this function accepts anything that is valid when + defining a function.' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.function__arg_types_text' + , $$arguments text$$ + , $$text LANGUAGE sql$$ + , $body$ +SELECT array_to_string(cat_tools.function__arg_types($1), ', ') +$body$ + , 'cat_tools__usage' + , 'Returns argument types for a function argument body as text. Unlike a + normal regprocedure cast, this function accepts anything that is valid when + defining a function.' + +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.regprocedure' + , $$ + function_name text + , arguments text$$ + , $$pg_catalog.regprocedure LANGUAGE sql$$ + , $body$ +SELECT format( + '%s(%s)' + , $1 + , cat_tools.function__arg_types_text($2) +)::pg_catalog.regprocedure +$body$ + , 'cat_tools__usage' + , 'Returns a regprocedure for a given function name and arguments. Unlike a + normal regprocedure cast, arguments can contain anything that is valid when + defining a function.' +); + + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +CREATE TYPE cat_tools.constraint_type AS ENUM( + 'domain constraint', 'table constraint' +); +COMMENT ON TYPE cat_tools.constraint_type IS $$Descriptive names for every type of Postgres object (table, operator, rule, etc)$$; +CREATE TYPE cat_tools.procedure_type AS ENUM( + 'aggregate', 'function' +); +COMMENT ON TYPE cat_tools.procedure_type IS $$Types of constraints (`domain constraint` or `table_constraint`)$$; + +CREATE TYPE cat_tools.relation_type AS ENUM( + 'table' + , 'index' + , 'sequence' + , 'toast table' + , 'view' + , 'materialized view' + , 'composite type' + , 'foreign table' +); +COMMENT ON TYPE cat_tools.relation_type IS $$Types of objects stored in `pg_class`$$; + +CREATE TYPE cat_tools.relation_relkind AS ENUM( + 'r' + , 'i' + , 'S' + , 't' + , 'v' + , 'c' + , 'f' + , 'm' +); +COMMENT ON TYPE cat_tools.relation_relkind IS $$Valid values for `pg_class.relkind`$$; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +CREATE TYPE cat_tools.object_type AS ENUM( + -- pg_class + 'table' + , 'index' + , 'sequence' + , 'toast table' + , 'view' + , 'materialized view' + , 'composite type' + , 'foreign table' + /* + * NOTE! These are a bit weird because columns live in pg_attribute, but + * address stuff recognizes columns as part of pg_class with a subobjid <> 0! + */ + , 'table column' + , 'index column' + , 'sequence column' + , 'toast table column' + , 'view column' + , 'materialized view column' + , 'composite type column' + , 'foreign table column' + -- pg_constraint + -- NOTE: a domain itself is considered to be a type + , 'domain constraint', 'table constraint' + -- pg_proc + , 'aggregate', 'function' + -- This is taken from getObjectTypeDescription() in objectaddress.c in the Postgres source code + , 'type' + , 'cast' + , 'collation' + , 'conversion' + , 'default value' -- pg_attrdef + , 'language' + , 'large object' -- pg_largeobject + , 'operator' + , 'operator class' -- pg_opclass + , 'operator family' -- pg_opfamily + , 'operator of access method' -- pg_amop + , 'function of access method' -- pg_amproc + , 'rule' -- pg_rewrite + , 'trigger' + , 'schema' -- pg_namespace + , 'text search parser' -- pg_ts_parser + , 'text search dictionary' -- pg_ts_dict + , 'text search template' -- pg_ts_template + , 'text search configuration' -- pg_ts_config + , 'role' -- pg_authid + , 'database' + , 'tablespace' + , 'foreign-data wrapper' -- pg_foreign_data_wrapper + , 'server' -- pg_foreign_server + , 'user mapping' -- pg_user_mapping + , 'default acl' -- pg_default_acl + , 'extension' + , 'event trigger' -- pg_event_trigger -- SED: REQUIRES 9.3! + , 'policy' -- SED: REQUIRES 9.5! + , 'transform' -- SED: REQUIRES 9.5! + , 'access method' -- pg_am +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.objects__shared' + , '' + , 'cat_tools.object_type[] LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT '{role,database,tablespace}'::cat_tools.object_type[] +$body$ + , 'cat_tools__usage' + , 'Returns array of object types for shared objects.' +); +SELECT __cat_tools.create_function( + 'cat_tools.objects__shared_srf' + , '' + , 'SETOF cat_tools.object_type LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT * FROM pg_catalog.unnest(cat_tools.objects__shared()) +$body$ + , 'cat_tools__usage' + , 'Returns set of object types for shared objects.' +); +SELECT __cat_tools.create_function( + 'cat_tools.object__is_shared' + , 'object_type cat_tools.object_type' + , 'boolean LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT object_type = ANY(cat_tools.objects__shared()) +$body$ + , 'cat_tools__usage' + , 'Returns true if object_type is a shared object.' +); +SELECT __cat_tools.create_function( + 'cat_tools.object__is_shared' + , 'object_type text' + , 'boolean LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT cat_tools.object__is_shared(object_type::cat_tools.object_type) +$body$ + , 'cat_tools__usage' + , 'Returns true if object_type is a shared object.' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.objects__address_unsupported' + , '' + , 'cat_tools.object_type[] LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT array[ + 'toast table'::cat_tools.object_type, 'composite type' + , 'index column' , 'sequence column', 'toast table column', 'view column' + , 'materialized view column', 'composite type column' +] +$body$ + , 'cat_tools__usage' + , 'Returns array of object types not supported by pg_get_object_address().' +); +SELECT __cat_tools.create_function( + 'cat_tools.objects__address_unsupported_srf' + , '' + , 'SETOF cat_tools.object_type LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT * FROM pg_catalog.unnest(cat_tools.objects__address_unsupported()) +$body$ + , 'cat_tools__usage' + , 'Returns set of object types not supported by pg_get_object_address().' +); +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +SELECT __cat_tools.create_function( + 'cat_tools.object__is_address_unsupported' + , 'object_type cat_tools.object_type' + , 'boolean LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT object_type = ANY(cat_tools.objects__address_unsupported()) +$body$ + , 'cat_tools__usage' + , 'Returns true if object type is not supported by pg_get_object_address().' +); +SELECT __cat_tools.create_function( + 'cat_tools.object__is_address_unsupported' + , 'object_type text' + , 'boolean LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT cat_tools.object__is_address_unsupported(object_type::cat_tools.object_type) +$body$ + , 'cat_tools__usage' + , 'Returns true if object type is not supported by pg_get_object_address().' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.object__catalog' + , 'object_type cat_tools.object_type' + , 'pg_catalog.regclass LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT ( + 'pg_catalog.' + || CASE + WHEN object_type = ANY( array[ + 'table' + , 'index' + , 'sequence' + , 'toast table' + , 'view' + , 'materialized view' + , 'composite type' + , 'foreign table' + ]::cat_tools.object_type[] ) + THEN 'pg_class' + WHEN object_type = ANY( '{domain constraint,table constraint}'::cat_tools.object_type[] ) + THEN 'pg_constraint' + WHEN object_type = ANY( '{aggregate,function}'::cat_tools.object_type[] ) + THEN 'pg_proc' + WHEN object_type::text LIKE '% column' + THEN 'pg_attribute' + ELSE CASE object_type + -- Unusual cases + -- s/, \(.\{-}\) -- \(.*\)/ WHEN \1 THEN '\2'/ + WHEN 'default value' THEN 'pg_attrdef' + WHEN 'large object' THEN 'pg_largeobject' + WHEN 'operator class' THEN 'pg_opclass' + WHEN 'operator family' THEN 'pg_opfamily' + WHEN 'operator of access method' THEN 'pg_amop' + WHEN 'function of access method' THEN 'pg_amproc' + WHEN 'rule' THEN 'pg_rewrite' + WHEN 'schema' THEN 'pg_namespace' + WHEN 'text search parser' THEN 'pg_ts_parser' + WHEN 'text search dictionary' THEN 'pg_ts_dict' + WHEN 'text search template' THEN 'pg_ts_template' + WHEN 'text search configuration' THEN 'pg_ts_config' + WHEN 'role' THEN 'pg_authid' + WHEN 'foreign-data wrapper' THEN 'pg_foreign_data_wrapper' + WHEN 'server' THEN 'pg_foreign_server' + WHEN 'user mapping' THEN 'pg_user_mapping' + WHEN 'default acl' THEN 'pg_default_acl' + WHEN 'event trigger' THEN 'pg_event_trigger' -- SED: REQUIRES 9.3! + WHEN 'access method' THEN 'pg_am' + ELSE 'pg_' || object_type::text + END + END + )::pg_catalog.regclass +$body$ + , 'cat_tools__usage' + , 'Returns catalog table that is used to store objects' +); +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +SELECT __cat_tools.create_function( + 'cat_tools.object__catalog' + , 'object_type text' + , 'pg_catalog.regclass LANGUAGE sql STRICT IMMUTABLE' + , $body$SELECT cat_tools.object__catalog(object_type::cat_tools.object_type)$body$ + , 'cat_tools__usage' + , 'Returns catalog table that is used to store objects' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.object__address_classid' + , 'object_type cat_tools.object_type' + , 'pg_catalog.regclass LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT CASE + WHEN c = 'pg_catalog.pg_attribute'::regclass THEN 'pg_catalog.pg_class'::regclass + ELSE c + END + FROM cat_tools.object__catalog(object_type::cat_tools.object_type) c +$body$ + , 'cat_tools__usage' + , 'Returns the classid used by the pg_*_object*() functions for an object_type' +); +SELECT __cat_tools.create_function( + 'cat_tools.object__address_classid' + , 'object_type text' + , 'pg_catalog.regclass LANGUAGE sql STRICT IMMUTABLE' + , $body$SELECT cat_tools.object__address_classid(object_type::cat_tools.object_type)$body$ + , 'cat_tools__usage' + , 'Returns the classid used by the pg_*_object*() functions for an object_type' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +CREATE TABLE _cat_tools.catalog_metadata( + object_catalog pg_catalog.regclass + CONSTRAINT catalog_metadata__pk_object_catalog PRIMARY KEY + , namespace_field name + , reg_type pg_catalog.regtype + , simple_reg_type pg_catalog.regtype +); +-- Table is populated later, after enum_range_srf is created +SELECT __cat_tools.create_function( + '_cat_tools.catalog_metadata__get' + , 'object_catalog _cat_tools.catalog_metadata.object_catalog%TYPE' + , '_cat_tools.catalog_metadata LANGUAGE plpgsql IMMUTABLE' -- Technically should be STABLE + , $body$ +DECLARE + o _cat_tools.catalog_metadata; +BEGIN + SELECT INTO STRICT o + * + FROM _cat_tools.catalog_metadata m + WHERE m.object_catalog = catalog_metadata__get.object_catalog + ; + RETURN o; +END +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.object__reg_type' + , 'object_catalog pg_catalog.regclass' + , 'pg_catalog.regtype LANGUAGE sql SECURITY DEFINER STRICT IMMUTABLE' + , $body$ +SELECT (_cat_tools.catalog_metadata__get(object_catalog)).reg_type +$body$ + , 'cat_tools__usage' + , 'Returns the object identifier type (ie: regclass) associated with a system catalog (ie: pg_class).' +); +SELECT __cat_tools.create_function( + 'cat_tools.object__reg_type' + , 'object_type cat_tools.object_type' + , 'pg_catalog.regtype LANGUAGE sql STRICT IMMUTABLE' + , $body$SELECT cat_tools.object__reg_type(cat_tools.object__catalog(object_type))$body$ + , 'cat_tools__usage' + , 'Returns the object identifier type (ie: regclass) associated with a system catalog (ie: pg_class).' +); +SELECT __cat_tools.create_function( + 'cat_tools.object__reg_type' + , 'object_type text' + , 'pg_catalog.regtype LANGUAGE sql STRICT IMMUTABLE' + , $body$SELECT cat_tools.object__reg_type(object_type::cat_tools.object_type)$body$ + , 'cat_tools__usage' + , 'Returns the object identifier type (ie: regclass) associated with a system catalog (ie: pg_class).' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.object__reg_type_catalog' + , 'object_identifier_type regtype' + , 'pg_catalog.regclass LANGUAGE plpgsql SECURITY DEFINER STRICT IMMUTABLE' + , $body$ +DECLARE + cat pg_catalog.regclass; +BEGIN + SELECT INTO STRICT cat + object_catalog + FROM _cat_tools.catalog_metadata m + WHERE m.reg_type = object_identifier_type + OR m.simple_reg_type = object_identifier_type + ; + RETURN cat; +EXCEPTION WHEN no_data_found THEN + IF object_identifier_type::text LIKE 'reg%' THEN + RAISE 'object identifier type % is not supported', object_identifier_type + USING + HINT = format( 'If %I is a valid object identifier type please open an issue on github.', object_identifier_type ) + , ERRCODE = 'feature_not_supported' + ; + ELSE + RAISE '% is not a object identifier type', object_identifier_type + USING + HINT = 'See https://www.postgresql.org/docs/current/static/datatype-oid.html' + , ERRCODE = 'wrong_object_type' + ; + END IF; +END +$body$ + , 'cat_tools__usage' + , 'Returns the system catalog that stores a particular object identifier type.' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.relation__kind' + , 'relkind cat_tools.relation_relkind' + , 'cat_tools.relation_type LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT CASE relkind + WHEN 'r' THEN 'table' + WHEN 'i' THEN 'index' + WHEN 'S' THEN 'sequence' + WHEN 't' THEN 'toast table' + WHEN 'v' THEN 'view' + WHEN 'c' THEN 'materialized view' + WHEN 'f' THEN 'composite type' + WHEN 'm' THEN 'foreign table' +END::cat_tools.relation_type +$body$ + , 'cat_tools__usage' + , 'Mapping from to a ' +); + +SELECT __cat_tools.create_function( + 'cat_tools.relation__relkind' + , 'kind cat_tools.relation_type' + , 'cat_tools.relation_relkind LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT CASE kind + WHEN 'table' THEN 'r' + WHEN 'index' THEN 'i' + WHEN 'sequence' THEN 'S' + WHEN 'toast table' THEN 't' + WHEN 'view' THEN 'v' + WHEN 'materialized view' THEN 'c' + WHEN 'composite type' THEN 'f' + WHEN 'foreign table' THEN 'm' +END::cat_tools.relation_relkind +$body$ + , 'cat_tools__usage' + , 'Mapping from to a value' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.relation__relkind' + , 'kind text' + , 'cat_tools.relation_relkind LANGUAGE sql STRICT IMMUTABLE' + , $body$SELECT cat_tools.relation__relkind(kind::cat_tools.relation_type)$body$ + , 'cat_tools__usage' + , 'Mapping from to a value' +); +SELECT __cat_tools.create_function( + 'cat_tools.relation__kind' + , 'relkind text' + , 'cat_tools.relation_type LANGUAGE sql STRICT IMMUTABLE' + , $body$SELECT cat_tools.relation__kind(relkind::cat_tools.relation_relkind)$body$ + , 'cat_tools__usage' + , 'Mapping from to a value' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +CREATE OR REPLACE VIEW _cat_tools.pg_depend_identity_v AS -- SED: REQUIRES 9.3! + SELECT o.type AS object_type -- SED: REQUIRES 9.3! + , o.schema AS object_schema -- SED: REQUIRES 9.3! + , o.name AS object_name -- SED: REQUIRES 9.3! + , o.identity AS object_identity -- SED: REQUIRES 9.3! + , r.type AS reference_type -- SED: REQUIRES 9.3! + , r.schema AS reference_schema -- SED: REQUIRES 9.3! + , r.name AS reference_name -- SED: REQUIRES 9.3! + , r.identity AS reference_identity -- SED: REQUIRES 9.3! + , d.* -- SED: REQUIRES 9.3! + FROM pg_catalog.pg_depend d -- SED: REQUIRES 9.3! + , pg_catalog.pg_identify_object(classid, objid, objsubid) o -- SED: REQUIRES 9.3! + , pg_catalog.pg_identify_object(refclassid, refobjid, refobjsubid) r -- SED: REQUIRES 9.3! + WHERE classid <> 0 -- SED: REQUIRES 9.3! + UNION ALL -- SED: REQUIRES 9.3! + SELECT NULL, NULL, NULL, NULL -- SED: REQUIRES 9.3! + , r.type AS reference_type -- SED: REQUIRES 9.3! + , r.schema AS reference_schema -- SED: REQUIRES 9.3! + , r.name AS reference_name -- SED: REQUIRES 9.3! + , r.identity AS reference_identity -- SED: REQUIRES 9.3! + , d.* -- SED: REQUIRES 9.3! + FROM pg_catalog.pg_depend d -- SED: REQUIRES 9.3! + , pg_catalog.pg_identify_object(refclassid, refobjid, refobjsubid) r -- SED: REQUIRES 9.3! + WHERE classid = 0 -- SED: REQUIRES 9.3! +; -- SED: REQUIRES 9.3! + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +CREATE OR REPLACE VIEW cat_tools.pg_class_v AS + SELECT * + FROM _cat_tools.pg_class_v + + /* + * Oddly, there's no security associated with schema or table visibility. + * Be a bit paranoid though. + */ + WHERE NOT pg_is_other_temp_schema(relnamespace) + AND relkind IN( 'r', 'v', 'f' ) +; +GRANT SELECT ON cat_tools.pg_class_v TO cat_tools__usage; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +CREATE OR REPLACE VIEW _cat_tools.pg_attribute_v AS + SELECT a.* + , c.* + , t.oid AS typoid + , t.* + FROM pg_attribute a + LEFT JOIN _cat_tools.pg_class_v c ON ( c.reloid = a.attrelid ) + LEFT JOIN pg_type t ON ( t.oid = a.atttypid ) +; +REVOKE ALL ON _cat_tools.pg_attribute_v FROM public; + +CREATE OR REPLACE VIEW _cat_tools.column AS + SELECT * + , pg_catalog.format_type(typoid, atttypmod) AS column_type + , CASE typtype + -- domain + WHEN 'd' THEN pg_catalog.format_type(typbasetype, typtypmod) + -- enum + WHEN 'e' THEN 'text' + ELSE pg_catalog.format_type(typoid, atttypmod) + END AS base_type + , pk.conkey AS pk_columns + , ARRAY[attnum] <@ pk.conkey AS is_pk_member + , (SELECT pg_catalog.pg_get_expr(d.adbin, d.adrelid) + FROM pg_catalog.pg_attrdef d + WHERE d.adrelid = a.attrelid + AND d.adnum = a.attnum + AND a.atthasdef + ) AS column_default + FROM _cat_tools.pg_attribute_v a + LEFT JOIN pg_constraint pk + ON ( reloid = pk.conrelid ) + AND pk.contype = 'p' +; +REVOKE ALL ON _cat_tools.column FROM public; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +CREATE OR REPLACE VIEW cat_tools.column AS + SELECT * + FROM _cat_tools.column + -- SECURITY + WHERE NOT pg_is_other_temp_schema(relnamespace) + AND attnum > 0 + AND NOT attisdropped + AND relkind IN( 'r', 'v', 'f' ) + AND ( + pg_has_role(SESSION_USER, relowner, 'USAGE'::text) + OR has_column_privilege(SESSION_USER, reloid, attnum, 'SELECT, INSERT, UPDATE, REFERENCES'::text) + ) + ORDER BY relschema, relname, attnum +; +GRANT SELECT ON cat_tools.column TO cat_tools__usage; + +-- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ +SELECT __cat_tools.create_function( + '_cat_tools._pg_sv_column_array' + , 'OID, SMALLINT[]' + , 'NAME[] LANGUAGE sql STABLE' + , $$ + SELECT ARRAY( + SELECT a.attname + FROM pg_catalog.pg_attribute a + JOIN generate_series(1, array_upper($2, 1)) s(i) ON a.attnum = $2[i] + WHERE attrelid = $1 + ORDER BY i + ) +$$ +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +-- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ +SELECT __cat_tools.create_function( + '_cat_tools._pg_sv_table_accessible' + , 'OID, OID' + , 'boolean LANGUAGE sql STABLE' + , $$ + SELECT CASE WHEN has_schema_privilege($1, 'USAGE') THEN ( + has_table_privilege($2, 'SELECT') + OR has_table_privilege($2, 'INSERT') + or has_table_privilege($2, 'UPDATE') + OR has_table_privilege($2, 'DELETE') + OR has_table_privilege($2, 'RULE') + OR has_table_privilege($2, 'REFERENCES') + OR has_table_privilege($2, 'TRIGGER') + ) ELSE FALSE + END; +$$ +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +-- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ +CREATE OR REPLACE VIEW cat_tools.pg_all_foreign_keys +AS + SELECT n1.nspname AS fk_schema_name, + c1.relname AS fk_table_name, + k1.conname AS fk_constraint_name, + c1.oid AS fk_table_oid, + _cat_tools._pg_sv_column_array(k1.conrelid,k1.conkey) AS fk_columns, + n2.nspname AS pk_schema_name, + c2.relname AS pk_table_name, + k2.conname AS pk_constraint_name, + c2.oid AS pk_table_oid, + ci.relname AS pk_index_name, + _cat_tools._pg_sv_column_array(k1.confrelid,k1.confkey) AS pk_columns, + CASE k1.confmatchtype WHEN 'f' THEN 'FULL' + WHEN 'p' THEN 'PARTIAL' + WHEN 'u' THEN 'NONE' + else null + END AS match_type, + CASE k1.confdeltype WHEN 'a' THEN 'NO ACTION' -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + WHEN 'c' THEN 'CASCADE' + WHEN 'd' THEN 'SET DEFAULT' + WHEN 'n' THEN 'SET NULL' + WHEN 'r' THEN 'RESTRICT' + else null + END AS on_delete, + CASE k1.confupdtype WHEN 'a' THEN 'NO ACTION' + WHEN 'c' THEN 'CASCADE' + WHEN 'd' THEN 'SET DEFAULT' + WHEN 'n' THEN 'SET NULL' + WHEN 'r' THEN 'RESTRICT' + ELSE NULL + END AS on_update, + k1.condeferrable AS is_deferrable, -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + k1.condeferred AS is_deferred + FROM pg_catalog.pg_constraint k1 + JOIN pg_catalog.pg_namespace n1 ON (n1.oid = k1.connamespace) + JOIN pg_catalog.pg_class c1 ON (c1.oid = k1.conrelid) + JOIN pg_catalog.pg_class c2 ON (c2.oid = k1.confrelid) + JOIN pg_catalog.pg_namespace n2 ON (n2.oid = c2.relnamespace) + JOIN pg_catalog.pg_depend d ON ( + d.classid = 'pg_constraint'::pg_catalog.regclass -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + AND d.objid = k1.oid + AND d.objsubid = 0 + AND d.deptype = 'n' + AND d.refclassid = 'pg_class'::pg_catalog.regclass + AND d.refobjsubid=0 + ) + JOIN pg_catalog.pg_class ci ON (ci.oid = d.refobjid AND ci.relkind = 'i') + LEFT JOIN pg_depend d2 ON ( + d2.classid = 'pg_class'::pg_catalog.regclass -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + AND d2.objid = ci.oid + AND d2.objsubid = 0 + AND d2.deptype = 'i' + AND d2.refclassid = 'pg_constraint'::pg_catalog.regclass + AND d2.refobjsubid = 0 + ) + LEFT JOIN pg_catalog.pg_constraint k2 ON ( -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + k2.oid = d2.refobjid + AND k2.contype IN ('p', 'u') + ) + WHERE k1.conrelid != 0 + AND k1.confrelid != 0 + AND k1.contype = 'f' + AND _cat_tools._pg_sv_table_accessible(n1.oid, c1.oid) +; +GRANT SELECT ON cat_tools.pg_all_foreign_keys TO cat_tools__usage; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.pg_attribute__get' + , $$ + relation pg_catalog.regclass + , column_name name +$$ + , $$pg_catalog.pg_attribute LANGUAGE plpgsql$$ + , $body$ +DECLARE + r pg_catalog.pg_attribute; +BEGIN + SELECT INTO STRICT r + * + FROM pg_catalog.pg_attribute + WHERE attrelid = relation + AND attname = column_name + ; + RETURN r; +EXCEPTION WHEN no_data_found THEN + RAISE 'column "%" of relation "%" does not exist', column_name, relation + USING ERRCODE = 'undefined_column' + ; +END +$body$ + , 'cat_tools__usage' +); + + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.get_serial_sequence' + , $$ + table_name text + , column_name text +$$ + , $$pg_catalog.regclass LANGUAGE plpgsql$$ + , $body$ +DECLARE + seq pg_catalog.regclass; +BEGIN + -- Note: the function will throw an error if table or column doesn't exist + seq := pg_get_serial_sequence( table_name, column_name ); + + IF seq IS NULL THEN + RAISE EXCEPTION '"%" is not a serial column', column_name + USING ERRCODE = 'wrong_object_type' + -- TODO: SCHEMA and COLUMN + , COLUMN = column_name -- SED: REQUIRES 9.3! + ; + END IF; + + RETURN seq; +END +$body$ + , 'cat_tools__usage' + , 'Return sequence that is associated with a column. Unlike the pg_get_serial_sequence, throw an exception if there is no sequence associated with the column.' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.sequence__last' + , $$ + table_name text + , column_name text +$$ + , $$bigint LANGUAGE sql$$ + , 'SELECT pg_catalog.currval(cat_tools.get_serial_sequence($1,$2))' + , 'cat_tools__usage' + , 'Return the last value assigned to a column with an associated sequence.' +); +SELECT __cat_tools.create_function( + 'cat_tools.currval' + , $$ + table_name text + , column_name text +$$ + , $$bigint LANGUAGE sql$$ + , 'SELECT cat_tools.sequence__last($1,$2)' + , 'cat_tools__usage' + , 'Return the last value assigned to a column with an associated sequence.' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.sequence__next' + , $$ + table_name text + , column_name text +$$ + , $$bigint LANGUAGE sql$$ + , 'SELECT pg_catalog.nextval(cat_tools.get_serial_sequence($1,$2))' + , 'cat_tools__usage' + , 'Return the next value to assign to a column with an associated sequence. THIS ADVANCES THE SEQUENCE.' +); +SELECT __cat_tools.create_function( + 'cat_tools.nextval' + , $$ + table_name text + , column_name text +$$ + , $$bigint LANGUAGE sql$$ + , 'SELECT cat_tools.sequence__next($1,$2)' + , 'cat_tools__usage' + , 'Return the next value to assign to a column with an associated sequence. THIS ADVANCES THE SEQUENCE.' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.setval' + , $$ + table_name text + , column_name text + , new_value bigint + , has_been_used boolean DEFAULT true +$$ + , $$bigint LANGUAGE sql$$ + , 'SELECT pg_catalog.setval(cat_tools.get_serial_sequence($1,$2), $3, $4)' + , 'cat_tools__usage' + , 'Changes the value for a sequence associated with a column. If has_been_used is true, the sequence will be set to new_value + 1. Returns new_value. See also sequence__set_last() and sequence__set_next().' +); +SELECT __cat_tools.create_function( + 'cat_tools.sequence__set_last' + , $$ + table_name text + , column_name text + , last_value bigint +$$ + , $$bigint LANGUAGE sql$$ + , 'SELECT cat_tools.setval($1,$2,$3,true)' + , 'cat_tools__usage' + , 'Changes the value for a sequence associated with a column. last_value is the last value used, so sequence is set to last_value+1. See also sequence__set_next().' +); +SELECT __cat_tools.create_function( + 'cat_tools.sequence__set_next' + , $$ + table_name text + , column_name text + , next_value bigint +$$ + , $$bigint LANGUAGE sql$$ + , 'SELECT cat_tools.setval($1,$2,$3,false)' + , 'cat_tools__usage' + , 'Changes the value for a sequence associated with a column. next_value is the next value the sequence will assign. See also sequence__last_value.' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.enum_range' + , 'enum pg_catalog.regtype' + , $$text[] LANGUAGE plpgsql STABLE$$ + , $body$ +DECLARE + ret text[]; +BEGIN + EXECUTE format('SELECT pg_catalog.enum_range( NULL::%s )', enum) INTO ret; + RETURN ret; +END +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.enum_range_srf' + , 'enum pg_catalog.regtype' + , $$SETOF text LANGUAGE sql$$ + , $body$ +SELECT * FROM unnest( cat_tools.enum_range($1) ) AS r(enum_label) +$body$ + , 'cat_tools__usage' +); + +SELECT __cat_tools.create_function( + 'cat_tools.pg_class' + , 'rel pg_catalog.regclass' + , $$cat_tools.pg_class_v LANGUAGE sql STABLE$$ + , $body$ +SELECT * FROM cat_tools.pg_class_v WHERE reloid = $1 +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.name__check' + , 'name_to_check text' + , $$void LANGUAGE plpgsql$$ + , $body$ +BEGIN + IF name_to_check IS DISTINCT FROM name_to_check::name THEN + RAISE '"%" becomes "%" when cast to name', name_to_check, name_to_check::name; + END IF; +END +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.trigger__parse' + , $$ + trigger_oid oid + , OUT timing text + , OUT events text[] + , OUT defer text + , OUT row_statement text + , OUT when_clause text + , OUT function_arguments text +$$ + , $$record LANGUAGE plpgsql$$ + , $body$ +DECLARE + r_trigger pg_catalog.pg_trigger; + v_triggerdef text; + v_create_stanza text; + v_on_clause text; + v_execute_clause text; + + v_work text; + v_array text[]; +BEGIN + -- Do this first to make sure trigger exists + v_triggerdef := pg_catalog.pg_get_triggerdef(trigger_oid, true); + SELECT * INTO STRICT r_trigger FROM pg_catalog.pg_trigger WHERE oid = trigger_oid; + + v_create_stanza := format( + 'CREATE %sTRIGGER %I ' + , CASE WHEN r_trigger.tgconstraint=0 THEN '' ELSE 'CONSTRAINT ' END + , r_trigger.tgname + ); + -- Strip CREATE [CONSTRAINT] TRIGGER ... off + v_work := replace( v_triggerdef, v_create_stanza, '' ); + + -- Get BEFORE | AFTER | INSTEAD OF + timing := split_part( v_work, ' ', 1 ); + timing := timing || CASE timing WHEN 'INSTEAD' THEN ' OF' ELSE '' END; + + -- Strip off timing clause + v_work := replace( v_work, timing || ' ', '' ); + + -- Get array of events (INSERT, UPDATE [OF column, column], DELETE, TRUNCATE) + v_on_clause := ' ON ' || r_trigger.tgrelid::pg_catalog.regclass || ' '; + v_array := regexp_split_to_array( v_work, v_on_clause ); + events := string_to_array( v_array[1], ' OR ' ); + -- Get everything after ON table_name + v_work := v_array[2]; + RAISE DEBUG 'v_work "%"', v_work; + + -- Strip off FROM referenced_table if we have it + IF r_trigger.tgconstrrelid<>0 THEN + v_work := replace( + v_work + , 'FROM ' || r_trigger.tgconstrrelid::pg_catalog.regclass || ' ' + , '' + ); + END IF; + RAISE DEBUG 'v_work "%"', v_work; + + -- Get function arguments + v_execute_clause := ' EXECUTE PROCEDURE ' || r_trigger.tgfoid::pg_catalog.regproc || E'\\('; + v_array := regexp_split_to_array( v_work, v_execute_clause ); + function_arguments := rtrim( v_array[2], ')' ); -- Yank trailing ) + -- Get everything prior to EXECUTE PROCEDURE ... + v_work := v_array[1]; + RAISE DEBUG 'v_work "%"', v_work; + + row_statement := (regexp_matches( v_work, 'FOR EACH (ROW|STATEMENT)' ))[1]; + + -- Get [ NOT DEFERRABLE | [ DEFERRABLE ] { INITIALLY IMMEDIATE | INITIALLY DEFERRED } ] + v_array := regexp_split_to_array( v_work, 'FOR EACH (ROW|STATEMENT)' ); + RAISE DEBUG 'v_work = "%", v_array = "%"', v_work, v_array; + defer := rtrim(v_array[1]); + + IF r_trigger.tgqual IS NOT NULL THEN + when_clause := rtrim( + (regexp_split_to_array( v_array[2], E' WHEN \\(' ))[2] + , ')' + ); + END IF; + + RAISE DEBUG +$$v_create_stanza = "%" + v_on_clause = "%" + v_execute_clause = "%"$$ + , v_create_stanza + , v_on_clause + , v_execute_clause + ; + + RETURN; +END +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.trigger__get_oid__loose' + , $$ + trigger_table pg_catalog.regclass + , trigger_name text +$$ + , $$oid LANGUAGE sql$$ + , $body$ + SELECT oid + FROM pg_trigger + WHERE tgrelid = $1 --trigger_table + AND tgname = $2 --trigger_name + ; +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +SELECT __cat_tools.create_function( + 'cat_tools.trigger__get_oid' + , $$ + trigger_table pg_catalog.regclass + , trigger_name text +$$ + , $$oid LANGUAGE plpgsql$$ + , $body$ +DECLARE + v_oid oid; +BEGIN + -- Note that because __loose isn't an SRF it'll always return a value + v_oid := cat_tools.trigger__get_oid__loose( trigger_table, trigger_name ) ; + + IF v_oid IS NULL THEN + RAISE EXCEPTION 'trigger % on table % does not exist', trigger_name, trigger_table; + END IF; + + RETURN v_oid; +END +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +INSERT INTO _cat_tools.catalog_metadata(object_catalog, reg_type, namespace_field) +SELECT object__catalog + , CASE object__catalog + WHEN 'pg_catalog.pg_class'::pg_catalog.regclass THEN 'pg_catalog.regclass' + WHEN 'pg_catalog.pg_ts_config'::pg_catalog.regclass THEN 'pg_catalog.regconfig' + WHEN 'pg_catalog.pg_ts_dict'::pg_catalog.regclass THEN 'pg_catalog.regdictionary' + WHEN 'pg_catalog.pg_namespace'::pg_catalog.regclass THEN 'pg_catalog.regnamespace' -- SED: REQUIRES 9.5! + WHEN 'pg_catalog.pg_operator'::pg_catalog.regclass THEN 'pg_catalog.regoperator' + WHEN 'pg_catalog.pg_proc'::pg_catalog.regclass THEN 'pg_catalog.regprocedure' + WHEN 'pg_catalog.pg_authid'::pg_catalog.regclass THEN 'pg_catalog.regrole' -- SED: REQUIRES 9.5! + WHEN 'pg_catalog.pg_type'::pg_catalog.regclass THEN 'pg_catalog.regtype' + END::pg_catalog.regtype + , n.attname + FROM ( + SELECT DISTINCT cat_tools.object__catalog(object_type) + FROM cat_tools.enum_range_srf('cat_tools.object_type') r(object_type) + ) d + LEFT JOIN cat_tools.column n + ON n.attrelid = object__catalog + AND n.attname ~ 'namespace$' + AND atttypid = 'oid'::pg_catalog.regtype +; +UPDATE _cat_tools.catalog_metadata + SET simple_reg_type = 'pg_catalog.regproc' + WHERE object_catalog = 'pg_catalog.pg_proc'::pg_catalog.regclass +; +UPDATE _cat_tools.catalog_metadata + SET simple_reg_type = 'pg_catalog.regoper' + WHERE object_catalog = 'pg_catalog.pg_operator'::pg_catalog.regclass +; +-- Cluster to get rid of dead rows +CLUSTER _cat_tools.catalog_metadata USING catalog_metadata__pk_object_catalog; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + +/* + * Drop "temporary" objects + */ +DROP FUNCTION __cat_tools.exec( + sql text +); +DROP FUNCTION __cat_tools.create_function( + function_name text + , args text + , options text + , body text + , grants text + , comment text +); +DROP SCHEMA __cat_tools; + +-- vi: expandtab ts=2 sw=2 +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql diff --git a/sql/cat_tools--0.2.1.sql b/sql/cat_tools--0.2.1.sql new file mode 100644 index 0000000..d9f5772 --- /dev/null +++ b/sql/cat_tools--0.2.1.sql @@ -0,0 +1,1472 @@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SET LOCAL client_min_messages = WARNING; + +DO $$ +BEGIN + CREATE ROLE cat_tools__usage NOLOGIN; +EXCEPTION WHEN duplicate_object THEN + NULL; +END +$$; + +/* + * NOTE: All pg_temp objects must be dropped at the end of the script! + * Otherwise the eventual DROP CASCADE of pg_temp when the session ends will + * also drop the extension! Instead of risking problems, create our own + * "temporary" schema instead. + */ +CREATE SCHEMA __cat_tools; + +-- Schema already created via CREATE EXTENSION +GRANT USAGE ON SCHEMA cat_tools TO cat_tools__usage; +CREATE SCHEMA _cat_tools; + +-- No permissions checks +CREATE OR REPLACE VIEW _cat_tools.pg_class_v AS + SELECT c.oid AS reloid, c.*, n.nspname AS relschema + FROM pg_class c + LEFT JOIN pg_namespace n ON( n.oid = c.relnamespace ) +; +REVOKE ALL ON _cat_tools.pg_class_v FROM public; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +CREATE FUNCTION __cat_tools.exec( + sql text +) RETURNS void LANGUAGE plpgsql AS $body$ +BEGIN + RAISE DEBUG 'sql = %', sql; + EXECUTE sql; +END +$body$; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +/* + * Temporary stub function. We do this so we can use the nice create_function + * function that we're about to create to create the real version of this + * function. + */ +CREATE FUNCTION cat_tools.function__arg_types_text(text +) RETURNS text LANGUAGE sql AS 'SELECT $1'; + +CREATE FUNCTION __cat_tools.create_function( + function_name text + , args text + , options text + , body text + , grants text DEFAULT NULL + , comment text DEFAULT NULL +) RETURNS void LANGUAGE plpgsql AS $body$ +DECLARE + c_simple_args CONSTANT text := cat_tools.function__arg_types_text(args); + + create_template CONSTANT text := $template$ +CREATE OR REPLACE FUNCTION %s( +%s +) RETURNS %s AS +%L +$template$ + ; + + revoke_template CONSTANT text := $template$ +REVOKE ALL ON FUNCTION %s( +%s +) FROM public; +$template$ + ; + + grant_template CONSTANT text := $template$ +GRANT EXECUTE ON FUNCTION %s( +%s +) TO %s; +$template$ + ; + + comment_template CONSTANT text := $template$ +COMMENT ON FUNCTION %s( +%s +) IS %L; +$template$ + ; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +BEGIN + PERFORM __cat_tools.exec( format( + create_template + , function_name + , args + , options -- TODO: Force search_path if options ~* 'definer' + , body + ) ) + ; + PERFORM __cat_tools.exec( format( + revoke_template + , function_name + , c_simple_args + ) ) + ; + + IF grants IS NOT NULL THEN + PERFORM __cat_tools.exec( format( + grant_template + , function_name + , c_simple_args + , grants + ) ) + ; + END IF; + + IF comment IS NOT NULL THEN + PERFORM __cat_tools.exec( format( + comment_template + , function_name + , c_simple_args + , comment + ) ) + ; + END IF; +END +$body$; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.function__arg_types' + , $$arguments text$$ + , $$pg_catalog.regtype[] LANGUAGE plpgsql$$ + , $body$ +DECLARE + input_arg_types pg_catalog.regtype[]; + + c_template CONSTANT text := $fmt$CREATE FUNCTION pg_temp.cat_tools__function__arg_types__temp_function( + %s + ) RETURNS %s LANGUAGE plpgsql AS 'BEGIN NULL; END' + $fmt$; + + temp_proc pg_catalog.regprocedure; + sql text; +BEGIN + sql := format( + c_template + , arguments + , 'void' + ); + --RAISE DEBUG 'Executing SQL %', sql; + DECLARE + v_type pg_catalog.regtype; + BEGIN + EXECUTE sql; + EXCEPTION WHEN invalid_function_definition THEN + v_type := (regexp_matches( SQLERRM, 'function result type must be ([^ ]+) because of' ))[1]; + sql := format( + c_template + , arguments + , v_type + ); + EXECUTE sql; + END; + + /* + * Get new OID. *This must be done dynamically!* Otherwise we get stuck + * with a CONST oid after first compilation. The regproc cast ensures there's + * only one function with this name. The cast to regprocedure is for the sake + * of the DROP down below. + */ + EXECUTE $$SELECT 'pg_temp.cat_tools__function__arg_types__temp_function'::pg_catalog.regproc::pg_catalog.regprocedure$$ INTO temp_proc; + SELECT INTO STRICT input_arg_types + -- This is here to re-cast the array as 1-based instead of 0 based (better solutions welcome!) + string_to_array(proargtypes::text,' ')::pg_catalog.regtype[] + FROM pg_proc + WHERE oid = temp_proc + ; + -- NOTE: DROP may not accept all the argument options that CREATE does, so use temp_proc + EXECUTE format( + $fmt$DROP FUNCTION %s$fmt$ + , temp_proc + ); + + RETURN input_arg_types; +END +$body$ + , 'cat_tools__usage' + , 'Returns argument types for a function argument body as an array. Unlike a + normal regprocedure cast, this function accepts anything that is valid when + defining a function.' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.function__arg_types_text' + , $$arguments text$$ + , $$text LANGUAGE sql$$ + , $body$ +SELECT array_to_string(cat_tools.function__arg_types($1), ', ') +$body$ + , 'cat_tools__usage' + , 'Returns argument types for a function argument body as text. Unlike a + normal regprocedure cast, this function accepts anything that is valid when + defining a function.' + +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.regprocedure' + , $$ + function_name text + , arguments text$$ + , $$pg_catalog.regprocedure LANGUAGE sql$$ + , $body$ +SELECT format( + '%s(%s)' + , $1 + , cat_tools.function__arg_types_text($2) +)::pg_catalog.regprocedure +$body$ + , 'cat_tools__usage' + , 'Returns a regprocedure for a given function name and arguments. Unlike a + normal regprocedure cast, arguments can contain anything that is valid when + defining a function.' +); + + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +CREATE TYPE cat_tools.constraint_type AS ENUM( + 'domain constraint', 'table constraint' +); +COMMENT ON TYPE cat_tools.constraint_type IS $$Descriptive names for every type of Postgres object (table, operator, rule, etc)$$; +CREATE TYPE cat_tools.procedure_type AS ENUM( + 'aggregate', 'function' +); +COMMENT ON TYPE cat_tools.procedure_type IS $$Types of constraints (`domain constraint` or `table_constraint`)$$; + +CREATE TYPE cat_tools.relation_type AS ENUM( + 'table' + , 'index' + , 'sequence' + , 'toast table' + , 'view' + , 'materialized view' + , 'composite type' + , 'foreign table' +); +COMMENT ON TYPE cat_tools.relation_type IS $$Types of objects stored in `pg_class`$$; + +CREATE TYPE cat_tools.relation_relkind AS ENUM( + 'r' + , 'i' + , 'S' + , 't' + , 'v' + , 'c' + , 'f' + , 'm' +); +COMMENT ON TYPE cat_tools.relation_relkind IS $$Valid values for `pg_class.relkind`$$; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +CREATE TYPE cat_tools.object_type AS ENUM( + -- pg_class + 'table' + , 'index' + , 'sequence' + , 'toast table' + , 'view' + , 'materialized view' + , 'composite type' + , 'foreign table' + /* + * NOTE! These are a bit weird because columns live in pg_attribute, but + * address stuff recognizes columns as part of pg_class with a subobjid <> 0! + */ + , 'table column' + , 'index column' + , 'sequence column' + , 'toast table column' + , 'view column' + , 'materialized view column' + , 'composite type column' + , 'foreign table column' + -- pg_constraint + -- NOTE: a domain itself is considered to be a type + , 'domain constraint', 'table constraint' + -- pg_proc + , 'aggregate', 'function' + -- This is taken from getObjectTypeDescription() in objectaddress.c in the Postgres source code + , 'type' + , 'cast' + , 'collation' + , 'conversion' + , 'default value' -- pg_attrdef + , 'language' + , 'large object' -- pg_largeobject + , 'operator' + , 'operator class' -- pg_opclass + , 'operator family' -- pg_opfamily + , 'operator of access method' -- pg_amop + , 'function of access method' -- pg_amproc + , 'rule' -- pg_rewrite + , 'trigger' + , 'schema' -- pg_namespace + , 'text search parser' -- pg_ts_parser + , 'text search dictionary' -- pg_ts_dict + , 'text search template' -- pg_ts_template + , 'text search configuration' -- pg_ts_config + , 'role' -- pg_authid + , 'database' + , 'tablespace' + , 'foreign-data wrapper' -- pg_foreign_data_wrapper + , 'server' -- pg_foreign_server + , 'user mapping' -- pg_user_mapping + , 'default acl' -- pg_default_acl + , 'extension' + , 'event trigger' -- pg_event_trigger -- SED: REQUIRES 9.3! + , 'policy' -- SED: REQUIRES 9.5! + , 'transform' -- SED: REQUIRES 9.5! + , 'access method' -- pg_am +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.objects__shared' + , '' + , 'cat_tools.object_type[] LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT '{role,database,tablespace}'::cat_tools.object_type[] +$body$ + , 'cat_tools__usage' + , 'Returns array of object types for shared objects.' +); +SELECT __cat_tools.create_function( + 'cat_tools.objects__shared_srf' + , '' + , 'SETOF cat_tools.object_type LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT * FROM pg_catalog.unnest(cat_tools.objects__shared()) +$body$ + , 'cat_tools__usage' + , 'Returns set of object types for shared objects.' +); +SELECT __cat_tools.create_function( + 'cat_tools.object__is_shared' + , 'object_type cat_tools.object_type' + , 'boolean LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT object_type = ANY(cat_tools.objects__shared()) +$body$ + , 'cat_tools__usage' + , 'Returns true if object_type is a shared object.' +); +SELECT __cat_tools.create_function( + 'cat_tools.object__is_shared' + , 'object_type text' + , 'boolean LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT cat_tools.object__is_shared(object_type::cat_tools.object_type) +$body$ + , 'cat_tools__usage' + , 'Returns true if object_type is a shared object.' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.objects__address_unsupported' + , '' + , 'cat_tools.object_type[] LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT array[ + 'toast table'::cat_tools.object_type, 'composite type' + , 'index column' , 'sequence column', 'toast table column', 'view column' + , 'materialized view column', 'composite type column' +] +$body$ + , 'cat_tools__usage' + , 'Returns array of object types not supported by pg_get_object_address().' +); +SELECT __cat_tools.create_function( + 'cat_tools.objects__address_unsupported_srf' + , '' + , 'SETOF cat_tools.object_type LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT * FROM pg_catalog.unnest(cat_tools.objects__address_unsupported()) +$body$ + , 'cat_tools__usage' + , 'Returns set of object types not supported by pg_get_object_address().' +); +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +SELECT __cat_tools.create_function( + 'cat_tools.object__is_address_unsupported' + , 'object_type cat_tools.object_type' + , 'boolean LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT object_type = ANY(cat_tools.objects__address_unsupported()) +$body$ + , 'cat_tools__usage' + , 'Returns true if object type is not supported by pg_get_object_address().' +); +SELECT __cat_tools.create_function( + 'cat_tools.object__is_address_unsupported' + , 'object_type text' + , 'boolean LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT cat_tools.object__is_address_unsupported(object_type::cat_tools.object_type) +$body$ + , 'cat_tools__usage' + , 'Returns true if object type is not supported by pg_get_object_address().' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.object__catalog' + , 'object_type cat_tools.object_type' + , 'pg_catalog.regclass LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT ( + 'pg_catalog.' + || CASE + WHEN object_type = ANY( array[ + 'table' + , 'index' + , 'sequence' + , 'toast table' + , 'view' + , 'materialized view' + , 'composite type' + , 'foreign table' + ]::cat_tools.object_type[] ) + THEN 'pg_class' + WHEN object_type = ANY( '{domain constraint,table constraint}'::cat_tools.object_type[] ) + THEN 'pg_constraint' + WHEN object_type = ANY( '{aggregate,function}'::cat_tools.object_type[] ) + THEN 'pg_proc' + WHEN object_type::text LIKE '% column' + THEN 'pg_attribute' + ELSE CASE object_type + -- Unusual cases + -- s/, \(.\{-}\) -- \(.*\)/ WHEN \1 THEN '\2'/ + WHEN 'default value' THEN 'pg_attrdef' + WHEN 'large object' THEN 'pg_largeobject' + WHEN 'operator class' THEN 'pg_opclass' + WHEN 'operator family' THEN 'pg_opfamily' + WHEN 'operator of access method' THEN 'pg_amop' + WHEN 'function of access method' THEN 'pg_amproc' + WHEN 'rule' THEN 'pg_rewrite' + WHEN 'schema' THEN 'pg_namespace' + WHEN 'text search parser' THEN 'pg_ts_parser' + WHEN 'text search dictionary' THEN 'pg_ts_dict' + WHEN 'text search template' THEN 'pg_ts_template' + WHEN 'text search configuration' THEN 'pg_ts_config' + WHEN 'role' THEN 'pg_authid' + WHEN 'foreign-data wrapper' THEN 'pg_foreign_data_wrapper' + WHEN 'server' THEN 'pg_foreign_server' + WHEN 'user mapping' THEN 'pg_user_mapping' + WHEN 'default acl' THEN 'pg_default_acl' + WHEN 'event trigger' THEN 'pg_event_trigger' -- SED: REQUIRES 9.3! + WHEN 'access method' THEN 'pg_am' + ELSE 'pg_' || object_type::text + END + END + )::pg_catalog.regclass +$body$ + , 'cat_tools__usage' + , 'Returns catalog table that is used to store objects' +); +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +SELECT __cat_tools.create_function( + 'cat_tools.object__catalog' + , 'object_type text' + , 'pg_catalog.regclass LANGUAGE sql STRICT IMMUTABLE' + , $body$SELECT cat_tools.object__catalog(object_type::cat_tools.object_type)$body$ + , 'cat_tools__usage' + , 'Returns catalog table that is used to store objects' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.object__address_classid' + , 'object_type cat_tools.object_type' + , 'pg_catalog.regclass LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT CASE + WHEN c = 'pg_catalog.pg_attribute'::regclass THEN 'pg_catalog.pg_class'::regclass + ELSE c + END + FROM cat_tools.object__catalog(object_type::cat_tools.object_type) c +$body$ + , 'cat_tools__usage' + , 'Returns the classid used by the pg_*_object*() functions for an object_type' +); +SELECT __cat_tools.create_function( + 'cat_tools.object__address_classid' + , 'object_type text' + , 'pg_catalog.regclass LANGUAGE sql STRICT IMMUTABLE' + , $body$SELECT cat_tools.object__address_classid(object_type::cat_tools.object_type)$body$ + , 'cat_tools__usage' + , 'Returns the classid used by the pg_*_object*() functions for an object_type' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +CREATE TABLE _cat_tools.catalog_metadata( + object_catalog pg_catalog.regclass + CONSTRAINT catalog_metadata__pk_object_catalog PRIMARY KEY + , namespace_field name + , reg_type pg_catalog.regtype + , simple_reg_type pg_catalog.regtype +); +-- Table is populated later, after enum_range_srf is created +SELECT __cat_tools.create_function( + '_cat_tools.catalog_metadata__get' + , 'object_catalog _cat_tools.catalog_metadata.object_catalog%TYPE' + , '_cat_tools.catalog_metadata LANGUAGE plpgsql IMMUTABLE' -- Technically should be STABLE + , $body$ +DECLARE + o _cat_tools.catalog_metadata; +BEGIN + SELECT INTO STRICT o + * + FROM _cat_tools.catalog_metadata m + WHERE m.object_catalog = catalog_metadata__get.object_catalog + ; + RETURN o; +END +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.object__reg_type' + , 'object_catalog pg_catalog.regclass' + , 'pg_catalog.regtype LANGUAGE sql SECURITY DEFINER STRICT IMMUTABLE' + , $body$ +SELECT (_cat_tools.catalog_metadata__get(object_catalog)).reg_type +$body$ + , 'cat_tools__usage' + , 'Returns the object identifier type (ie: regclass) associated with a system catalog (ie: pg_class).' +); +SELECT __cat_tools.create_function( + 'cat_tools.object__reg_type' + , 'object_type cat_tools.object_type' + , 'pg_catalog.regtype LANGUAGE sql STRICT IMMUTABLE' + , $body$SELECT cat_tools.object__reg_type(cat_tools.object__catalog(object_type))$body$ + , 'cat_tools__usage' + , 'Returns the object identifier type (ie: regclass) associated with a system catalog (ie: pg_class).' +); +SELECT __cat_tools.create_function( + 'cat_tools.object__reg_type' + , 'object_type text' + , 'pg_catalog.regtype LANGUAGE sql STRICT IMMUTABLE' + , $body$SELECT cat_tools.object__reg_type(object_type::cat_tools.object_type)$body$ + , 'cat_tools__usage' + , 'Returns the object identifier type (ie: regclass) associated with a system catalog (ie: pg_class).' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.object__reg_type_catalog' + , 'object_identifier_type regtype' + , 'pg_catalog.regclass LANGUAGE plpgsql SECURITY DEFINER STRICT IMMUTABLE' + , $body$ +DECLARE + cat pg_catalog.regclass; +BEGIN + SELECT INTO STRICT cat + object_catalog + FROM _cat_tools.catalog_metadata m + WHERE m.reg_type = object_identifier_type + OR m.simple_reg_type = object_identifier_type + ; + RETURN cat; +EXCEPTION WHEN no_data_found THEN + IF object_identifier_type::text LIKE 'reg%' THEN + RAISE 'object identifier type % is not supported', object_identifier_type + USING + HINT = format( 'If %I is a valid object identifier type please open an issue at https://github.com/decibel/cat_tools/issues.', object_identifier_type ) + , ERRCODE = 'feature_not_supported' + ; + ELSE + RAISE '% is not a object identifier type', object_identifier_type + USING + HINT = 'See https://www.postgresql.org/docs/current/static/datatype-oid.html' + , ERRCODE = 'wrong_object_type' + ; + END IF; +END +$body$ + , 'cat_tools__usage' + , 'Returns the system catalog that stores a particular object identifier type.' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.relation__kind' + , 'relkind cat_tools.relation_relkind' + , 'cat_tools.relation_type LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT CASE relkind + WHEN 'r' THEN 'table' + WHEN 'i' THEN 'index' + WHEN 'S' THEN 'sequence' + WHEN 't' THEN 'toast table' + WHEN 'v' THEN 'view' + WHEN 'c' THEN 'materialized view' + WHEN 'f' THEN 'composite type' + WHEN 'm' THEN 'foreign table' +END::cat_tools.relation_type +$body$ + , 'cat_tools__usage' + , 'Mapping from to a ' +); + +SELECT __cat_tools.create_function( + 'cat_tools.relation__relkind' + , 'kind cat_tools.relation_type' + , 'cat_tools.relation_relkind LANGUAGE sql STRICT IMMUTABLE' + , $body$ +SELECT CASE kind + WHEN 'table' THEN 'r' + WHEN 'index' THEN 'i' + WHEN 'sequence' THEN 'S' + WHEN 'toast table' THEN 't' + WHEN 'view' THEN 'v' + WHEN 'materialized view' THEN 'c' + WHEN 'composite type' THEN 'f' + WHEN 'foreign table' THEN 'm' +END::cat_tools.relation_relkind +$body$ + , 'cat_tools__usage' + , 'Mapping from to a value' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.relation__relkind' + , 'kind text' + , 'cat_tools.relation_relkind LANGUAGE sql STRICT IMMUTABLE' + , $body$SELECT cat_tools.relation__relkind(kind::cat_tools.relation_type)$body$ + , 'cat_tools__usage' + , 'Mapping from to a value' +); +SELECT __cat_tools.create_function( + 'cat_tools.relation__kind' + , 'relkind text' + , 'cat_tools.relation_type LANGUAGE sql STRICT IMMUTABLE' + , $body$SELECT cat_tools.relation__kind(relkind::cat_tools.relation_relkind)$body$ + , 'cat_tools__usage' + , 'Mapping from to a value' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +CREATE OR REPLACE VIEW _cat_tools.pg_depend_identity_v AS -- SED: REQUIRES 9.3! + SELECT o.type AS object_type -- SED: REQUIRES 9.3! + , o.schema AS object_schema -- SED: REQUIRES 9.3! + , o.name AS object_name -- SED: REQUIRES 9.3! + , o.identity AS object_identity -- SED: REQUIRES 9.3! + , r.type AS reference_type -- SED: REQUIRES 9.3! + , r.schema AS reference_schema -- SED: REQUIRES 9.3! + , r.name AS reference_name -- SED: REQUIRES 9.3! + , r.identity AS reference_identity -- SED: REQUIRES 9.3! + , d.* -- SED: REQUIRES 9.3! + FROM pg_catalog.pg_depend d -- SED: REQUIRES 9.3! + , pg_catalog.pg_identify_object(classid, objid, objsubid) o -- SED: REQUIRES 9.3! + , pg_catalog.pg_identify_object(refclassid, refobjid, refobjsubid) r -- SED: REQUIRES 9.3! + WHERE classid <> 0 -- SED: REQUIRES 9.3! + UNION ALL -- SED: REQUIRES 9.3! + SELECT NULL, NULL, NULL, NULL -- SED: REQUIRES 9.3! + , r.type AS reference_type -- SED: REQUIRES 9.3! + , r.schema AS reference_schema -- SED: REQUIRES 9.3! + , r.name AS reference_name -- SED: REQUIRES 9.3! + , r.identity AS reference_identity -- SED: REQUIRES 9.3! + , d.* -- SED: REQUIRES 9.3! + FROM pg_catalog.pg_depend d -- SED: REQUIRES 9.3! + , pg_catalog.pg_identify_object(refclassid, refobjid, refobjsubid) r -- SED: REQUIRES 9.3! + WHERE classid = 0 -- SED: REQUIRES 9.3! +; -- SED: REQUIRES 9.3! + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +CREATE OR REPLACE VIEW cat_tools.pg_class_v AS + SELECT * + FROM _cat_tools.pg_class_v + + /* + * Oddly, there's no security associated with schema or table visibility. + * Be a bit paranoid though. + */ + WHERE NOT pg_is_other_temp_schema(relnamespace) + AND relkind IN( 'r', 'v', 'f' ) +; +GRANT SELECT ON cat_tools.pg_class_v TO cat_tools__usage; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +CREATE OR REPLACE VIEW _cat_tools.pg_attribute_v AS + SELECT a.* + , c.* + , t.oid AS typoid + , t.* + FROM pg_attribute a + LEFT JOIN _cat_tools.pg_class_v c ON ( c.reloid = a.attrelid ) + LEFT JOIN pg_type t ON ( t.oid = a.atttypid ) +; +REVOKE ALL ON _cat_tools.pg_attribute_v FROM public; + +CREATE OR REPLACE VIEW _cat_tools.column AS + SELECT * + , pg_catalog.format_type(typoid, atttypmod) AS column_type + , CASE typtype + -- domain + WHEN 'd' THEN pg_catalog.format_type(typbasetype, typtypmod) + -- enum + WHEN 'e' THEN 'text' + ELSE pg_catalog.format_type(typoid, atttypmod) + END AS base_type + , pk.conkey AS pk_columns + , ARRAY[attnum] <@ pk.conkey AS is_pk_member + , (SELECT pg_catalog.pg_get_expr(d.adbin, d.adrelid) + FROM pg_catalog.pg_attrdef d + WHERE d.adrelid = a.attrelid + AND d.adnum = a.attnum + AND a.atthasdef + ) AS column_default + FROM _cat_tools.pg_attribute_v a + LEFT JOIN pg_constraint pk + ON ( reloid = pk.conrelid ) + AND pk.contype = 'p' +; +REVOKE ALL ON _cat_tools.column FROM public; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +-- No perms on extension visibility +CREATE OR REPLACE VIEW cat_tools.pg_extension_v AS + SELECT e.oid, e.* + + , extnamespace::regnamespace AS extschema -- SED: REQUIRES 9.5! +-- Not used prior to 9.5: , nspname AS extschema + + , extconfig::pg_catalog.regclass[] AS ext_config_tables + FROM pg_catalog.pg_extension e + LEFT JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace +; +GRANT SELECT ON cat_tools.pg_extension_v TO cat_tools__usage; + +CREATE OR REPLACE VIEW cat_tools.column AS + SELECT * + FROM _cat_tools.column + -- SECURITY + WHERE NOT pg_is_other_temp_schema(relnamespace) + AND attnum > 0 + AND NOT attisdropped + AND relkind IN( 'r', 'v', 'f' ) + AND ( + pg_has_role(SESSION_USER, relowner, 'USAGE'::text) + OR has_column_privilege(SESSION_USER, reloid, attnum, 'SELECT, INSERT, UPDATE, REFERENCES'::text) + ) + ORDER BY relschema, relname, attnum +; +GRANT SELECT ON cat_tools.column TO cat_tools__usage; + +-- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ +SELECT __cat_tools.create_function( + '_cat_tools._pg_sv_column_array' + , 'OID, SMALLINT[]' + , 'NAME[] LANGUAGE sql STABLE' + , $$ + SELECT ARRAY( + SELECT a.attname + FROM pg_catalog.pg_attribute a + JOIN generate_series(1, array_upper($2, 1)) s(i) ON a.attnum = $2[i] + WHERE attrelid = $1 + ORDER BY i + ) +$$ +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +-- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ +SELECT __cat_tools.create_function( + '_cat_tools._pg_sv_table_accessible' + , 'OID, OID' + , 'boolean LANGUAGE sql STABLE' + , $$ + SELECT CASE WHEN has_schema_privilege($1, 'USAGE') THEN ( + has_table_privilege($2, 'SELECT') + OR has_table_privilege($2, 'INSERT') + or has_table_privilege($2, 'UPDATE') + OR has_table_privilege($2, 'DELETE') + OR has_table_privilege($2, 'RULE') + OR has_table_privilege($2, 'REFERENCES') + OR has_table_privilege($2, 'TRIGGER') + ) ELSE FALSE + END; +$$ +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +-- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ +CREATE OR REPLACE VIEW cat_tools.pg_all_foreign_keys +AS + SELECT n1.nspname AS fk_schema_name, + c1.relname AS fk_table_name, + k1.conname AS fk_constraint_name, + c1.oid AS fk_table_oid, + _cat_tools._pg_sv_column_array(k1.conrelid,k1.conkey) AS fk_columns, + n2.nspname AS pk_schema_name, + c2.relname AS pk_table_name, + k2.conname AS pk_constraint_name, + c2.oid AS pk_table_oid, + ci.relname AS pk_index_name, + _cat_tools._pg_sv_column_array(k1.confrelid,k1.confkey) AS pk_columns, + CASE k1.confmatchtype WHEN 'f' THEN 'FULL' + WHEN 'p' THEN 'PARTIAL' + WHEN 'u' THEN 'NONE' + else null + END AS match_type, + CASE k1.confdeltype WHEN 'a' THEN 'NO ACTION' -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + WHEN 'c' THEN 'CASCADE' + WHEN 'd' THEN 'SET DEFAULT' + WHEN 'n' THEN 'SET NULL' + WHEN 'r' THEN 'RESTRICT' + else null + END AS on_delete, + CASE k1.confupdtype WHEN 'a' THEN 'NO ACTION' + WHEN 'c' THEN 'CASCADE' + WHEN 'd' THEN 'SET DEFAULT' + WHEN 'n' THEN 'SET NULL' + WHEN 'r' THEN 'RESTRICT' + ELSE NULL + END AS on_update, + k1.condeferrable AS is_deferrable, -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + k1.condeferred AS is_deferred + FROM pg_catalog.pg_constraint k1 + JOIN pg_catalog.pg_namespace n1 ON (n1.oid = k1.connamespace) + JOIN pg_catalog.pg_class c1 ON (c1.oid = k1.conrelid) + JOIN pg_catalog.pg_class c2 ON (c2.oid = k1.confrelid) + JOIN pg_catalog.pg_namespace n2 ON (n2.oid = c2.relnamespace) + JOIN pg_catalog.pg_depend d ON ( + d.classid = 'pg_constraint'::pg_catalog.regclass -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + AND d.objid = k1.oid + AND d.objsubid = 0 + AND d.deptype = 'n' + AND d.refclassid = 'pg_class'::pg_catalog.regclass + AND d.refobjsubid=0 + ) + JOIN pg_catalog.pg_class ci ON (ci.oid = d.refobjid AND ci.relkind = 'i') + LEFT JOIN pg_depend d2 ON ( + d2.classid = 'pg_class'::pg_catalog.regclass -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + AND d2.objid = ci.oid + AND d2.objsubid = 0 + AND d2.deptype = 'i' + AND d2.refclassid = 'pg_constraint'::pg_catalog.regclass + AND d2.refobjsubid = 0 + ) + LEFT JOIN pg_catalog.pg_constraint k2 ON ( -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + k2.oid = d2.refobjid + AND k2.contype IN ('p', 'u') + ) + WHERE k1.conrelid != 0 + AND k1.confrelid != 0 + AND k1.contype = 'f' + AND _cat_tools._pg_sv_table_accessible(n1.oid, c1.oid) +; +GRANT SELECT ON cat_tools.pg_all_foreign_keys TO cat_tools__usage; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.pg_attribute__get' + , $$ + relation pg_catalog.regclass + , column_name name +$$ + , $$pg_catalog.pg_attribute LANGUAGE plpgsql$$ + , $body$ +DECLARE + r pg_catalog.pg_attribute; +BEGIN + SELECT INTO STRICT r + * + FROM pg_catalog.pg_attribute + WHERE attrelid = relation + AND attname = column_name + ; + RETURN r; +EXCEPTION WHEN no_data_found THEN + RAISE 'column "%" of relation "%" does not exist', column_name, relation + USING ERRCODE = 'undefined_column' + ; +END +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.pg_extension__get' + , 'extension_name name' + , $$cat_tools.pg_extension_v LANGUAGE plpgsql$$ + , $body$ +DECLARE + r cat_tools.pg_extension_v; +BEGIN + SELECT INTO STRICT r + * + FROM cat_tools.pg_extension_v + WHERE extname = extension_name + ; + RETURN r; +EXCEPTION WHEN no_data_found THEN + RAISE 'extension "%" does not exist', extension_name + USING ERRCODE = 'undefined_object' + ; +END +$body$ + , 'cat_tools__usage' +); +SELECT __cat_tools.create_function( + 'cat_tools.extension__schemas' + , 'extension_names name[]' + , $$pg_catalog.regnamespace[] LANGUAGE sql$$ -- SED: REQUIRES 9.5! +-- Not used prior to 9.5: , $$pg_catalog.name[] LANGUAGE sql$$ + , $body$ +SELECT array( + SELECT (cat_tools.pg_extension__get(en)).extschema + FROM unnest(extension_names) en +) +$body$ + , 'cat_tools__usage' +); +SELECT __cat_tools.create_function( + 'cat_tools.extension__schemas_unique' + , 'extension_names name[]' + , $$pg_catalog.regnamespace[] LANGUAGE sql$$ -- SED: REQUIRES 9.5! +-- Not used prior to 9.5: , $$pg_catalog.name[] LANGUAGE sql$$ + , $body$ +SELECT array( + SELECT DISTINCT (cat_tools.pg_extension__get(en)).extschema + FROM unnest(extension_names) en +) +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +-- Text versions +SELECT __cat_tools.create_function( + 'cat_tools.extension__schemas' + , 'extension_names text' + , $$pg_catalog.regnamespace[] LANGUAGE sql$$ -- SED: REQUIRES 9.5! +-- Not used prior to 9.5: , $$pg_catalog.name[] LANGUAGE sql$$ + , $body$ +SELECT cat_tools.extension__schemas( + CASE WHEN extension_names LIKE '{%}' THEN extension_names + ELSE '{' || extension_names || '}' + END::name[] +) +$body$ + , 'cat_tools__usage' +); +SELECT __cat_tools.create_function( + 'cat_tools.extension__schemas_unique' + , 'extension_names text' + , $$pg_catalog.regnamespace[] LANGUAGE sql$$ -- SED: REQUIRES 9.5! +-- Not used prior to 9.5: , $$pg_catalog.name[] LANGUAGE sql$$ + , $body$ +SELECT cat_tools.extension__schemas_unique( + CASE WHEN extension_names LIKE '{%}' THEN extension_names + ELSE '{' || extension_names || '}' + END::name[] +) +$body$ + , 'cat_tools__usage' +); + + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.get_serial_sequence' + , $$ + table_name text + , column_name text +$$ + , $$pg_catalog.regclass LANGUAGE plpgsql$$ + , $body$ +DECLARE + seq pg_catalog.regclass; +BEGIN + -- Note: the function will throw an error if table or column doesn't exist + seq := pg_get_serial_sequence( table_name, column_name ); + + IF seq IS NULL THEN + RAISE EXCEPTION '"%" is not a serial column', column_name + USING ERRCODE = 'wrong_object_type' + -- TODO: SCHEMA and COLUMN + , COLUMN = column_name -- SED: REQUIRES 9.3! + ; + END IF; + + RETURN seq; +END +$body$ + , 'cat_tools__usage' + , 'Return sequence that is associated with a column. Unlike the pg_get_serial_sequence, throw an exception if there is no sequence associated with the column.' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.sequence__last' + , $$ + table_name text + , column_name text +$$ + , $$bigint LANGUAGE sql$$ + , 'SELECT pg_catalog.currval(cat_tools.get_serial_sequence($1,$2))' + , 'cat_tools__usage' + , 'Return the last value assigned to a column with an associated sequence.' +); +SELECT __cat_tools.create_function( + 'cat_tools.currval' + , $$ + table_name text + , column_name text +$$ + , $$bigint LANGUAGE sql$$ + , 'SELECT cat_tools.sequence__last($1,$2)' + , 'cat_tools__usage' + , 'Return the last value assigned to a column with an associated sequence.' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.sequence__next' + , $$ + table_name text + , column_name text +$$ + , $$bigint LANGUAGE sql$$ + , 'SELECT pg_catalog.nextval(cat_tools.get_serial_sequence($1,$2))' + , 'cat_tools__usage' + , 'Return the next value to assign to a column with an associated sequence. THIS ADVANCES THE SEQUENCE.' +); +SELECT __cat_tools.create_function( + 'cat_tools.nextval' + , $$ + table_name text + , column_name text +$$ + , $$bigint LANGUAGE sql$$ + , 'SELECT cat_tools.sequence__next($1,$2)' + , 'cat_tools__usage' + , 'Return the next value to assign to a column with an associated sequence. THIS ADVANCES THE SEQUENCE.' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.setval' + , $$ + table_name text + , column_name text + , new_value bigint + , has_been_used boolean DEFAULT true +$$ + , $$bigint LANGUAGE sql$$ + , 'SELECT pg_catalog.setval(cat_tools.get_serial_sequence($1,$2), $3, $4)' + , 'cat_tools__usage' + , 'Changes the value for a sequence associated with a column. If has_been_used is true, the sequence will be set to new_value + 1. Returns new_value. See also sequence__set_last() and sequence__set_next().' +); +SELECT __cat_tools.create_function( + 'cat_tools.sequence__set_last' + , $$ + table_name text + , column_name text + , last_value bigint +$$ + , $$bigint LANGUAGE sql$$ + , 'SELECT cat_tools.setval($1,$2,$3,true)' + , 'cat_tools__usage' + , 'Changes the value for a sequence associated with a column. last_value is the last value used, so sequence is set to last_value+1. See also sequence__set_next().' +); +SELECT __cat_tools.create_function( + 'cat_tools.sequence__set_next' + , $$ + table_name text + , column_name text + , next_value bigint +$$ + , $$bigint LANGUAGE sql$$ + , 'SELECT cat_tools.setval($1,$2,$3,false)' + , 'cat_tools__usage' + , 'Changes the value for a sequence associated with a column. next_value is the next value the sequence will assign. See also sequence__last_value.' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.enum_range' + , 'enum pg_catalog.regtype' + , $$text[] LANGUAGE plpgsql STABLE$$ + , $body$ +DECLARE + ret text[]; +BEGIN + EXECUTE format('SELECT pg_catalog.enum_range( NULL::%s )', enum) INTO ret; + RETURN ret; +END +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.enum_range_srf' + , 'enum pg_catalog.regtype' + , $$SETOF text LANGUAGE sql$$ + , $body$ +SELECT * FROM unnest( cat_tools.enum_range($1) ) AS r(enum_label) +$body$ + , 'cat_tools__usage' +); + +SELECT __cat_tools.create_function( + 'cat_tools.pg_class' + , 'rel pg_catalog.regclass' + , $$cat_tools.pg_class_v LANGUAGE sql STABLE$$ + , $body$ +SELECT * FROM cat_tools.pg_class_v WHERE reloid = $1 +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.name__check' + , 'name_to_check text' + , $$void LANGUAGE plpgsql$$ + , $body$ +BEGIN + IF name_to_check IS DISTINCT FROM name_to_check::name THEN + RAISE '"%" becomes "%" when cast to name', name_to_check, name_to_check::name; + END IF; +END +$body$ + , 'cat_tools__usage' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +/* + * Trigger functions + */ +SELECT __cat_tools.create_function( + 'cat_tools.trigger__get_oid__loose' + , $$ + trigger_table pg_catalog.regclass + , trigger_name text +$$ + , $$oid LANGUAGE sql$$ + , $body$ + SELECT oid + FROM pg_trigger + WHERE tgrelid = $1 --trigger_table + AND tgname = CASE + /* + * tgname isn't quoted, so strip quotes, but only if the string both + * starts and ends with quotes + */ + WHEN $2 LIKE '"%"' THEN btrim($2, '"') + ELSE $2 + END --trigger_name + ; +$body$ + , 'cat_tools__usage' + , 'Return the OID for a trigger. Returns NULL if trigger does not exist.' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.trigger__get_oid' + , $$ + trigger_table pg_catalog.regclass + , trigger_name text +$$ + , $$oid LANGUAGE plpgsql$$ + , $body$ +DECLARE + v_oid oid; +BEGIN + -- Note that because __loose isn't an SRF it'll always return a value + v_oid := cat_tools.trigger__get_oid__loose( trigger_table, trigger_name ) ; + + IF v_oid IS NULL THEN + RAISE EXCEPTION 'trigger % on table % does not exist', trigger_name, trigger_table + USING errcode = 'undefined_object' -- 42704 + ; + END IF; + + RETURN v_oid; +END +$body$ + , 'cat_tools__usage' + , 'Return the OID for a trigger. Throws an undefined_object error if the trigger does not exist.' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.trigger__parse' + , $$ + trigger_oid oid + , OUT trigger_table regclass + , OUT timing text + , OUT events text[] + , OUT defer text + , OUT row_statement text + , OUT when_clause text + , OUT trigger_function regprocedure + , OUT function_arguments text[] +$$ + , $$record STABLE LANGUAGE plpgsql$$ + , $body$ +DECLARE + r_trigger pg_catalog.pg_trigger; + v_triggerdef text; + v_create_stanza text; + v_on_clause text; + v_execute_clause text; + + v_work text; + v_array text[]; +BEGIN + /* + * Do this first to make sure trigger exists. + * + * TODO: After we no longer support < 9.6, test v_triggerdef for NULL instead + * using the extra block here. + */ + BEGIN + SELECT * INTO STRICT r_trigger FROM pg_catalog.pg_trigger WHERE oid = trigger_oid; + EXCEPTION WHEN no_data_found THEN + RAISE EXCEPTION 'trigger with OID % does not exist', trigger_oid + USING errcode = 'undefined_object' -- 42704 + ; + END; + trigger_table := r_trigger.tgrelid; + trigger_function := r_trigger.tgfoid; + + v_triggerdef := pg_catalog.pg_get_triggerdef(trigger_oid, true); + + v_create_stanza := format( + 'CREATE %sTRIGGER %I ' + , CASE WHEN r_trigger.tgconstraint=0 THEN '' ELSE 'CONSTRAINT ' END + , r_trigger.tgname + ); + -- Strip CREATE [CONSTRAINT] TRIGGER ... off + v_work := replace( v_triggerdef, v_create_stanza, '' ); + + -- Get BEFORE | AFTER | INSTEAD OF + timing := split_part( v_work, ' ', 1 ); + timing := timing || CASE timing WHEN 'INSTEAD' THEN ' OF' ELSE '' END; + + -- Strip off timing clause + v_work := replace( v_work, timing || ' ', '' ); + + -- Get array of events (INSERT, UPDATE [OF column, column], DELETE, TRUNCATE) + v_on_clause := ' ON ' || r_trigger.tgrelid::pg_catalog.regclass || ' '; + v_array := regexp_split_to_array( v_work, v_on_clause ); + events := string_to_array( v_array[1], ' OR ' ); + -- Get everything after ON table_name + v_work := v_array[2]; + RAISE DEBUG 'v_work "%"', v_work; + + -- Strip off FROM referenced_table if we have it + IF r_trigger.tgconstrrelid<>0 THEN + v_work := replace( + v_work + , 'FROM ' || r_trigger.tgconstrrelid::pg_catalog.regclass || ' ' + , '' + ); + END IF; + RAISE DEBUG 'v_work "%"', v_work; + + -- Get function arguments + v_execute_clause := ' EXECUTE PROCEDURE ' || r_trigger.tgfoid::pg_catalog.regproc || E'\\('; + v_array := regexp_split_to_array( v_work, v_execute_clause ); + EXECUTE format( + 'SELECT array[ %s ]' + , rtrim( v_array[2], ')' ) -- Yank trailing ) + ) + INTO function_arguments + ; + RAISE DEBUG 'v_array[2] "%"', v_array[2]; + -- Get everything prior to EXECUTE PROCEDURE ... + v_work := v_array[1]; + RAISE DEBUG 'v_work "%"', v_work; + + row_statement := (regexp_matches( v_work, 'FOR EACH (ROW|STATEMENT)' ))[1]; + + -- Get [ NOT DEFERRABLE | [ DEFERRABLE ] { INITIALLY IMMEDIATE | INITIALLY DEFERRED } ] + v_array := regexp_split_to_array( v_work, 'FOR EACH (ROW|STATEMENT)' ); + RAISE DEBUG 'v_work = "%", v_array = "%"', v_work, v_array; + defer := rtrim(v_array[1]); + + IF r_trigger.tgqual IS NOT NULL THEN + when_clause := rtrim( + (regexp_split_to_array( v_array[2], E' WHEN \\(' ))[2] + , ')' + ); + END IF; + + RAISE DEBUG +$$v_create_stanza = "%" + v_on_clause = "%" + v_execute_clause = "%"$$ + , v_create_stanza + , v_on_clause + , v_execute_clause + ; + + RETURN; +END +$body$ + , 'cat_tools__usage' + , 'Provide details about a trigger.' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.trigger__parse' + , $$ + trigger_table pg_catalog.regclass + , trigger_name text + , OUT timing text + , OUT events text[] + , OUT defer text + , OUT row_statement text + , OUT when_clause text + , OUT trigger_function regprocedure + , OUT function_arguments text[] +$$ + , $$record STABLE LANGUAGE sql$$ + -- s/, OUT \(\w*\).*/ , \1/ + , $body$ +SELECT + timing + , events + , "defer" + , row_statement + , when_clause + , trigger_function + , function_arguments + FROM cat_tools.trigger__parse( + cat_tools.trigger__get_oid(trigger_table, trigger_name) + ) +$body$ + , 'cat_tools__usage' + , 'Provide details about a trigger.' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +SELECT __cat_tools.create_function( + 'cat_tools.trigger__args_as_text' + , $$function_arguments text[]$$ + , $$text IMMUTABLE STRICT LANGUAGE sql$$ + , $body$ + SELECT format( + $$'%s'$$ + , array_to_string( + function_arguments + , $$', '$$ + ) + ) +$body$ + , 'cat_tools__usage' + , 'Convert function_arguments as returned by trigger__parse() to text (for backwards compatibility).' +); + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +INSERT INTO _cat_tools.catalog_metadata(object_catalog, reg_type, namespace_field) +SELECT object__catalog + , CASE object__catalog + WHEN 'pg_catalog.pg_class'::pg_catalog.regclass THEN 'pg_catalog.regclass' + WHEN 'pg_catalog.pg_ts_config'::pg_catalog.regclass THEN 'pg_catalog.regconfig' + WHEN 'pg_catalog.pg_ts_dict'::pg_catalog.regclass THEN 'pg_catalog.regdictionary' + WHEN 'pg_catalog.pg_namespace'::pg_catalog.regclass THEN 'pg_catalog.regnamespace' -- SED: REQUIRES 9.5! + WHEN 'pg_catalog.pg_operator'::pg_catalog.regclass THEN 'pg_catalog.regoperator' + WHEN 'pg_catalog.pg_proc'::pg_catalog.regclass THEN 'pg_catalog.regprocedure' + WHEN 'pg_catalog.pg_authid'::pg_catalog.regclass THEN 'pg_catalog.regrole' -- SED: REQUIRES 9.5! + WHEN 'pg_catalog.pg_type'::pg_catalog.regclass THEN 'pg_catalog.regtype' + END::pg_catalog.regtype + , n.attname + FROM ( + SELECT DISTINCT cat_tools.object__catalog(object_type) + FROM cat_tools.enum_range_srf('cat_tools.object_type') r(object_type) + ) d + LEFT JOIN cat_tools.column n + ON n.attrelid = object__catalog + AND n.attname ~ 'namespace$' + AND atttypid = 'oid'::pg_catalog.regtype +; +UPDATE _cat_tools.catalog_metadata + SET simple_reg_type = 'pg_catalog.regproc' + WHERE object_catalog = 'pg_catalog.pg_proc'::pg_catalog.regclass +; +UPDATE _cat_tools.catalog_metadata + SET simple_reg_type = 'pg_catalog.regoper' + WHERE object_catalog = 'pg_catalog.pg_operator'::pg_catalog.regclass +; +-- Cluster to get rid of dead rows +CLUSTER _cat_tools.catalog_metadata USING catalog_metadata__pk_object_catalog; + +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + +/* + * Drop "temporary" objects + */ +DROP FUNCTION __cat_tools.exec( + sql text +); +DROP FUNCTION __cat_tools.create_function( + function_name text + , args text + , options text + , body text + , grants text + , comment text +); +DROP SCHEMA __cat_tools; + +-- vi: expandtab ts=2 sw=2 +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in From 7173bc9521b0823bc20296a02c5e65b9eb904292 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 14 Apr 2026 15:38:39 -0500 Subject: [PATCH 2/4] Replace pre-built historical install SQLs with .sql.in sources For versions 0.1.5, 0.2.0, and 0.2.1, replace the pre-built SQL files with versioned .sql.in source files extracted from the original PGXN distributions. The build system will now generate version-appropriate SQL for the running Postgres version using the existing sed rules. Findings from PGXN zip inspection: - 0.1.0, 0.1.3, 0.1.4: only pre-built sql/cat_tools.sql (no .in source); kept as-is in sql/ with explicit DATA += entries - 0.1.5: sql/cat_tools.in.sql exists but has no SED markers (pre-dates the conditional system); used as-is, sed processing is a no-op - 0.2.0: sql/cat_tools.in.sql with SED: REQUIRES 9.3/9.5 markers - 0.2.1: sql/cat_tools.sql.in with SED: REQUIRES/PRIOR TO 9.3/9.5 markers Makefile changes: - versioned_in glob widened from *--*--*.sql.in to *--*.sql.in so that single-version install scripts are processed alongside upgrade scripts - Added DATA += for pre-built install scripts (0.1.0, 0.1.3, 0.1.4) - Added DATA += $(versioned_out) for generated install scripts sql/.gitignore: ignore generated cat_tools--0.1.5/0.2.0/0.2.1.sql files Co-Authored-By: Claude Sonnet 4.6 --- Makefile | 7 +- sql/.gitignore | 3 + ...ols--0.1.5.sql => cat_tools--0.1.5.sql.in} | 42 ++++--- ...ols--0.2.0.sql => cat_tools--0.2.0.sql.in} | 90 +++++++-------- ...ols--0.2.1.sql => cat_tools--0.2.1.sql.in} | 108 +++++++++--------- 5 files changed, 126 insertions(+), 124 deletions(-) rename sql/{cat_tools--0.1.5.sql => cat_tools--0.1.5.sql.in} (89%) rename sql/{cat_tools--0.2.0.sql => cat_tools--0.2.0.sql.in} (92%) rename sql/{cat_tools--0.2.1.sql => cat_tools--0.2.1.sql.in} (92%) diff --git a/Makefile b/Makefile index b4faf23..c90bcd4 100644 --- a/Makefile +++ b/Makefile @@ -10,9 +10,14 @@ LT93 = $(call test, $(MAJORVER), -lt, 93) $B: @mkdir -p $@ -versioned_in = $(wildcard sql/*--*--*.sql.in) +versioned_in = $(wildcard sql/*--*.sql.in) versioned_out = $(subst sql/,$B/,$(subst .sql.in,.sql,$(versioned_in))) +# Pre-built historical install scripts (no .sql.in source available) +DATA += sql/cat_tools--0.1.0.sql sql/cat_tools--0.1.3.sql sql/cat_tools--0.1.4.sql +# Generated historical install scripts (built from .sql.in source) +DATA += $(versioned_out) + all: $B/cat_tools.sql $(versioned_out) installcheck: $B/cat_tools.sql $(versioned_out) EXTRA_CLEAN += $B/cat_tools.sql $(versioned_out) diff --git a/sql/.gitignore b/sql/.gitignore index 7c595fb..f824797 100644 --- a/sql/.gitignore +++ b/sql/.gitignore @@ -1 +1,4 @@ cat_tools.sql +cat_tools--0.1.5.sql +cat_tools--0.2.0.sql +cat_tools--0.2.1.sql diff --git a/sql/cat_tools--0.1.5.sql b/sql/cat_tools--0.1.5.sql.in similarity index 89% rename from sql/cat_tools--0.1.5.sql rename to sql/cat_tools--0.1.5.sql.in index 1760e3b..71fc1f0 100644 --- a/sql/cat_tools--0.1.5.sql +++ b/sql/cat_tools--0.1.5.sql.in @@ -1,4 +1,3 @@ --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql DO $$ BEGIN CREATE ROLE cat_tools__usage NOLOGIN; @@ -23,7 +22,7 @@ BEGIN END $body$; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ CREATE FUNCTION __cat_tools.create_function( function_name text @@ -56,7 +55,7 @@ GRANT EXECUTE ON FUNCTION %s( $template$ ; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ BEGIN PERFORM __cat_tools.exec( format( @@ -86,7 +85,7 @@ BEGIN END $body$; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ CREATE SCHEMA cat_tools; GRANT USAGE ON SCHEMA cat_tools TO cat_tools__usage; @@ -112,7 +111,7 @@ CREATE OR REPLACE VIEW cat_tools.pg_class_v AS ; GRANT SELECT ON cat_tools.pg_class_v TO cat_tools__usage; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ CREATE OR REPLACE VIEW _cat_tools.pg_attribute_v AS SELECT a.* @@ -150,7 +149,7 @@ CREATE OR REPLACE VIEW _cat_tools.column AS ; REVOKE ALL ON _cat_tools.column FROM public; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ CREATE OR REPLACE VIEW cat_tools.column AS SELECT * @@ -184,7 +183,7 @@ SELECT __cat_tools.create_function( $$ ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ -- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ SELECT __cat_tools.create_function( @@ -205,7 +204,7 @@ SELECT __cat_tools.create_function( $$ ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ -- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ CREATE OR REPLACE VIEW cat_tools.pg_all_foreign_keys @@ -226,7 +225,7 @@ AS WHEN 'u' THEN 'NONE' else null END AS match_type, - CASE k1.confdeltype WHEN 'a' THEN 'NO ACTION' -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + CASE k1.confdeltype WHEN 'a' THEN 'NO ACTION' -- @generated@ WHEN 'c' THEN 'CASCADE' WHEN 'd' THEN 'SET DEFAULT' WHEN 'n' THEN 'SET NULL' @@ -240,7 +239,7 @@ AS WHEN 'r' THEN 'RESTRICT' ELSE NULL END AS on_update, - k1.condeferrable AS is_deferrable, -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + k1.condeferrable AS is_deferrable, -- @generated@ k1.condeferred AS is_deferred FROM pg_catalog.pg_constraint k1 JOIN pg_catalog.pg_namespace n1 ON (n1.oid = k1.connamespace) @@ -248,7 +247,7 @@ AS JOIN pg_catalog.pg_class c2 ON (c2.oid = k1.confrelid) JOIN pg_catalog.pg_namespace n2 ON (n2.oid = c2.relnamespace) JOIN pg_catalog.pg_depend d ON ( - d.classid = 'pg_constraint'::regclass -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + d.classid = 'pg_constraint'::regclass -- @generated@ AND d.objid = k1.oid AND d.objsubid = 0 AND d.deptype = 'n' @@ -257,14 +256,14 @@ AS ) JOIN pg_catalog.pg_class ci ON (ci.oid = d.refobjid AND ci.relkind = 'i') LEFT JOIN pg_depend d2 ON ( - d2.classid = 'pg_class'::regclass -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + d2.classid = 'pg_class'::regclass -- @generated@ AND d2.objid = ci.oid AND d2.objsubid = 0 AND d2.deptype = 'i' AND d2.refclassid = 'pg_constraint'::regclass AND d2.refobjsubid = 0 ) - LEFT JOIN pg_catalog.pg_constraint k2 ON ( -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + LEFT JOIN pg_catalog.pg_constraint k2 ON ( -- @generated@ k2.oid = d2.refobjid AND k2.contype IN ('p', 'u') ) @@ -275,7 +274,7 @@ AS ; GRANT SELECT ON cat_tools.pg_all_foreign_keys TO cat_tools__usage; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.currval' @@ -305,7 +304,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.enum_range' @@ -322,7 +321,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.enum_range_srf' @@ -344,7 +343,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.name__check' @@ -360,7 +359,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.trigger__parse' @@ -459,7 +458,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.trigger__get_oid__loose' @@ -478,7 +477,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.trigger__get_oid' @@ -504,7 +503,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ /* * Drop "temporary" objects @@ -522,4 +521,3 @@ DROP FUNCTION __cat_tools.create_function( DROP SCHEMA __cat_tools; -- vi: expandtab ts=2 sw=2 --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql diff --git a/sql/cat_tools--0.2.0.sql b/sql/cat_tools--0.2.0.sql.in similarity index 92% rename from sql/cat_tools--0.2.0.sql rename to sql/cat_tools--0.2.0.sql.in index 92dc797..d21ed27 100644 --- a/sql/cat_tools--0.2.0.sql +++ b/sql/cat_tools--0.2.0.sql.in @@ -1,5 +1,4 @@ --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SET LOCAL client_min_messages = WARNING; @@ -30,7 +29,7 @@ CREATE OR REPLACE VIEW _cat_tools.pg_class_v AS ; REVOKE ALL ON _cat_tools.pg_class_v FROM public; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ CREATE FUNCTION __cat_tools.exec( sql text @@ -41,7 +40,7 @@ BEGIN END $body$; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ /* * Temporary stub function. We do this so we can use the nice create_function @@ -91,7 +90,7 @@ COMMENT ON FUNCTION %s( $template$ ; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ BEGIN PERFORM __cat_tools.exec( format( @@ -131,7 +130,7 @@ BEGIN END $body$; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.function__arg_types' @@ -197,7 +196,7 @@ $body$ defining a function.' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.function__arg_types_text' @@ -213,7 +212,7 @@ $body$ ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.regprocedure' @@ -235,7 +234,7 @@ $body$ ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ CREATE TYPE cat_tools.constraint_type AS ENUM( 'domain constraint', 'table constraint' @@ -270,7 +269,7 @@ CREATE TYPE cat_tools.relation_relkind AS ENUM( ); COMMENT ON TYPE cat_tools.relation_relkind IS $$Valid values for `pg_class.relkind`$$; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ CREATE TYPE cat_tools.object_type AS ENUM( -- pg_class @@ -333,7 +332,7 @@ CREATE TYPE cat_tools.object_type AS ENUM( , 'access method' -- pg_am ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.objects__shared' @@ -376,7 +375,7 @@ $body$ , 'Returns true if object_type is a shared object.' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.objects__address_unsupported' @@ -402,7 +401,7 @@ $body$ , 'cat_tools__usage' , 'Returns set of object types not supported by pg_get_object_address().' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.object__is_address_unsupported' , 'object_type cat_tools.object_type' @@ -424,7 +423,7 @@ $body$ , 'Returns true if object type is not supported by pg_get_object_address().' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.object__catalog' @@ -481,7 +480,7 @@ $body$ , 'cat_tools__usage' , 'Returns catalog table that is used to store objects' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.object__catalog' , 'object_type text' @@ -491,7 +490,7 @@ SELECT __cat_tools.create_function( , 'Returns catalog table that is used to store objects' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.object__address_classid' @@ -516,7 +515,7 @@ SELECT __cat_tools.create_function( , 'Returns the classid used by the pg_*_object*() functions for an object_type' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ CREATE TABLE _cat_tools.catalog_metadata( object_catalog pg_catalog.regclass @@ -545,7 +544,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.object__reg_type' @@ -574,7 +573,7 @@ SELECT __cat_tools.create_function( , 'Returns the object identifier type (ie: regclass) associated with a system catalog (ie: pg_class).' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.object__reg_type_catalog' @@ -611,7 +610,7 @@ $body$ , 'Returns the system catalog that stores a particular object identifier type.' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.relation__kind' @@ -653,7 +652,7 @@ $body$ , 'Mapping from to a value' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.relation__relkind' @@ -672,7 +671,7 @@ SELECT __cat_tools.create_function( , 'Mapping from to a value' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ CREATE OR REPLACE VIEW _cat_tools.pg_depend_identity_v AS -- SED: REQUIRES 9.3! SELECT o.type AS object_type -- SED: REQUIRES 9.3! @@ -700,7 +699,7 @@ CREATE OR REPLACE VIEW _cat_tools.pg_depend_identity_v AS -- SED: REQUIRES 9.3! WHERE classid = 0 -- SED: REQUIRES 9.3! ; -- SED: REQUIRES 9.3! --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ CREATE OR REPLACE VIEW cat_tools.pg_class_v AS SELECT * @@ -715,7 +714,7 @@ CREATE OR REPLACE VIEW cat_tools.pg_class_v AS ; GRANT SELECT ON cat_tools.pg_class_v TO cat_tools__usage; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ CREATE OR REPLACE VIEW _cat_tools.pg_attribute_v AS SELECT a.* @@ -753,7 +752,7 @@ CREATE OR REPLACE VIEW _cat_tools.column AS ; REVOKE ALL ON _cat_tools.column FROM public; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ CREATE OR REPLACE VIEW cat_tools.column AS SELECT * @@ -787,7 +786,7 @@ SELECT __cat_tools.create_function( $$ ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ -- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ SELECT __cat_tools.create_function( @@ -808,7 +807,7 @@ SELECT __cat_tools.create_function( $$ ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ -- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ CREATE OR REPLACE VIEW cat_tools.pg_all_foreign_keys @@ -829,7 +828,7 @@ AS WHEN 'u' THEN 'NONE' else null END AS match_type, - CASE k1.confdeltype WHEN 'a' THEN 'NO ACTION' -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + CASE k1.confdeltype WHEN 'a' THEN 'NO ACTION' -- @generated@ WHEN 'c' THEN 'CASCADE' WHEN 'd' THEN 'SET DEFAULT' WHEN 'n' THEN 'SET NULL' @@ -843,7 +842,7 @@ AS WHEN 'r' THEN 'RESTRICT' ELSE NULL END AS on_update, - k1.condeferrable AS is_deferrable, -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + k1.condeferrable AS is_deferrable, -- @generated@ k1.condeferred AS is_deferred FROM pg_catalog.pg_constraint k1 JOIN pg_catalog.pg_namespace n1 ON (n1.oid = k1.connamespace) @@ -851,7 +850,7 @@ AS JOIN pg_catalog.pg_class c2 ON (c2.oid = k1.confrelid) JOIN pg_catalog.pg_namespace n2 ON (n2.oid = c2.relnamespace) JOIN pg_catalog.pg_depend d ON ( - d.classid = 'pg_constraint'::pg_catalog.regclass -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + d.classid = 'pg_constraint'::pg_catalog.regclass -- @generated@ AND d.objid = k1.oid AND d.objsubid = 0 AND d.deptype = 'n' @@ -860,14 +859,14 @@ AS ) JOIN pg_catalog.pg_class ci ON (ci.oid = d.refobjid AND ci.relkind = 'i') LEFT JOIN pg_depend d2 ON ( - d2.classid = 'pg_class'::pg_catalog.regclass -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + d2.classid = 'pg_class'::pg_catalog.regclass -- @generated@ AND d2.objid = ci.oid AND d2.objsubid = 0 AND d2.deptype = 'i' AND d2.refclassid = 'pg_constraint'::pg_catalog.regclass AND d2.refobjsubid = 0 ) - LEFT JOIN pg_catalog.pg_constraint k2 ON ( -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql + LEFT JOIN pg_catalog.pg_constraint k2 ON ( -- @generated@ k2.oid = d2.refobjid AND k2.contype IN ('p', 'u') ) @@ -878,7 +877,7 @@ AS ; GRANT SELECT ON cat_tools.pg_all_foreign_keys TO cat_tools__usage; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.pg_attribute__get' @@ -908,7 +907,7 @@ $body$ ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.get_serial_sequence' @@ -939,7 +938,7 @@ $body$ , 'Return sequence that is associated with a column. Unlike the pg_get_serial_sequence, throw an exception if there is no sequence associated with the column.' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.sequence__last' @@ -964,7 +963,7 @@ $$ , 'Return the last value assigned to a column with an associated sequence.' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.sequence__next' @@ -989,7 +988,7 @@ $$ , 'Return the next value to assign to a column with an associated sequence. THIS ADVANCES THE SEQUENCE.' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.setval' @@ -1029,7 +1028,7 @@ $$ , 'Changes the value for a sequence associated with a column. next_value is the next value the sequence will assign. See also sequence__last_value.' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.enum_range' @@ -1046,7 +1045,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.enum_range_srf' @@ -1068,7 +1067,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.name__check' @@ -1084,7 +1083,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.trigger__parse' @@ -1183,7 +1182,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.trigger__get_oid__loose' @@ -1202,7 +1201,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ SELECT __cat_tools.create_function( 'cat_tools.trigger__get_oid' @@ -1228,7 +1227,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ INSERT INTO _cat_tools.catalog_metadata(object_catalog, reg_type, namespace_field) SELECT object__catalog @@ -1263,7 +1262,7 @@ UPDATE _cat_tools.catalog_metadata -- Cluster to get rid of dead rows CLUSTER _cat_tools.catalog_metadata USING catalog_metadata__pk_object_catalog; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql +@generated@ /* * Drop "temporary" objects @@ -1282,4 +1281,3 @@ DROP FUNCTION __cat_tools.create_function( DROP SCHEMA __cat_tools; -- vi: expandtab ts=2 sw=2 --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql diff --git a/sql/cat_tools--0.2.1.sql b/sql/cat_tools--0.2.1.sql.in similarity index 92% rename from sql/cat_tools--0.2.1.sql rename to sql/cat_tools--0.2.1.sql.in index d9f5772..dda82d8 100644 --- a/sql/cat_tools--0.2.1.sql +++ b/sql/cat_tools--0.2.1.sql.in @@ -1,5 +1,4 @@ --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SET LOCAL client_min_messages = WARNING; @@ -31,7 +30,7 @@ CREATE OR REPLACE VIEW _cat_tools.pg_class_v AS ; REVOKE ALL ON _cat_tools.pg_class_v FROM public; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ CREATE FUNCTION __cat_tools.exec( sql text @@ -42,7 +41,7 @@ BEGIN END $body$; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ /* * Temporary stub function. We do this so we can use the nice create_function @@ -92,7 +91,7 @@ COMMENT ON FUNCTION %s( $template$ ; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ BEGIN PERFORM __cat_tools.exec( format( @@ -132,7 +131,7 @@ BEGIN END $body$; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.function__arg_types' @@ -198,7 +197,7 @@ $body$ defining a function.' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.function__arg_types_text' @@ -214,7 +213,7 @@ $body$ ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.regprocedure' @@ -236,7 +235,7 @@ $body$ ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ CREATE TYPE cat_tools.constraint_type AS ENUM( 'domain constraint', 'table constraint' @@ -271,7 +270,7 @@ CREATE TYPE cat_tools.relation_relkind AS ENUM( ); COMMENT ON TYPE cat_tools.relation_relkind IS $$Valid values for `pg_class.relkind`$$; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ CREATE TYPE cat_tools.object_type AS ENUM( -- pg_class @@ -334,7 +333,7 @@ CREATE TYPE cat_tools.object_type AS ENUM( , 'access method' -- pg_am ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.objects__shared' @@ -377,7 +376,7 @@ $body$ , 'Returns true if object_type is a shared object.' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.objects__address_unsupported' @@ -403,7 +402,7 @@ $body$ , 'cat_tools__usage' , 'Returns set of object types not supported by pg_get_object_address().' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.object__is_address_unsupported' , 'object_type cat_tools.object_type' @@ -425,7 +424,7 @@ $body$ , 'Returns true if object type is not supported by pg_get_object_address().' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.object__catalog' @@ -482,7 +481,7 @@ $body$ , 'cat_tools__usage' , 'Returns catalog table that is used to store objects' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.object__catalog' , 'object_type text' @@ -492,7 +491,7 @@ SELECT __cat_tools.create_function( , 'Returns catalog table that is used to store objects' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.object__address_classid' @@ -517,7 +516,7 @@ SELECT __cat_tools.create_function( , 'Returns the classid used by the pg_*_object*() functions for an object_type' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ CREATE TABLE _cat_tools.catalog_metadata( object_catalog pg_catalog.regclass @@ -546,7 +545,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.object__reg_type' @@ -575,7 +574,7 @@ SELECT __cat_tools.create_function( , 'Returns the object identifier type (ie: regclass) associated with a system catalog (ie: pg_class).' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.object__reg_type_catalog' @@ -612,7 +611,7 @@ $body$ , 'Returns the system catalog that stores a particular object identifier type.' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.relation__kind' @@ -654,7 +653,7 @@ $body$ , 'Mapping from to a value' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.relation__relkind' @@ -673,7 +672,7 @@ SELECT __cat_tools.create_function( , 'Mapping from to a value' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ CREATE OR REPLACE VIEW _cat_tools.pg_depend_identity_v AS -- SED: REQUIRES 9.3! SELECT o.type AS object_type -- SED: REQUIRES 9.3! @@ -701,7 +700,7 @@ CREATE OR REPLACE VIEW _cat_tools.pg_depend_identity_v AS -- SED: REQUIRES 9.3! WHERE classid = 0 -- SED: REQUIRES 9.3! ; -- SED: REQUIRES 9.3! --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ CREATE OR REPLACE VIEW cat_tools.pg_class_v AS SELECT * @@ -716,7 +715,7 @@ CREATE OR REPLACE VIEW cat_tools.pg_class_v AS ; GRANT SELECT ON cat_tools.pg_class_v TO cat_tools__usage; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ CREATE OR REPLACE VIEW _cat_tools.pg_attribute_v AS SELECT a.* @@ -754,14 +753,14 @@ CREATE OR REPLACE VIEW _cat_tools.column AS ; REVOKE ALL ON _cat_tools.column FROM public; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ -- No perms on extension visibility CREATE OR REPLACE VIEW cat_tools.pg_extension_v AS SELECT e.oid, e.* , extnamespace::regnamespace AS extschema -- SED: REQUIRES 9.5! --- Not used prior to 9.5: , nspname AS extschema + , nspname AS extschema -- SED: PRIOR TO 9.5! , extconfig::pg_catalog.regclass[] AS ext_config_tables FROM pg_catalog.pg_extension e @@ -801,7 +800,7 @@ SELECT __cat_tools.create_function( $$ ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ -- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ SELECT __cat_tools.create_function( @@ -822,7 +821,7 @@ SELECT __cat_tools.create_function( $$ ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ -- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ CREATE OR REPLACE VIEW cat_tools.pg_all_foreign_keys @@ -843,7 +842,7 @@ AS WHEN 'u' THEN 'NONE' else null END AS match_type, - CASE k1.confdeltype WHEN 'a' THEN 'NO ACTION' -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + CASE k1.confdeltype WHEN 'a' THEN 'NO ACTION' -- @generated@ WHEN 'c' THEN 'CASCADE' WHEN 'd' THEN 'SET DEFAULT' WHEN 'n' THEN 'SET NULL' @@ -857,7 +856,7 @@ AS WHEN 'r' THEN 'RESTRICT' ELSE NULL END AS on_update, - k1.condeferrable AS is_deferrable, -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + k1.condeferrable AS is_deferrable, -- @generated@ k1.condeferred AS is_deferred FROM pg_catalog.pg_constraint k1 JOIN pg_catalog.pg_namespace n1 ON (n1.oid = k1.connamespace) @@ -865,7 +864,7 @@ AS JOIN pg_catalog.pg_class c2 ON (c2.oid = k1.confrelid) JOIN pg_catalog.pg_namespace n2 ON (n2.oid = c2.relnamespace) JOIN pg_catalog.pg_depend d ON ( - d.classid = 'pg_constraint'::pg_catalog.regclass -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + d.classid = 'pg_constraint'::pg_catalog.regclass -- @generated@ AND d.objid = k1.oid AND d.objsubid = 0 AND d.deptype = 'n' @@ -874,14 +873,14 @@ AS ) JOIN pg_catalog.pg_class ci ON (ci.oid = d.refobjid AND ci.relkind = 'i') LEFT JOIN pg_depend d2 ON ( - d2.classid = 'pg_class'::pg_catalog.regclass -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + d2.classid = 'pg_class'::pg_catalog.regclass -- @generated@ AND d2.objid = ci.oid AND d2.objsubid = 0 AND d2.deptype = 'i' AND d2.refclassid = 'pg_constraint'::pg_catalog.regclass AND d2.refobjsubid = 0 ) - LEFT JOIN pg_catalog.pg_constraint k2 ON ( -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in + LEFT JOIN pg_catalog.pg_constraint k2 ON ( -- @generated@ k2.oid = d2.refobjid AND k2.contype IN ('p', 'u') ) @@ -892,7 +891,7 @@ AS ; GRANT SELECT ON cat_tools.pg_all_foreign_keys TO cat_tools__usage; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.pg_attribute__get' @@ -921,7 +920,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.pg_extension__get' @@ -949,7 +948,7 @@ SELECT __cat_tools.create_function( 'cat_tools.extension__schemas' , 'extension_names name[]' , $$pg_catalog.regnamespace[] LANGUAGE sql$$ -- SED: REQUIRES 9.5! --- Not used prior to 9.5: , $$pg_catalog.name[] LANGUAGE sql$$ + , $$pg_catalog.name[] LANGUAGE sql$$ -- SED: PRIOR TO 9.5! , $body$ SELECT array( SELECT (cat_tools.pg_extension__get(en)).extschema @@ -962,7 +961,7 @@ SELECT __cat_tools.create_function( 'cat_tools.extension__schemas_unique' , 'extension_names name[]' , $$pg_catalog.regnamespace[] LANGUAGE sql$$ -- SED: REQUIRES 9.5! --- Not used prior to 9.5: , $$pg_catalog.name[] LANGUAGE sql$$ + , $$pg_catalog.name[] LANGUAGE sql$$ -- SED: PRIOR TO 9.5! , $body$ SELECT array( SELECT DISTINCT (cat_tools.pg_extension__get(en)).extschema @@ -972,14 +971,14 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ -- Text versions SELECT __cat_tools.create_function( 'cat_tools.extension__schemas' , 'extension_names text' , $$pg_catalog.regnamespace[] LANGUAGE sql$$ -- SED: REQUIRES 9.5! --- Not used prior to 9.5: , $$pg_catalog.name[] LANGUAGE sql$$ + , $$pg_catalog.name[] LANGUAGE sql$$ -- SED: PRIOR TO 9.5! , $body$ SELECT cat_tools.extension__schemas( CASE WHEN extension_names LIKE '{%}' THEN extension_names @@ -993,7 +992,7 @@ SELECT __cat_tools.create_function( 'cat_tools.extension__schemas_unique' , 'extension_names text' , $$pg_catalog.regnamespace[] LANGUAGE sql$$ -- SED: REQUIRES 9.5! --- Not used prior to 9.5: , $$pg_catalog.name[] LANGUAGE sql$$ + , $$pg_catalog.name[] LANGUAGE sql$$ -- SED: PRIOR TO 9.5! , $body$ SELECT cat_tools.extension__schemas_unique( CASE WHEN extension_names LIKE '{%}' THEN extension_names @@ -1005,7 +1004,7 @@ $body$ ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.get_serial_sequence' @@ -1036,7 +1035,7 @@ $body$ , 'Return sequence that is associated with a column. Unlike the pg_get_serial_sequence, throw an exception if there is no sequence associated with the column.' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.sequence__last' @@ -1061,7 +1060,7 @@ $$ , 'Return the last value assigned to a column with an associated sequence.' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.sequence__next' @@ -1086,7 +1085,7 @@ $$ , 'Return the next value to assign to a column with an associated sequence. THIS ADVANCES THE SEQUENCE.' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.setval' @@ -1126,7 +1125,7 @@ $$ , 'Changes the value for a sequence associated with a column. next_value is the next value the sequence will assign. See also sequence__last_value.' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.enum_range' @@ -1143,7 +1142,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.enum_range_srf' @@ -1165,7 +1164,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.name__check' @@ -1181,7 +1180,7 @@ $body$ , 'cat_tools__usage' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ /* * Trigger functions @@ -1211,7 +1210,7 @@ $body$ , 'Return the OID for a trigger. Returns NULL if trigger does not exist.' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.trigger__get_oid' @@ -1240,7 +1239,7 @@ $body$ , 'Return the OID for a trigger. Throws an undefined_object error if the trigger does not exist.' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.trigger__parse' @@ -1362,7 +1361,7 @@ $body$ , 'Provide details about a trigger.' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.trigger__parse' @@ -1396,7 +1395,7 @@ $body$ , 'Provide details about a trigger.' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ SELECT __cat_tools.create_function( 'cat_tools.trigger__args_as_text' @@ -1415,7 +1414,7 @@ $body$ , 'Convert function_arguments as returned by trigger__parse() to text (for backwards compatibility).' ); --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ INSERT INTO _cat_tools.catalog_metadata(object_catalog, reg_type, namespace_field) SELECT object__catalog @@ -1450,7 +1449,7 @@ UPDATE _cat_tools.catalog_metadata -- Cluster to get rid of dead rows CLUSTER _cat_tools.catalog_metadata USING catalog_metadata__pk_object_catalog; --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in +@generated@ /* * Drop "temporary" objects @@ -1469,4 +1468,3 @@ DROP FUNCTION __cat_tools.create_function( DROP SCHEMA __cat_tools; -- vi: expandtab ts=2 sw=2 --- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.sql.in From fb9418f72e4f5c29f3fed1f5157a45c6ce644642 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Wed, 15 Apr 2026 15:23:36 -0500 Subject: [PATCH 3/4] Fix: revert cat_tools--0.1.5 to pre-built .sql (no SED markers) 0.1.5's PGXN source predates the SED conditional system and has no REQUIRES/PRIOR TO markers, so building from .sql.in would produce identical output regardless of PG version. Treat it like 0.1.0-0.1.4: commit the pre-built SQL directly. Also add a comment to sql/.gitignore explaining which versions are generated vs committed. Co-Authored-By: Claude Sonnet 4.6 --- Makefile | 2 +- sql/.gitignore | 4 +- ...ols--0.1.5.sql.in => cat_tools--0.1.5.sql} | 42 ++++++++++--------- 3 files changed, 26 insertions(+), 22 deletions(-) rename sql/{cat_tools--0.1.5.sql.in => cat_tools--0.1.5.sql} (89%) diff --git a/Makefile b/Makefile index c90bcd4..bcdfde8 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ versioned_in = $(wildcard sql/*--*.sql.in) versioned_out = $(subst sql/,$B/,$(subst .sql.in,.sql,$(versioned_in))) # Pre-built historical install scripts (no .sql.in source available) -DATA += sql/cat_tools--0.1.0.sql sql/cat_tools--0.1.3.sql sql/cat_tools--0.1.4.sql +DATA += sql/cat_tools--0.1.0.sql sql/cat_tools--0.1.3.sql sql/cat_tools--0.1.4.sql sql/cat_tools--0.1.5.sql # Generated historical install scripts (built from .sql.in source) DATA += $(versioned_out) diff --git a/sql/.gitignore b/sql/.gitignore index f824797..55e43ad 100644 --- a/sql/.gitignore +++ b/sql/.gitignore @@ -1,4 +1,6 @@ cat_tools.sql -cat_tools--0.1.5.sql +# The following are generated by make from their .sql.in counterparts. +# Versions 0.1.0-0.1.5 have no .sql.in (pre-dates the conditional SED system +# or only pre-built SQL was published to PGXN), so they are committed as-is. cat_tools--0.2.0.sql cat_tools--0.2.1.sql diff --git a/sql/cat_tools--0.1.5.sql.in b/sql/cat_tools--0.1.5.sql similarity index 89% rename from sql/cat_tools--0.1.5.sql.in rename to sql/cat_tools--0.1.5.sql index 71fc1f0..1760e3b 100644 --- a/sql/cat_tools--0.1.5.sql.in +++ b/sql/cat_tools--0.1.5.sql @@ -1,3 +1,4 @@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql DO $$ BEGIN CREATE ROLE cat_tools__usage NOLOGIN; @@ -22,7 +23,7 @@ BEGIN END $body$; -@generated@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql CREATE FUNCTION __cat_tools.create_function( function_name text @@ -55,7 +56,7 @@ GRANT EXECUTE ON FUNCTION %s( $template$ ; -@generated@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql BEGIN PERFORM __cat_tools.exec( format( @@ -85,7 +86,7 @@ BEGIN END $body$; -@generated@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql CREATE SCHEMA cat_tools; GRANT USAGE ON SCHEMA cat_tools TO cat_tools__usage; @@ -111,7 +112,7 @@ CREATE OR REPLACE VIEW cat_tools.pg_class_v AS ; GRANT SELECT ON cat_tools.pg_class_v TO cat_tools__usage; -@generated@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql CREATE OR REPLACE VIEW _cat_tools.pg_attribute_v AS SELECT a.* @@ -149,7 +150,7 @@ CREATE OR REPLACE VIEW _cat_tools.column AS ; REVOKE ALL ON _cat_tools.column FROM public; -@generated@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql CREATE OR REPLACE VIEW cat_tools.column AS SELECT * @@ -183,7 +184,7 @@ SELECT __cat_tools.create_function( $$ ); -@generated@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql -- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ SELECT __cat_tools.create_function( @@ -204,7 +205,7 @@ SELECT __cat_tools.create_function( $$ ); -@generated@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql -- Borrowed from newsysviews: http://pgfoundry.org/projects/newsysviews/ CREATE OR REPLACE VIEW cat_tools.pg_all_foreign_keys @@ -225,7 +226,7 @@ AS WHEN 'u' THEN 'NONE' else null END AS match_type, - CASE k1.confdeltype WHEN 'a' THEN 'NO ACTION' -- @generated@ + CASE k1.confdeltype WHEN 'a' THEN 'NO ACTION' -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql WHEN 'c' THEN 'CASCADE' WHEN 'd' THEN 'SET DEFAULT' WHEN 'n' THEN 'SET NULL' @@ -239,7 +240,7 @@ AS WHEN 'r' THEN 'RESTRICT' ELSE NULL END AS on_update, - k1.condeferrable AS is_deferrable, -- @generated@ + k1.condeferrable AS is_deferrable, -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql k1.condeferred AS is_deferred FROM pg_catalog.pg_constraint k1 JOIN pg_catalog.pg_namespace n1 ON (n1.oid = k1.connamespace) @@ -247,7 +248,7 @@ AS JOIN pg_catalog.pg_class c2 ON (c2.oid = k1.confrelid) JOIN pg_catalog.pg_namespace n2 ON (n2.oid = c2.relnamespace) JOIN pg_catalog.pg_depend d ON ( - d.classid = 'pg_constraint'::regclass -- @generated@ + d.classid = 'pg_constraint'::regclass -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql AND d.objid = k1.oid AND d.objsubid = 0 AND d.deptype = 'n' @@ -256,14 +257,14 @@ AS ) JOIN pg_catalog.pg_class ci ON (ci.oid = d.refobjid AND ci.relkind = 'i') LEFT JOIN pg_depend d2 ON ( - d2.classid = 'pg_class'::regclass -- @generated@ + d2.classid = 'pg_class'::regclass -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql AND d2.objid = ci.oid AND d2.objsubid = 0 AND d2.deptype = 'i' AND d2.refclassid = 'pg_constraint'::regclass AND d2.refobjsubid = 0 ) - LEFT JOIN pg_catalog.pg_constraint k2 ON ( -- @generated@ + LEFT JOIN pg_catalog.pg_constraint k2 ON ( -- -- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql k2.oid = d2.refobjid AND k2.contype IN ('p', 'u') ) @@ -274,7 +275,7 @@ AS ; GRANT SELECT ON cat_tools.pg_all_foreign_keys TO cat_tools__usage; -@generated@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql SELECT __cat_tools.create_function( 'cat_tools.currval' @@ -304,7 +305,7 @@ $body$ , 'cat_tools__usage' ); -@generated@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql SELECT __cat_tools.create_function( 'cat_tools.enum_range' @@ -321,7 +322,7 @@ $body$ , 'cat_tools__usage' ); -@generated@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql SELECT __cat_tools.create_function( 'cat_tools.enum_range_srf' @@ -343,7 +344,7 @@ $body$ , 'cat_tools__usage' ); -@generated@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql SELECT __cat_tools.create_function( 'cat_tools.name__check' @@ -359,7 +360,7 @@ $body$ , 'cat_tools__usage' ); -@generated@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql SELECT __cat_tools.create_function( 'cat_tools.trigger__parse' @@ -458,7 +459,7 @@ $body$ , 'cat_tools__usage' ); -@generated@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql SELECT __cat_tools.create_function( 'cat_tools.trigger__get_oid__loose' @@ -477,7 +478,7 @@ $body$ , 'cat_tools__usage' ); -@generated@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql SELECT __cat_tools.create_function( 'cat_tools.trigger__get_oid' @@ -503,7 +504,7 @@ $body$ , 'cat_tools__usage' ); -@generated@ +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql /* * Drop "temporary" objects @@ -521,3 +522,4 @@ DROP FUNCTION __cat_tools.create_function( DROP SCHEMA __cat_tools; -- vi: expandtab ts=2 sw=2 +-- GENERATED FILE! DO NOT EDIT! See sql/cat_tools.in.sql From 90183e0b794436c5cf501de1021c95b6ace0d699 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Thu, 16 Apr 2026 17:59:31 -0500 Subject: [PATCH 4/4] Fix 2 test failures on historical-sql-files branch Makefile: filter EXTENSION_VERSION_FILES out of versioned_out to prevent cat_tools--0.2.1.sql appearing twice in DATA (once from EXTENSION_VERSION_FILES in base.mk, once from versioned_out since cat_tools--0.2.1.sql.in now exists). trigger__parse: replace broken current_setting('server_version')::real version check (fails on PG17 due to full version string like "17.9 (Ubuntu ...)") with the proper EXECUTE (?:PROCEDURE|FUNCTION) regex approach. Also handle empty function arguments with ARRAY[]::text[] cast. test/deps.sql: grant CREATE on public schema to test role for PG15+ compatibility (PG15 removed implicit CREATE from PUBLIC). Co-Authored-By: Claude Sonnet 4.6 --- Makefile | 7 ++++--- sql/cat_tools.sql.in | 18 +++++++++--------- test/deps.sql | 3 +++ 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index bcdfde8..6fe257a 100644 --- a/Makefile +++ b/Makefile @@ -15,12 +15,13 @@ versioned_out = $(subst sql/,$B/,$(subst .sql.in,.sql,$(versioned_in))) # Pre-built historical install scripts (no .sql.in source available) DATA += sql/cat_tools--0.1.0.sql sql/cat_tools--0.1.3.sql sql/cat_tools--0.1.4.sql sql/cat_tools--0.1.5.sql -# Generated historical install scripts (built from .sql.in source) -DATA += $(versioned_out) +# Generated historical install scripts (built from .sql.in source). +# Exclude EXTENSION_VERSION_FILES since the current version is managed by control.mk. +DATA += $(filter-out $(EXTENSION_VERSION_FILES), $(versioned_out)) all: $B/cat_tools.sql $(versioned_out) installcheck: $B/cat_tools.sql $(versioned_out) -EXTRA_CLEAN += $B/cat_tools.sql $(versioned_out) +EXTRA_CLEAN += $B/cat_tools.sql $(filter-out $(EXTENSION_VERSION_FILES), $(versioned_out)) # TODO: refactor the version stuff into a function # diff --git a/sql/cat_tools.sql.in b/sql/cat_tools.sql.in index fba34a6..6d43fd8 100644 --- a/sql/cat_tools.sql.in +++ b/sql/cat_tools.sql.in @@ -1356,16 +1356,16 @@ BEGIN RAISE DEBUG 'v_work "%"', v_work; -- Get function arguments - IF current_setting('server_version')::real >= 11.0 THEN - v_execute_clause := ' EXECUTE FUNCTION ' || r_trigger.tgfoid::pg_catalog.regproc || E'\\('; - ELSE - v_execute_clause := ' EXECUTE PROCEDURE ' || r_trigger.tgfoid::pg_catalog.regproc || E'\\('; - END IF; + -- PG11+ uses "EXECUTE FUNCTION"; older versions use "EXECUTE PROCEDURE". + -- Note: ::regproc returns the internal pg_temp_N schema name while pg_get_triggerdef + -- uses the pg_temp alias, so we match on EXECUTE PROCEDURE/FUNCTION + any non-space + -- chars (the function name) rather than the specific function name. + v_execute_clause := E' EXECUTE (?:PROCEDURE|FUNCTION) \\S+\\('; v_array := regexp_split_to_array( v_work, v_execute_clause ); - EXECUTE format( - 'SELECT array[ %s ]' - , rtrim( v_array[2], ')' ) -- Yank trailing ) - ) + EXECUTE CASE + WHEN trim(rtrim(v_array[2], ')')) = '' THEN 'SELECT ARRAY[]::text[]' + ELSE format('SELECT array[ %s ]', rtrim( v_array[2], ')' )) + END INTO function_arguments ; RAISE DEBUG 'v_array[2] "%"', v_array[2]; diff --git a/test/deps.sql b/test/deps.sql index 32fd5bf..f7fe4d9 100644 --- a/test/deps.sql +++ b/test/deps.sql @@ -14,4 +14,7 @@ CREATE ROLE :no_use_role; CREATE ROLE :use_role; GRANT cat_tools__usage TO :use_role; +-- PG15+ removed CREATE on public schema from PUBLIC; grant it explicitly for tests +-- that need to create shadow names in public to test catalog lookup correctness. +GRANT CREATE ON SCHEMA public TO :use_role;