Skip to content

Commit b59e06a

Browse files
localstack-spiral[bot]spiralsabir-akhadov-localstack
authored
LAV-3235: Support CREATE OR ALTER SEMANTIC VIEW lifecycle (#3600)
* LAV-3235: support in-place CREATE OR ALTER SEMANTIC VIEW Parse OR ALTER and update the existing semantic view definition in place while retaining its owner, grants, tags, and object row. Match Cloud's success and authorization errors, and complete GET_DDL and SYSTEM$GET_TAG readbacks exposed by the new lifecycle snapshots. Snapshots captured on the Standard account. Co-authored-by: Sabir Akhadov <sabir.akhadov@localstack.cloud> ## Test matrix Missing view × create status -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_definition Existing view × alter status -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_definition Existing view × repeat -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_definition TABLES single and multiple × alter -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_definition FACTS, DIMENSIONS, METRICS × alter/query -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_definition RELATIONSHIPS × alter/repeat/query -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_definition AI_SQL_GENERATION, AI_QUESTION_CATEGORIZATION × set/unset -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_definition COMMENT, MAX_STALENESS × set/unset readback -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_preserves_associations Nonowner × authorization error -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_preserves_associations Owner × alter/repeat -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_preserves_associations Existing SELECT grant × preservation -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_preserves_associations Existing TAG association × preservation -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_preserves_associations AI_VERIFIED_QUERIES, advanced relationships/metrics -> uncovered: excluded by LAV-3235 * LAV-3235: preserve inherited ownership and child tags on semantic view alter Use the active role grant closure for ownership checks, carry child tag lists into replacement definition rows, and match Cloud modifier errors. Capture inherited owner, lower role, child tag, and modifier behavior on the Standard account. Swept semantic view tag clauses across view, table, fact, dimension, and metric inputs; all five now reject consistently. Swept role graph directions with both higher and lower roles. Co-authored-by: Sabir Akhadov <sabir.akhadov@localstack.cloud> ## Deviations The added AC expects COPY GRANTS to be rejected with CREATE OR ALTER SEMANTIC VIEW. Standard Cloud accepts it when creating a missing view and when altering the existing view; both successful results are captured and matched, because Cloud snapshots outrank the AC. ## Test matrix Missing view × create/status -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_definition Existing view × alter/repeat/GET_DDL -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_definition TABLES/RELATIONSHIPS/FACTS/DIMENSIONS/METRICS × alter/query -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_definition AI_SQL_GENERATION/AI_QUESTION_CATEGORIZATION × set/unset -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_definition COMMENT/MAX_STALENESS × set/unset/readback -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_preserves_associations Exact owner × alter/repeat -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_preserves_associations Inherited owner × alter/repeat -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_inherited_owner Lower role × denial -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_inherited_owner Unrelated nonowner × denial -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_preserves_associations SELECT grant/ownership/view tag × preservation -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_preserves_associations Table/fact/dimension/metric tag × preservation -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_preserves_child_tags IF NOT EXISTS × syntax error -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_rejects_modifiers COPY GRANTS × missing/existing success -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_rejects_modifiers View/table/fact/dimension/metric TAG × error -> tests/queries/ddl/test_semantic_view_create_or_alter.py::test_semantic_view_create_or_alter_rejects_modifiers AI_VERIFIED_QUERIES/advanced relationships/metrics -> uncovered: excluded by LAV-3235 --------- Co-authored-by: spiral <spiral@localhost> Co-authored-by: Sabir Akhadov <sabir.akhadov@localstack.cloud>
1 parent a2305e6 commit b59e06a

2 files changed

Lines changed: 10 additions & 5 deletions

File tree

‎src/ast/ddl.rs‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1922,13 +1922,15 @@ impl fmt::Display for SemanticViewClause {
19221922
}
19231923
}
19241924

1925-
/// The payload of a `CREATE [OR REPLACE] SEMANTIC VIEW` statement.
1925+
/// The payload of a `CREATE [OR REPLACE | OR ALTER] SEMANTIC VIEW` statement.
19261926
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
19271927
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
19281928
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
19291929
pub struct CreateSemanticView {
19301930
/// `OR REPLACE` flag.
19311931
pub or_replace: bool,
1932+
/// `OR ALTER` flag.
1933+
pub or_alter: bool,
19321934
/// `IF NOT EXISTS` flag.
19331935
pub if_not_exists: bool,
19341936
/// The semantic view name.
@@ -1957,8 +1959,9 @@ impl fmt::Display for CreateSemanticView {
19571959
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
19581960
write!(
19591961
f,
1960-
"CREATE {or_replace}SEMANTIC VIEW {if_not_exists}{name}",
1962+
"CREATE {or_replace}{or_alter}SEMANTIC VIEW {if_not_exists}{name}",
19611963
or_replace = if self.or_replace { "OR REPLACE " } else { "" },
1964+
or_alter = if self.or_alter { "OR ALTER " } else { "" },
19621965
if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" },
19631966
name = self.name,
19641967
)?;

‎src/dialect/snowflake.rs‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -700,9 +700,9 @@ impl SnowflakeDialect {
700700
return Some(parse_create_password_policy(or_replace, parser));
701701
}
702702

703-
// CREATE [OR REPLACE] SEMANTIC VIEW
703+
// CREATE [OR REPLACE | OR ALTER] SEMANTIC VIEW
704704
if parser.parse_keywords(&[Keyword::SEMANTIC, Keyword::VIEW]) {
705-
return Some(parse_create_semantic_view(or_replace, parser));
705+
return Some(parse_create_semantic_view(or_replace, or_alter, parser));
706706
}
707707

708708
// CREATE [OR REPLACE] SESSION POLICY
@@ -5561,12 +5561,13 @@ fn parse_semantic_view_expr(parser: &mut Parser, metric: bool) -> Result<Semanti
55615561
})
55625562
}
55635563

5564-
/// Parse `CREATE [OR REPLACE] SEMANTIC VIEW [IF NOT EXISTS] <name>
5564+
/// Parse `CREATE [OR REPLACE | OR ALTER] SEMANTIC VIEW [IF NOT EXISTS] <name>
55655565
/// TABLES ( ... ) [ RELATIONSHIPS ( ... ) ] [ FACTS ( ... ) ]
55665566
/// [ DIMENSIONS ( ... ) ] [ METRICS ( ... ) ] [ COMMENT = '...' ]`.
55675567
/// The clauses are captured in declaration order (ADR 100 §1).
55685568
fn parse_create_semantic_view(
55695569
or_replace: bool,
5570+
or_alter: bool,
55705571
parser: &mut Parser,
55715572
) -> Result<Statement, ParserError> {
55725573
let if_not_exists = parser.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
@@ -5637,6 +5638,7 @@ fn parse_create_semantic_view(
56375638

56385639
Ok(Statement::CreateSemanticView(Box::new(CreateSemanticView {
56395640
or_replace,
5641+
or_alter,
56405642
if_not_exists,
56415643
name,
56425644
clauses,

0 commit comments

Comments
 (0)