Repository navigation
Commit 386c8b6
LAV-4465: ALTER FUNCTION rename: qualified destinations and targeting parity (#4685)
* LAV-4465: Match qualified function rename targeting and moved identity
Capture new rename fixtures against Snowflake Cloud and implement source,
destination, signature-conflict, IF EXISTS, and managed-access gates. Preserve
canonical quoted session namespaces and overload isolation. Reuse the existing
relocation and routine-catalog postlude, preserving grants across qualified moves.
Cloud rebinds relative SQL references to the function's destination namespace.
Recompile the SQL definition inside the existing atomic DDL postlude and pin SQL
creation's search path to its declared namespace, including GET_DDL replay while
the caller remains in the source schema. Restore quoted GET_DDL identifiers and
JavaScript comments; reconstruct external-function DDL for the exercised API
integration, headers, and batch-size fixtures without adding a runtime.
Validation: make check passed; make test-vendored-sqlparser passed; focused
make test-compat replay passed with 100 passed and 3 strict-xfailed. The focused
replay includes existing SQL, overload, GET_DDL, mapped JavaScript identity, and
Python secret-binding rename regressions. Existing snapshot entries remain
semantically unchanged; the Cloud snapshot writer reordered the external file.
Co-authored-by: Przemek Denkiewicz <przemyslaw.denkiewicz@localstack.cloud>
## Deviations
- Captures require SQL namespace rebinding and correctly qualified GET_DDL replay, so the fix also touches processing.rs, SQL creation namespace pinning, and the existing GET_DDL renderer rather than only the hinted rename synchronization sites.
- Three newly captured cells remain strict-xfail with explicit owner LAV-4241: two JavaScript dotted quoted-name runtime/DDL-replay cases (Cloud call error 100131 and recreation error 090216), and Python DESC's installed_packages projection. Python calls, other metadata, and DDL replay pass without changing metadata column sets or edition gates.
- External invocation is env-blocked by the existing fixture's explicit Cloud skip (test_external_function_scalar_invocation: no gateway). New external move fixtures verify SHOW, DESC, GET_DDL and recreated DESC instead; invocation remains owned by LAV-4241, without introducing another runtime or gateway.
## Test matrix
SQL × unqualified destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-unqualified]
SQL × unqualified destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-unqualified]
SQL × unqualified destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-unqualified]
SQL × unqualified destination × NUMBER × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-unqualified]
SQL × unqualified destination × NUMBER × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-unqualified]
SQL × unqualified destination × NUMBER × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-unqualified]
SQL × schema destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-schema]
SQL × schema destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-schema]
SQL × schema destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-schema]
SQL × schema destination × NUMBER × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-schema]
SQL × schema destination × NUMBER × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-schema]
SQL × schema destination × NUMBER × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-schema]
SQL × database destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-database]
SQL × database destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-database]
SQL × database destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-database]
SQL × database destination × NUMBER × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-database]
SQL × database destination × NUMBER × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-database]
SQL × database destination × NUMBER × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-database]
SQL × quoted destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-quoted]
SQL × quoted destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-quoted]
SQL × quoted destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-quoted]
SQL × quoted destination × NUMBER × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-quoted]
SQL × quoted destination × NUMBER × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-quoted]
SQL × quoted destination × NUMBER × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-quoted]
JAVASCRIPT × unqualified destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-unqualified]
JAVASCRIPT × unqualified destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-unqualified]
JAVASCRIPT × unqualified destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-unqualified]
JAVASCRIPT × unqualified destination × FLOAT × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-unqualified]
JAVASCRIPT × unqualified destination × FLOAT × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-unqualified]
JAVASCRIPT × unqualified destination × FLOAT × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-unqualified]
JAVASCRIPT × schema destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-schema]
JAVASCRIPT × schema destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-schema]
JAVASCRIPT × schema destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-schema]
JAVASCRIPT × schema destination × FLOAT × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-schema]
JAVASCRIPT × schema destination × FLOAT × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-schema]
JAVASCRIPT × schema destination × FLOAT × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-schema]
JAVASCRIPT × database destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-database]
JAVASCRIPT × database destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-database]
JAVASCRIPT × database destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-database]
JAVASCRIPT × database destination × FLOAT × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-database]
JAVASCRIPT × database destination × FLOAT × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-database]
JAVASCRIPT × database destination × FLOAT × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-database]
JAVASCRIPT × quoted destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-quoted]
JAVASCRIPT × quoted destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-quoted]
JAVASCRIPT × quoted destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-quoted]
JAVASCRIPT × quoted destination × FLOAT × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-quoted]
JAVASCRIPT × quoted destination × FLOAT × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-quoted]
JAVASCRIPT × quoted destination × FLOAT × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-quoted]
PYTHON × unqualified destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-unqualified]
PYTHON × unqualified destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-unqualified]
PYTHON × unqualified destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-unqualified]
PYTHON × unqualified destination × NUMBER × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-unqualified]
PYTHON × unqualified destination × NUMBER × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-unqualified]
PYTHON × unqualified destination × NUMBER × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-unqualified]
PYTHON × schema destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-schema]
PYTHON × schema destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-schema]
PYTHON × schema destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-schema]
PYTHON × schema destination × NUMBER × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-schema]
PYTHON × schema destination × NUMBER × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-schema]
PYTHON × schema destination × NUMBER × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-schema]
PYTHON × database destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-database]
PYTHON × database destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-database]
PYTHON × database destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-database]
PYTHON × database destination × NUMBER × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-database]
PYTHON × database destination × NUMBER × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-database]
PYTHON × database destination × NUMBER × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-database]
PYTHON × quoted destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-quoted]
PYTHON × quoted destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-quoted]
PYTHON × quoted destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-quoted]
PYTHON × quoted destination × NUMBER × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-quoted]
PYTHON × quoted destination × NUMBER × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-quoted]
PYTHON × quoted destination × NUMBER × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-quoted]
RENAME targeting × missing × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[missing]
RENAME targeting × wrong-signature × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[wrong-signature]
RENAME targeting × missing-if-exists × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[missing-if-exists]
RENAME targeting × wrong-if-exists × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[wrong-if-exists]
RENAME targeting × missing-schema × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[missing-schema]
RENAME targeting × missing-database × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[missing-database]
RENAME targeting × conflict × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[conflict]
RENAME targeting × different-overload × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[different-overload]
RENAME targeting × same-name × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[same-name]
RENAME targeting × conflict-if-exists × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[conflict-if-exists]
RENAME targeting × missing-schema-if-exists × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[missing-schema-if-exists]
RENAME targeting × missing-database-if-exists × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[missing-database-if-exists]
RENAME targeting × destination-signature × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[destination-signature]
managed-access destination × database_owner × accepted/rejected move and preserved state -> tests/queries/access_control/test_schema_ownership.py::test_function_rename_managed_access[database_owner]
managed-access destination × schema_owner × accepted/rejected move and preserved state -> tests/queries/access_control/test_schema_ownership.py::test_function_rename_managed_access[schema_owner]
managed-access destination × inherited_owner × accepted/rejected move and preserved state -> tests/queries/access_control/test_schema_ownership.py::test_function_rename_managed_access[inherited_owner]
external function × cross_database=False × move/SHOW/DESC/GET_DDL/recreated DESC -> tests/queries/ddl/test_external_functions.py::test_external_function_qualified_rename[False]
external function × cross_database=True × move/SHOW/DESC/GET_DDL/recreated DESC -> tests/queries/ddl/test_external_functions.py::test_external_function_qualified_rename[True]
SQL relative body × SOURCE namespace × IF EXISTS move/call/parameters/grants/DDL replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_sql_binding[SOURCE]
SQL relative body × TARGET namespace × IF EXISTS move/call/parameters/grants/DDL replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_sql_binding[TARGET]
SQL relative body × QUALIFIED namespace × IF EXISTS move/call/parameters/grants/DDL replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_sql_binding[QUALIFIED]
ordered multi-argument overload × INT/STRING/DECIMAL aliases × move/call/isolation/DESC/GET_DDL -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_ordered_signature
Python moved installed_packages DESC × metadata boundary -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_python_installed_packages (strict-xfail; LAV-4241)
JavaScript dotted quoted name × zero/FLOAT argument runtime error and DDL rejection -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-quoted], tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-quoted] (strict-xfail; LAV-4241)
external function × post-move remote invocation -> uncovered: existing fixture skips Cloud explicitly because no gateway is available; LAV-4241 owns this env-blocked cell
* LAV-4465: wip (budget exhausted: wall_clock)
Co-authored-by: Przemek Denkiewicz <przemyslaw.denkiewicz@localstack.cloud>
* LAV-4465: investigator: validate saved nested-DROP fix; retain Cloud quote contract
Investigation: first wall-clock exhaustion, not a bail-out or repeated recovery. The original checkout was clean (git status --porcelain empty). Commits 879f99c42 and 0289f9d9e advance the rename spec; the latter saves the reviewer-gap fixes and regression captures. No issue implementation was changed by this investigation.
Evidence: /var/lib/spiral/transcripts/driver.log records the first implementation ending 06:03:04, driver checks lasting until 06:58:06, review until 07:03:16, and the second implementation killed for wall_clock at 07:50:56 on October 14, 2026. checks.log explicitly says compat and state-snapshot validation were unverified, not green. The second implementer transcript shows changing failures and concrete fixes, not a repeated unchanged blocker.
The rebinder at processing.rs:7049 now builds SQL directly from the catalog row filtered by owning session rather than calling the token-dependent GET_DDL renderer. get_ddl.rs:80 parses argument identifiers rather than regex-double-quoting stored tokens. Cloud capture at 07:17:32 passed 16 temporary/quoted/replay cells; final temporary capture at 07:37:58 passed six cells. /tmp/lav4465-regressions2.log finished with 230 passed, seven strict-xfailed, and 16 failures, all test_javascript_rename_dropped_destination cases involving nested destination DROP, error 002002 (42710), Object ... already exists. In that same run all four temporary-move tests, all ten quoted-argument tests and the defaulted-argument test passed.
The implementer then added nested DROP catalog cleanup to routine_ddl_postlude at procedure_transformer.rs:259 and make check passed at 07:49:33 (/tmp/lav4465-check3.log). Final regression replay was launched at 07:49:52, but the worker was killed during startup/build at 07:50:56: /tmp/lav4465-final-regressions.log has no pytest result. Do not claim the final DROP patch passed compat.
Next run: reuse the saved captures and fixes. First verify test_javascript_rename_dropped_destination, including the nested-DROP variants, then complete the already-selected rename/temp/overload/metadata/runtime regression replay from the final transcript command. Review the cleanup for overload/session isolation and sweep the new visibility hook for regressions; fix code, never weaken existing assertions. Re-run make check after code changes. Leave .spiral/check.sh to the driver; do not start a full manual gate or re-capture the whole Cloud matrix. This round differs because both reported gaps already pass and the remaining concrete task is validating/refining the saved nested-DROP cleanup, not repeating discovery.
Cloud contradicts the added embedded-double-quote AC: snapshot test_alter_function_rename_embedded_quote_replay_error[schema], recorded 14-10-2026 07:17:30, contains GET_DDL argument "with"quote" (unescaped interior quote) and replay error 001003 / 42000, then missing-function error 002141 / 42601. Pin Cloud behavior; record the contradiction under ## Deviations. Keep the captured replay-diagnostic and invisible-temp overload-fallback cells strict-xfail with explicit LAV-4241 ownership when genuinely outside this child. Do not demand successful replay of malformed Cloud DDL or couple rename to that renderer again.
Fetched origin/main to f25c2c554. Incorporate current trunk under normal workflow before final verification. No credential, prerequisite, external provisioning, or test waiver blocker was established. No tests/builds were run by the investigator.
Co-authored-by: Przemek Denkiewicz <przemyslaw.denkiewicz@localstack.cloud>
* LAV-4465: Verify temporary and quoted rename fixes and nested DROP cleanup
Continue the saved implementation and Cloud captures rather than replacing
them. Merge current origin/main, verify both reviewer gaps, and complete
the previously unverified nested-DROP destination cleanup replay. No new
snapshot capture or changes to existing tests were necessary this round.
The saved rebinder reads the owning session's catalog definition directly,
independent of GET_DDL's session-token lookup. The argument renderer parses
stored identifiers and defaults instead of wrapping already-quoted tokens.
The visibility hook rejects calls to another session's temporary function.
Nested DROP updates the selected signature's catalog, tags and grants so a
subsequent rename does not encounter a stale destination identity.
Swept function_rename_rebind_sql, GET_DDL argument rendering, the function
visibility hook and routine_ddl_postlude for session/overload and identifier
boundary siblings. The saved fixes cover zero-argument and NUMBER temporary
moves, mixed-case/space/dotted/embedded-quote and combined argument names,
defaulted arguments, and nested/top-level DROP and RENAME combinations with
SQL/JavaScript destination overloads. Catalog function identities have a
primary key including the argument signature; cleanup remains signature-scoped.
Co-authored-by: Przemek Denkiewicz <przemyslaw.denkiewicz@localstack.cloud>
## Verification
- make test-compat PYTEST_PATH=tests/queries/test_javascript_runtime_identity.py PYTEST_ARGS='-k test_javascript_rename_dropped_destination': 64 passed, including every nested-DROP variant.
- make test-compat across test_alter_function_rename.py, test_javascript_runtime_identity.py, test_functions.py, test_function_metadata_configuration.py, metadata/test_get_ddl_function_overloads.py, metadata/test_metadata_queries.py, test_alter_function_external_access_edges.py, access_control/test_schema_ownership.py, access_control/test_restricted_store.py, ddl/test_external_functions.py, filtered to rename, overload, mapped_identity, nested_ddl_contract, logical_error_identity, function_metadata and GET_DDL function cells: 300 passed, seven strict-xfailed.
- make check: passed, including workspace clippy, warnings-as-errors, formatting and vendored parser tests.
- git diff --check: passed. No source or snapshot edits were needed in this verification round; this commit records the completed verification of the previously saved patch.
## Deviations
- Captures require SQL namespace rebinding and correctly qualified GET_DDL replay, so the fix also touches processing.rs, SQL creation namespace pinning, and the existing GET_DDL renderer rather than only the hinted rename synchronization sites.
- Two JavaScript dotted quoted-name runtime/DDL-replay cells and Python DESC's installed_packages projection remain strict-xfail with explicit owner LAV-4241. Python calls, other metadata and DDL replay pass without changing metadata column sets or edition gates.
- External invocation is env-blocked by the existing fixture's explicit Cloud skip (test_external_function_scalar_invocation: no gateway). External move fixtures verify SHOW, DESC, GET_DDL and recreated DESC; invocation remains owned by LAV-4241 without introducing another runtime or gateway.
- Cloud GET_DDL emits an unescaped embedded double quote in argument names, contradicting the added successful-replay AC. Preserve the recorded renderer output and accepted rename/calls; the separate captured malformed-DDL replay diagnostic remains strict-xfail with owner LAV-4241 rather than coupling rename to this malformed renderer output.
- The captured second-session coercion fallback past an invisible temporary overload remains strict-xfail with explicit owner LAV-4241. Exact temporary invisibility, owning-session calls, metadata and supported replay are verified here.
## Test matrix additions
Temporary SQL × schema × zero args × owning call/rebinding/metadata/DDL replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_temporary[-schema]
Temporary SQL × database × zero args × owning call/rebinding/metadata/DDL replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_temporary[-database]
Temporary SQL × schema × NUMBER × owning call/rebinding/metadata/DDL replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_temporary[NUMBER-schema]
Temporary SQL × database × NUMBER × owning call/rebinding/metadata/DDL replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_temporary[NUMBER-database]
Temporary SQL × schema × zero args × source disappearance/other-session call and metadata errors -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_temporary[-schema]
Temporary SQL × database × zero args × source disappearance/other-session call and metadata errors -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_temporary[-database]
Temporary SQL × schema × NUMBER × source disappearance/other-session call and metadata errors -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_temporary[NUMBER-schema]
Temporary SQL × database × NUMBER × source disappearance/other-session call and metadata errors -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_temporary[NUMBER-database]
Quoted arguments × mixed case × schema × rename/call/metadata/DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_quoted_arguments[mixed-schema]
Quoted arguments × mixed case × database × rename/call/metadata/DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_quoted_arguments[mixed-database]
Quoted arguments × spaces × schema × rename/call/metadata/DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_quoted_arguments[space-schema]
Quoted arguments × spaces × database × rename/call/metadata/DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_quoted_arguments[space-database]
Quoted arguments × dots × schema × rename/call/metadata/DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_quoted_arguments[dot-schema]
Quoted arguments × dots × database × rename/call/metadata/DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_quoted_arguments[dot-database]
Quoted arguments × embedded quote × schema × rename/call/metadata/Cloud DDL -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_quoted_arguments[quote-schema]
Quoted arguments × embedded quote × database × rename/call/metadata/Cloud DDL -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_quoted_arguments[quote-database]
Quoted arguments × combined × schema × rename/call/metadata/Cloud DDL -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_quoted_arguments[combined-schema]
Quoted arguments × combined × database × rename/call/metadata/Cloud DDL -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_quoted_arguments[combined-database]
Quoted arguments × defaults with string comma × omitted/NULL args/metadata/DDL replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_defaulted_quoted_arguments
Embedded quote × schema × malformed Cloud DDL replay/missing recreated function -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_embedded_quote_replay_error[schema] (strict-xfail; LAV-4241)
Embedded quote × database × malformed Cloud DDL replay/missing recreated function -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_embedded_quote_replay_error[database] (strict-xfail; LAV-4241)
Temporary NUMBER × schema × owner call/other-session VARCHAR call/coercion fallback -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_temporary_overload_fallback[schema] (strict-xfail; LAV-4241)
Temporary NUMBER × database × owner call/other-session VARCHAR call/coercion fallback -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_temporary_overload_fallback[database] (strict-xfail; LAV-4241)
Nested/top-level DROP × nested/top-level RENAME × SQL/JavaScript destination × NULL policies/NOT NULL × selected-overload cleanup/sibling isolation/runtime contract -> tests/queries/test_javascript_runtime_identity.py::test_javascript_rename_dropped_destination (all 64 cells)
## Test matrix
SQL × unqualified destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-unqualified]
SQL × unqualified destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-unqualified]
SQL × unqualified destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-unqualified]
SQL × unqualified destination × NUMBER × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-unqualified]
SQL × unqualified destination × NUMBER × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-unqualified]
SQL × unqualified destination × NUMBER × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-unqualified]
SQL × schema destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-schema]
SQL × schema destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-schema]
SQL × schema destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-schema]
SQL × schema destination × NUMBER × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-schema]
SQL × schema destination × NUMBER × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-schema]
SQL × schema destination × NUMBER × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-schema]
SQL × database destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-database]
SQL × database destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-database]
SQL × database destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-database]
SQL × database destination × NUMBER × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-database]
SQL × database destination × NUMBER × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-database]
SQL × database destination × NUMBER × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-database]
SQL × quoted destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-quoted]
SQL × quoted destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-quoted]
SQL × quoted destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-SQL-quoted]
SQL × quoted destination × NUMBER × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-quoted]
SQL × quoted destination × NUMBER × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-quoted]
SQL × quoted destination × NUMBER × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-SQL-quoted]
JAVASCRIPT × unqualified destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-unqualified]
JAVASCRIPT × unqualified destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-unqualified]
JAVASCRIPT × unqualified destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-unqualified]
JAVASCRIPT × unqualified destination × FLOAT × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-unqualified]
JAVASCRIPT × unqualified destination × FLOAT × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-unqualified]
JAVASCRIPT × unqualified destination × FLOAT × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-unqualified]
JAVASCRIPT × schema destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-schema]
JAVASCRIPT × schema destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-schema]
JAVASCRIPT × schema destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-schema]
JAVASCRIPT × schema destination × FLOAT × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-schema]
JAVASCRIPT × schema destination × FLOAT × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-schema]
JAVASCRIPT × schema destination × FLOAT × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-schema]
JAVASCRIPT × database destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-database]
JAVASCRIPT × database destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-database]
JAVASCRIPT × database destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-database]
JAVASCRIPT × database destination × FLOAT × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-database]
JAVASCRIPT × database destination × FLOAT × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-database]
JAVASCRIPT × database destination × FLOAT × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-database]
JAVASCRIPT × quoted destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-quoted]
JAVASCRIPT × quoted destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-quoted]
JAVASCRIPT × quoted destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-quoted]
JAVASCRIPT × quoted destination × FLOAT × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-quoted]
JAVASCRIPT × quoted destination × FLOAT × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-quoted]
JAVASCRIPT × quoted destination × FLOAT × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-quoted]
PYTHON × unqualified destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-unqualified]
PYTHON × unqualified destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-unqualified]
PYTHON × unqualified destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-unqualified]
PYTHON × unqualified destination × NUMBER × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-unqualified]
PYTHON × unqualified destination × NUMBER × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-unqualified]
PYTHON × unqualified destination × NUMBER × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-unqualified]
PYTHON × schema destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-schema]
PYTHON × schema destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-schema]
PYTHON × schema destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-schema]
PYTHON × schema destination × NUMBER × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-schema]
PYTHON × schema destination × NUMBER × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-schema]
PYTHON × schema destination × NUMBER × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-schema]
PYTHON × database destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-database]
PYTHON × database destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-database]
PYTHON × database destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-database]
PYTHON × database destination × NUMBER × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-database]
PYTHON × database destination × NUMBER × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-database]
PYTHON × database destination × NUMBER × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-database]
PYTHON × quoted destination × zero-argument × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-quoted]
PYTHON × quoted destination × zero-argument × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-quoted]
PYTHON × quoted destination × zero-argument × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-PYTHON-quoted]
PYTHON × quoted destination × NUMBER × happy move/call -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-quoted]
PYTHON × quoted destination × NUMBER × boundary old-target/sibling isolation -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-quoted]
PYTHON × quoted destination × NUMBER × post-move SHOW/DESC/GET_DDL/replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-PYTHON-quoted]
RENAME targeting × missing × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[missing]
RENAME targeting × wrong-signature × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[wrong-signature]
RENAME targeting × missing-if-exists × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[missing-if-exists]
RENAME targeting × wrong-if-exists × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[wrong-if-exists]
RENAME targeting × missing-schema × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[missing-schema]
RENAME targeting × missing-database × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[missing-database]
RENAME targeting × conflict × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[conflict]
RENAME targeting × different-overload × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[different-overload]
RENAME targeting × same-name × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[same-name]
RENAME targeting × conflict-if-exists × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[conflict-if-exists]
RENAME targeting × missing-schema-if-exists × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[missing-schema-if-exists]
RENAME targeting × missing-database-if-exists × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[missing-database-if-exists]
RENAME targeting × destination-signature × outcome and source/destination state -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[destination-signature]
managed-access destination × database_owner × accepted/rejected move and preserved state -> tests/queries/access_control/test_schema_ownership.py::test_function_rename_managed_access[database_owner]
managed-access destination × schema_owner × accepted/rejected move and preserved state -> tests/queries/access_control/test_schema_ownership.py::test_function_rename_managed_access[schema_owner]
managed-access destination × inherited_owner × accepted/rejected move and preserved state -> tests/queries/access_control/test_schema_ownership.py::test_function_rename_managed_access[inherited_owner]
external function × cross_database=False × move/SHOW/DESC/GET_DDL/recreated DESC -> tests/queries/ddl/test_external_functions.py::test_external_function_qualified_rename[False]
external function × cross_database=True × move/SHOW/DESC/GET_DDL/recreated DESC -> tests/queries/ddl/test_external_functions.py::test_external_function_qualified_rename[True]
SQL relative body × SOURCE namespace × IF EXISTS move/call/parameters/grants/DDL replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_sql_binding[SOURCE]
SQL relative body × TARGET namespace × IF EXISTS move/call/parameters/grants/DDL replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_sql_binding[TARGET]
SQL relative body × QUALIFIED namespace × IF EXISTS move/call/parameters/grants/DDL replay -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_sql_binding[QUALIFIED]
ordered multi-argument overload × INT/STRING/DECIMAL aliases × move/call/isolation/DESC/GET_DDL -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_ordered_signature
Python moved installed_packages DESC × metadata boundary -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_python_installed_packages (strict-xfail; LAV-4241)
JavaScript dotted quoted name × zero/FLOAT argument runtime error and DDL rejection -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-quoted], tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[NUMBER-JAVASCRIPT-quoted] (strict-xfail; LAV-4241)
external function × post-move remote invocation -> uncovered: existing fixture skips Cloud explicitly because no gateway is available; LAV-4241 owns this env-blocked cell
* LAV-4465: Preserve caller-scoped function rename authorization
Run the rename probe with the session token and resolve source USAGE and
OWNERSHIP through the existing principal-closure authorization helpers.
Check the selected source before returning destination-dependent errors;
hidden sources cannot reveal conflicting destination signatures. Include
inherited and selected secondary roles, retain temporary-session filtering,
and match the primary-only diagnostics for USE SECONDARY ROLES NONE.
Leave executable-context statements on their existing scoped routine DDL
authorization path. Its CALLER OWNERSHIP and FULL MANAGEMENT checks cannot
be replaced by a flat function-USAGE predicate. Existing restricted-caller
rename and namespace-creation regressions pass without modifying their tests.
Add 42 real-Cloud captures for denied-role targeting, zero-argument quoted
identities with inherited/secondary ownership, and missing-namespace call
readback. All 61 pre-existing rename snapshots remain byte-value equivalent.
Use AST identities to resolve quoted dotted function names in call diagnostics
and preserve Cloud's identifier rendering; namespace failures from function
calls now report the captured unknown-function error instead of table-style
container errors. No new runtime, privilege subsystem, metadata projection,
account-edition gate or existing-test assertion change.
Swept gate_function_rename's source, signature, temporary-session, destination
conflict, namespace and managed-access predicates for privileged early-return
siblings; also fixed USAGE-only ownership rejection, inherited/secondary-role
resolution, primary-only diagnostics and hidden-source IF EXISTS behavior.
Swept scoped executable dispatch and kept its existing authorizer authoritative.
Swept qualified unknown-function readback for schema/database qualification,
quoted dots/spaces and multiple calls using AST visitors rather than SQL scans.
Co-authored-by: Przemek Denkiewicz <przemyslaw.denkiewicz@localstack.cloud>
## Verification
- Cloud capture: denied_role, serial --snapshot-update: 30 passed.
- Cloud capture: role_closure and missing_namespace_readback, serial --snapshot-update: 12 passed (role_closure recaptured after final fixture namespace setup).
- make check: passed, including formatting, clippy, warnings-as-errors and vendored parser tests.
- make test-compat PYTEST_PATH=tests/queries/test_alter_function_rename.py: 96 passed, seven existing strict-xfails.
- Focused replay of test_javascript_runtime_identity.py, test_functions.py, test_function_metadata_configuration.py, metadata/test_get_ddl_function_overloads.py, metadata/test_metadata_queries.py, test_alter_function_external_access_edges.py, access_control/test_schema_ownership.py, access_control/test_restricted_store.py and ddl/test_external_functions.py, selected by rename/overload/mapped_identity/nested_ddl_contract/logical_error_identity/function_metadata/get_ddl_function: 231 passed.
- Restricted source/namespace/dropped-destination replay: 15 passed.
- Before the fix, the new denied-role suite failed 28 of 30 cells; all 30 now match Cloud.
- git diff --check: passed. The driver owns .spiral/check.sh; it was not run here.
## Deviations
- Cloud still validates destination database/schema access and managed-access restrictions for IF EXISTS when the source is hidden or absent, while ignoring signature conflicts and performing no move. Follow these captures rather than treating every invisible IF EXISTS source as an unconditional early success.
- Newly captured post-rejection calls require changes in handlers/execution.rs as well as the hinted rename gate: resolve dotted quoted identities from the AST and distinguish unknown-function calls from missing-container table errors. Existing error mapping is extended without changing the runtime or metadata column sets.
- The seven existing strict-xfail cells remain owned by LAV-4241: JavaScript dotted runtime identities, Python installed_packages DESC, malformed embedded-quote GET_DDL replay diagnostics, and temporary overload-coercion fallback. External invocation still has the existing no-gateway Cloud fixture restriction, owned by LAV-4241.
## Test matrix
Denominator: offline SF:SQL:STATEMENT:ALTER FUNCTION RENAME TO syntax, this child's ACs, and the reviewer's caller-visibility additions. Other alteration families retain their existing owners.
Existing rename contract × test_alter_function_rename_boundaries[conflict-if-exists] -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[conflict-if-exists]
Existing rename contract × test_alter_function_rename_boundaries[conflict] -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[conflict]
Existing rename contract × test_alter_function_rename_boundaries[destination-signature] -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[destination-signature]
Existing rename contract × test_alter_function_rename_boundaries[different-overload] -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[different-overload]
Existing rename contract × test_alter_function_rename_boundaries[missing-database-if-exists] -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[missing-database-if-exists]
Existing rename contract × test_alter_function_rename_boundaries[missing-database] -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[missing-database]
Existing rename contract × test_alter_function_rename_boundaries[missing-if-exists] -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[missing-if-exists]
Existing rename contract × test_alter_function_rename_boundaries[missing-schema-if-exists] -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[missing-schema-if-exists]
Existing rename contract × test_alter_function_rename_boundaries[missing-schema] -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[missing-schema]
Existing rename contract × test_alter_function_rename_boundaries[missing] -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[missing]
Existing rename contract × test_alter_function_rename_boundaries[same-name] -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[same-name]
Existing rename contract × test_alter_function_rename_boundaries[wrong-if-exists] -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[wrong-if-exists]
Existing rename contract × test_alter_function_rename_boundaries[wrong-signature] -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_boundaries[wrong-signature]
Existing rename contract × test_alter_function_rename_defaulted_quoted_arguments -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_defaulted_quoted_arguments
Caller resolution available-False-hidden × 002003 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[available-False-hidden]
Caller resolution available-False-missing × 002003 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[available-False-missing]
Caller resolution available-False-usage × 003001 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[available-False-usage]
Caller resolution available-True-hidden × no-op success × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[available-True-hidden]
Caller resolution available-True-missing × no-op success × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[available-True-missing]
Caller resolution available-True-usage × 003001 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[available-True-usage]
Caller resolution conflict-False-hidden × 002003 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[conflict-False-hidden]
Caller resolution conflict-False-missing × 002003 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[conflict-False-missing]
Caller resolution conflict-False-usage × 003001 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[conflict-False-usage]
Caller resolution conflict-True-hidden × no-op success × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[conflict-True-hidden]
Caller resolution conflict-True-missing × no-op success × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[conflict-True-missing]
Caller resolution conflict-True-usage × 003001 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[conflict-True-usage]
Caller resolution managed-False-hidden × 002003 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[managed-False-hidden]
Caller resolution managed-False-missing × 002003 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[managed-False-missing]
Caller resolution managed-False-usage × 003001 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[managed-False-usage]
Caller resolution managed-True-hidden × 003509 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[managed-True-hidden]
Caller resolution managed-True-missing × 003509 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[managed-True-missing]
Caller resolution managed-True-usage × 003001 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[managed-True-usage]
Caller resolution missing-database-False-hidden × 002003 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[missing-database-False-hidden]
Caller resolution missing-database-False-missing × 002003 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[missing-database-False-missing]
Caller resolution missing-database-False-usage × 003001 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[missing-database-False-usage]
Caller resolution missing-database-True-hidden × 002003 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[missing-database-True-hidden]
Caller resolution missing-database-True-missing × 002003 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[missing-database-True-missing]
Caller resolution missing-database-True-usage × 003001 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[missing-database-True-usage]
Caller resolution missing-schema-False-hidden × 002003 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[missing-schema-False-hidden]
Caller resolution missing-schema-False-missing × 002003 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[missing-schema-False-missing]
Caller resolution missing-schema-False-usage × 003001 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[missing-schema-False-usage]
Caller resolution missing-schema-True-hidden × 002003 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[missing-schema-True-hidden]
Caller resolution missing-schema-True-missing × 002003 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[missing-schema-True-missing]
Caller resolution missing-schema-True-usage × 003001 × preserved source/destination calls, siblings and metadata -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_denied_role[missing-schema-True-usage]
Existing rename contract × test_alter_function_rename_destination[-JAVASCRIPT-database] -> tests/queries/test_alter_function_rename.py::test_alter_function_rename_destination[-JAVASCRIPT-database]
Existing rename contract × test_alter_function_rename_destination[-JAVASCRIPT-quoted] -> tests/queries/test_alter_function_rena…1 parent 8235c01 commit 386c8b6
2 files changed
Lines changed: 7 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7175 | 7175 | | |
7176 | 7176 | | |
7177 | 7177 | | |
| 7178 | + | |
| 7179 | + | |
7178 | 7180 | | |
7179 | 7181 | | |
7180 | 7182 | | |
| |||
7285 | 7287 | | |
7286 | 7288 | | |
7287 | 7289 | | |
| 7290 | + | |
| 7291 | + | |
| 7292 | + | |
7288 | 7293 | | |
7289 | 7294 | | |
7290 | 7295 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13519 | 13519 | | |
13520 | 13520 | | |
13521 | 13521 | | |
| 13522 | + | |
13522 | 13523 | | |
13523 | 13524 | | |
13524 | 13525 | | |
| |||
13569 | 13570 | | |
13570 | 13571 | | |
13571 | 13572 | | |
| 13573 | + | |
13572 | 13574 | | |
13573 | 13575 | | |
13574 | 13576 | | |
| |||
0 commit comments