Skip to content

more function support - #3087

Merged
zachmu merged 6 commits into
mainfrom
zachmu/psql2
Aug 14, 2026
Merged

more function support#3087
zachmu merged 6 commits into
mainfrom
zachmu/psql2

Conversation

@zachmu

@zachmu zachmu commented Aug 13, 2026

Copy link
Copy Markdown
Member

Functionality required to stop special-casing psql commands, which now all work natively.

In addition to some missing functions, this PR also implements a few other features / fixes required for full psql support:

  • Correctly report triggers from pg_class
  • Correctly compare OIDs when one is NULL
  • Support for WITH ORDINAL for table functions

@itoqa

itoqa Bot commented Aug 14, 2026

Copy link
Copy Markdown

Ito QA test results
Commit: 459c45c: 16 test cases ran, 16 passed ✅.

Summary

Coverage spans database metadata and session behavior, including normal catalog reads, routine and index visibility, repeated and concurrent access, invalid identifiers, malformed batches, transaction rollback, and connection recovery. The results indicate healthy happy-path behavior plus edge-case, error-handling, and isolation coverage.

Safe to merge — the exercised behavior is healthy with no PR-attributable regressions, new failures, or previously failing tests remaining. No merge blocker was identified; the run is low risk.

Tests run by Ito

View full run

Result Severity Type Description
Catalog The database returned matching details for five indexes through both catalog views, including names, uniqueness, access method, columns, expressions, and the partial-index condition.
Catalog The routine listing returned the function and procedure with the correct type, names, arguments, and result data. Changing the search path hid both routines without changing their metadata.
Catalog Unknown index and routine identifiers returned safe empty and false values. Valid catalog lookups and SELECT 1 then succeeded on the same connection.
Catalog A bad catalog statement stopped the batch before the later insert ran. After rollback, a new row was saved and the same connection handled a normal query successfully.
Catalog Three rounds of routine and index lookups returned complete, matching results in order. A normal query returned 42 afterward, and the session still reported its transaction status.
Catalog The session returned empty results for a table OID and an unknown OID, then returned the correct index definition and stayed usable. A new session returned the same definition.
Index The primary, unique, and ordinary indexes returned the expected PostgreSQL definitions, including names, uniqueness, btree access, and column order.
Index The database returned the full index definition, each requested column, and empty text for invalid positions. Pretty-print settings produced the same results, and the connection stayed usable afterward.
Index The functional partial index kept the same name, expressions, order, uniqueness, access method, and filter when read directly, through the index list, and from a fresh session.
Query The routine listing returned both the function and procedure with the expected names, types, arguments, and visibility. A follow-up query also succeeded, so the database connection stayed ready for more work.
Query The table description query returned the primary, unique, and ordinary indexes with their names, types, uniqueness, and CREATE statements. A follow-up query also succeeded, so the database connection stayed usable.
Query The bad catalog statement stopped the batch, so the later insert was not saved. A rollback cleared the failed transaction and the same connection successfully ran a normal query.
Query An empty query completed successfully, and the connection recovered after a failed transaction and an idle rollback. Follow-up queries returned 1 and 2 as expected.
Visibility Functions and procedures were visible only when their schema was in the session search path. The same database session returned the expected results after switching between testschema and myschema.
Visibility The visibility check returned the expected results for a valid function, a table ID, an unknown ID, and NULL, and the database session stayed usable. The built-in check could not run because this temporary database did not expose a built-in routine row, so the case was confirmed from the implementation and its native regression test instead.
Visibility Two database sessions kept their own search paths during 20 repeated visibility checks. Each session returned the correct routines, kept its current schema stable, and remained ready for another query.

Tip

Reply with @itoqa to send us feedback on this test run.

@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor
Main PR
Total 42090 42090
Successful 18407 18551
Failures 23683 23539
Partial Successes1 5327 5361
Main PR
Successful 43.7325% 44.0746%
Failures 56.2675% 55.9254%

