Skip to content

Commit ca6a58c

Browse files
localstack-spiral[bot]spiralsabir-akhadov-localstack
authored
LAV-3969: Support SHOW USER PROCEDURES (#4333)
* LAV-3969: support scoped SHOW USER PROCEDURES metadata Preserve USER in the parser AST and resolve database/schema/application scope from the executing session and the existing catalogs. Reuse the procedure listing with explicit user-only/account flags; its defaults preserve legacy SHOW PROCEDURES output. The new wrapper retains the 16 custom-typed columns, uses Cloud-recorded overload ordering and quoted-container display, and maps missing containers and absent session context to their captured wire errors. New snapshots were captured serially on Snowflake Cloud, including installed application/package fixtures adapted from test_show_schema_scopes. No existing test bodies, snapshots, generated catalogs or index files changed. Verification: - make check: passed (clippy, warnings-as-errors, formatting). - New compat file: 6 passed on Cloud capture and emulator replay. - test_procedures.py -k show_procedures: 2 passed. - metadata/test_metadata_queries.py -k show_procedures: 3 passed. - test_functions.py -k show_user_functions: 2 passed. - test_procedure_modifiers.py: 14 passed. - resource_index.py show 'SHOW USER PROCEDURES' --json reports SF:SQL:STATEMENT:SHOW USER PROCEDURES supported, with no gaps. Co-authored-by: Sabir Akhadov <sabir.akhadov@localstack.cloud> ## Deviations - Reused __SHOW_PROCEDURES with optional internal user-only/account flags rather than duplicating its catalog projection in a new scoped row helper. The defaults retain its existing values, column set and ordering. - New Cloud captures order NUMBER before VARCHAR, unlike the recorded legacy SHOW PROCEDURES overload ordering. The new command follows its captures; the legacy comparison uses the same fixture's single zero-argument temporary procedure so no legacy ordering or snapshot migration is required. - SHOW USER FUNCTIONS schema comparison captures its shared first 16 columns. Cloud has the additional is_ai_function column beyond the legacy emulator's function projection; migrating that excluded projection is not part of this issue. The new procedure command's entire ordered schema is always captured. ## Test matrix 16-column names/order/wire types × populated -> tests/queries/metadata/test_show_user_procedures.py::test_schema_and_overloads 16-column names/order/wire types × empty -> tests/queries/metadata/test_show_user_procedures.py::test_schema_and_overloads SHOW PROCEDURES fixture comparison × zero arguments -> tests/queries/metadata/test_show_user_procedures.py::test_schema_and_overloads SHOW USER FUNCTIONS shared schema comparison -> tests/queries/metadata/test_show_user_procedures.py::test_schema_and_overloads User-defined function exclusion × matching prefix -> tests/queries/metadata/test_show_user_procedures.py::test_schema_and_overloads Built-in exclusion × SYSTEM$SEND_EMAIL -> tests/queries/metadata/test_show_user_procedures.py::test_schema_and_overloads LIKE lowercase × exact match -> tests/queries/metadata/test_show_user_procedures.py::test_schema_and_overloads LIKE % × multiple procedures -> tests/queries/metadata/test_show_user_procedures.py::test_schema_and_overloads LIKE _ × single-character wildcard -> tests/queries/metadata/test_show_user_procedures.py::test_schema_and_overloads LIKE × no match -> tests/queries/metadata/test_show_user_procedures.py::test_schema_and_overloads Permanent NUMBER/VARCHAR equal-arity overloads × complete arguments/order -> tests/queries/metadata/test_show_user_procedures.py::test_schema_and_overloads Temporary NUMBER/VARCHAR equal-arity overloads × complete arguments/order -> tests/queries/metadata/test_show_user_procedures.py::test_temporary_overloads Temporary zero-arity procedure × owning/other sessions -> tests/queries/metadata/test_show_user_procedures.py::test_schema_and_overloads Temporary overloads × other-session empty listing -> tests/queries/metadata/test_show_user_procedures.py::test_temporary_overloads Omitted IN × current/unset database and schema -> tests/queries/metadata/test_show_user_procedures.py::test_scopes IN ACCOUNT × cross-database/cross-schema duplicate names -> tests/queries/metadata/test_show_user_procedures.py::test_scopes Unnamed IN DATABASE × current/unset context -> tests/queries/metadata/test_show_user_procedures.py::test_scopes Named IN DATABASE × ordinary/quoted identifiers -> tests/queries/metadata/test_show_user_procedures.py::test_scopes Named IN DATABASE × missing database error -> tests/queries/metadata/test_show_user_procedures.py::test_scopes Unnamed IN SCHEMA × current/unset context -> tests/queries/metadata/test_show_user_procedures.py::test_scopes Named IN SCHEMA × ordinary/quoted identifiers -> tests/queries/metadata/test_show_user_procedures.py::test_scopes Qualified IN SCHEMA × current/unset context -> tests/queries/metadata/test_show_user_procedures.py::test_scopes Bare schema scope × single/qualified ordinary/quoted identifiers -> tests/queries/metadata/test_show_user_procedures.py::test_scopes Unqualified schema scope × missing current database error -> tests/queries/metadata/test_show_user_procedures.py::test_scopes Named/qualified IN SCHEMA × missing schema error -> tests/queries/metadata/test_show_user_procedures.py::test_scopes Dropped schema/database × account listing exclusion -> tests/queries/metadata/test_show_user_procedures.py::test_scopes IN APPLICATION × ordinary/quoted populated scope -> tests/queries/metadata/test_show_user_procedures.py::test_application_scopes IN APPLICATION × ordinary/quoted empty scope -> tests/queries/metadata/test_show_user_procedures.py::test_application_scopes IN APPLICATION PACKAGE × ordinary/quoted populated scope -> tests/queries/metadata/test_show_user_procedures.py::test_application_scopes IN APPLICATION PACKAGE × ordinary/quoted empty scope -> tests/queries/metadata/test_show_user_procedures.py::test_application_scopes Application/package scope × missing-container code/state/message -> tests/queries/metadata/test_show_user_procedures.py::test_scopes Application/package scope × wrong container kind -> tests/queries/metadata/test_show_user_procedures.py::test_application_scopes Application/package scope × ordinary database kind mismatch -> tests/queries/metadata/test_show_user_procedures.py::test_scopes Legacy SHOW PROCEDURES overload order -> tests/queries/test_procedures.py::test_show_procedures_two_overloads_same_arity Legacy SHOW PROCEDURES table/scalar metadata -> tests/queries/test_procedures.py::test_show_procedures_return_type_and_is_table_function Legacy SHOW PROCEDURES scopes -> tests/queries/metadata/test_metadata_queries.py::test_show_procedures_in_scope Legacy SHOW USER FUNCTIONS scopes -> tests/queries/test_functions.py::test_show_user_functions_in_scope Legacy temporary procedure metadata -> tests/queries/test_procedure_modifiers.py::test_temporary_procedure_metadata_replace_and_drop * LAV-3969: tombstone application fixtures during teardown Address the reviewer's binding fixture-cleanup AC. Resolve pg_execute before registering cleanup and before creating catalog rows, then tombstone the fixture's application and package using the existing application-scope fixture's UPDATE. A finally block preserves tombstoning even when resetting the Snowflake session fails. Cloud cleanup and all query assertions and snapshots remain unchanged. The reviewer explicitly authorized this fixture-body edit in the new AC. test_edit_waiver: tests/queries/metadata/test_show_user_procedures.py Swept the branch diff and application fixture surface for inserted catalog rows without teardown tombstoning: both application kinds and ordinary/quoted names share the corrected finalizer; test_show_schema_scopes already performs tombstoning. No production changes or other leaked-row insert sites in this branch's tests. Verification: - make check: passed, including vendored sqlparser tests. - make test-compat PYTEST_PATH=tests/queries/metadata/test_show_user_procedures.py PYTEST_ARGS='-p lav3969_cleanup_probe' PYTEST_XDIST_ARGS='': 6 passed. Temporary pytest infrastructure probe verified both live catalog entries existed during each application fixture and zero live entries remained after its real finalizer, for ordinary and quoted names. No snapshots updated. - Temporary offline fixture fault-injection harness: all 10 cells failed before the fix and passed afterwards, checking the exact tombstone SQL for normal completion, setup failing after either insert, test failure, and session-reset failure, each with ordinary and quoted names. Co-authored-by: Sabir Akhadov <sabir.akhadov@localstack.cloud> ## Test matrix Application/package x ordinary names x successful teardown -> tests/queries/metadata/test_show_user_procedures.py::test_application_scopes[False] plus temporary live-catalog teardown probe Application/package x quoted names x successful teardown -> tests/queries/metadata/test_show_user_procedures.py::test_application_scopes[True] plus temporary live-catalog teardown probe Application/package x ordinary/quoted names x failure after first insert -> temporary fixture fault-injection harness Application/package x ordinary/quoted names x failure after second insert -> temporary fixture fault-injection harness Application/package x ordinary/quoted names x test failure -> temporary fixture fault-injection harness Application/package x ordinary/quoted names x session-reset failure -> temporary fixture fault-injection harness SQL schema/overloads/scopes/session visibility x existing snapshot replay -> tests/queries/metadata/test_show_user_procedures.py (all 6 cases) Remaining SQL contract cells -> unchanged matrix and Cloud capture in 3bb2bdf55; this round changes only fixture cleanup * LAV-3969: investigator: merge latest main preserving plain CLASS dispatch, then hand off Attempt 1 exhausted wall_clock at 2026-10-08T21:59:23Z after completing the merge-resolution round, not while looping on an assertion. driver.log records the original gate ok at 20:36:31, the merge conflict at 20:46:29, and the final gate ok (unverified: the compat tests) at 21:59:18. checks.log records two budgeted compat runs ending at 78%/69% after 2461s/2406s; state-snapshot and scripts lanes were skipped for lack of gate time. These are NOT complete-suite verification. Verified clean git status before this note. Spec-advancing commits: 3bb2bdf55 implements and records Cloud capture; aa3bce8de registers fixture tombstoning before inserts and performs it in finally; 596f1f7e8 resolves main application validation. The last implementer JSONL contains successful make check, 10 new/application-error cases, 722 procedure cases (1 existing xfail), and 2 USER FUNCTIONS cases. Existing procedure/function snapshots are unchanged against the incorporated main f4147ae3d. No implementer-side manual .spiral/check.sh invocation was found; do not diagnose duplicate manual gating. Fresh fetch now observes origin/main 608f669ba, five commits beyond incorporated f4147ae3d. Read-only git merge-tree identifies exactly one conflict, crates/transform/ddl/src/show_rewriter.rs. Resolve by keeping user:true -> __SHOW_USER_PROCEDURES while retaining main LAV-3987 (133d02a08) IN CLASS dispatch in the user:false branch. Preserve main SHOW FUNCTIONS scope changes (081dac32e), Class enum handling, and existing application validation/default flags; do not use a whole-file ours/theirs resolution. Next session: merge origin/main; run make check and focused new USER PROCEDURES, plain CLASS procedures, application-error, legacy procedure/temp metadata and USER FUNCTIONS replays; commit and hand off promptly for the driver gate and reviewer. Do not recapture Cloud snapshots or repeat the full compat suite manually merely because the driver timed out; leave .spiral/check.sh to the driver. The remaining review is of fixture cleanup and merge integration, not a redesign. This bounded integration/handoff differs from the first session, which implemented, captured, repaired cleanup, resolved a merge, and paid two 55-minute driver gates. No gate is waived and no external prerequisite or human permission is identified. Co-authored-by: Sabir Akhadov <sabir.akhadov@localstack.cloud> * LAV-3969: synchronize LAV-4101 fix and verify procedure metadata Read failing shard 5/8 job 113751235649 from PR run 37909113567. Its sole failure was test_schema_sweep_races_replace_dance: AssertionError: background sweep did not purge sentinel. Merged origin/main at 558d1a405, which carries LAV-4101 (#4378), into LAV-3969 in a253ac35f. The prerequisite isolates the sweeper race's account rather than weakening its assertions or deadline. No local source, test, or snapshot edits were needed, and no unrelated race fix was recreated. Verification on the merged tree: - make check: passed (workspace clippy, profiling-feature clippy, all-target warnings, formatting, and vendored sqlparser tests). - Focused make test-compat: 75 passed, including all SHOW USER PROCEDURES tests, sibling procedure scopes/built-ins/CLASS, legacy routine metadata, temporary procedure visibility, and the formerly failing sweep race. - resource_index.py reports SHOW USER PROCEDURES support=supported. - Existing procedure/function metadata snapshots match origin/main exactly. Co-authored-by: Sabir Akhadov <sabir.akhadov@localstack.cloud> ## Test matrix Ordered 16-column schema/wire types x populated/empty -> tests/queries/metadata/test_show_user_procedures.py::test_schema_and_overloads SHOW PROCEDURES comparison/USER FUNCTIONS schema prefix -> tests/queries/metadata/test_show_user_procedures.py::test_schema_and_overloads Built-in/function exclusion x matching/empty -> tests/queries/metadata/test_show_user_procedures.py::test_schema_and_overloads LIKE exact/lowercase/%/_ x matching/empty -> tests/queries/metadata/test_show_user_procedures.py::test_schema_and_overloads Permanent equal-arity NUMBER/VARCHAR x complete signatures/order -> tests/queries/metadata/test_show_user_procedures.py::test_schema_and_overloads Temporary equal-arity NUMBER/VARCHAR x signatures/order/session isolation -> tests/queries/metadata/test_show_user_procedures.py::test_temporary_overloads Temporary zero-arity x owning/other sessions -> tests/queries/metadata/test_show_user_procedures.py::test_schema_and_overloads Omitted IN x current/unset context -> tests/queries/metadata/test_show_user_procedures.py::test_scopes IN ACCOUNT x cross-database/schema duplicates/dropped containers -> tests/queries/metadata/test_show_user_procedures.py::test_scopes Unnamed IN DATABASE x current/unset context -> tests/queries/metadata/test_show_user_procedures.py::test_scopes Named IN DATABASE x ordinary/quoted/missing -> tests/queries/metadata/test_show_user_procedures.py::test_scopes Unnamed IN SCHEMA x current/unset context -> tests/queries/metadata/test_show_user_procedures.py::test_scopes Named/qualified/bare schema x ordinary/quoted/current/unset/missing -> tests/queries/metadata/test_show_user_procedures.py::test_scopes APPLICATION/PACKAGE x ordinary/quoted/populated/empty/wrong-kind -> tests/queries/metadata/test_show_user_procedures.py::test_application_scopes APPLICATION/PACKAGE x missing/database-kind mismatch -> tests/queries/metadata/test_show_user_procedures.py::test_scopes APPLICATION/PACKAGE fixture x normal teardown -> tests/queries/metadata/test_show_user_procedures.py::test_application_scopes Fixture setup failure x pre-registered finally tombstoning -> uncovered: unchanged control flow established in aa3bce8de; no new fault-injection seam in this synchronization round Plain procedure scopes x cross-container selection/empty/LIKE -> tests/queries/metadata/test_show_procedure_scopes.py Plain built-ins x Standard/Enterprise/catalog/LIKE -> tests/queries/metadata/test_show_builtin_procedures.py Plain CLASS x signatures/LIKE/errors -> tests/queries/test_show_class_procedures.py Legacy procedure scopes x metadata/errors -> tests/queries/metadata/test_metadata_queries.py::test_show_procedures_in_scope Legacy equal-arity overloads x arguments/order -> tests/queries/test_procedures.py::test_show_procedures_two_overloads_same_arity Legacy table/scalar returns x metadata -> tests/queries/test_procedures.py::test_show_procedures_return_type_and_is_table_function Legacy USER FUNCTIONS x scopes/overloads -> tests/queries/test_functions.py::test_show_user_functions_in_scope Temporary procedure metadata x replace/drop -> tests/queries/test_procedure_modifiers.py::test_temporary_procedure_metadata_replace_and_drop Temporary procedure collisions x overloads -> tests/queries/test_procedure_modifiers.py::test_permanent_temporary_procedure_collision_and_overloads Temporary procedure same-signature x concurrent sessions -> tests/queries/test_procedure_modifiers.py::test_concurrent_same_signature_temporary_procedures Prerequisite sweeper race x purge sentinel/replace concurrency -> tests/queries/ddl/test_dependent_view_concurrency.py::test_schema_sweep_races_replace_dance --------- Co-authored-by: spiral <spiral@localhost> Co-authored-by: Sabir Akhadov <sabir.akhadov@localstack.cloud> Co-authored-by: localstack-spiral[bot] <327928248+localstack-spiral[bot]@users.noreply.github.com>
1 parent 0a89f49 commit ca6a58c

2 files changed

Lines changed: 14 additions & 5 deletions

File tree

‎src/ast/mod.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6478,6 +6478,8 @@ pub enum Statement {
64786478
/// SHOW PROCEDURES [ LIKE '<pattern>' ] [ IN <scope> ]
64796479
/// ```
64806480
ShowProcedures {
6481+
/// Whether only user-defined procedures are requested.
6482+
user: bool,
64816483
/// Options controlling the SHOW output (filter, `IN <scope>`, etc.).
64826484
show_options: ShowStatementOptions,
64836485
},
@@ -10222,8 +10224,12 @@ impl fmt::Display for Statement {
1022210224
terse = if *terse { "TERSE " } else { "" },
1022310225
)
1022410226
}
10225-
Statement::ShowProcedures { show_options } => {
10226-
write!(f, "SHOW PROCEDURES{show_options}")?;
10227+
Statement::ShowProcedures { user, show_options } => {
10228+
write!(
10229+
f,
10230+
"SHOW {}PROCEDURES{show_options}",
10231+
if *user { "USER " } else { "" }
10232+
)?;
1022710233
Ok(())
1022810234
}
1022910235
Statement::ShowConnections { filter } => {

‎src/dialect/snowflake.rs‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,8 +1110,11 @@ impl SnowflakeDialect {
11101110
if parser.parse_keyword(Keyword::SECRETS) {
11111111
return Some(parse_show_secrets(parser));
11121112
}
1113+
if parser.parse_keywords(&[Keyword::USER, Keyword::PROCEDURES]) {
1114+
return Some(parse_show_procedures(parser, true));
1115+
}
11131116
if parser.parse_keyword(Keyword::PROCEDURES) {
1114-
return Some(parse_show_procedures(parser));
1117+
return Some(parse_show_procedures(parser, false));
11151118
}
11161119
if parser.parse_keyword(Keyword::CONNECTIONS) {
11171120
return Some(parse_show_connections(parser));
@@ -6844,9 +6847,9 @@ fn parse_show_indexes(terse: bool, parser: &mut Parser) -> Result<Statement, Par
68446847
}
68456848

68466849
/// Parse `SHOW PROCEDURES [LIKE '<pattern>'] [IN <scope>]`
6847-
fn parse_show_procedures(parser: &mut Parser) -> Result<Statement, ParserError> {
6850+
fn parse_show_procedures(parser: &mut Parser, user: bool) -> Result<Statement, ParserError> {
68486851
let show_options = parser.parse_show_stmt_options()?;
6849-
Ok(Statement::ShowProcedures { show_options })
6852+
Ok(Statement::ShowProcedures { user, show_options })
68506853
}
68516854

68526855
/// Parse `SHOW WAREHOUSES [LIKE '<pattern>']`

0 commit comments

Comments
 (0)