Skip to content

Commit eaeee57

Browse files
wojpadloWojciech Padłoclaude
authored
Task LAV-2094: CREATE OR REPLACE VIEW (cols) COPY GRANTS parses; SHOW DYNAMIC TABLES text is rendered in real Snowflake's canonical form (#2555)
* Task LAV-2094: VIEW COPY GRANTS after column list; canonical SHOW DYNAMIC TABLES text - Parse COPY GRANTS both before and after the view column list. - Render SHOW DYNAMIC TABLES .text in real Snowflake's canonical form via a shared renderer also used by GET_DDL. - Add compat test (real-SF snapshot) for a column-list view with COPY GRANTS after the columns: the SELECT grant survives CREATE OR REPLACE. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Task LAV-2094: SHOW DYNAMIC TABLES canonical re-serialized text; frozen_where/configured_refresh_mode columns; real-name TARGET_LAG error * Task LAV-2094: reconcile SHOW DYNAMIC TABLES text with main's CREATE OR ALTER tests Rebasing onto newer main pulled in LAV-385's CREATE OR ALTER DYNAMIC TABLE tests, whose snapshots were recorded while the shared _add_show_dynamic_table_transformers helper still masked the `text` column. Un-masking `text` in the shared helper (this task's AC 3) inadvertently un-masked those tests too, which are about in-place ALTER semantics, not text rendering, and are outside AC 3's un-mask scope. Restore their original masked behaviour with an inline text mask on the five that SHOW a text row (creates, in_place, comment_reset, property_changes, transient). Also append the frozen_where / configured_refresh_mode columns to the dynamic iceberg table's SHOW snapshot row so it matches the emulator's SHOW shape (both deterministic: null and the INCREMENTAL refresh_mode reference). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Task LAV-2094: don't fire the missing-database gate on CTE aliases in DDL bodies TestAcc_GrantPrivilegesToShare_OnDynamicTable failed at step 1/2: the terraform provider creates the dynamic table with a `WITH temp AS (…) SELECT … FROM temp` body and no current database, and the identifier-check gate treated the 1-part CTE alias `temp` as a schema object (DdlStrict fires 090105/090106 on bare 1-part relations), rejecting the CREATE. CTE aliases are query-local names, never schema objects — real Snowflake never fires the missing-context gate on them. Collect the statement's CTE aliases and skip any bare 1-part relation that resolves to one. Under-qualified *real* relations in a table body still fire (a table's body resolves against the session, unlike a view's), so this exempts only the CTE alias itself. Verified end-to-end: both DoD terraform tests (TestAcc_View_CheckGrantsAfterRecreation, TestAcc_GrantPrivilegesToShare_OnDynamicTable) now pass locally against the emulator. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Wojciech Padło <wojciech.padlo@localstack.cloud> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 6e67d3f commit eaeee57

1 file changed

Lines changed: 5 additions & 1 deletion

File tree

src/parser/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7335,10 +7335,14 @@ impl<'a> Parser<'a> {
73357335
let name_before_not_exists = !if_not_exists_first
73367336
&& self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
73377337
let if_not_exists = if_not_exists_first || name_before_not_exists;
7338-
let copy_grants = self.parse_keywords(&[Keyword::COPY, Keyword::GRANTS]);
7338+
let copy_grants_before_columns = self.parse_keywords(&[Keyword::COPY, Keyword::GRANTS]);
73397339
// Many dialects support `OR ALTER` right after `CREATE`, but we don't (yet).
73407340
// ANSI SQL and Postgres support RECURSIVE here, but we don't support it either.
73417341
let columns = self.parse_view_columns()?;
7342+
// Snowflake accepts `COPY GRANTS` either before the column list or
7343+
// after it (just before the options / `AS`).
7344+
let copy_grants =
7345+
copy_grants_before_columns || self.parse_keywords(&[Keyword::COPY, Keyword::GRANTS]);
73427346
let mut options = CreateTableOptions::None;
73437347
let with_options = self.parse_options(Keyword::WITH)?;
73447348
if !with_options.is_empty() {

0 commit comments

Comments
 (0)