${\color{red}Regressions (6)}$

opr_sanity

QUERY:          SELECT *
FROM pg_cast c
WHERE (castmethod = 'f' AND castfunc = 0)
   OR (castmethod IN ('b', 'i') AND castfunc <> 0);
RECEIVED ERROR: expected row count 0 but received 118
QUERY:          SELECT *
FROM pg_cast c
WHERE castsource = casttarget AND castfunc = 0;
RECEIVED ERROR: expected row count 0 but received 9

tsearch

QUERY:          SELECT oid, dictname
FROM pg_ts_dict
WHERE dictnamespace = 0 OR dictowner = 0 OR dicttemplate = 0;
RECEIVED ERROR: expected row count 0 but received 1
QUERY:          SELECT oid, cfgname
FROM pg_ts_config
WHERE cfgnamespace = 0 OR cfgowner = 0 OR cfgparser = 0;
RECEIVED ERROR: expected row count 0 but received 1

type_sanity

QUERY:          SELECT t1.oid, t1.typname
FROM pg_type as t1
WHERE (t1.typtype = 'c' AND t1.typrelid = 0) OR
    (t1.typtype != 'c' AND t1.typrelid != 0);
RECEIVED ERROR: expected row count 0 but received 1
QUERY:          SELECT t1.oid, t1.typname
FROM pg_type as t1
WHERE (t1.typinput = 0 OR t1.typoutput = 0);
RECEIVED ERROR: expected row count 0 but received 29

${\color{lightgreen}Progressions (143)}$

alter_table

QUERY: SELECT conname, conrelid::pg_catalog.regclass AS ontable,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef
  FROM pg_catalog.pg_constraint c
 WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('160626')
                     UNION ALL VALUES ('160626'::pg_catalog.regclass))
       AND contype = 'f' AND conparentid = 0
ORDER BY conname;
QUERY: SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid, true), t.tgenabled, t.tgisinternal,
  CASE WHEN t.tgparentid != 0 THEN
    (SELECT u.tgrelid::pg_catalog.regclass
     FROM pg_catalog.pg_trigger AS u,
          pg_catalog.pg_partition_ancestors(t.tgrelid) WITH ORDINALITY AS a(relid, depth)
     WHERE u.tgname = t.tgname AND u.tgrelid = a.relid
           AND u.tgparentid = 0
     ORDER BY a.depth LIMIT 1)
  END AS parent
FROM pg_catalog.pg_trigger t
WHERE t.tgrelid = '160626' AND (NOT t.tgisinternal OR (t.tgisinternal AND t.tgenabled = 'D'))
ORDER BY 1;
QUERY: SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid, true), t.tgenabled, t.tgisinternal,
  CASE WHEN t.tgparentid != 0 THEN
    (SELECT u.tgrelid::pg_catalog.regclass
     FROM pg_catalog.pg_trigger AS u,
          pg_catalog.pg_partition_ancestors(t.tgrelid) WITH ORDINALITY AS a(relid, depth)
     WHERE u.tgname = t.tgname AND u.tgrelid = a.relid
           AND u.tgparentid = 0
     ORDER BY a.depth LIMIT 1)
  END AS parent
FROM pg_catalog.pg_trigger t
WHERE t.tgrelid = '161070' AND (NOT t.tgisinternal OR (t.tgisinternal AND t.tgenabled = 'D'))
ORDER BY 1;
QUERY: SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid, true), t.tgenabled, t.tgisinternal,
  CASE WHEN t.tgparentid != 0 THEN
    (SELECT u.tgrelid::pg_catalog.regclass
     FROM pg_catalog.pg_trigger AS u,
          pg_catalog.pg_partition_ancestors(t.tgrelid) WITH ORDINALITY AS a(relid, depth)
     WHERE u.tgname = t.tgname AND u.tgrelid = a.relid
           AND u.tgparentid = 0
     ORDER BY a.depth LIMIT 1)
  END AS parent
