Skip to content

Commit cc519d5

Browse files
committed
Merge main 00e831a (#40) into the ALTER batch
Conflicts were helper visibility (main's pub(super) kept) and the ddl module list (both modules kept).
2 parents ecd1e64 + 00e831a commit cc519d5

6 files changed

Lines changed: 1100 additions & 13 deletions

File tree

‎crates/sqlquack-syntax/src/expressions/schema_objects/models.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,9 @@ pub struct AlterObject {
11221122
pub kind: String,
11231123
/// The object name
11241124
pub name: TableRef,
1125+
/// The argument types that identify a function or procedure; a TABLE( ... ) argument is a tuple
1126+
#[serde(default, skip_serializing_if = "Vec::is_empty")]
1127+
pub arguments: Vec<Expression>,
11251128
/// IF EXISTS clause
11261129
#[serde(default)]
11271130
pub if_exists: bool,

‎crates/sqlquack-syntax/src/parser/_helpers/ddl/alter.rs‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,12 @@ impl Parser {
971971
}
972972

973973
fn parse_alter_add_partition(&mut self) -> Result<AlterTableAction> {
974+
if matches!(
975+
self.config.dialect,
976+
Some(crate::tokens::models::DialectType::Snowflake)
977+
) {
978+
return Err(self.parse_error("Snowflake adds partitions to external tables only"));
979+
}
974980
self.skip();
975981
self.expect_token(TokenType::LParen)?;
976982
let mut partition_exprs: Vec<Expression> = Vec::new();

‎crates/sqlquack-syntax/src/parser/_helpers/ddl/mod.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ pub(crate) mod explain;
99
pub(crate) mod scripting;
1010
pub(crate) mod snowflake_alter;
1111
pub(crate) mod snowflake_alter_objects;
12+
pub(crate) mod snowflake_alter_resources;
1213
pub(crate) mod table_options;

‎crates/sqlquack-syntax/src/parser/_helpers/ddl/snowflake_alter.rs‎

Lines changed: 241 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
//! Snowflake ALTER of object kinds with no statement of their own: EXPERIMENT, SNAPSHOT, SNAPSHOT SET, TAG, TASK and TASK GRAPH.
1+
//! Snowflake ALTER of object kinds that have no statement of their own, such as TASK, TAG or ALERT.
22
33
use crate::expressions::names::models::Identifier;
44
use crate::expressions::names::models::TableRef;
55
use crate::expressions::schema_objects::models::AlterObject;
66
use crate::expressions::schema_objects::models::ObjectProperty;
77
use crate::expressions::tree::models::Expression;
8+
use crate::expressions::types::models::Tuple;
89
use crate::parser::constants::SNOWFLAKE_ALTER_KINDS;
910
use crate::parser::constants::TASK_ACTIONS;
1011
use crate::parser::models::Parser;
@@ -51,6 +52,28 @@ impl Parser {
5152
if self.match_identifier("EXPERIMENT") {
5253
return self.parse_alter_experiment().map(Some);
5354
}
55+
if self.match_identifier("ALERT") {
56+
return self.parse_alter_alert().map(Some);
57+
}
58+
if self.match_text_seq(&["ONLINE", "FEATURE", "TABLE"]) {
59+
return self.parse_alter_online_feature_table().map(Some);
60+
}
61+
if self.check_identifier("ONLINE")
62+
|| self.check_identifier("FEATURE") && !self.check_next_identifier("POLICY")
63+
{
64+
return Err(self.parse_error(
65+
"Snowflake has ALTER ONLINE FEATURE TABLE and ALTER FEATURE POLICY only",
66+
));
67+
}
68+
if self.match_identifier("VARIABLE") {
69+
return self.parse_alter_variable().map(Some);
70+
}
71+
if self.match_token(TokenType::Function) || self.match_identifier("FUNCTION") {
72+
return self.parse_alter_function().map(Some);
73+
}
74+
if let Some(alter) = self.parse_alter_snowflake_resource()? {
75+
return Ok(Some(alter));
76+
}
5477
if !self.is_at_end()
5578
&& !SNOWFLAKE_ALTER_KINDS.contains(&self.peek_text().to_ascii_uppercase().as_str())
5679
{
@@ -63,20 +86,20 @@ impl Parser {
6386
}
6487

6588
/// The uppercase text of the token `offset` tokens ahead, if there is one.
66-
pub(crate) fn text_at(&self, offset: usize) -> Option<String> {
89+
pub(super) fn text_at(&self, offset: usize) -> Option<String> {
6790
self.tokens
6891
.get(self.current + offset)
6992
.map(|token| token.text.to_ascii_uppercase())
7093
}
7194

7295
/// Parse `[ IF EXISTS ] <name>` after the kind.
73-
pub(crate) fn parse_alter_object_head(&mut self) -> Result<(TableRef, bool)> {
96+
pub(super) fn parse_alter_object_head(&mut self) -> Result<(TableRef, bool)> {
7497
let if_exists = self.match_keywords(&[TokenType::If, TokenType::Exists]);
7598
Ok((self.parse_object_name()?, if_exists))
7699
}
77100

78101
/// Parse an object name: an identifier, never a string or an unquoted reserved keyword.
79-
pub(crate) fn parse_object_name(&mut self) -> Result<TableRef> {
102+
pub(super) fn parse_object_name(&mut self) -> Result<TableRef> {
80103
if self.check(TokenType::String)
81104
|| self.is_snowflake_reserved_keyword()
82105
|| !self.is_object_name_start()
@@ -94,7 +117,7 @@ impl Parser {
94117
}
95118

96119
/// Parse a simple name, such as a contact purpose or a property: an identifier, not a reserved keyword.
97-
pub(crate) fn parse_simple_name(&mut self) -> Result<Identifier> {
120+
pub(super) fn parse_simple_name(&mut self) -> Result<Identifier> {
98121
if self.check(TokenType::String)
99122
|| self.is_snowflake_reserved_keyword()
100123
|| !self.is_object_name_start()
@@ -105,7 +128,7 @@ impl Parser {
105128
}
106129

107130
/// Parse a property value: a literal, TRUE, FALSE or a name.
108-
pub(crate) fn parse_object_value(&mut self) -> Result<Expression> {
131+
pub(super) fn parse_object_value(&mut self) -> Result<Expression> {
109132
if self.check(TokenType::String)
110133
|| self.check(TokenType::Number)
111134
|| self.check(TokenType::DollarString)
@@ -129,15 +152,15 @@ impl Parser {
129152
}
130153

131154
/// Parse a string literal value.
132-
pub(crate) fn parse_string_value(&mut self) -> Result<Expression> {
155+
pub(super) fn parse_string_value(&mut self) -> Result<Expression> {
133156
if !self.check(TokenType::String) {
134157
return Err(self.parse_error("Expected a string"));
135158
}
136159
self.parse_primary()
137160
}
138161

139162
/// Consume one of `choices`, each a sequence of words, and return its words joined.
140-
pub(crate) fn expect_alter_words(&mut self, choices: &[&[&str]]) -> Result<String> {
163+
pub(super) fn expect_alter_words(&mut self, choices: &[&[&str]]) -> Result<String> {
141164
match choices.iter().find(|words| self.match_text_seq(words)) {
142165
Some(words) => Ok(words.join(" ")),
143166
None => Err(self.parse_error(format!(
@@ -152,7 +175,7 @@ impl Parser {
152175
}
153176

154177
/// Parse a comma-separated list of object names.
155-
fn parse_object_name_list(&mut self) -> Result<Vec<Expression>> {
178+
pub(super) fn parse_object_name_list(&mut self) -> Result<Vec<Expression>> {
156179
let mut names = vec![Expression::Table(Box::new(self.parse_object_name()?))];
157180
while self.match_token(TokenType::Comma) {
158181
names.push(Expression::Table(Box::new(self.parse_object_name()?)));
@@ -161,7 +184,7 @@ impl Parser {
161184
}
162185

163186
/// Parse the properties of a SET (`set`) or UNSET action; `graph` admits TASK_DEFAULTS and always reads CONTACT as contacts.
164-
fn parse_alter_object_properties(
187+
pub(super) fn parse_alter_object_properties(
165188
&mut self,
166189
set: bool,
167190
graph: bool,
@@ -248,7 +271,7 @@ impl Parser {
248271
}
249272

250273
/// Parse a possibly qualified name, such as a tag name, as one identifier.
251-
pub(crate) fn parse_simple_qualified_name(&mut self) -> Result<Identifier> {
274+
pub(super) fn parse_simple_qualified_name(&mut self) -> Result<Identifier> {
252275
let mut name = self.parse_simple_name()?;
253276
while self.match_token(TokenType::Dot) {
254277
let part = self.parse_simple_name()?;
@@ -496,10 +519,214 @@ impl Parser {
496519
(operands, Vec::new()),
497520
))
498521
}
522+
523+
/// Parse ALTER ALERT after its kind.
524+
fn parse_alter_alert(&mut self) -> Result<Expression> {
525+
let head = self.parse_alter_object_head()?;
526+
let mut action = self.expect_alter_words(&[
527+
&["RESUME"],
528+
&["SUSPEND"],
529+
&["FROM", "TEMPLATE"],
530+
&["MODIFY", "CONDITION", "EXISTS"],
531+
&["MODIFY", "ACTION"],
532+
&["SET"],
533+
&["UNSET"],
534+
])?;
535+
let mut operands: Vec<Expression> = Vec::new();
536+
let mut properties: Vec<ObjectProperty> = Vec::new();
537+
match action.as_str() {
538+
"FROM TEMPLATE" => {
539+
operands.push(Expression::Table(Box::new(self.parse_object_name()?)));
540+
action.push_str(&format!(" {}", self.expect_alter_words(&[&["SET"]])?));
541+
properties = self.parse_alter_object_properties(true, false)?;
542+
}
543+
"MODIFY CONDITION EXISTS" => {
544+
self.expect_token(TokenType::LParen)?;
545+
operands.push(self.parse_statement()?);
546+
self.expect_token(TokenType::RParen)?;
547+
}
548+
"MODIFY ACTION" => operands.push(self.parse_statement()?),
549+
"SET" => properties = self.parse_alter_object_properties(true, false)?,
550+
"UNSET" => properties = self.parse_alter_object_properties(false, false)?,
551+
_ => {}
552+
}
553+
Ok(alter_object("ALERT", head, action, (operands, properties)))
554+
}
555+
556+
/// Parse ALTER ONLINE FEATURE TABLE after its kind.
557+
fn parse_alter_online_feature_table(&mut self) -> Result<Expression> {
558+
let head = self.parse_alter_object_head()?;
559+
let action = self.expect_alter_words(&[
560+
&["SUSPEND"],
561+
&["RESUME"],
562+
&["REFRESH"],
563+
&["RENAME", "TO"],
564+
&["SET"],
565+
&["UNSET"],
566+
])?;
567+
let mut operands: Vec<Expression> = Vec::new();
568+
let mut properties: Vec<ObjectProperty> = Vec::new();
569+
match action.as_str() {
570+
"RENAME TO" => operands.push(Expression::Table(Box::new(self.parse_object_name()?))),
571+
"SET" => properties = self.parse_alter_object_properties(true, false)?,
572+
"UNSET" => {
573+
self.expect_alter_words(&[&["TAG"]])?;
574+
loop {
575+
let name = self.parse_simple_qualified_name()?;
576+
properties.push(property("TAG", Some(name), None));
577+
if !self.match_token(TokenType::Comma) {
578+
break;
579+
}
580+
}
581+
}
582+
_ => {}
583+
}
584+
Ok(alter_object(
585+
"ONLINE FEATURE TABLE",
586+
head,
587+
action,
588+
(operands, properties),
589+
))
590+
}
591+
592+
/// Parse ALTER VARIABLE after its kind.
593+
fn parse_alter_variable(&mut self) -> Result<Expression> {
594+
let head = self.parse_alter_object_head()?;
595+
let action = self.expect_alter_words(&[
596+
&["RENAME", "TO"],
597+
&["SET", "DEFAULT"],
598+
&["DROP", "DEFAULT"],
599+
&["SET", "COMMENT"],
600+
&["UNSET", "COMMENT"],
601+
])?;
602+
let mut operands: Vec<Expression> = Vec::new();
603+
let mut properties: Vec<ObjectProperty> = Vec::new();
604+
match action.as_str() {
605+
"RENAME TO" => operands.push(Expression::Table(Box::new(self.parse_object_name()?))),
606+
"SET DEFAULT" => operands.push(self.parse_expression()?),
607+
"SET COMMENT" => {
608+
self.expect_token(TokenType::Eq)?;
609+
properties.push(property("COMMENT", None, Some(self.parse_string_value()?)));
610+
}
611+
_ => {}
612+
}
613+
Ok(alter_object(
614+
"VARIABLE",
615+
head,
616+
action,
617+
(operands, properties),
618+
))
619+
}
620+
621+
/// Parse ALTER FUNCTION after its kind: UDF, external, service and data metric functions.
622+
fn parse_alter_function(&mut self) -> Result<Expression> {
623+
let head = self.parse_alter_object_head()?;
624+
let arguments = self.parse_routine_signature()?;
625+
let mut action = self.expect_alter_words(&[&["RENAME", "TO"], &["SET"], &["UNSET"]])?;
626+
let mut operands: Vec<Expression> = Vec::new();
627+
let mut properties: Vec<ObjectProperty> = Vec::new();
628+
match action.as_str() {
629+
"RENAME TO" => operands.push(Expression::Table(Box::new(self.parse_object_name()?))),
630+
"SET" if self.check_identifier("SECURE") && self.is_statement_end_at(1) => {
631+
self.skip();
632+
action.push_str(" SECURE");
633+
}
634+
"SET" => properties = self.parse_routine_set_properties()?,
635+
_ => properties = self.parse_alter_object_properties(false, false)?,
636+
}
637+
let Expression::AlterObject(mut alter) =
638+
alter_object("FUNCTION", head, action, (operands, properties))
639+
else {
640+
return Err(self.parse_error("Expected an ALTER statement"));
641+
};
642+
alter.arguments = arguments;
643+
Ok(Expression::AlterObject(alter))
644+
}
645+
646+
/// Whether the token `offset` tokens ahead ends the statement.
647+
pub(super) fn is_statement_end_at(&self, offset: usize) -> bool {
648+
self.tokens
649+
.get(self.current + offset)
650+
.is_none_or(|token| token.token_type == TokenType::Semicolon)
651+
}
652+
653+
/// Parse `( [ <type> , ... ] )` or `( TABLE( <type> , ... ) [ , TABLE( ... ) ] )` after a routine name.
654+
pub(super) fn parse_routine_signature(&mut self) -> Result<Vec<Expression>> {
655+
self.expect_token(TokenType::LParen)?;
656+
let mut arguments: Vec<Expression> = Vec::new();
657+
if self.match_token(TokenType::RParen) {
658+
return Ok(arguments);
659+
}
660+
loop {
661+
if self.check(TokenType::Table) && self.check_next(TokenType::LParen) {
662+
self.current += 2;
663+
let mut columns = vec![Expression::DataType(self.parse_data_type()?)];
664+
while self.match_token(TokenType::Comma) {
665+
columns.push(Expression::DataType(self.parse_data_type()?));
666+
}
667+
self.expect_token(TokenType::RParen)?;
668+
arguments.push(Expression::Tuple(Box::new(Tuple {
669+
expressions: columns,
670+
})));
671+
} else {
672+
arguments.push(Expression::DataType(self.parse_data_type()?));
673+
}
674+
if !self.match_token(TokenType::Comma) {
675+
break;
676+
}
677+
}
678+
self.expect_token(TokenType::RParen)?;
679+
Ok(arguments)
680+
}
681+
682+
/// Parse the properties after a routine's SET: TAG pairs, or `<name> = <value>` with list values.
683+
fn parse_routine_set_properties(&mut self) -> Result<Vec<ObjectProperty>> {
684+
if self.check_identifier("TAG") && !self.check_next(TokenType::Eq) {
685+
return self.parse_alter_object_properties(true, false);
686+
}
687+
let mut properties: Vec<ObjectProperty> = Vec::new();
688+
loop {
689+
let name = self.parse_simple_name()?;
690+
self.expect_token(TokenType::Eq)?;
691+
let value = if self.check(TokenType::LParen) {
692+
self.parse_routine_value_list()?
693+
} else {
694+
self.parse_object_value()?
695+
};
696+
properties.push(property(&name.name.to_ascii_uppercase(), None, Some(value)));
697+
self.match_token(TokenType::Comma);
698+
if self.is_at_end() || self.check(TokenType::Semicolon) {
699+
return Ok(properties);
700+
}
701+
}
702+
}
703+
704+
/// Parse `( [ <item> [ , ... ] ] )`, each item a value or a `'<key>' = <value>` pair.
705+
pub(super) fn parse_routine_value_list(&mut self) -> Result<Expression> {
706+
self.expect_token(TokenType::LParen)?;
707+
let mut items: Vec<Expression> = Vec::new();
708+
if !self.check(TokenType::RParen) {
709+
loop {
710+
let item = self.parse_object_value()?;
711+
items.push(if self.match_token(TokenType::Eq) {
712+
Expression::Tuple(Box::new(Tuple {
713+
expressions: vec![item, self.parse_object_value()?],
714+
}))
715+
} else {
716+
item
717+
});
718+
if !self.match_token(TokenType::Comma) {
719+
break;
720+
}
721+
}
722+
}
723+
self.expect_token(TokenType::RParen)?;
724+
Ok(Expression::Tuple(Box::new(Tuple { expressions: items })))
725+
}
499726
}
500727

501728
/// An ALTER of `kind` on the named object, with its action, operands and properties.
502-
pub(crate) fn alter_object(
729+
pub(super) fn alter_object(
503730
kind: &str,
504731
(name, if_exists): (TableRef, bool),
505732
action: String,
@@ -508,6 +735,7 @@ pub(crate) fn alter_object(
508735
Expression::AlterObject(Box::new(AlterObject {
509736
kind: kind.to_owned(),
510737
name,
738+
arguments: Vec::new(),
511739
if_exists,
512740
action,
513741
operands,
@@ -516,7 +744,7 @@ pub(crate) fn alter_object(
516744
}
517745

518746
/// One property of kind `kind`.
519-
pub(crate) fn property(
747+
pub(super) fn property(
520748
kind: &str,
521749
name: Option<Identifier>,
522750
value: Option<Expression>,

0 commit comments

Comments
 (0)