What feature or improvement would you like to see?
Summary
The ADBC PostgreSQL driver currently supports discovery of databases, schemas, tables (regular, views, materialized views, foreign, partitioned), columns, primary/foreign/unique/check constraints, and table statistics via GetStatistics(). However, PostgreSQL has a rich object model that data development tools need — functions, procedures, indexes, triggers, sequences, custom types, and more. This issue requests expanding metadata discovery to cover these gaps.
We build a collaborative data operations platform and currently query PostgreSQL system catalogs (pg_catalog) directly via JDBC for comprehensive metadata extraction. We are evaluating the ADBC driver as a modern Arrow-native replacement but cannot adopt it without coverage for the object categories listed below.
Each section describes what we need, why it matters, what metadata properties are required, and the exact pg_catalog queries to obtain it.
Table of Contents
- Functions (Scalar)
- Table-Returning Functions
- Aggregate Functions
- Stored Procedures (PG 12+)
- Function & Procedure Parameters
- Indexes
- Triggers
- Sequences
- View & Materialized View Definitions
- Exclusion Constraints
- Check Constraint Expressions
- Foreign Key Actions & Deferrability
- Reverse Foreign Keys (Referenced By)
- Partition Hierarchy
- Custom Types (Enums, Composites, Domains, Ranges)
- Extensions
- Foreign Data Wrappers & Foreign Servers
- Row-Level Security Policies
- Rules
- Database & Schema Properties
1. Functions (Scalar)
Motivation
User-defined functions are a core part of PostgreSQL's extensibility. They support SQL, PL/pgSQL, PL/Python, PL/Perl, C, and other languages. Functions can be overloaded (same name, different argument types). Data development tools need to enumerate them for autocomplete, signature help, documentation, and catalog browsing.
Required Metadata
| Property |
Description |
Source |
| OID |
Unique function identifier (needed for overload resolution) |
pg_proc.oid |
| Schema |
Containing schema |
pg_namespace.nspname |
| Function name |
Function identifier |
pg_proc.proname |
| Owner |
Function owner |
pg_roles.rolname via pg_proc.proowner |
| Language |
SQL, plpgsql, plpython3u, C, etc. |
pg_language.lanname via pg_proc.prolang |
| Return type |
Return data type |
format_type(pg_proc.prorettype, NULL) |
| Volatility |
VOLATILE, STABLE, IMMUTABLE |
pg_proc.provolatile |
| Is strict |
Returns NULL on NULL input |
pg_proc.proisstrict |
| Security definer |
Runs as definer vs invoker |
pg_proc.prosecdef |
| Source code |
Full CREATE FUNCTION statement |
pg_get_functiondef(pg_proc.oid) |
| Description |
User-provided comment |
pg_description |
| Parallel safety |
SAFE, RESTRICTED, UNSAFE |
pg_proc.proparallel (PG 9.6+) |
| Cost |
Estimated execution cost |
pg_proc.procost |
| Rows |
Estimated rows returned (set-returning) |
pg_proc.prorows |
How to Obtain
SELECT
p.oid,
p.proname AS name,
n.nspname AS schema,
r.rolname AS owner,
l.lanname AS language,
format_type(p.prorettype, NULL) AS return_type,
p.provolatile,
p.proisstrict,
p.prosecdef,
p.proparallel,
p.procost,
pg_get_functiondef(p.oid) AS definition,
d.description
FROM pg_catalog.pg_proc p
INNER JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
INNER JOIN pg_catalog.pg_language l ON l.oid = p.prolang
LEFT JOIN pg_catalog.pg_roles r ON r.oid = p.proowner
LEFT JOIN pg_catalog.pg_description d
ON d.objoid = p.oid
AND d.classoid = 'pg_proc'::regclass
AND d.objsubid = 0
WHERE n.nspname = $1
AND p.prokind = 'f' -- PG 11+; for older: NOT p.proisagg AND p.prorettype != 0
AND NOT p.proretset -- scalar only (not set-returning)
ORDER BY p.proname;
Overload Handling
PostgreSQL allows multiple functions with the same name but different argument types. The driver should:
- Use
pg_proc.oid as the unique identifier
- Include argument type signatures to distinguish overloads
- Group or label overloads clearly in results
2. Table-Returning Functions
Motivation
Set-returning functions (table functions) return tabular results and are used in FROM clauses. They need to be distinguished from scalar functions because they produce a result set with named columns.
Required Metadata
Same as scalar functions (section 1), plus:
| Property |
Description |
Source |
| Returns set |
Always true for table functions |
pg_proc.proretset |
| Result columns |
Column names and types |
Derived from return type or OUT params |
How to Identify
-- Table functions: prokind='f' AND proretset=true
WHERE p.prokind = 'f' AND p.proretset = true
Result columns come from:
pg_proc.proallargtypes + pg_proc.proargmodes — OUT and TABLE parameters define result columns
- Or from the return composite type via
pg_type + pg_attribute if returning a composite type
3. Aggregate Functions
Motivation
PostgreSQL has a rich aggregate function system supporting custom aggregates with transition functions, final functions, combine functions (for parallel aggregation), moving aggregates, and ordered-set/hypothetical-set aggregates. Tools need to display these alongside regular functions.
Required Metadata
| Property |
Description |
Source |
| All function properties |
Same as section 1 |
pg_proc |
| Aggregate kind |
Normal, ordered-set, hypothetical-set |
pg_aggregate.aggkind |
| Transition function |
State transition function |
pg_aggregate.aggtransfn |
| Final function |
Finalization function |
pg_aggregate.aggfinalfn |
| Combine function |
Parallel combine function |
pg_aggregate.aggcombinefn |
| Serialization function |
Parallel state serialization |
pg_aggregate.aggserialfn |
| Deserialization function |
Parallel state deserialization |
pg_aggregate.aggdeserialfn |
| Internal state type |
Transition state data type |
format_type(pg_aggregate.aggtranstype, NULL) |
| Initial value |
Transition state initial value |
pg_aggregate.agginitval |
| Sort operator |
Sort operator for min/max aggregates |
pg_operator.oprname via pg_aggregate.aggsortop |
| Moving transition function |
For moving aggregates (window mode) |
pg_aggregate.aggmtransfn |
| Moving inverse function |
Inverse transition for moving aggregates |
pg_aggregate.aggminvtransfn |
| Moving final function |
Final function for moving aggregates |
pg_aggregate.aggmfinalfn |
| Number of direct args |
For ordered-set aggregates |
pg_aggregate.aggnumdirectargs |
How to Obtain
SELECT
p.oid,
p.proname,
a.aggkind,
a.aggtransfn::regproc AS transition_function,
a.aggfinalfn::regproc AS final_function,
a.aggcombinefn::regproc AS combine_function,
a.aggserialfn::regproc AS serialization_function,
a.aggdeserialfn::regproc AS deserialization_function,
format_type(a.aggtranstype, NULL) AS internal_state_type,
a.agginitval AS initial_value,
a.aggkind,
a.aggnumdirectargs,
a.aggmtransfn::regproc AS moving_transition_function,
a.aggminvtransfn::regproc AS moving_inverse_function,
a.aggmfinalfn::regproc AS moving_final_function,
format_type(a.aggmtranstype, NULL) AS moving_state_type,
a.aggminitval AS moving_initial_value
FROM pg_catalog.pg_proc p
INNER JOIN pg_catalog.pg_aggregate a ON a.aggfnoid = p.oid
INNER JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
WHERE n.nspname = $1
AND p.prokind IN ('a', 'w') -- aggregate or window
ORDER BY p.proname;
4. Stored Procedures (PG 12+)
Motivation
PostgreSQL 12 introduced true stored procedures (distinct from functions) with transaction control capabilities (COMMIT/ROLLBACK). Tools need to distinguish procedures from functions and display them appropriately.
Required Metadata
Same as scalar functions (section 1), but:
| Property |
Description |
Source |
| Procedure kind |
Always 'p' |
pg_proc.prokind = 'p' |
| Support for CALL |
Invoked via CALL, not SELECT |
Implicit from kind |
| OUT parameters |
PG 14+ supports OUT args in procedures |
pg_proc.proargmodes |
How to Identify
WHERE p.prokind = 'p' -- PG 11+ only
Version Considerations
- PG < 11: No
prokind column. Use proisagg and return type heuristics
- PG 11:
prokind added but procedures are PG 12+
- PG 14: OUT parameters in procedures fully supported
5. Function & Procedure Parameters
Motivation
Parameter metadata enables signature help, call template generation, and documentation. PostgreSQL functions support IN, OUT, INOUT, and VARIADIC parameter modes.
Required Metadata
| Property |
Description |
Source |
| Parameter name |
May be unnamed |
pg_proc.proargnames[i] |
| Parameter type |
Data type OID |
pg_proc.proargtypes[i] (IN only) or pg_proc.proallargtypes[i] (all) |
| Parameter mode |
IN, OUT, INOUT, VARIADIC, TABLE |
pg_proc.proargmodes[i] |
| Ordinal position |
1-based |
Array index |
| Has default |
Whether parameter has a default |
pg_proc.pronargdefaults > 0 |
How to Obtain
Parameters are stored as arrays on pg_proc:
SELECT
p.oid,
p.proname,
p.proargtypes, -- IN argument type OIDs (oidvector)
p.proallargtypes, -- All argument type OIDs (including OUT)
p.proargnames, -- Argument names (text[])
p.proargmodes, -- Argument modes: i=IN, o=OUT, b=INOUT, v=VARIADIC, t=TABLE
p.pronargdefaults, -- Number of arguments with defaults
pg_get_function_arguments(p.oid) AS argument_list, -- Formatted argument list
pg_get_function_result(p.oid) AS result_type -- Formatted return type
FROM pg_catalog.pg_proc p
WHERE p.oid = $1;
The arrays must be unnested in application code or via UNNEST():
proargtypes only includes IN parameters
proallargtypes includes all parameters (IN, OUT, INOUT, VARIADIC, TABLE) — NULL if only IN params
proargmodes — NULL if all parameters are IN
proargnames — NULL entries for unnamed parameters
6. Indexes
Motivation
Index metadata is critical for query performance analysis, database optimization, and schema documentation. PostgreSQL supports multiple access methods (btree, hash, gin, gist, spgist, brin) with rich options (partial indexes, expression indexes, included columns, etc.).
Required Metadata
| Property |
Description |
Source |
| Index name |
Index identifier |
pg_class.relname (index class) |
| Table name |
Indexed table |
pg_class.relname (table class) |
| Access method |
btree, hash, gin, gist, spgist, brin |
pg_am.amname |
| Is unique |
Whether the index enforces uniqueness |
pg_index.indisunique |
| Is primary |
Whether it backs the primary key |
pg_index.indisprimary |
| Is clustered |
Whether the table is clustered on this index |
pg_index.indisclustered |
| Is valid |
Whether the index is valid (concurrent build may leave invalid) |
pg_index.indisvalid |
| Is exclusion |
Whether it backs an exclusion constraint |
pg_index.indisexclusion |
| Column count |
Number of index columns |
pg_class.relnatts |
| Column expressions |
Expression per column position |
pg_get_indexdef(indexrelid, col, true) |
| Column options |
ASC/DESC, NULLS FIRST/LAST per column |
pg_index.indoption |
| Partial predicate |
WHERE clause for partial indexes |
pg_get_expr(pg_index.indpred, indrelid) |
| Included columns |
Columns stored but not indexed (PG 11+) |
Columns beyond indnkeyatts |
| Full DDL |
Complete CREATE INDEX statement |
pg_get_indexdef(indexrelid) |
| Tablespace |
Tablespace storing the index |
pg_indexes.tablespace |
| Description |
User-provided comment |
pg_description |
| Size |
Index size in bytes |
pg_relation_size(indexrelid) |
How to Obtain
SELECT
ic.relname AS index_name,
tc.relname AS table_name,
am.amname AS access_method,
i.indisunique AS is_unique,
i.indisprimary AS is_primary,
i.indisclustered AS is_clustered,
i.indisvalid AS is_valid,
i.indisexclusion AS is_exclusion,
ic.relnatts AS column_count,
i.indnkeyatts AS key_column_count, -- PG 11+
i.indkey AS column_numbers,
i.indoption AS column_options,
pg_get_expr(i.indpred, i.indrelid) AS predicate,
pg_get_indexdef(i.indexrelid) AS definition,
pg_indexes.tablespace,
d.description,
pg_relation_size(i.indexrelid) AS size_bytes
FROM pg_catalog.pg_index i
INNER JOIN pg_catalog.pg_class ic ON ic.oid = i.indexrelid
INNER JOIN pg_catalog.pg_class tc ON tc.oid = i.indrelid
INNER JOIN pg_catalog.pg_namespace n ON n.oid = tc.relnamespace
INNER JOIN pg_catalog.pg_am am ON am.oid = ic.relam
LEFT JOIN pg_catalog.pg_indexes
ON pg_indexes.schemaname = n.nspname
AND pg_indexes.tablename = tc.relname
AND pg_indexes.indexname = ic.relname
LEFT JOIN pg_catalog.pg_description d
ON d.objoid = i.indexrelid
AND d.classoid = 'pg_class'::regclass
WHERE n.nspname = $1 AND tc.relname = $2
ORDER BY ic.relname;
Per-column expressions:
SELECT pg_get_indexdef(indexrelid, column_number, true) AS column_expression
7. Triggers
Motivation
Triggers are essential for understanding data modification side effects, audit logging, constraint enforcement, and event-driven logic. Tools need to display trigger metadata for schema comprehension and debugging.
Required Metadata
| Property |
Description |
Source |
| Trigger name |
Trigger identifier |
pg_trigger.tgname |
| Table name |
Table the trigger is on |
pg_class.relname |
| Timing |
BEFORE, AFTER, INSTEAD OF |
Decoded from pg_trigger.tgtype bits |
| Events |
INSERT, UPDATE, DELETE, TRUNCATE |
Decoded from pg_trigger.tgtype bits |
| Row/statement level |
FOR EACH ROW vs FOR EACH STATEMENT |
Decoded from pg_trigger.tgtype bit |
| Function name |
Trigger function called |
pg_proc.proname via pg_trigger.tgfoid |
| Function schema |
Schema of trigger function |
pg_namespace.nspname |
| Enabled state |
O=origin, D=disabled, R=replica, A=always |
pg_trigger.tgenabled |
| Deferrable |
Whether the trigger is deferrable |
pg_trigger.tgdeferrable |
| Initially deferred |
Default deferral state |
pg_trigger.tginitdeferred |
| Is internal |
System-generated (for constraint FK triggers) |
pg_trigger.tgisinternal |
| When condition |
Conditional execution expression |
pg_get_triggerdef() contains WHEN clause |
| Columns |
Specific columns for UPDATE OF |
pg_trigger.tgattr |
| Old table alias |
REFERENCING OLD TABLE AS name |
pg_trigger.tgoldtable |
| New table alias |
REFERENCING NEW TABLE AS name |
pg_trigger.tgnewtable |
| Constraint name |
For constraint triggers |
pg_trigger.tgconstrname |
| Referenced table |
For constraint triggers (FK table) |
pg_class.relname via pg_trigger.tgconstrrelid |
| Parent trigger |
For partition triggers (PG 13+) |
pg_trigger.tgparentid |
| Full DDL |
Complete CREATE TRIGGER statement |
pg_get_triggerdef(pg_trigger.oid) |
| Description |
User-provided comment |
pg_description |
How to Obtain
SELECT
t.oid,
t.tgname AS trigger_name,
tc.relname AS table_name,
pg_get_triggerdef(t.oid) AS definition,
t.tgtype,
t.tgenabled,
t.tgdeferrable,
t.tginitdeferred,
t.tgisinternal,
t.tgattr AS update_columns,
t.tgoldtable AS old_table_alias,
t.tgnewtable AS new_table_alias,
f.proname AS function_name,
fn.nspname AS function_schema,
t.tgconstrname AS constraint_name,
rt.relname AS referenced_table,
rn.nspname AS referenced_schema,
pt.tgname AS parent_trigger_name,
d.description
FROM pg_catalog.pg_trigger t
INNER JOIN pg_catalog.pg_class tc ON tc.oid = t.tgrelid
INNER JOIN pg_catalog.pg_namespace tn ON tn.oid = tc.relnamespace
LEFT JOIN pg_catalog.pg_proc f ON f.oid = t.tgfoid
LEFT JOIN pg_catalog.pg_namespace fn ON fn.oid = f.pronamespace
LEFT JOIN pg_catalog.pg_class rt ON rt.oid = t.tgconstrrelid
LEFT JOIN pg_catalog.pg_namespace rn ON rn.oid = rt.relnamespace
LEFT JOIN pg_catalog.pg_trigger pt ON pt.oid = t.tgparentid
LEFT JOIN pg_catalog.pg_description d
ON d.objoid = t.oid
AND d.classoid = 'pg_trigger'::regclass
WHERE tn.nspname = $1 AND tc.relname = $2
ORDER BY t.tgname;
Decoding tgtype
The tgtype column is a bitmask:
- Bit 0 (1): ROW-level (vs STATEMENT)
- Bit 1 (2): BEFORE (vs AFTER)
- Bit 2 (4): INSERT
- Bit 3 (8): DELETE
- Bit 4 (16): UPDATE
- Bit 5 (32): TRUNCATE
- Bit 6 (64): INSTEAD OF
8. Sequences
Motivation
Sequences generate unique numeric identifiers and are referenced by SERIAL/BIGSERIAL columns and GENERATED AS IDENTITY columns. Tools need to display sequence properties for schema comprehension.
Required Metadata
| Property |
Description |
Source |
| Sequence name |
Sequence identifier |
pg_class.relname (relkind='S') |
| Schema |
Containing schema |
pg_namespace.nspname |
| Data type |
smallint, integer, bigint |
format_type(pg_sequence.seqtypid, NULL) |
| Start value |
Initial value |
pg_sequence.seqstart |
| Increment |
Step value |
pg_sequence.seqincrement |
| Minimum value |
Lower bound |
pg_sequence.seqmin |
| Maximum value |
Upper bound |
pg_sequence.seqmax |
| Cache size |
Pre-allocated values |
pg_sequence.seqcache |
| Cycle |
Whether sequence wraps around |
pg_sequence.seqcycle |
| Last value |
Most recently used value |
pg_sequences.last_value |
| Owner |
Sequence owner |
pg_roles.rolname |
| Owned by column |
Owning column (for SERIAL) |
pg_depend → table.column |
| Description |
User-provided comment |
pg_description |
How to Obtain
SELECT
c.relname AS sequence_name,
n.nspname AS schema_name,
format_type(s.seqtypid, NULL) AS data_type,
s.seqstart AS start_value,
s.seqincrement AS increment_by,
s.seqmin AS min_value,
s.seqmax AS max_value,
s.seqcache AS cache_size,
s.seqcycle AS is_cycle,
r.rolname AS owner,
d.description
FROM pg_catalog.pg_sequence s
INNER JOIN pg_catalog.pg_class c ON c.oid = s.seqrelid
INNER JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
LEFT JOIN pg_catalog.pg_roles r ON r.oid = c.relowner
LEFT JOIN pg_catalog.pg_description d
ON d.objoid = c.oid
AND d.classoid = 'pg_class'::regclass
AND d.objsubid = 0
WHERE n.nspname = $1
ORDER BY c.relname;
For current last value (requires pg_sequences view, PG 10+):
SELECT last_value FROM pg_sequences WHERE schemaname = $1 AND sequencename = $2;
9. View & Materialized View Definitions
Motivation
View SQL is essential for understanding data transformations, debugging query behavior, migration, and documentation. The driver currently returns views as table objects but does not include their defining query.
Required Metadata
| Property |
Description |
Source |
| View name |
View identifier |
pg_class.relname |
| Definition |
The SELECT statement |
pg_views.definition or pg_get_viewdef() |
| Is materialized |
Regular view vs materialized |
pg_class.relkind ('v' vs 'm') |
| Check option |
CASCADED, LOCAL, or NONE |
pg_views.definition contains WITH CHECK OPTION |
| Tablespace |
Storage location (materialized views only) |
pg_tablespace.spcname |
How to Obtain
-- Views
SELECT viewname, definition
FROM pg_catalog.pg_views
WHERE schemaname = $1;
-- Materialized views
SELECT c.relname, pg_get_viewdef(c.oid, true) AS definition,
t.spcname AS tablespace
FROM pg_catalog.pg_class c
INNER JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
LEFT JOIN pg_catalog.pg_tablespace t ON t.oid = c.reltablespace
WHERE n.nspname = $1 AND c.relkind = 'm';
Suggested Approach
Add an optional table_definition (utf8) field to TABLE_SCHEMA in the GetObjects result, populated for views and materialized views.
10. Exclusion Constraints
Motivation
Exclusion constraints (EXCLUDE USING) are a PostgreSQL-specific constraint type that prevents overlapping values (commonly used with range types and GiST indexes). The driver currently supports PRIMARY KEY, FOREIGN KEY, UNIQUE, and CHECK constraints but not exclusion constraints.
Required Metadata
| Property |
Description |
Source |
| Constraint name |
Constraint identifier |
pg_constraint.conname |
| Constraint type |
EXCLUDE |
pg_constraint.contype = 'x' |
| Column names |
Columns in the constraint |
pg_constraint.conkey → pg_attribute.attname |
| Access method |
Index access method (typically gist) |
pg_am.amname via index |
| Full definition |
Complete constraint SQL |
pg_get_constraintdef(oid, true) |
| Index name |
Backing index |
pg_class.relname via pg_constraint.conindid |
How to Obtain
SELECT
con.conname AS constraint_name,
pg_get_constraintdef(con.oid, true) AS definition,
ic.relname AS index_name,
am.amname AS access_method
FROM pg_catalog.pg_constraint con
INNER JOIN pg_catalog.pg_class tc ON tc.oid = con.conrelid
INNER JOIN pg_catalog.pg_namespace n ON n.oid = con.connamespace
LEFT JOIN pg_catalog.pg_class ic ON ic.oid = con.conindid
LEFT JOIN pg_catalog.pg_am am ON am.oid = ic.relam
WHERE n.nspname = $1 AND tc.relname = $2
AND con.contype = 'x';
Note
The existing ADBC CONSTRAINT_SCHEMA would need a new constraint_type value ("EXCLUDE") and ideally a constraint_expression field to carry the full definition.
11. Check Constraint Expressions
Motivation
The driver currently returns check constraints with column names but not the actual expression. The expression is the most important part — it tells users what validation rule is being enforced (e.g., price > 0, status IN ('active', 'inactive')).
Required Metadata
| Property |
Description |
Source |
| Expression |
The CHECK expression text |
pg_get_constraintdef(oid, true) |
How to Obtain
SELECT
con.conname,
pg_get_constraintdef(con.oid, true) AS definition
FROM pg_catalog.pg_constraint con
WHERE con.contype = 'c' AND con.conrelid = $1::regclass;
Returns text like: CHECK ((price > 0)) or CHECK ((status = ANY (ARRAY['active'::text, 'inactive'::text]))).
Suggested Approach
Add a constraint_expression (utf8) field to CONSTRAINT_SCHEMA in the ADBC spec, or encode the expression in the existing constraint_column_names field as a single-element list.
12. Foreign Key Actions & Deferrability
Motivation
The driver currently returns foreign key references (referenced table and columns) but not the ON UPDATE/ON DELETE actions or deferrability settings. These are essential for understanding cascading behavior and constraint timing.
Required Metadata
| Property |
Description |
Source |
| On update action |
NO ACTION, RESTRICT, CASCADE, SET NULL, SET DEFAULT |
pg_constraint.confupdtype |
| On delete action |
NO ACTION, RESTRICT, CASCADE, SET NULL, SET DEFAULT |
pg_constraint.confdeltype |
| Match type |
FULL, PARTIAL, SIMPLE |
pg_constraint.confmatchtype |
| Is deferrable |
Whether the constraint can be deferred |
pg_constraint.condeferrable |
| Initially deferred |
Default deferral state |
pg_constraint.condeferred |
Action Code Mapping
| Code |
Action |
a |
NO ACTION |
r |
RESTRICT |
c |
CASCADE |
n |
SET NULL |
d |
SET DEFAULT |
How to Obtain
These columns are already available on pg_constraint, which the driver already queries for FK constraints. They just need to be included in the result.
13. Reverse Foreign Keys (Referenced By)
Motivation
When inspecting a table, users need to see not only which tables it references but also which tables reference it. This is essential for impact analysis — understanding what would break if a table or column is modified.
Required Metadata
| Property |
Description |
| Referencing schema |
Schema of the table holding the FK |
| Referencing table |
Table that holds the FK |
| FK constraint name |
Foreign key constraint name |
| Referencing columns |
Columns in the referencing table |
| Referenced columns |
Columns in the target table |
How to Obtain
SELECT
rn.nspname AS referencing_schema,
rc.relname AS referencing_table,
con.conname AS constraint_name,
con.conkey AS referencing_column_nums,
con.confkey AS referenced_column_nums
FROM pg_catalog.pg_constraint con
INNER JOIN pg_catalog.pg_class rc ON rc.oid = con.conrelid
INNER JOIN pg_catalog.pg_namespace rn ON rn.oid = rc.relnamespace
WHERE con.contype = 'f'
AND con.confrelid = $1::regclass -- the target table OID
ORDER BY rn.nspname, rc.relname, con.conname;
14. Partition Hierarchy
Motivation
PostgreSQL 10+ supports declarative partitioning. Tools need to display the partition hierarchy — the parent partitioned table and its child partitions, including partition bounds and strategy.
Required Metadata
| Property |
Description |
Source |
| Parent table |
Partitioned table name |
pg_class.relname (relkind='p') |
| Partition strategy |
RANGE, LIST, HASH |
pg_partitioned_table.partstrat |
| Partition key |
Key columns/expressions |
pg_partitioned_table.partattrs + pg_partitioned_table.partexprs |
| Child partitions |
List of partition table names |
pg_inherits.inhrelid → pg_class.relname |
| Partition bounds |
Bound specification per child |
pg_get_expr(pg_class.relpartbound, oid) |
How to Obtain
-- Partition strategy and key
SELECT
pt.partstrat,
pt.partnatts,
pt.partattrs,
pg_get_partkeydef(c.oid) AS partition_key_def
FROM pg_catalog.pg_partitioned_table pt
INNER JOIN pg_catalog.pg_class c ON c.oid = pt.partrelid
WHERE c.oid = $1::regclass;
-- Child partitions with bounds
SELECT
child.relname AS partition_name,
pg_get_expr(child.relpartbound, child.oid) AS partition_bound
FROM pg_catalog.pg_inherits i
INNER JOIN pg_catalog.pg_class child ON child.oid = i.inhrelid
WHERE i.inhparent = $1::regclass
ORDER BY child.relname;
15. Custom Types (Enums, Composites, Domains, Ranges)
Motivation
PostgreSQL's extensible type system is a major feature. Custom types appear in column definitions, function signatures, and domain constraints. Tools need to enumerate and describe them.
Required Metadata
Enum Types
| Property |
Description |
Source |
| Type name |
Enum type name |
pg_type.typname (typtype='e') |
| Schema |
Containing schema |
pg_namespace.nspname |
| Labels |
Ordered list of enum values |
pg_enum.enumlabel ordered by enumsortorder |
SELECT t.typname, n.nspname, e.enumlabel
FROM pg_catalog.pg_type t
INNER JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
INNER JOIN pg_catalog.pg_enum e ON e.enumtypid = t.oid
WHERE n.nspname = $1 AND t.typtype = 'e'
ORDER BY t.typname, e.enumsortorder;
Composite Types
| Property |
Description |
Source |
| Type name |
Composite type name |
pg_type.typname (typtype='c') |
| Fields |
Ordered list of field names and types |
pg_attribute for pg_type.typrelid |
SELECT t.typname, a.attname, format_type(a.atttypid, a.atttypmod) AS field_type, a.attnum
FROM pg_catalog.pg_type t
INNER JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
INNER JOIN pg_catalog.pg_attribute a ON a.attrelid = t.typrelid
WHERE n.nspname = $1 AND t.typtype = 'c'
AND a.attnum > 0 AND NOT a.attisdropped
AND NOT EXISTS (SELECT 1 FROM pg_class c WHERE c.oid = t.typrelid AND c.relkind IN ('r','v','m','p','f'))
ORDER BY t.typname, a.attnum;
Domain Types
| Property |
Description |
Source |
| Domain name |
Domain type name |
pg_type.typname (typtype='d') |
| Base type |
Underlying data type |
format_type(pg_type.typbasetype, pg_type.typtypmod) |
| Not null |
Whether domain is NOT NULL |
pg_type.typnotnull |
| Default |
Default expression |
pg_type.typdefault |
| Check constraints |
Domain constraints |
pg_constraint for domain OID |
SELECT t.typname, format_type(t.typbasetype, t.typtypmod) AS base_type,
t.typnotnull, t.typdefault,
pg_get_constraintdef(con.oid) AS constraint_def
FROM pg_catalog.pg_type t
INNER JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
LEFT JOIN pg_catalog.pg_constraint con ON con.contypid = t.oid
WHERE n.nspname = $1 AND t.typtype = 'd'
ORDER BY t.typname;
Range Types
| Property |
Description |
Source |
| Range name |
Range type name |
pg_type.typname (typtype='r') |
| Subtype |
Element type of range |
format_type(pg_range.rngsubtype, NULL) |
| Canonical function |
Canonicalization function |
pg_range.rngcanonical |
| Subtype diff function |
Difference function |
pg_range.rngsubdiff |
SELECT t.typname, format_type(r.rngsubtype, NULL) AS subtype,
r.rngcanonical::regproc, r.rngsubdiff::regproc
FROM pg_catalog.pg_type t
INNER JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
INNER JOIN pg_catalog.pg_range r ON r.rngtypid = t.oid
WHERE n.nspname = $1
ORDER BY t.typname;
16. Extensions
Motivation
Extensions package functions, types, operators, and other objects into installable modules. Tools need to show installed extensions for schema comprehension and dependency tracking.
Required Metadata
| Property |
Description |
Source |
| Extension name |
Extension identifier |
pg_extension.extname |
| Version |
Installed version |
pg_extension.extversion |
| Schema |
Installation schema |
pg_namespace.nspname via pg_extension.extnamespace |
| Relocatable |
Whether extension can be moved |
pg_extension.extrelocatable |
| Description |
Extension description |
pg_description or pg_available_extensions.comment |
How to Obtain
SELECT
e.extname,
e.extversion,
n.nspname AS schema,
e.extrelocatable,
ae.comment AS description
FROM pg_catalog.pg_extension e
INNER JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace
LEFT JOIN pg_catalog.pg_available_extensions ae ON ae.name = e.extname
ORDER BY e.extname;
17. Foreign Data Wrappers & Foreign Servers
Motivation
Foreign data wrappers (FDWs) enable access to external data sources. Tools need to display FDW and foreign server configurations to understand external data integration.
Required Metadata
Foreign Data Wrappers
| Property |
Description |
Source |
| FDW name |
Wrapper identifier |
pg_foreign_data_wrapper.fdwname |
| Handler function |
FDW handler |
pg_proc.proname via fdwhandler |
| Validator function |
FDW validator |
pg_proc.proname via fdwvalidator |
| Options |
Key-value options |
pg_foreign_data_wrapper.fdwoptions |
| Owner |
FDW owner |
pg_roles.rolname |
Foreign Servers
| Property |
Description |
Source |
| Server name |
Server identifier |
pg_foreign_server.srvname |
| FDW name |
Associated wrapper |
pg_foreign_data_wrapper.fdwname |
| Type |
Server type string |
pg_foreign_server.srvtype |
| Version |
Server version string |
pg_foreign_server.srvversion |
| Options |
Connection options (host, port, dbname, etc.) |
pg_foreign_server.srvoptions |
| Owner |
Server owner |
pg_roles.rolname |
How to Obtain
-- Foreign data wrappers
SELECT fdw.fdwname, h.proname AS handler, v.proname AS validator,
fdw.fdwoptions, r.rolname AS owner
FROM pg_catalog.pg_foreign_data_wrapper fdw
LEFT JOIN pg_catalog.pg_proc h ON h.oid = fdw.fdwhandler
LEFT JOIN pg_catalog.pg_proc v ON v.oid = fdw.fdwvalidator
LEFT JOIN pg_catalog.pg_roles r ON r.oid = fdw.fdwowner;
-- Foreign servers
SELECT s.srvname, fdw.fdwname, s.srvtype, s.srvversion,
s.srvoptions, r.rolname AS owner
FROM pg_catalog.pg_foreign_server s
INNER JOIN pg_catalog.pg_foreign_data_wrapper fdw ON fdw.oid = s.srvfdw
LEFT JOIN pg_catalog.pg_roles r ON r.oid = s.srvowner;
18. Row-Level Security Policies
Motivation
Row-level security (RLS) policies control which rows are visible or modifiable by different roles. Tools should display these policies for security audit and documentation.
Required Metadata
| Property |
Description |
Source |
| Policy name |
Policy identifier |
pg_policy.polname |
| Table name |
Table the policy applies to |
pg_class.relname |
| Command |
ALL, SELECT, INSERT, UPDATE, DELETE |
pg_policy.polcmd |
| Permissive/Restrictive |
Policy type |
pg_policy.polpermissive |
| Roles |
Roles the policy applies to |
pg_policy.polroles |
| USING expression |
Visibility filter |
pg_get_expr(pg_policy.polqual, polrelid) |
| WITH CHECK expression |
Modification filter |
pg_get_expr(pg_policy.polwithcheck, polrelid) |
How to Obtain
SELECT
pol.polname AS policy_name,
c.relname AS table_name,
pol.polcmd AS command,
pol.polpermissive AS is_permissive,
pol.polroles AS roles,
pg_get_expr(pol.polqual, pol.polrelid) AS using_expression,
pg_get_expr(pol.polwithcheck, pol.polrelid) AS with_check_expression
FROM pg_catalog.pg_policy pol
INNER JOIN pg_catalog.pg_class c ON c.oid = pol.polrelid
INNER JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname = $1
ORDER BY c.relname, pol.polname;
19. Rules
Motivation
Rules rewrite queries before execution. While triggers are generally preferred for most use cases, rules are used for view UPDATE/INSERT/DELETE support and some legacy patterns. Tools should display them when present.
Required Metadata
| Property |
Description |
Source |
| Rule name |
Rule identifier |
pg_rewrite.rulename |
| Table/view name |
Object the rule applies to |
pg_class.relname |
| Event |
SELECT, INSERT, UPDATE, DELETE |
pg_rewrite.ev_type |
| Is instead |
INSTEAD rule vs ALSO |
pg_rewrite.is_instead |
| Definition |
Full rule SQL |
pg_get_ruledef(oid) |
How to Obtain
SELECT
rw.rulename,
c.relname AS table_name,
rw.ev_type,
rw.is_instead,
pg_get_ruledef(rw.oid) AS definition
FROM pg_catalog.pg_rewrite rw
INNER JOIN pg_catalog.pg_class c ON c.oid = rw.ev_class
INNER JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname = $1
AND rw.rulename != '_RETURN' -- exclude default view rules
ORDER BY c.relname, rw.rulename;
20. Database & Schema Properties
Motivation
The driver currently returns database and schema names but no additional properties. Tools need descriptions, owners, and configuration for context display.
Required Metadata
Databases
| Property |
Description |
Source |
| Database name |
Database identifier |
pg_database.datname |
| Owner |
Database owner |
pg_roles.rolname via pg_database.datdba |
| Encoding |
Character encoding |
pg_encoding_to_char(pg_database.encoding) |
| Collation |
Default collation |
pg_database.datcollate |
| Tablespace |
Default tablespace |
pg_tablespace.spcname via pg_database.dattablespace |
| Connection limit |
Max concurrent connections |
pg_database.datconnlimit |
| Description |
User-provided comment |
pg_shdescription |
Schemas
| Property |
Description |
Source |
| Schema name |
Schema identifier |
pg_namespace.nspname |
| Owner |
Schema owner |
pg_roles.rolname via pg_namespace.nspowner |
| Description |
User-provided comment |
pg_description |
How to Obtain
-- Databases
SELECT d.datname, r.rolname AS owner,
pg_encoding_to_char(d.encoding) AS encoding,
d.datcollate, t.spcname AS tablespace,
d.datconnlimit, sd.description
FROM pg_catalog.pg_database d
LEFT JOIN pg_catalog.pg_roles r ON r.oid = d.datdba
LEFT JOIN pg_catalog.pg_tablespace t ON t.oid = d.dattablespace
LEFT JOIN pg_catalog.pg_shdescription sd
ON sd.objoid = d.oid AND sd.classoid = 'pg_database'::regclass
WHERE d.datname != 'template0';
-- Schemas
SELECT n.nspname, r.rolname AS owner, d.description
FROM pg_catalog.pg_namespace n
LEFT JOIN pg_catalog.pg_roles r ON r.oid = n.nspowner
LEFT JOIN pg_catalog.pg_description d
ON d.objoid = n.oid AND d.classoid = 'pg_namespace'::regclass
WHERE n.nspname NOT LIKE 'pg_temp_%' AND n.nspname NOT LIKE 'pg_toast_%';
Summary Priority Table
| # |
Category |
pg_catalog Source |
Impact |
| 1 |
Scalar Functions |
pg_proc (prokind='f') |
High — core SQL development |
| 2 |
Table Functions |
pg_proc (proretset=true) |
High — SQL development |
| 3 |
Aggregate Functions |
pg_proc + pg_aggregate |
High — SQL development |
| 4 |
Stored Procedures (PG 12+) |
pg_proc (prokind='p') |
High — SQL development |
| 5 |
Function/Procedure Parameters |
pg_proc arrays |
High — signature help |
| 6 |
Indexes |
pg_index + pg_am |
High — performance tuning |
| 7 |
Triggers |
pg_trigger |
High — schema comprehension |
| 8 |
Sequences |
pg_sequence |
Medium — schema browsing |
| 9 |
View/MV Definitions |
pg_views / pg_get_viewdef() |
High — SQL development |
| 10 |
Exclusion Constraints |
pg_constraint (contype='x') |
Medium — constraint completeness |
| 11 |
Check Constraint Expressions |
pg_get_constraintdef() |
Medium — constraint detail |
| 12 |
FK Actions & Deferrability |
pg_constraint columns |
Medium — constraint detail |
| 13 |
Reverse Foreign Keys |
pg_constraint (reversed) |
Medium — impact analysis |
| 14 |
Partition Hierarchy |
pg_partitioned_table + pg_inherits |
Medium — PG 10+ |
| 15 |
Custom Types |
pg_type + pg_enum + pg_range |
Medium — type system |
| 16 |
Extensions |
pg_extension |
Low — admin context |
| 17 |
Foreign Data Wrappers |
pg_foreign_data_wrapper + pg_foreign_server |
Low — external data |
| 18 |
Row-Level Security |
pg_policy |
Low — security audit |
| 19 |
Rules |
pg_rewrite |
Low — legacy feature |
| 20 |
Database & Schema Properties |
pg_database + pg_namespace |
Low — enriched context |
Note on GetStatistics
The ADBC PostgreSQL driver already implements GetStatistics() using pg_stats, which is a capability the other ADBC drivers (Databricks, Snowflake, BigQuery) lack. This is a strength of the PostgreSQL driver.
We're happy to provide further details on any of these categories.
What feature or improvement would you like to see?
Summary
The ADBC PostgreSQL driver currently supports discovery of databases, schemas, tables (regular, views, materialized views, foreign, partitioned), columns, primary/foreign/unique/check constraints, and table statistics via
GetStatistics(). However, PostgreSQL has a rich object model that data development tools need — functions, procedures, indexes, triggers, sequences, custom types, and more. This issue requests expanding metadata discovery to cover these gaps.We build a collaborative data operations platform and currently query PostgreSQL system catalogs (
pg_catalog) directly via JDBC for comprehensive metadata extraction. We are evaluating the ADBC driver as a modern Arrow-native replacement but cannot adopt it without coverage for the object categories listed below.Each section describes what we need, why it matters, what metadata properties are required, and the exact
pg_catalogqueries to obtain it.Table of Contents
1. Functions (Scalar)
Motivation
User-defined functions are a core part of PostgreSQL's extensibility. They support SQL, PL/pgSQL, PL/Python, PL/Perl, C, and other languages. Functions can be overloaded (same name, different argument types). Data development tools need to enumerate them for autocomplete, signature help, documentation, and catalog browsing.
Required Metadata
pg_proc.oidpg_namespace.nspnamepg_proc.pronamepg_roles.rolnameviapg_proc.proownerpg_language.lannameviapg_proc.prolangformat_type(pg_proc.prorettype, NULL)pg_proc.provolatilepg_proc.proisstrictpg_proc.prosecdefpg_get_functiondef(pg_proc.oid)pg_descriptionpg_proc.proparallel(PG 9.6+)pg_proc.procostpg_proc.prorowsHow to Obtain
Overload Handling
PostgreSQL allows multiple functions with the same name but different argument types. The driver should:
pg_proc.oidas the unique identifier2. Table-Returning Functions
Motivation
Set-returning functions (table functions) return tabular results and are used in FROM clauses. They need to be distinguished from scalar functions because they produce a result set with named columns.
Required Metadata
Same as scalar functions (section 1), plus:
pg_proc.proretsetHow to Identify
Result columns come from:
pg_proc.proallargtypes+pg_proc.proargmodes— OUT and TABLE parameters define result columnspg_type+pg_attributeif returning a composite type3. Aggregate Functions
Motivation
PostgreSQL has a rich aggregate function system supporting custom aggregates with transition functions, final functions, combine functions (for parallel aggregation), moving aggregates, and ordered-set/hypothetical-set aggregates. Tools need to display these alongside regular functions.
Required Metadata
pg_procpg_aggregate.aggkindpg_aggregate.aggtransfnpg_aggregate.aggfinalfnpg_aggregate.aggcombinefnpg_aggregate.aggserialfnpg_aggregate.aggdeserialfnformat_type(pg_aggregate.aggtranstype, NULL)pg_aggregate.agginitvalpg_operator.oprnameviapg_aggregate.aggsortoppg_aggregate.aggmtransfnpg_aggregate.aggminvtransfnpg_aggregate.aggmfinalfnpg_aggregate.aggnumdirectargsHow to Obtain
4. Stored Procedures (PG 12+)
Motivation
PostgreSQL 12 introduced true stored procedures (distinct from functions) with transaction control capabilities (
COMMIT/ROLLBACK). Tools need to distinguish procedures from functions and display them appropriately.Required Metadata
Same as scalar functions (section 1), but:
pg_proc.prokind = 'p'pg_proc.proargmodesHow to Identify
Version Considerations
prokindcolumn. Useproisaggand return type heuristicsprokindadded but procedures are PG 12+5. Function & Procedure Parameters
Motivation
Parameter metadata enables signature help, call template generation, and documentation. PostgreSQL functions support IN, OUT, INOUT, and VARIADIC parameter modes.
Required Metadata
pg_proc.proargnames[i]pg_proc.proargtypes[i](IN only) orpg_proc.proallargtypes[i](all)pg_proc.proargmodes[i]pg_proc.pronargdefaults > 0How to Obtain
Parameters are stored as arrays on
pg_proc:The arrays must be unnested in application code or via
UNNEST():proargtypesonly includes IN parametersproallargtypesincludes all parameters (IN, OUT, INOUT, VARIADIC, TABLE) — NULL if only IN paramsproargmodes— NULL if all parameters are INproargnames— NULL entries for unnamed parameters6. Indexes
Motivation
Index metadata is critical for query performance analysis, database optimization, and schema documentation. PostgreSQL supports multiple access methods (btree, hash, gin, gist, spgist, brin) with rich options (partial indexes, expression indexes, included columns, etc.).
Required Metadata
pg_class.relname(index class)pg_class.relname(table class)pg_am.amnamepg_index.indisuniquepg_index.indisprimarypg_index.indisclusteredpg_index.indisvalidpg_index.indisexclusionpg_class.relnattspg_get_indexdef(indexrelid, col, true)pg_index.indoptionpg_get_expr(pg_index.indpred, indrelid)indnkeyattspg_get_indexdef(indexrelid)pg_indexes.tablespacepg_descriptionpg_relation_size(indexrelid)How to Obtain
Per-column expressions:
7. Triggers
Motivation
Triggers are essential for understanding data modification side effects, audit logging, constraint enforcement, and event-driven logic. Tools need to display trigger metadata for schema comprehension and debugging.
Required Metadata
pg_trigger.tgnamepg_class.relnamepg_trigger.tgtypebitspg_trigger.tgtypebitspg_trigger.tgtypebitpg_proc.pronameviapg_trigger.tgfoidpg_namespace.nspnamepg_trigger.tgenabledpg_trigger.tgdeferrablepg_trigger.tginitdeferredpg_trigger.tgisinternalpg_get_triggerdef()contains WHEN clausepg_trigger.tgattrpg_trigger.tgoldtablepg_trigger.tgnewtablepg_trigger.tgconstrnamepg_class.relnameviapg_trigger.tgconstrrelidpg_trigger.tgparentidpg_get_triggerdef(pg_trigger.oid)pg_descriptionHow to Obtain
Decoding
tgtypeThe
tgtypecolumn is a bitmask:8. Sequences
Motivation
Sequences generate unique numeric identifiers and are referenced by
SERIAL/BIGSERIALcolumns andGENERATED AS IDENTITYcolumns. Tools need to display sequence properties for schema comprehension.Required Metadata
pg_class.relname(relkind='S')pg_namespace.nspnameformat_type(pg_sequence.seqtypid, NULL)pg_sequence.seqstartpg_sequence.seqincrementpg_sequence.seqminpg_sequence.seqmaxpg_sequence.seqcachepg_sequence.seqcyclepg_sequences.last_valuepg_roles.rolnamepg_depend→ table.columnpg_descriptionHow to Obtain
For current last value (requires
pg_sequencesview, PG 10+):9. View & Materialized View Definitions
Motivation
View SQL is essential for understanding data transformations, debugging query behavior, migration, and documentation. The driver currently returns views as table objects but does not include their defining query.
Required Metadata
pg_class.relnamepg_views.definitionorpg_get_viewdef()pg_class.relkind('v' vs 'm')pg_views.definitioncontainsWITH CHECK OPTIONpg_tablespace.spcnameHow to Obtain
Suggested Approach
Add an optional
table_definition(utf8) field toTABLE_SCHEMAin theGetObjectsresult, populated for views and materialized views.10. Exclusion Constraints
Motivation
Exclusion constraints (
EXCLUDE USING) are a PostgreSQL-specific constraint type that prevents overlapping values (commonly used with range types and GiST indexes). The driver currently supports PRIMARY KEY, FOREIGN KEY, UNIQUE, and CHECK constraints but not exclusion constraints.Required Metadata
pg_constraint.connamepg_constraint.contype = 'x'pg_constraint.conkey→pg_attribute.attnamepg_am.amnamevia indexpg_get_constraintdef(oid, true)pg_class.relnameviapg_constraint.conindidHow to Obtain
Note
The existing ADBC
CONSTRAINT_SCHEMAwould need a newconstraint_typevalue ("EXCLUDE") and ideally aconstraint_expressionfield to carry the full definition.11. Check Constraint Expressions
Motivation
The driver currently returns check constraints with column names but not the actual expression. The expression is the most important part — it tells users what validation rule is being enforced (e.g.,
price > 0,status IN ('active', 'inactive')).Required Metadata
pg_get_constraintdef(oid, true)How to Obtain
Returns text like:
CHECK ((price > 0))orCHECK ((status = ANY (ARRAY['active'::text, 'inactive'::text]))).Suggested Approach
Add a
constraint_expression(utf8) field toCONSTRAINT_SCHEMAin the ADBC spec, or encode the expression in the existingconstraint_column_namesfield as a single-element list.12. Foreign Key Actions & Deferrability
Motivation
The driver currently returns foreign key references (referenced table and columns) but not the ON UPDATE/ON DELETE actions or deferrability settings. These are essential for understanding cascading behavior and constraint timing.
Required Metadata
pg_constraint.confupdtypepg_constraint.confdeltypepg_constraint.confmatchtypepg_constraint.condeferrablepg_constraint.condeferredAction Code Mapping
arcndHow to Obtain
These columns are already available on
pg_constraint, which the driver already queries for FK constraints. They just need to be included in the result.13. Reverse Foreign Keys (Referenced By)
Motivation
When inspecting a table, users need to see not only which tables it references but also which tables reference it. This is essential for impact analysis — understanding what would break if a table or column is modified.
Required Metadata
How to Obtain
14. Partition Hierarchy
Motivation
PostgreSQL 10+ supports declarative partitioning. Tools need to display the partition hierarchy — the parent partitioned table and its child partitions, including partition bounds and strategy.
Required Metadata
pg_class.relname(relkind='p')pg_partitioned_table.partstratpg_partitioned_table.partattrs+pg_partitioned_table.partexprspg_inherits.inhrelid→pg_class.relnamepg_get_expr(pg_class.relpartbound, oid)How to Obtain
15. Custom Types (Enums, Composites, Domains, Ranges)
Motivation
PostgreSQL's extensible type system is a major feature. Custom types appear in column definitions, function signatures, and domain constraints. Tools need to enumerate and describe them.
Required Metadata
Enum Types
pg_type.typname(typtype='e')pg_namespace.nspnamepg_enum.enumlabelordered byenumsortorderComposite Types
pg_type.typname(typtype='c')pg_attributeforpg_type.typrelidDomain Types
pg_type.typname(typtype='d')format_type(pg_type.typbasetype, pg_type.typtypmod)pg_type.typnotnullpg_type.typdefaultpg_constraintfor domain OIDRange Types
pg_type.typname(typtype='r')format_type(pg_range.rngsubtype, NULL)pg_range.rngcanonicalpg_range.rngsubdiff16. Extensions
Motivation
Extensions package functions, types, operators, and other objects into installable modules. Tools need to show installed extensions for schema comprehension and dependency tracking.
Required Metadata
pg_extension.extnamepg_extension.extversionpg_namespace.nspnameviapg_extension.extnamespacepg_extension.extrelocatablepg_descriptionorpg_available_extensions.commentHow to Obtain
17. Foreign Data Wrappers & Foreign Servers
Motivation
Foreign data wrappers (FDWs) enable access to external data sources. Tools need to display FDW and foreign server configurations to understand external data integration.
Required Metadata
Foreign Data Wrappers
pg_foreign_data_wrapper.fdwnamepg_proc.pronameviafdwhandlerpg_proc.pronameviafdwvalidatorpg_foreign_data_wrapper.fdwoptionspg_roles.rolnameForeign Servers
pg_foreign_server.srvnamepg_foreign_data_wrapper.fdwnamepg_foreign_server.srvtypepg_foreign_server.srvversionpg_foreign_server.srvoptionspg_roles.rolnameHow to Obtain
18. Row-Level Security Policies
Motivation
Row-level security (RLS) policies control which rows are visible or modifiable by different roles. Tools should display these policies for security audit and documentation.
Required Metadata
pg_policy.polnamepg_class.relnamepg_policy.polcmdpg_policy.polpermissivepg_policy.polrolespg_get_expr(pg_policy.polqual, polrelid)pg_get_expr(pg_policy.polwithcheck, polrelid)How to Obtain
19. Rules
Motivation
Rules rewrite queries before execution. While triggers are generally preferred for most use cases, rules are used for view UPDATE/INSERT/DELETE support and some legacy patterns. Tools should display them when present.
Required Metadata
pg_rewrite.rulenamepg_class.relnamepg_rewrite.ev_typepg_rewrite.is_insteadpg_get_ruledef(oid)How to Obtain
20. Database & Schema Properties
Motivation
The driver currently returns database and schema names but no additional properties. Tools need descriptions, owners, and configuration for context display.
Required Metadata
Databases
pg_database.datnamepg_roles.rolnameviapg_database.datdbapg_encoding_to_char(pg_database.encoding)pg_database.datcollatepg_tablespace.spcnameviapg_database.dattablespacepg_database.datconnlimitpg_shdescriptionSchemas
pg_namespace.nspnamepg_roles.rolnameviapg_namespace.nspownerpg_descriptionHow to Obtain
Summary Priority Table
pg_proc(prokind='f')pg_proc(proretset=true)pg_proc+pg_aggregatepg_proc(prokind='p')pg_procarrayspg_index+pg_ampg_triggerpg_sequencepg_views/pg_get_viewdef()pg_constraint(contype='x')pg_get_constraintdef()pg_constraintcolumnspg_constraint(reversed)pg_partitioned_table+pg_inheritspg_type+pg_enum+pg_rangepg_extensionpg_foreign_data_wrapper+pg_foreign_serverpg_policypg_rewritepg_database+pg_namespaceNote on GetStatistics
The ADBC PostgreSQL driver already implements
GetStatistics()usingpg_stats, which is a capability the other ADBC drivers (Databricks, Snowflake, BigQuery) lack. This is a strength of the PostgreSQL driver.We're happy to provide further details on any of these categories.