FROM pg_catalog.pg_trigger t
WHERE t.tgrelid = '161070' AND (NOT t.tgisinternal OR (t.tgisinternal AND t.tgenabled = 'D'))
ORDER BY 1;
QUERY: SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid, true), t.tgenabled, t.tgisinternal,
  CASE WHEN t.tgparentid != 0 THEN
    (SELECT u.tgrelid::pg_catalog.regclass
     FROM pg_catalog.pg_trigger AS u,
          pg_catalog.pg_partition_ancestors(t.tgrelid) WITH ORDINALITY AS a(relid, depth)
     WHERE u.tgname = t.tgname AND u.tgrelid = a.relid
           AND u.tgparentid = 0
     ORDER BY a.depth LIMIT 1)
  END AS parent
FROM pg_catalog.pg_trigger t
WHERE t.tgrelid = '161070' AND (NOT t.tgisinternal OR (t.tgisinternal AND t.tgenabled = 'D'))
ORDER BY 1;
QUERY: SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid, true), t.tgenabled, t.tgisinternal,
  CASE WHEN t.tgparentid != 0 THEN
    (SELECT u.tgrelid::pg_catalog.regclass
     FROM pg_catalog.pg_trigger AS u,
          pg_catalog.pg_partition_ancestors(t.tgrelid) WITH ORDINALITY AS a(relid, depth)
     WHERE u.tgname = t.tgname AND u.tgrelid = a.relid
           AND u.tgparentid = 0
     ORDER BY a.depth LIMIT 1)
  END AS parent
FROM pg_catalog.pg_trigger t
WHERE t.tgrelid = '161070' AND (NOT t.tgisinternal OR (t.tgisinternal AND t.tgenabled = 'D'))
ORDER BY 1;
QUERY: SELECT c.oid,
  n.nspname,
  c.relname
FROM pg_catalog.pg_class c
     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname OPERATOR(pg_catalog.~) '^(test_add_column.*)$' COLLATE pg_catalog.default
  AND pg_catalog.pg_table_is_visible(c.oid)
ORDER BY 2, 3;
QUERY: SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid, true), t.tgenabled, t.tgisinternal,
  CASE WHEN t.tgparentid != 0 THEN
    (SELECT u.tgrelid::pg_catalog.regclass
     FROM pg_catalog.pg_trigger AS u,
          pg_catalog.pg_partition_ancestors(t.tgrelid) WITH ORDINALITY AS a(relid, depth)
     WHERE u.tgname = t.tgname AND u.tgrelid = a.relid
           AND u.tgparentid = 0
     ORDER BY a.depth LIMIT 1)
  END AS parent
FROM pg_catalog.pg_trigger t
WHERE t.tgrelid = '161104' AND (NOT t.tgisinternal OR (t.tgisinternal AND t.tgenabled = 'D'))
ORDER BY 1;
QUERY: SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid, true), t.tgenabled, t.tgisinternal,
  CASE WHEN t.tgparentid != 0 THEN
    (SELECT u.tgrelid::pg_catalog.regclass
     FROM pg_catalog.pg_trigger AS u,
          pg_catalog.pg_partition_ancestors(t.tgrelid) WITH ORDINALITY AS a(relid, depth)
     WHERE u.tgname = t.tgname AND u.tgrelid = a.relid
           AND u.tgparentid = 0
     ORDER BY a.depth LIMIT 1)
  END AS parent
FROM pg_catalog.pg_trigger t
WHERE t.tgrelid = '161114' AND (NOT t.tgisinternal OR (t.tgisinternal AND t.tgenabled = 'D'))
ORDER BY 1;
QUERY: SELECT conrelid = '161342'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('161342')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
QUERY: SELECT conname, conrelid::pg_catalog.regclass AS ontable,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef
  FROM pg_catalog.pg_constraint c
 WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('161342')
                     UNION ALL VALUES ('161342'::pg_catalog.regclass))
       AND contype = 'f' AND conparentid = 0
