Skip to content

Commit b3a86ab

Browse files
Merge branch 'main' into type_no_as
2 parents ec95269 + a00d5cd commit b3a86ab

File tree

14 files changed

+345
-32
lines changed

14 files changed

+345
-32
lines changed

src/ast/ddl.rs

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,18 @@ pub enum AlterTableOperation {
365365
DropClusteringKey,
366366
SuspendRecluster,
367367
ResumeRecluster,
368+
/// `REFRESH`
369+
///
370+
/// Note: this is Snowflake specific for dynamic tables <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
371+
Refresh,
372+
/// `SUSPEND`
373+
///
374+
/// Note: this is Snowflake specific for dynamic tables <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
375+
Suspend,
376+
/// `RESUME`
377+
///
378+
/// Note: this is Snowflake specific for dynamic tables <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
379+
Resume,
368380
/// `ALGORITHM [=] { DEFAULT | INSTANT | INPLACE | COPY }`
369381
///
370382
/// [MySQL]-specific table alter algorithm.
@@ -845,6 +857,15 @@ impl fmt::Display for AlterTableOperation {
845857
write!(f, "RESUME RECLUSTER")?;
846858
Ok(())
847859
}
860+
AlterTableOperation::Refresh => {
861+
write!(f, "REFRESH")
862+
}
863+
AlterTableOperation::Suspend => {
864+
write!(f, "SUSPEND")
865+
}
866+
AlterTableOperation::Resume => {
867+
write!(f, "RESUME")
868+
}
848869
AlterTableOperation::AutoIncrement { equals, value } => {
849870
write!(
850871
f,
@@ -3837,6 +3858,20 @@ impl Spanned for DropExtension {
38373858
}
38383859
}
38393860

3861+
/// Table type for ALTER TABLE statements.
3862+
/// Used to distinguish between regular tables, Iceberg tables, and Dynamic tables.
3863+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3864+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3865+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3866+
pub enum AlterTableType {
3867+
/// Iceberg table type
3868+
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-iceberg-table>
3869+
Iceberg,
3870+
/// Dynamic table type
3871+
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
3872+
Dynamic,
3873+
}
3874+
38403875
/// ALTER TABLE statement
38413876
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
38423877
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -3853,19 +3888,18 @@ pub struct AlterTable {
38533888
/// For example: `ALTER TABLE table_name ON CLUSTER cluster_name ADD COLUMN c UInt32`
38543889
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/alter/update)
38553890
pub on_cluster: Option<Ident>,
3856-
/// Snowflake "ICEBERG" clause for Iceberg tables
3857-
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-iceberg-table>
3858-
pub iceberg: bool,
3891+
/// Table type: None for regular tables, Some(AlterTableType) for Iceberg or Dynamic tables
3892+
pub table_type: Option<AlterTableType>,
38593893
/// Token that represents the end of the statement (semicolon or EOF)
38603894
pub end_token: AttachedToken,
38613895
}
38623896

38633897
impl fmt::Display for AlterTable {
38643898
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3865-
if self.iceberg {
3866-
write!(f, "ALTER ICEBERG TABLE ")?;
3867-
} else {
3868-
write!(f, "ALTER TABLE ")?;
3899+
match &self.table_type {
3900+
Some(AlterTableType::Iceberg) => write!(f, "ALTER ICEBERG TABLE ")?,
3901+
Some(AlterTableType::Dynamic) => write!(f, "ALTER DYNAMIC TABLE ")?,
3902+
None => write!(f, "ALTER TABLE ")?,
38693903
}
38703904

38713905
if self.if_exists {

src/ast/mod.rs

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ pub use self::dcl::{
5959
AlterRoleOperation, CreateRole, ResetConfig, RoleOption, SecondaryRoles, SetConfigValue, Use,
6060
};
6161
pub use self::ddl::{
62-
Alignment, AlterColumnOperation, AlterConnectorOwner, AlterIndexOperation,
63-
AlterPolicyOperation, AlterSchema, AlterSchemaOperation, AlterTable, AlterTableAlgorithm,
64-
AlterTableLock, AlterTableOperation, AlterType, AlterTypeAddValue, AlterTypeAddValuePosition,
62+
Alignment, AlterColumnOperation, AlterConnectorOwner, AlterIndexOperation, AlterPolicyOperation,
63+
AlterSchema, AlterSchemaOperation, AlterTable, AlterTableAlgorithm, AlterTableLock,
64+
AlterTableOperation, AlterTableType, AlterType, AlterTypeAddValue, AlterTypeAddValuePosition,
6565
AlterTypeOperation, AlterTypeRename, AlterTypeRenameValue, ClusteredBy, ColumnDef,
6666
ColumnOption, ColumnOptionDef, ColumnOptions, ColumnPolicy, ColumnPolicyProperty,
6767
ConstraintCharacteristics, CreateConnector, CreateDomain, CreateExtension, CreateFunction,
@@ -2921,6 +2921,15 @@ pub enum Set {
29212921
/// MySQL-style
29222922
/// SET a = 1, b = 2, ..;
29232923
MultipleAssignments { assignments: Vec<SetAssignment> },
2924+
/// Session authorization for Postgres/Redshift
2925+
///
2926+
/// ```sql
2927+
/// SET SESSION AUTHORIZATION { user_name | DEFAULT }
2928+
/// ```
2929+
///
2930+
/// See <https://www.postgresql.org/docs/current/sql-set-session-authorization.html>
2931+
/// See <https://docs.aws.amazon.com/redshift/latest/dg/r_SET_SESSION_AUTHORIZATION.html>
2932+
SetSessionAuthorization(SetSessionAuthorizationParam),
29242933
/// MS-SQL session
29252934
///
29262935
/// See <https://learn.microsoft.com/en-us/sql/t-sql/statements/set-statements-transact-sql>
@@ -2995,6 +3004,7 @@ impl Display for Set {
29953004
modifier = context_modifier.map(|m| format!("{m}")).unwrap_or_default()
29963005
)
29973006
}
3007+
Self::SetSessionAuthorization(kind) => write!(f, "SET SESSION AUTHORIZATION {kind}"),
29983008
Self::SetSessionParam(kind) => write!(f, "SET {kind}"),
29993009
Self::SetTransaction {
30003010
modes,
@@ -4260,6 +4270,14 @@ pub enum Statement {
42604270
/// ```
42614271
/// [Redshift](https://docs.aws.amazon.com/redshift/latest/dg/r_VACUUM_command.html)
42624272
Vacuum(VacuumStatement),
4273+
/// Restore the value of a run-time parameter to the default value.
4274+
///
4275+
/// ```sql
4276+
/// RESET configuration_parameter;
4277+
/// RESET ALL;
4278+
/// ```
4279+
/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-reset.html)
4280+
Reset(ResetStatement),
42634281
}
42644282

42654283
impl From<Analyze> for Statement {
@@ -5758,6 +5776,7 @@ impl fmt::Display for Statement {
57585776
Statement::AlterSchema(s) => write!(f, "{s}"),
57595777
Statement::Vacuum(s) => write!(f, "{s}"),
57605778
Statement::AlterUser(s) => write!(f, "{s}"),
5779+
Statement::Reset(s) => write!(f, "{s}"),
57615780
}
57625781
}
57635782
}
@@ -9819,6 +9838,42 @@ impl fmt::Display for TableObject {
98199838
}
98209839
}
98219840

9841+
/// Represents a SET SESSION AUTHORIZATION statement
9842+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
9843+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
9844+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
9845+
pub struct SetSessionAuthorizationParam {
9846+
pub scope: ContextModifier,
9847+
pub kind: SetSessionAuthorizationParamKind,
9848+
}
9849+
9850+
impl fmt::Display for SetSessionAuthorizationParam {
9851+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
9852+
write!(f, "{}", self.kind)
9853+
}
9854+
}
9855+
9856+
/// Represents the parameter kind for SET SESSION AUTHORIZATION
9857+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
9858+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
9859+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
9860+
pub enum SetSessionAuthorizationParamKind {
9861+
/// Default authorization
9862+
Default,
9863+
9864+
/// User name
9865+
User(Ident),
9866+
}
9867+
9868+
impl fmt::Display for SetSessionAuthorizationParamKind {
9869+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
9870+
match self {
9871+
SetSessionAuthorizationParamKind::Default => write!(f, "DEFAULT"),
9872+
SetSessionAuthorizationParamKind::User(name) => write!(f, "{}", name),
9873+
}
9874+
}
9875+
}
9876+
98229877
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
98239878
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
98249879
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
@@ -10520,6 +10575,38 @@ impl fmt::Display for VacuumStatement {
1052010575
}
1052110576
}
1052210577

