Skip to content

Commit 43c42ab

Browse files
wojpadloWojciech Padloclaude
authored
Snowflake: parse ALTER STAGE (SET / RENAME TO) (#9)
* Snowflake: parse ALTER STAGE (SET / RENAME TO) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Fix pre-existing CI failures on the snowflake branch lineage These checks were already red on the base branch (lav-379-2-for-over-cursor), inherited from the cursor/scripting/ACCOUNT commits — unrelated to ALTER STAGE, but required for green CI on this PR: - codestyle: run cargo fmt --all across the crate - lint: collapse a match-in-match (parser scripting list), replace a forbidden unreachable! in DESCRIBE object-type parsing with a parse error, and collapse nested match arms in the warehouse/account tests - docs: drop unresolved intra-doc link brackets in scripting-list doc comments - compile-no-std: gate 'use alloc::vec' behind not(feature = std) in spans.rs Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Wojciech Padlo <wojciech.padlo@localstack.cloud> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent b7529a2 commit 43c42ab

5 files changed

Lines changed: 421 additions & 147 deletions

File tree

src/ast/mod.rs

Lines changed: 83 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4766,6 +4766,18 @@ pub enum Statement {
47664766
comment: Option<String>,
47674767
},
47684768
/// ```sql
4769+
/// ALTER STAGE [IF EXISTS] <name> { SET ... | RENAME TO <new_name> }
4770+
/// ```
4771+
/// See <https://docs.snowflake.com/en/sql-reference/sql/alter-stage>
4772+
AlterStage {
4773+
/// Stage name.
4774+
name: ObjectName,
4775+
/// `IF EXISTS` flag.
4776+
if_exists: bool,
4777+
/// The alter operation.
4778+
operation: AlterStageOperation,
4779+
},
4780+
/// ```sql
47694781
/// CREATE [OR REPLACE] WAREHOUSE [IF NOT EXISTS] <name>
47704782
/// ```
47714783
CreateWarehouse {
@@ -6839,6 +6851,17 @@ impl fmt::Display for Statement {
68396851
}
68406852
Ok(())
68416853
}
6854+
Statement::AlterStage {
6855+
name,
6856+
if_exists,
6857+
operation,
6858+
} => {
6859+
write!(
6860+
f,
6861+
"ALTER STAGE {if_exists}{name} {operation}",
6862+
if_exists = if *if_exists { "IF EXISTS " } else { "" },
6863+
)
6864+
}
68426865
Statement::CreateWarehouse {
68436866
or_replace,
68446867
if_not_exists,
@@ -7001,18 +7024,10 @@ impl fmt::Display for Statement {
70017024
}
70027025
write!(f, ")")?;
70037026
if let Some(val) = allow_writes {
7004-
write!(
7005-
f,
7006-
" ALLOW_WRITES = {}",
7007-
if *val { "TRUE" } else { "FALSE" }
7008-
)?;
7027+
write!(f, " ALLOW_WRITES = {}", if *val { "TRUE" } else { "FALSE" })?;
70097028
}
70107029
if let Some(ref c) = comment {
7011-
write!(
7012-
f,
7013-
" COMMENT = '{}'",
7014-
value::escape_single_quote_string(c)
7015-
)?;
7030+
write!(f, " COMMENT = '{}'", value::escape_single_quote_string(c))?;
70167031
}
70177032
Ok(())
70187033
}
@@ -7140,20 +7155,12 @@ impl fmt::Display for Statement {
71407155
if let Some(ref auth) = rest_authentication {
71417156
write!(f, " REST_AUTHENTICATION = ({auth})")?;
71427157
}
7143-
write!(
7144-
f,
7145-
" ENABLED = {}",
7146-
if *enabled { "TRUE" } else { "FALSE" }
7147-
)?;
7158+
write!(f, " ENABLED = {}", if *enabled { "TRUE" } else { "FALSE" })?;
71487159
if let Some(secs) = refresh_interval_seconds {
71497160
write!(f, " REFRESH_INTERVAL_SECONDS = {secs}")?;
71507161
}
71517162
if let Some(ref c) = comment {
7152-
write!(
7153-
f,
7154-
" COMMENT = '{}'",
7155-
value::escape_single_quote_string(c)
7156-
)?;
7163+
write!(f, " COMMENT = '{}'", value::escape_single_quote_string(c))?;
71577164
}
71587165
Ok(())
71597166
}
@@ -12138,6 +12145,61 @@ impl fmt::Display for AlterFileFormatOperation {
1213812145
}
1213912146
}
1214012147