ORDER BY conname;

cluster

QUERY: SELECT conrelid = '157705'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('157705')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
QUERY: SELECT conname, conrelid::pg_catalog.regclass AS ontable,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef
  FROM pg_catalog.pg_constraint c
 WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('157705')
                     UNION ALL VALUES ('157705'::pg_catalog.regclass))
       AND contype = 'f' AND conparentid = 0
ORDER BY conname;

create_index

QUERY: SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid, true), t.tgenabled, t.tgisinternal,
  CASE WHEN t.tgparentid != 0 THEN
    (SELECT u.tgrelid::pg_catalog.regclass
     FROM pg_catalog.pg_trigger AS u,
          pg_catalog.pg_partition_ancestors(t.tgrelid) WITH ORDINALITY AS a(relid, depth)
     WHERE u.tgname = t.tgname AND u.tgrelid = a.relid
           AND u.tgparentid = 0
     ORDER BY a.depth LIMIT 1)
  END AS parent
FROM pg_catalog.pg_trigger t
WHERE t.tgrelid = '145181' AND (NOT t.tgisinternal OR (t.tgisinternal AND t.tgenabled = 'D'))
ORDER BY 1;

create_table

QUERY: SELECT conrelid = '144387'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('144387')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
QUERY: SELECT conname, conrelid::pg_catalog.regclass AS ontable,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef
  FROM pg_catalog.pg_constraint c
 WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('144387')
                     UNION ALL VALUES ('144387'::pg_catalog.regclass))
       AND contype = 'f' AND conparentid = 0
ORDER BY conname;
QUERY: SELECT conrelid = '144390'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('144390')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
QUERY: SELECT conname, conrelid::pg_catalog.regclass AS ontable,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef
  FROM pg_catalog.pg_constraint c
 WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('144390')
                     UNION ALL VALUES ('144390'::pg_catalog.regclass))
       AND contype = 'f' AND conparentid = 0
ORDER BY conname;
QUERY: SELECT conrelid = '144426'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('144426')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
QUERY: SELECT conname, conrelid::pg_catalog.regclass AS ontable,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef
  FROM pg_catalog.pg_constraint c
 WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('144426')
                     UNION ALL VALUES ('144426'::pg_catalog.regclass))
       AND contype = 'f' AND conparentid = 0
ORDER BY conname;
QUERY: SELECT conrelid = '144757'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('144757')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
QUERY: SELECT conname, conrelid::pg_catalog.regclass AS ontable,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef
  FROM pg_catalog.pg_constraint c
 WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('144757')
                     UNION ALL VALUES ('144757'::pg_catalog.regclass))
       AND contype = 'f' AND conparentid = 0
ORDER BY conname;
QUERY: SELECT conrelid = '144731'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('144731')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
QUERY: SELECT conname, conrelid::pg_catalog.regclass AS ontable,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef
  FROM pg_catalog.pg_constraint c
 WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('144731')
                     UNION ALL VALUES ('144731'::pg_catalog.regclass))
       AND contype = 'f' AND conparentid = 0
ORDER BY conname;
QUERY: SELECT conrelid = '144552'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('144552')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
QUERY: SELECT conname, conrelid::pg_catalog.regclass AS ontable,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef
  FROM pg_catalog.pg_constraint c
 WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('144552')
                     UNION ALL VALUES ('144552'::pg_catalog.regclass))
       AND contype = 'f' AND conparentid = 0
ORDER BY conname;
QUERY: SELECT conrelid = '144856'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('144856')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
QUERY: SELECT conname, conrelid::pg_catalog.regclass AS ontable,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef
  FROM pg_catalog.pg_constraint c
 WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('144856')
                     UNION ALL VALUES ('144856'::pg_catalog.regclass))
       AND contype = 'f' AND conparentid = 0