10578+
/// Variants of the RESET statement
10579+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
10580+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10581+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
10582+
pub enum Reset {
10583+
/// Resets all session parameters to their default values.
10584+
ALL,
10585+
10586+
/// Resets a specific session parameter to its default value.
10587+
ConfigurationParameter(ObjectName),
10588+
}
10589+
10590+
/// Resets a session parameter to its default value.
10591+
/// ```sql
10592+
/// RESET { ALL | <configuration_parameter> }
10593+
/// ```
10594+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
10595+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10596+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
10597+
pub struct ResetStatement {
10598+
pub reset: Reset,
10599+
}
10600+
10601+
impl fmt::Display for ResetStatement {
10602+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
10603+
match &self.reset {
10604+
Reset::ALL => write!(f, "RESET ALL"),
10605+
Reset::ConfigurationParameter(param) => write!(f, "RESET {}", param),
10606+
}
10607+
}
10608+
}
10609+
1052310610
impl From<Set> for Statement {
1052410611
fn from(s: Set) -> Self {
1052510612
Self::Set(s)
@@ -10760,6 +10847,12 @@ impl From<VacuumStatement> for Statement {
1076010847
}
1076110848
}
1076210849

10850+
impl From<ResetStatement> for Statement {
10851+
fn from(r: ResetStatement) -> Self {
10852+
Self::Reset(r)
10853+
}
10854+
}
10855+
1076310856
#[cfg(test)]
1076410857
mod tests {
1076510858
use crate::tokenizer::Location;

src/ast/query.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3135,12 +3135,18 @@ pub struct Values {
31353135
/// Was there an explicit ROWs keyword (MySQL)?
31363136
/// <https://dev.mysql.com/doc/refman/8.0/en/values.html>
31373137
pub explicit_row: bool,
3138+
// MySql supports both VALUES and VALUE keywords.
3139+
// <https://dev.mysql.com/doc/refman/9.2/en/insert.html>
3140+
pub value_keyword: bool,
31383141
pub rows: Vec<Vec<Expr>>,
31393142
}
31403143

31413144
impl fmt::Display for Values {
31423145
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3143-
f.write_str("VALUES")?;
3146+
match self.value_keyword {
3147+
true => f.write_str("VALUE")?,
3148+
false => f.write_str("VALUES")?,
3149+
};
31443150
let prefix = if self.explicit_row { "ROW" } else { "" };
31453151
let mut delim = "";
31463152
for row in &self.rows {

src/ast/spans.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ impl Spanned for Values {
223223
fn span(&self) -> Span {
224224
let Values {
225225
explicit_row: _, // bool,
226+
value_keyword: _,
226227
rows,
227228
} = self;
228229

@@ -475,6 +476,7 @@ impl Spanned for Statement {
475476
Statement::AlterSchema(s) => s.span(),
476477
Statement::Vacuum(..) => Span::empty(),
477478
Statement::AlterUser(..) => Span::empty(),
479+
Statement::Reset(..) => Span::empty(),
478480
}
479481
}
480482
}
@@ -1107,6 +1109,9 @@ impl Spanned for AlterTableOperation {
11071109
AlterTableOperation::DropClusteringKey => Span::empty(),
11081110
AlterTableOperation::SuspendRecluster => Span::empty(),
11091111
AlterTableOperation::ResumeRecluster => Span::empty(),
1112+
AlterTableOperation::Refresh => Span::empty(),
1113+
AlterTableOperation::Suspend => Span::empty(),
1114+
AlterTableOperation::Resume => Span::empty(),
11101115
AlterTableOperation::Algorithm { .. } => Span::empty(),
11111116
AlterTableOperation::AutoIncrement { value, .. } => value.span(),
11121117
AlterTableOperation::Lock { .. } => Span::empty(),

src/dialect/snowflake.rs

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#[cfg(not(feature = "std"))]
1919
use crate::alloc::string::ToString;
20+
use crate::ast::helpers::attached_token::AttachedToken;
2021
use crate::ast::helpers::key_value_options::{
2122
KeyValueOption, KeyValueOptionKind, KeyValueOptions, KeyValueOptionsDelimiter,
2223
};
@@ -26,11 +27,12 @@ use crate::ast::helpers::stmt_data_loading::{
2627
FileStagingCommand, StageLoadSelectItem, StageLoadSelectItemKind, StageParamsObject,
2728
};
2829
use crate::ast::{
29-
CatalogSyncNamespaceMode, ColumnOption, ColumnPolicy, ColumnPolicyProperty, ContactEntry,
30-
CopyIntoSnowflakeKind, CreateTableLikeKind, DollarQuotedString, Ident, IdentityParameters,
31-
IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder,
32-
InitializeKind, ObjectName, ObjectNamePart, RefreshModeKind, RowAccessPolicy, ShowObjects,
33-
SqlOption, Statement, StorageSerializationPolicy, TagsColumnOption, Value, WrappedCollection,
30+
AlterTable, AlterTableOperation, AlterTableType, CatalogSyncNamespaceMode, ColumnOption,
31+
ColumnPolicy, ColumnPolicyProperty, ContactEntry, CopyIntoSnowflakeKind, CreateTableLikeKind,
32+
DollarQuotedString, Ident, IdentityParameters, IdentityProperty, IdentityPropertyFormatKind,
33+
IdentityPropertyKind, IdentityPropertyOrder, InitializeKind, ObjectName, ObjectNamePart,
34+
RefreshModeKind, RowAccessPolicy, ShowObjects, SqlOption, Statement,
35+
StorageSerializationPolicy, TagsColumnOption, Value, WrappedCollection,
3436
};
3537
use crate::dialect::{Dialect, Precedence};
3638
use crate::keywords::Keyword;
@@ -214,6 +216,11 @@ impl Dialect for SnowflakeDialect {
214216
return Some(parser.parse_begin_exception_end());
215217
}
216218

219+
if parser.parse_keywords(&[Keyword::ALTER, Keyword::DYNAMIC, Keyword::TABLE]) {
220+
// ALTER DYNAMIC TABLE
221+
return Some(parse_alter_dynamic_table(parser));
222+
}
223+
217224
if parser.parse_keywords(&[Keyword::ALTER, Keyword::SESSION]) {
218225
// ALTER SESSION
219226
let set = match parser.parse_one_of_keywords(&[Keyword::SET, Keyword::UNSET]) {
@@ -604,6 +611,44 @@ fn parse_file_staging_command(kw: Keyword, parser: &mut Parser) -> Result<Statem
604611
}
605612
}
606613

614+
/// Parse snowflake alter dynamic table.
615+
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-table>
616+
fn parse_alter_dynamic_table(parser: &mut Parser) -> Result<Statement, ParserError> {
617+
// Use parse_object_name(true) to support IDENTIFIER() function
618+
let table_name = parser.parse_object_name(true)?;
619+
620+
// Parse the operation (REFRESH, SUSPEND, or RESUME)
621+
let operation = if parser.parse_keyword(Keyword::REFRESH) {
622+
AlterTableOperation::Refresh
623+
} else if parser.parse_keyword(Keyword::SUSPEND) {
624+
AlterTableOperation::Suspend
625+
} else if parser.parse_keyword(Keyword::RESUME) {
626+
AlterTableOperation::Resume
627+
} else {
628+
return parser.expected(
629+
"REFRESH, SUSPEND, or RESUME after ALTER DYNAMIC TABLE",
630+
parser.peek_token(),
631+
);
632+
};
633+
634+
let end_token = if parser.peek_token_ref().token == Token::SemiColon {
635+
parser.peek_token_ref().clone()
636+
} else {
637+
parser.get_current_token().clone()
638+
};
639+
640+
Ok(Statement::AlterTable(AlterTable {
641+
name: table_name,
642+
if_exists: false,
643+
only: false,
644+
operations: vec![operation],
645+
location: None,
646+
on_cluster: None,
647+
table_type: Some(AlterTableType::Dynamic),
648+
end_token: AttachedToken(end_token),
649+
}))
650+
}
651+
607652
/// Parse snowflake alter session.
608653
/// <https://docs.snowflake.com/en/sql-reference/sql/alter-session>
609654
fn parse_alter_session(parser: &mut Parser, set: bool) -> Result<Statement, ParserError> {

src/keywords.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,7 @@ define_keywords!(
794794
REF,
795795
REFERENCES,
796796
REFERENCING,
797+
REFRESH,
797798
REFRESH_MODE,
798799
REGCLASS,
799800
REGEXP,

0 commit comments

Comments
 (0)