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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: CI
on: [push, pull_request]
jobs:
test:
strategy:
matrix:
pg: [18, 17, 16, 15, 14, 13, 12, 11, 10]
name: 🐘 PostgreSQL ${{ matrix.pg }}
runs-on: ubuntu-latest
container: pgxn/pgxn-tools
steps:
- name: Start PostgreSQL ${{ matrix.pg }}
run: pg-start ${{ matrix.pg }}
- name: Check out the repo
uses: actions/checkout@v4
- name: Test on PostgreSQL ${{ matrix.pg }}
run: make test PGUSER=postgres
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ regression.out
# Misc
tmp/
.DS_Store
.claude/*.local.json
19 changes: 0 additions & 19 deletions .travis.yml

This file was deleted.

4 changes: 2 additions & 2 deletions META.in.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"name": "cat_tools",

"X_comment": "REQUIRED. Version of the distribution. http://pgxn.org/spec/#version",
"version": "0.2.1",
"version": "0.3.0",

"X_comment": "REQUIRED. Short description of distribution.",
"abstract": "Tools for interfacing with the Postgres catalog",
Expand All @@ -37,7 +37,7 @@
"file": "sql/cat_tools.sql",

"X_comment": "REQUIRED. Version the extension is at.",
"version": "0.2.1",
"version": "0.3.0",

"X_comment": "Optional: \"abstract\": Description of the extension.",
"abstract": "Tools for interfacing with the catalog",
Expand Down
4 changes: 2 additions & 2 deletions META.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"name": "cat_tools",

"X_comment": "REQUIRED. Version of the distribution. http://pgxn.org/spec/#version",
"version": "0.2.1",
"version": "0.3.0",

"X_comment": "REQUIRED. Short description of distribution.",
"abstract": "Tools for interfacing with the Postgres catalog",
Expand All @@ -37,7 +37,7 @@
"file": "sql/cat_tools.sql",

"X_comment": "REQUIRED. Version the extension is at.",
"version": "0.2.1",
"version": "0.3.0",

"X_comment": "Optional: \"abstract\": Description of the extension.",
"abstract": "Tools for interfacing with the catalog",
Expand Down
49 changes: 39 additions & 10 deletions README.asc
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ To make use of them, you need to grant `cat_tools__usage` to any roles that need

== Current Status

image:https://badge.fury.io/pg/cat_tools.svg["PGXN version",link="https://badge.fury.io/pg/cat_tools"]
image:https://travis-ci.org/decibel/cat_tools.png["Build Status",link="https://travis-ci.org/decibel/cat_tools"]

This is very much a work in progress. If it doesn't do something you need, please https://github.com/decibel/cat_tools/issues[open an issue]!

=== Supported Versions
Expand All @@ -21,8 +18,13 @@ Works on Postgres 9.3 and above.
* `cat_tools.constraint_type` - Types of constraints (`domain constraint` or `table_constraint`)
* `cat_tools.relation_type` - Types of objects stored in `pg_class`
* `cat_tools.relation_relkind` - Valid values for `pg_class.relkind`
* `cat_tools.routine_type` - Types of routines stored in `pg_proc`
* `cat_tools.routine_argument_mode` - Argument modes for function/procedure parameters
* `cat_tools.routine_volatility` - Volatility levels for functions/procedures`
* `cat_tools.routine_parallel_safety` - Parallel safety levels for functions/procedures
* `cat_tools.routine_argument` - Detailed information about a single function/procedure argument

== Functions
== General Introspection Functions

* `cat_tools.currval(table, column)` - Returns current value for a sequence owned by a column
* `cat_tools.enum_range(regtype)` - Returns valid values for an ENUM as an array
Expand All @@ -32,19 +34,46 @@ Works on Postgres 9.3 and above.
* `cat_tools.pg_extension__get(extension_name name)` - Returns cat_tools.pg_extension_v row for an extension
* `cat_tools.extension__schemas(extension_names text/name[])` - Returns the schemas for the requested functions
* `cat_tools.extension__schemas_unique(extension_names text/name[])` - Returns a unique array of schemas
* `cat_tools.function__arg_types(arguments)` - Accepts full function argument string and returns regtype[] of IN/INOUT arguments
* `cat_tools.function__arg_types_text(arguments)` - Version of `function__arg_types` that returns text
* `cat_tools.object__catalog(object_type)` - Returns catalog table that is used to store `object_type` objects
* `cat_tools.object__reg_type(object_catalog)` - Returns the "reg" pseudotype (ie: regclass) associated with a system catalog (ie: pg_class)
* `cat_tools.regprocedure(function_name, arguments)` - Returns regprocedure for function_name and it's full set of arguments
* `cat_tools.relation__kind(relkind)` - Mapping from `pg_class.relkind` to a `cat_tools.relation_type`
* `cat_tools.relation__relkind(relation_type)` - Mapping from `cat_tools.relation_type` to a `pg_class.relkind` value
* `cat_tools.relation__column_names(relation regclass)` - Returns an array of quoted column names for a relation in ordinal position order
* `cat_tools.relation__is_catalog(relation regclass)` - Returns true if the relation is in the `pg_catalog` schema
* `cat_tools.relation__is_temp(relation regclass)` - Returns true if the relation is a temporary table (lives in a schema that starts with 'pg_temp')

== Routine / Function / Procedure Functions

* `cat_tools.routine__parse_arg_types(arguments)` - Accepts full function argument string and returns regtype[] of IN/INOUT arguments
* `cat_tools.routine__parse_arg_types_text(arguments)` - Version of `routine__parse_arg_types` that returns text
* `cat_tools.routine__parse_arg_names(arguments)` - Accepts full function argument string and returns text[] of IN/INOUT argument names
* `cat_tools.routine__parse_arg_names_text(arguments)` - Version of `routine__parse_arg_names` that returns text
* `cat_tools.routine__arg_types(regprocedure)` - Returns argument types for a function as regtype[]
* `cat_tools.routine__arg_types_text(regprocedure)` - Version of `routine__arg_types` that returns text
* `cat_tools.routine__arg_names(regprocedure)` - Returns argument names for a function as text[]
* `cat_tools.routine__arg_names_text(regprocedure)` - Version of `routine__arg_names` that returns text
* `cat_tools.regprocedure(routine_name, arguments)` - Returns regprocedure for routine_name and it's full set of arguments

== Trigger Functions

* `cat_tools.trigger__args_as_text(text)` - Converts the arguments for a trigger function (as returned by `trigger__parse()`) to text (for backwards compatibility).
* `cat_tools.trigger__get_oid(trigger_table, trigger_name)` - oid of a trigger. Throws error if trigger doesn't exits.
* `cat_tools.trigger__get_oid__loose(trigger_table, trigger_name)` - oid of a trigger. Does _not_ throw error if trigger doesn't exits.
* `cat_tools.trigger__parse(trigger oid)` - Returns information about a trigger
* `cat_tools.trigger__parse(table_name regclass, trigger_name text)` - Returns information about a trigger

== Mapping Functions

* `cat_tools.relation__kind(relkind)` - Mapping from `pg_class.relkind` to a `cat_tools.relation_type`
* `cat_tools.relation__relkind(relation_type)` - Mapping from `cat_tools.relation_type` to a `pg_class.relkind` value
* `cat_tools.routine__type(prokind)` - Mapping from `pg_proc.prokind` to `cat_tools.routine_type`
* `cat_tools.routine__argument_mode(mode)` - Mapping from `pg_proc.proargmodes` element to `cat_tools.routine_argument_mode`
* `cat_tools.routine__volatility(volatile)` - Mapping from `pg_proc.provolatile` to `cat_tools.routine_volatility`
* `cat_tools.routine__parallel_safety(parallel)` - Mapping from `pg_proc.proparallel` to `cat_tools.routine_parallel_safety`

== Deprecated Functions

* `cat_tools.function__arg_types(arguments)` - DEPRECATED: Use `routine__parse_arg_types` instead
* `cat_tools.function__arg_types_text(arguments)` - DEPRECATED: Use `routine__parse_arg_types_text` instead

== Views
WARNING: These views may eventually move into a separate extension!

Expand All @@ -58,4 +87,4 @@ Copyright and License

Cat Tools is released under a https://github.com/decibel/cattools/blob/master/LICENSE[MIT license].

Copyright (c) 2016 Jim Nasby <Jim.Nasby@BlueTreble.com>.
Copyright (c) 2025 Jim Nasby <Jim.Nasby@gmail.com>.
2 changes: 1 addition & 1 deletion cat_tools.control
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
comment = 'Tools for intorfacing with the catalog'
default_version = '0.2.1'
default_version = '0.3.0'
relocatable = false
schema = 'cat_tools'
3 changes: 3 additions & 0 deletions pgxntool/HISTORY.asc
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
STABLE
------
== Support 13+
The `--load-language` option was removed from `pg_regress` in 13.

== Reduce verbosity from test setup
As part of this change, you will want to review the changes to test/deps.sql.

Expand Down
6 changes: 4 additions & 2 deletions pgxntool/base.mk
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ TEST_SQL_FILES += $(wildcard $(TESTDIR)/sql/*.sql)
TEST_RESULT_FILES = $(patsubst $(TESTDIR)/sql/%.sql,$(TESTDIR)/expected/%.out,$(TEST_SQL_FILES))
TEST_FILES = $(TEST_SOURCE_FILES) $(TEST_SQL_FILES)
REGRESS = $(sort $(notdir $(subst .source,,$(TEST_FILES:.sql=)))) # Sort is to get unique list
REGRESS_OPTS = --inputdir=$(TESTDIR) --outputdir=$(TESTOUT) --load-language=plpgsql
REGRESS_OPTS = --inputdir=$(TESTDIR) --outputdir=$(TESTOUT) # See additional setup below
MODULES = $(patsubst %.c,%,$(wildcard src/*.c))
ifeq ($(strip $(MODULES)),)
MODULES =# Set to NUL so PGXS doesn't puke
Expand All @@ -57,8 +57,10 @@ GE91 = $(call test, $(MAJORVER), -ge, 91)

ifeq ($(GE91),yes)
all: $(EXTENSION_VERSION_FILES)
endif

#DATA = $(wildcard sql/*--*.sql)
ifeq ($($call test, $(MAJORVER), -lt 13), yes)
REGRESS_OPTS += --load-language=plpgsql
endif

PGXS := $(shell $(PG_CONFIG) --pgxs)
Expand Down
155 changes: 155 additions & 0 deletions sql/cat_tools--0.2.1--0.3.0.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
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
, 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$
;

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$;

ALTER TYPE cat_tools.relation_type ADD VALUE 'partitioned table';
ALTER TYPE cat_tools.relation_type ADD VALUE 'partitioned index';

ALTER TYPE cat_tools.relation_relkind ADD VALUE 'p';
ALTER TYPE cat_tools.relation_relkind ADD VALUE 'I';

ALTER TYPE cat_tools.object_type ADD VALUE 'partitioned table' AFTER 'foreign table';
ALTER TYPE cat_tools.object_type ADD VALUE 'partitioned index' AFTER 'partitioned table';


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'
WHEN 'p' THEN 'partitioned table'
WHEN 'I' THEN 'partitioned index'
END::cat_tools.relation_type
$body$
, 'cat_tools__usage'
, 'Mapping from <pg_class.relkind> to a <cat_tools.relation_type>'
);

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'
WHEN 'partitioned table' THEN 'p'
WHEN 'partitioned index' THEN 'I'
END::cat_tools.relation_relkind
$body$
, 'cat_tools__usage'
, 'Mapping from <cat_tools.relation_type> to a <pg_class.relkind> value'
);

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;
Loading