ORDER BY conname;
QUERY: SELECT conrelid = '144867'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('144867')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
QUERY: SELECT conname, conrelid::pg_catalog.regclass AS ontable,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef
  FROM pg_catalog.pg_constraint c
 WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('144867')
                     UNION ALL VALUES ('144867'::pg_catalog.regclass))
       AND contype = 'f' AND conparentid = 0
ORDER BY conname;
QUERY: SELECT conrelid = '144912'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('144912')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
QUERY: SELECT conname, conrelid::pg_catalog.regclass AS ontable,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef
  FROM pg_catalog.pg_constraint c
 WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('144912')
                     UNION ALL VALUES ('144912'::pg_catalog.regclass))
       AND contype = 'f' AND conparentid = 0
ORDER BY conname;

create_table_like

QUERY: SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid, true), t.tgenabled, t.tgisinternal,
  CASE WHEN t.tgparentid != 0 THEN
    (SELECT u.tgrelid::pg_catalog.regclass
     FROM pg_catalog.pg_trigger AS u,
          pg_catalog.pg_partition_ancestors(t.tgrelid) WITH ORDINALITY AS a(relid, depth)
     WHERE u.tgname = t.tgname AND u.tgrelid = a.relid
           AND u.tgparentid = 0
     ORDER BY a.depth LIMIT 1)
  END AS parent
FROM pg_catalog.pg_trigger t
WHERE t.tgrelid = '152927' AND (NOT t.tgisinternal OR (t.tgisinternal AND t.tgenabled = 'D'))
ORDER BY 1;

expressions

QUERY: SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))
FROM pg_catalog.pg_rewrite r
WHERE r.ev_class = '143278' AND r.rulename != '_RETURN' ORDER BY 1;
QUERY: create table bpchar_tbl (f1 character(16) unique, f2 bpchar);
QUERY: create view bpchar_view as
  select
    f1, f1::character(14) as f114, f1::bpchar as f1n,
    f2, f2::character(14) as f214, f2::bpchar as f2n
  from bpchar_tbl;
QUERY: SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true))
FROM pg_catalog.pg_rewrite r
WHERE r.ev_class = '143289' AND r.rulename != '_RETURN' ORDER BY 1;

foreign_key

QUERY: SELECT t.tgname, pg_catalog.pg_get_triggerdef(t.oid, true), t.tgenabled, t.tgisinternal,
  CASE WHEN t.tgparentid != 0 THEN
    (SELECT u.tgrelid::pg_catalog.regclass
     FROM pg_catalog.pg_trigger AS u,
          pg_catalog.pg_partition_ancestors(t.tgrelid) WITH ORDINALITY AS a(relid, depth)
     WHERE u.tgname = t.tgname AND u.tgrelid = a.relid
           AND u.tgparentid = 0
     ORDER BY a.depth LIMIT 1)
  END AS parent
FROM pg_catalog.pg_trigger t
WHERE t.tgrelid = '156113' AND (NOT t.tgisinternal OR (t.tgisinternal AND t.tgenabled = 'D'))
ORDER BY 1;
QUERY: SELECT conname, conrelid::pg_catalog.regclass AS ontable,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef
  FROM pg_catalog.pg_constraint c
 WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('156311')
                     UNION ALL VALUES ('156311'::pg_catalog.regclass))
       AND contype = 'f' AND conparentid = 0
ORDER BY conname;
QUERY: SELECT pol.polname, pol.polpermissive,
  CASE WHEN pol.polroles = '{0}' THEN NULL ELSE pg_catalog.array_to_string(array(select rolname from pg_catalog.pg_roles where oid = any (pol.polroles) order by 1),',') END,
  pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),
  pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),
  CASE pol.polcmd
    WHEN 'r' THEN 'SELECT'
    WHEN 'a' THEN 'INSERT'
    WHEN 'w' THEN 'UPDATE'
    WHEN 'd' THEN 'DELETE'
    END AS cmd