12148+
/// Operations for `ALTER STAGE`.
12149+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
12150+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12151+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
12152+
pub enum AlterStageOperation {
12153+
/// `RENAME TO <new_name>`
12154+
RenameTo(ObjectName),
12155+
/// `SET <stage-params/options>` — the same property groups as `CREATE STAGE`.
12156+
Set {
12157+
/// Internal/external stage parameters (URL, STORAGE_INTEGRATION,
12158+
/// CREDENTIALS, ENCRYPTION, ENDPOINT).
12159+
stage_params: StageParamsObject,
12160+
/// Directory table parameters (`DIRECTORY = (...)`).
12161+
directory_table_params: KeyValueOptions,
12162+
/// File format options (`FILE_FORMAT = (...)`).
12163+
file_format: KeyValueOptions,
12164+
/// Copy options (`COPY_OPTIONS = (...)`).
12165+
copy_options: KeyValueOptions,
12166+
/// Optional `COMMENT` value.
12167+
comment: Option<String>,
12168+
},
12169+
}
12170+
12171+
impl fmt::Display for AlterStageOperation {
12172+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
12173+
match self {
12174+
AlterStageOperation::RenameTo(name) => {
12175+
write!(f, "RENAME TO {name}")
12176+
}
12177+
AlterStageOperation::Set {
12178+
stage_params,
12179+
directory_table_params,
12180+
file_format,
12181+
copy_options,
12182+
comment,
12183+
} => {
12184+
write!(f, "SET{stage_params}")?;
12185+
if !directory_table_params.options.is_empty() {
12186+
write!(f, " DIRECTORY=({directory_table_params})")?;
12187+
}
12188+
if !file_format.options.is_empty() {
12189+
write!(f, " FILE_FORMAT=({file_format})")?;
12190+
}
12191+
if !copy_options.options.is_empty() {
12192+
write!(f, " COPY_OPTIONS=({copy_options})")?;
12193+
}
12194+
if let Some(comment) = comment {
12195+
write!(f, " COMMENT='{comment}'")?;
12196+
}
12197+
Ok(())
12198+
}
12199+
}
12200+
}
12201+
}
12202+
1214112203
/// A `<key> = <value>` pair inside `ALTER WAREHOUSE … SET …`.
1214212204
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1214312205
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -12388,11 +12450,7 @@ impl fmt::Display for CatalogRestConfig {
1238812450
write!(f, " CATALOG_API_TYPE = {t}")?;
1238912451
}
1239012452
if let Some(ref w) = self.warehouse {
12391-
write!(
12392-
f,
12393-
" WAREHOUSE = '{}'",
12394-
value::escape_single_quote_string(w)
12395-
)?;
12453+
write!(f, " WAREHOUSE = '{}'", value::escape_single_quote_string(w))?;
1239612454
}
1239712455
if let Some(ref m) = self.access_delegation_mode {
1239812456
write!(f, " ACCESS_DELEGATION_MODE = {m}")?;

src/ast/spans.rs

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ use crate::{
2323
},
2424
tokenizer::TokenWithSpan,
2525
};
26+
#[cfg(not(feature = "std"))]
27+
use alloc::vec;
2628
use core::iter;
2729