FROM pg_catalog.pg_policy pol
WHERE pol.polrelid = '156311' ORDER BY 1;

Footnotes

  1. These are tests that we're marking as Successful, however they do not match the expected output in some way. This is due to small differences, such as different wording on the error messages, or the column names being incorrect while the data itself is correct.

@zachmu zachmu changed the title implemented a couple more missing functions more function support Aug 14, 2026
@zachmu
zachmu requested a review from Hydrocharged August 14, 2026 00:22
@itoqa

itoqa Bot commented Aug 14, 2026

Copy link
Copy Markdown

Ito QA test results
Ito Diff Report459c45c4fc2f56: 20 test cases ran, 1 new failure ❌, 19 passing ✅.

Diff Summary

The run covers database catalog behavior across normal lookups, type and identifier comparisons, generated-row numbering, trigger and relationship metadata, session recovery, repeated and concurrent access, and relation lifecycle edge cases. The exercised paths are broadly healthy, including invalid-input handling and boundary conditions, but a multi-function query form exposes an alias-collision failure.

Not safe to merge yet — this PR introduces a medium-severity functional failure for a valid edge-case query involving multiple unnamed generated-function sources, while explicitly aliased queries continue to work. The issue is localized and avoidable, but it breaks supported query behavior and is directly attributable to the change.

Tests run by Ito

View full run

Result State Severity Type Description
❌ New Failure Medium severity Ancestor The query with two unnamed WITH ORDINALITY function items does not return rows. It fails because both generated derived tables are assigned the alias generate_series.
Passing Ancestor The existing table was found, and the ancestor query returned exactly one row for that table.
Passing Ancestor The catalog function returns one row for the primary index, no rows for a view or unknown OID, and the database session stays usable afterward.
Passing Ancestor The ancestor query returned the expected table name and depth, and filtering to depth 1 kept exactly one row. The database connection also stayed usable afterward.
Passing Ancestor Repeated catalog calls returned the same ancestor and trigger results in clean, warmed, and separate database connections. Each session stayed usable after the calls.
Passing Ancestor An existing table returned one ancestor row, unsupported relations returned no rows, and repeated reads stayed bounded. The session also remained usable after each lookup.
Passing Ancestor Removing a relation while an ancestor query was running did not return a stale relation ID. The removed relation disappeared from fresh reads, the existing table still returned one row, and the database session stayed usable.
Passing Oid The table OID from the catalog matched the same OID obtained through a relation name, while the table and its primary-index OIDs remained different.
Passing Oid NULL comparisons stayed NULL, while zero values compared as numbers. A follow-up query still returned the expected row.
Passing Oid OID values sorted in the same ascending numeric order whether they came from regclass values, casts, or a raw number.
Passing Oid Ancestor lookups joined to the correct table and index for both named and numeric OIDs. An unknown OID returned no rows, so the catalog did not add an unrelated relation.
Passing Ordinality The query returned values 2, 3, and 4 with one-based ordinals 1, 2, and 3.
Passing Ordinality The query renamed the generated value and position columns, then returned number 6 at position 2 after filtering.
Passing Ordinality Applying WITH ORDINALITY to an ordinary table returns a clear error, and the database still accepts the next query.
Passing Ordinality The direct query and the subquery returned the same middle row: value 3 with position 2. Sorting and filtering worked correctly in both forms.
Passing Trigger A stored trigger returned the same normalized SQL through both supported lookup forms, with extra spaces and the final semicolon removed.
Passing Trigger Invalid trigger identifiers return empty text, and later catalog queries continue to work normally.
Passing Trigger The parent and child tables both show trigger metadata after the foreign key is added, while the unrelated table stays unmarked.
Passing Trigger The system returned empty results for unknown and non-trigger IDs, then returned the same valid trigger definition through both supported calls.
Passing Trigger Adding a foreign key marked both tables as trigger-bearing and created the catalog relationship. Removing it cleared both flags and removed the relationship.
⏸️ Skipped Catalog The database returned matching details for five indexes through both catalog views, including names, uniqueness, access method, columns, expressions, and the partial-index condition.
⏸️ Skipped Catalog The routine listing returned the function and procedure with the correct type, names, arguments, and result data. Changing the search path hid both routines without changing their metadata.
⏸️ Skipped Catalog Unknown index and routine identifiers returned safe empty and false values. Valid catalog lookups and SELECT 1 then succeeded on the same connection.
⏸️ Skipped Catalog A bad catalog statement stopped the batch before the later insert ran. After rollback, a new row was saved and the same connection handled a normal query successfully.
⏸️ Skipped Catalog Three rounds of routine and index lookups returned complete, matching results in order. A normal query returned 42 afterward, and the session still reported its transaction status.
⏸️ Skipped Catalog The session returned empty results for a table OID and an unknown OID, then returned the correct index definition and stayed usable. A new session returned the same definition.
⏸️ Skipped Index The primary, unique, and ordinary indexes returned the expected PostgreSQL definitions, including names, uniqueness, btree access, and column order.
⏸️ Skipped Index The database returned the full index definition, each requested column, and empty text for invalid positions. Pretty-print settings produced the same results, and the connection stayed usable afterward.
⏸️ Skipped Index The functional partial index kept the same name, expressions, order, uniqueness, access method, and filter when read directly, through the index list, and from a fresh session.
⏸️ Skipped Query The routine listing returned both the function and procedure with the expected names, types, arguments, and visibility. A follow-up query also succeeded, so the database connection stayed ready for more work.
⏸️ Skipped Query The table description query returned the primary, unique, and ordinary indexes with their names, types, uniqueness, and CREATE statements. A follow-up query also succeeded, so the database connection stayed usable.
⏸️ Skipped Query The bad catalog statement stopped the batch, so the later insert was not saved. A rollback cleared the failed transaction and the same connection successfully ran a normal query.
⏸️ Skipped Query An empty query completed successfully, and the connection recovered after a failed transaction and an idle rollback. Follow-up queries returned 1 and 2 as expected.
⏸️ Skipped Visibility Functions and procedures were visible only when their schema was in the session search path. The same database session returned the expected results after switching between testschema and myschema.
⏸️ Skipped Visibility The visibility check returned the expected results for a valid function, a table ID, an unknown ID, and NULL, and the database session stayed usable. The built-in check could not run because this temporary database did not expose a built-in routine row, so the case was confirmed from the implementation and its native regression test instead.
⏸️ Skipped Visibility Two database sessions kept their own search paths during 20 repeated visibility checks. Each session returned the correct routines, kept its current schema stable, and remained ready for another query.

Tip

Reply with @itoqa to send us feedback on this test run.

Comment thread server/ast/aliased_table_expr.go

@Hydrocharged Hydrocharged left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Comment thread server/functions/pg_function_is_visible.go
@zachmu
zachmu enabled auto-merge August 14, 2026 18:43
@itoqa

itoqa Bot commented Aug 14, 2026

Copy link
Copy Markdown

Ito QA test results
Ito Diff Report4fc2f56ead93f7: 8 test cases ran, 8 passing ✅.

Diff Summary

The run covered database catalog behavior across normal create, replace, and preserve flows, along with edge cases for duplicates, invalid object types, missing metadata, foreign-key removal, trigger replacement, and unknown or null identifiers. It also checked that catalog state, comparisons, ordering, and later database operations remain consistent after errors or changes.

Safe to merge — all exercised behaviors passed, with no regressions or PR-attributable failures identified. Previously passing areas not exercised in this run are not merge blockers based on these results.

Tests run by Ito

View full run