2830
use crate::tokenizer::Span;
@@ -35,20 +37,19 @@ use super::{
3537
ConflictTarget, ConnectByKind, ConstraintCharacteristics, CopySource, CreateIndex, CreateTable,
3638
CreateTableOptions, Cte, Delete, DoUpdate, ExceptSelectItem, ExcludeSelectItem, Expr,
3739
ExprWithAlias, Fetch, ForIterationSource, ForStatement, ForValues, FromTable, Function,
38-
FunctionArg,
39-
FunctionArgExpr, FunctionArgumentClause, FunctionArgumentList, FunctionArguments, GroupByExpr,
40-
HavingBound, IfStatement, IlikeSelectItem, IndexColumn, Insert, Interpolate, InterpolateExpr,
41-
Join, JoinConstraint, JoinOperator, JsonPath, JsonPathElem, LateralView, LimitClause,
42-
LoopControlStatement, LoopStatement, MatchRecognizePattern, Measure, Merge, MergeAction,
43-
MergeClause, MergeInsertExpr, MergeInsertKind, MergeUpdateExpr, NamedParenthesizedList,
44-
NamedWindowDefinition, ObjectName, ObjectNamePart, Offset, OnConflict, OnConflictAction,
45-
OnInsert, OpenStatement, OrderBy, OrderByExpr, OrderByKind, OutputClause, Parens, Partition,
46-
PartitionBoundValue, PivotValueSource, ProjectionSelect, Query, RaiseStatement,
47-
RaiseStatementValue, ReferentialAction, RenameSelectItem, RepeatStatement, ReplaceSelectElement,
48-
ReplaceSelectItem, Select, SelectInto, SelectItem, SetExpr, SqlOption, Statement, Subscript,
49-
SymbolDefinition, TableAlias, TableAliasColumnDef, TableConstraint, TableFactor, TableObject,
50-
TableOptionsClustered, TableWithJoins, Update, UpdateTableFromKind, Use, Values, ViewColumnDef,
51-
WhileStatement, WildcardAdditionalOptions, With, WithFill,
40+
FunctionArg, FunctionArgExpr, FunctionArgumentClause, FunctionArgumentList, FunctionArguments,
41+
GroupByExpr, HavingBound, IfStatement, IlikeSelectItem, IndexColumn, Insert, Interpolate,
42+
InterpolateExpr, Join, JoinConstraint, JoinOperator, JsonPath, JsonPathElem, LateralView,
43+
LimitClause, LoopControlStatement, LoopStatement, MatchRecognizePattern, Measure, Merge,
44+
MergeAction, MergeClause, MergeInsertExpr, MergeInsertKind, MergeUpdateExpr,
45+
NamedParenthesizedList, NamedWindowDefinition, ObjectName, ObjectNamePart, Offset, OnConflict,
46+
OnConflictAction, OnInsert, OpenStatement, OrderBy, OrderByExpr, OrderByKind, OutputClause,
47+
Parens, Partition, PartitionBoundValue, PivotValueSource, ProjectionSelect, Query,
48+
RaiseStatement, RaiseStatementValue, ReferentialAction, RenameSelectItem, RepeatStatement,
49+
ReplaceSelectElement, ReplaceSelectItem, Select, SelectInto, SelectItem, SetExpr, SqlOption,
50+
Statement, Subscript, SymbolDefinition, TableAlias, TableAliasColumnDef, TableConstraint,
51+
TableFactor, TableObject, TableOptionsClustered, TableWithJoins, Update, UpdateTableFromKind,
52+
Use, Values, ViewColumnDef, WhileStatement, WildcardAdditionalOptions, With, WithFill,
5253
};
5354

5455
/// Given an iterator of spans, return the [Span::union] of all spans.
@@ -462,6 +463,7 @@ impl Spanned for Statement {
462463
Statement::CreateProcedure { .. } => Span::empty(),
463464
Statement::CreateMacro { .. } => Span::empty(),
464465
Statement::CreateStage { .. } => Span::empty(),
466+
Statement::AlterStage { .. } => Span::empty(),
465467
Statement::Assert { .. } => Span::empty(),
466468
Statement::Grant { .. } => Span::empty(),
467469
Statement::Deny { .. } => Span::empty(),
@@ -831,10 +833,7 @@ impl Spanned for RepeatStatement {
831833
impl Spanned for LoopControlStatement {
832834
fn span(&self) -> Span {
833835
let LoopControlStatement { kind: _, label } = self;
834-
label
835-
.as_ref()
836-
.map(|l| l.span)
837-
.unwrap_or_else(Span::empty)
836+
label.as_ref().map(|l| l.span).unwrap_or_else(Span::empty)
838837
}
839838
}
840839

0 commit comments

Comments
 (0)