Result State Severity Type Description
Passing Catalog Trying to create an existing table, index, sequence, or view returned the expected duplicate-object error, and the original objects remained usable.
Passing Catalog An existing view was replaced successfully and returned its new column. Trying to replace a table as a view was rejected, and both catalog entries kept their correct types.
Passing Catalog Creating an existing table and index with IF NOT EXISTS succeeded without replacing them. The catalog still had one table and one index, and the original row was still readable.
Passing Identity Raw and cached object IDs matched in equality checks, membership checks, and sorting. Unknown values did not change later results, and NULL comparisons kept normal SQL behavior.
Passing Identity Known OID values compare and sort the same whether they come from a number or a catalog lookup. Unknown values stay separate, and NULL comparisons keep normal SQL behavior after collection checks.
Passing Trigger The parent and child tables both showed trigger metadata while the foreign key existed. After the constraint was removed, both tables returned to the normal state and no foreign key remained.
Passing Trigger The metadata lookup error was shown, and the catalog still returned the same three relations afterward. No partial or mixed results were exposed.
Passing Trigger The trigger definition changed to the new function after the trigger was recreated. Relation metadata also stayed current, with the trigger still listed and no old definition left behind.
⏸️ Skipped Ancestor The existing table was found, and the ancestor query returned exactly one row for that table.
⏸️ Skipped Ancestor The catalog function returns one row for the primary index, no rows for a view or unknown OID, and the database session stays usable afterward.
⏸️ Skipped Ancestor The ancestor query returned the expected table name and depth, and filtering to depth 1 kept exactly one row. The database connection also stayed usable afterward.
⏸️ Skipped Ancestor Repeated catalog calls returned the same ancestor and trigger results in clean, warmed, and separate database connections. Each session stayed usable after the calls.
⏸️ Skipped Ancestor An existing table returned one ancestor row, unsupported relations returned no rows, and repeated reads stayed bounded. The session also remained usable after each lookup.
⏸️ Skipped Ancestor Removing a relation while an ancestor query was running did not return a stale relation ID. The removed relation disappeared from fresh reads, the existing table still returned one row, and the database session stayed usable.
⏸️ Skipped Oid The table OID from the catalog matched the same OID obtained through a relation name, while the table and its primary-index OIDs remained different.
⏸️ Skipped Oid NULL comparisons stayed NULL, while zero values compared as numbers. A follow-up query still returned the expected row.
⏸️ Skipped Oid OID values sorted in the same ascending numeric order whether they came from regclass values, casts, or a raw number.
⏸️ Skipped Oid Ancestor lookups joined to the correct table and index for both named and numeric OIDs. An unknown OID returned no rows, so the catalog did not add an unrelated relation.
⏸️ Skipped Ordinality The query returned values 2, 3, and 4 with one-based ordinals 1, 2, and 3.
⏸️ Skipped Ordinality The query renamed the generated value and position columns, then returned number 6 at position 2 after filtering.
⏸️ Skipped Ordinality Applying WITH ORDINALITY to an ordinary table returns a clear error, and the database still accepts the next query.
⏸️ Skipped Ordinality The direct query and the subquery returned the same middle row: value 3 with position 2. Sorting and filtering worked correctly in both forms.
⏸️ Skipped Trigger A stored trigger returned the same normalized SQL through both supported lookup forms, with extra spaces and the final semicolon removed.
⏸️ Skipped Trigger Invalid trigger identifiers return empty text, and later catalog queries continue to work normally.
⏸️ Skipped Trigger The parent and child tables both show trigger metadata after the foreign key is added, while the unrelated table stays unmarked.
⏸️ Skipped Trigger The system returned empty results for unknown and non-trigger IDs, then returned the same valid trigger definition through both supported calls.

Tip

Reply with @itoqa to send us feedback on this test run.

@zachmu
zachmu disabled auto-merge August 14, 2026 21:53
@zachmu
zachmu merged commit a7b5f1b into main Aug 14, 2026
29 of 34 checks passed
@zachmu
zachmu deleted the zachmu/psql2 branch August 14, 2026 21:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants