This is an automated email from the ASF dual-hosted git repository.
iffyio pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
The following commit(s) were added to refs/heads/main by this push:
new 85f85515 SET with a list of comma separated assignments (#1757)
85f85515 is described below
commit 85f855150fddf9326b0c2de0a5808fb46a1f2527
Author: Mohamed Abdeen <[email protected]>
AuthorDate: Wed Mar 12 22:02:39 2025 +0200
SET with a list of comma separated assignments (#1757)
---
src/ast/mod.rs | 361 ++++++++++++++++++++++++++------------------
src/ast/spans.rs | 15 +-
src/dialect/mod.rs | 10 ++
src/dialect/mssql.rs | 1 +
src/dialect/mysql.rs | 4 +
src/keywords.rs | 2 +
src/parser/mod.rs | 294 ++++++++++++++++++++++++------------
tests/sqlparser_common.rs | 119 ++++++++-------
tests/sqlparser_hive.rs | 17 +--
tests/sqlparser_mssql.rs | 8 +-
tests/sqlparser_mysql.rs | 22 +--
tests/sqlparser_postgres.rs | 82 +++++-----
12 files changed, 562 insertions(+), 373 deletions(-)
diff --git a/src/ast/mod.rs b/src/ast/mod.rs
index e5e4aef0..8ab3fc0f 100644
--- a/src/ast/mod.rs
+++ b/src/ast/mod.rs
@@ -2394,6 +2394,168 @@ pub enum CreatePolicyCommand {
Delete,
}
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum Set {
+ /// SQL Standard-style
+ /// SET a = 1;
+ SingleAssignment {
+ local: bool,
+ hivevar: bool,
+ variable: ObjectName,
+ values: Vec<Expr>,
+ },
+ /// Snowflake-style
+ /// SET (a, b, ..) = (1, 2, ..);
+ ParenthesizedAssignments {
+ variables: Vec<ObjectName>,
+ values: Vec<Expr>,
+ },
+ /// MySQL-style
+ /// SET a = 1, b = 2, ..;
+ MultipleAssignments { assignments: Vec<SetAssignment> },
+ /// MS-SQL session
+ ///
+ /// See
<https://learn.microsoft.com/en-us/sql/t-sql/statements/set-statements-transact-sql>
+ SetSessionParam(SetSessionParamKind),
+ /// ```sql
+ /// SET [ SESSION | LOCAL ] ROLE role_name
+ /// ```
+ ///
+ /// Sets session state. Examples: [ANSI][1], [Postgresql][2], [MySQL][3],
and [Oracle][4]
+ ///
+ /// [1]:
https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#set-role-statement
+ /// [2]: https://www.postgresql.org/docs/14/sql-set-role.html
+ /// [3]: https://dev.mysql.com/doc/refman/8.0/en/set-role.html
+ /// [4]:
https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_10004.htm
+ SetRole {
+ /// Non-ANSI optional identifier to inform if the role is defined
inside the current session (`SESSION`) or transaction (`LOCAL`).
+ context_modifier: ContextModifier,
+ /// Role name. If NONE is specified, then the current role name is
removed.
+ role_name: Option<Ident>,
+ },
+ /// ```sql
+ /// SET TIME ZONE <value>
+ /// ```
+ ///
+ /// Note: this is a PostgreSQL-specific statements
+ /// `SET TIME ZONE <value>` is an alias for `SET timezone TO <value>` in
PostgreSQL
+ /// However, we allow it for all dialects.
+ SetTimeZone { local: bool, value: Expr },
+ /// ```sql
+ /// SET NAMES 'charset_name' [COLLATE 'collation_name']
+ /// ```
+ SetNames {
+ charset_name: Ident,
+ collation_name: Option<String>,
+ },
+ /// ```sql
+ /// SET NAMES DEFAULT
+ /// ```
+ ///
+ /// Note: this is a MySQL-specific statement.
+ SetNamesDefault {},
+ /// ```sql
+ /// SET TRANSACTION ...
+ /// ```
+ SetTransaction {
+ modes: Vec<TransactionMode>,
+ snapshot: Option<Value>,
+ session: bool,
+ },
+}
+
+impl Display for Set {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Self::ParenthesizedAssignments { variables, values } => write!(
+ f,
+ "SET ({}) = ({})",
+ display_comma_separated(variables),
+ display_comma_separated(values)
+ ),
+ Self::MultipleAssignments { assignments } => {
+ write!(f, "SET {}", display_comma_separated(assignments))
+ }
+ Self::SetRole {
+ context_modifier,
+ role_name,
+ } => {
+ let role_name = role_name.clone().unwrap_or_else(||
Ident::new("NONE"));
+ write!(f, "SET{context_modifier} ROLE {role_name}")
+ }
+ Self::SetSessionParam(kind) => write!(f, "SET {kind}"),
+ Self::SetTransaction {
+ modes,
+ snapshot,
+ session,
+ } => {
+ if *session {
+ write!(f, "SET SESSION CHARACTERISTICS AS TRANSACTION")?;
+ } else {
+ write!(f, "SET TRANSACTION")?;
+ }
+ if !modes.is_empty() {
+ write!(f, " {}", display_comma_separated(modes))?;
+ }
+ if let Some(snapshot_id) = snapshot {
+ write!(f, " SNAPSHOT {snapshot_id}")?;
+ }
+ Ok(())
+ }
+ Self::SetTimeZone { local, value } => {
+ f.write_str("SET ")?;
+ if *local {
+ f.write_str("LOCAL ")?;
+ }
+ write!(f, "TIME ZONE {value}")
+ }
+ Self::SetNames {
+ charset_name,
+ collation_name,
+ } => {
+ write!(f, "SET NAMES {}", charset_name)?;
+
+ if let Some(collation) = collation_name {
+ f.write_str(" COLLATE ")?;
+ f.write_str(collation)?;
+ };
+
+ Ok(())
+ }
+ Self::SetNamesDefault {} => {
+ f.write_str("SET NAMES DEFAULT")?;
+
+ Ok(())
+ }
+ Set::SingleAssignment {
+ local,
+ hivevar,
+ variable,
+ values,
+ } => {
+ write!(
+ f,
+ "SET {}{}{} = {}",
+ if *local { "LOCAL " } else { "" },
+ if *hivevar { "HIVEVAR:" } else { "" },
+ variable,
+ display_comma_separated(values)
+ )
+ }
+ }
+ }
+}
+
+/// Convert a `Set` into a `Statement`.
+/// Convenience function, instead of writing `Statement::Set(Set::Set...{...})`
+impl From<Set> for Statement {
+ fn from(set: Set) -> Self {
+ Statement::Set(set)
+ }
+}
+
/// A top-level statement (SELECT, INSERT, CREATE, etc.)
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
@@ -2419,6 +2581,7 @@ pub enum Statement {
compute_statistics: bool,
has_table_keyword: bool,
},
+ Set(Set),
/// ```sql
/// TRUNCATE
/// ```
@@ -2846,7 +3009,10 @@ pub enum Statement {
/// DROP CONNECTOR
/// ```
/// See
[Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-DropConnector)
- DropConnector { if_exists: bool, name: Ident },
+ DropConnector {
+ if_exists: bool,
+ name: Ident,
+ },
/// ```sql
/// DECLARE
/// ```
@@ -2854,7 +3020,9 @@ pub enum Statement {
///
/// Note: this is a PostgreSQL-specific statement,
/// but may also compatible with other SQL.
- Declare { stmts: Vec<Declare> },
+ Declare {
+ stmts: Vec<Declare>,
+ },
/// ```sql
/// CREATE EXTENSION [ IF NOT EXISTS ] extension_name
/// [ WITH ] [ SCHEMA schema_name ]
@@ -2916,67 +3084,23 @@ pub enum Statement {
///
/// Note: this is a PostgreSQL-specific statement,
/// but may also compatible with other SQL.
- Discard { object_type: DiscardObject },
- /// ```sql
- /// SET [ SESSION | LOCAL ] ROLE role_name
- /// ```
- ///
- /// Sets session state. Examples: [ANSI][1], [Postgresql][2], [MySQL][3],
and [Oracle][4]
- ///
- /// [1]:
https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#set-role-statement
- /// [2]: https://www.postgresql.org/docs/14/sql-set-role.html
- /// [3]: https://dev.mysql.com/doc/refman/8.0/en/set-role.html
- /// [4]:
https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_10004.htm
- SetRole {
- /// Non-ANSI optional identifier to inform if the role is defined
inside the current session (`SESSION`) or transaction (`LOCAL`).
- context_modifier: ContextModifier,
- /// Role name. If NONE is specified, then the current role name is
removed.
- role_name: Option<Ident>,
- },
- /// ```sql
- /// SET <variable> = expression;
- /// SET (variable[, ...]) = (expression[, ...]);
- /// ```
- ///
- /// Note: this is not a standard SQL statement, but it is supported by at
- /// least MySQL and PostgreSQL. Not all MySQL-specific syntactic forms are
- /// supported yet.
- SetVariable {
- local: bool,
- hivevar: bool,
- variables: OneOrManyWithParens<ObjectName>,
- value: Vec<Expr>,
+ Discard {
+ object_type: DiscardObject,
},
- /// ```sql
- /// SET TIME ZONE <value>
- /// ```
- ///
- /// Note: this is a PostgreSQL-specific statements
- /// `SET TIME ZONE <value>` is an alias for `SET timezone TO <value>` in
PostgreSQL
- SetTimeZone { local: bool, value: Expr },
- /// ```sql
- /// SET NAMES 'charset_name' [COLLATE 'collation_name']
- /// ```
- SetNames {
- charset_name: Ident,
- collation_name: Option<String>,
- },
- /// ```sql
- /// SET NAMES DEFAULT
- /// ```
- ///
- /// Note: this is a MySQL-specific statement.
- SetNamesDefault {},
/// `SHOW FUNCTIONS`
///
/// Note: this is a Presto-specific statement.
- ShowFunctions { filter: Option<ShowStatementFilter> },
+ ShowFunctions {
+ filter: Option<ShowStatementFilter>,
+ },
/// ```sql
/// SHOW <variable>
/// ```
///
/// Note: this is a PostgreSQL-specific statement.
- ShowVariable { variable: Vec<Ident> },
+ ShowVariable {
+ variable: Vec<Ident>,
+ },
/// ```sql
/// SHOW [GLOBAL | SESSION] STATUS [LIKE 'pattern' | WHERE expr]
/// ```
@@ -3060,7 +3184,9 @@ pub enum Statement {
/// ```
///
/// Note: this is a MySQL-specific statement.
- ShowCollation { filter: Option<ShowStatementFilter> },
+ ShowCollation {
+ filter: Option<ShowStatementFilter>,
+ },
/// ```sql
/// `USE ...`
/// ```
@@ -3103,14 +3229,6 @@ pub enum Statement {
has_end_keyword: bool,
},
/// ```sql
- /// SET TRANSACTION ...
- /// ```
- SetTransaction {
- modes: Vec<TransactionMode>,
- snapshot: Option<Value>,
- session: bool,
- },
- /// ```sql
/// COMMENT ON ...
/// ```
///
@@ -3329,7 +3447,10 @@ pub enum Statement {
/// ```
///
/// Note: this is a PostgreSQL-specific statement.
- Deallocate { name: Ident, prepare: bool },
+ Deallocate {
+ name: Ident,
+ prepare: bool,
+ },
/// ```sql
/// An `EXECUTE` statement
/// ```
@@ -3415,11 +3536,15 @@ pub enum Statement {
/// SAVEPOINT
/// ```
/// Define a new savepoint within the current transaction
- Savepoint { name: Ident },
+ Savepoint {
+ name: Ident,
+ },
/// ```sql
/// RELEASE [ SAVEPOINT ] savepoint_name
/// ```
- ReleaseSavepoint { name: Ident },
+ ReleaseSavepoint {
+ name: Ident,
+ },
/// A `MERGE` statement.
///
/// ```sql
@@ -3499,7 +3624,9 @@ pub enum Statement {
/// LOCK TABLES <table_name> [READ [LOCAL] | [LOW_PRIORITY] WRITE]
/// ```
/// Note: this is a MySQL-specific statement. See
<https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html>
- LockTables { tables: Vec<LockTable> },
+ LockTables {
+ tables: Vec<LockTable>,
+ },
/// ```sql
/// UNLOCK TABLES
/// ```
@@ -3533,14 +3660,18 @@ pub enum Statement {
/// listen for a notification channel
///
/// See Postgres <https://www.postgresql.org/docs/current/sql-listen.html>
- LISTEN { channel: Ident },
+ LISTEN {
+ channel: Ident,
+ },
/// ```sql
/// UNLISTEN
/// ```
/// stop listening for a notification
///
/// See Postgres
<https://www.postgresql.org/docs/current/sql-unlisten.html>
- UNLISTEN { channel: Ident },
+ UNLISTEN {
+ channel: Ident,
+ },
/// ```sql
/// NOTIFY channel [ , payload ]
/// ```
@@ -3580,10 +3711,6 @@ pub enum Statement {
/// Snowflake `REMOVE`
/// See: <https://docs.snowflake.com/en/sql-reference/sql/remove>
Remove(FileStagingCommand),
- /// MS-SQL session
- ///
- /// See
<https://learn.microsoft.com/en-us/sql/t-sql/statements/set-statements-transact-sql>
- SetSessionParam(SetSessionParamKind),
/// RaiseError (MSSQL)
/// RAISERROR ( { msg_id | msg_str | @local_variable }
/// { , severity , state }
@@ -4644,59 +4771,7 @@ impl fmt::Display for Statement {
write!(f, "DISCARD {object_type}")?;
Ok(())
}
- Self::SetRole {
- context_modifier,
- role_name,
- } => {
- let role_name = role_name.clone().unwrap_or_else(||
Ident::new("NONE"));
- write!(f, "SET{context_modifier} ROLE {role_name}")
- }
- Statement::SetVariable {
- local,
- variables,
- hivevar,
- value,
- } => {
- f.write_str("SET ")?;
- if *local {
- f.write_str("LOCAL ")?;
- }
- let parenthesized = matches!(variables,
OneOrManyWithParens::Many(_));
- write!(
- f,
- "{hivevar}{name} = {l_paren}{value}{r_paren}",
- hivevar = if *hivevar { "HIVEVAR:" } else { "" },
- name = variables,
- l_paren = parenthesized.then_some("(").unwrap_or_default(),
- value = display_comma_separated(value),
- r_paren = parenthesized.then_some(")").unwrap_or_default(),
- )
- }
- Statement::SetTimeZone { local, value } => {
- f.write_str("SET ")?;
- if *local {
- f.write_str("LOCAL ")?;
- }
- write!(f, "TIME ZONE {value}")
- }
- Statement::SetNames {
- charset_name,
- collation_name,
- } => {
- write!(f, "SET NAMES {}", charset_name)?;
-
- if let Some(collation) = collation_name {
- f.write_str(" COLLATE ")?;
- f.write_str(collation)?;
- };
-
- Ok(())
- }
- Statement::SetNamesDefault {} => {
- f.write_str("SET NAMES DEFAULT")?;
-
- Ok(())
- }
+ Self::Set(set) => write!(f, "{set}"),
Statement::ShowVariable { variable } => {
write!(f, "SHOW")?;
if !variable.is_empty() {
@@ -4885,24 +4960,6 @@ impl fmt::Display for Statement {
}
Ok(())
}
- Statement::SetTransaction {
- modes,
- snapshot,
- session,
- } => {
- if *session {
- write!(f, "SET SESSION CHARACTERISTICS AS TRANSACTION")?;
- } else {
- write!(f, "SET TRANSACTION")?;
- }
- if !modes.is_empty() {
- write!(f, " {}", display_comma_separated(modes))?;
- }
- if let Some(snapshot_id) = snapshot {
- write!(f, " SNAPSHOT {snapshot_id}")?;
- }
- Ok(())
- }
Statement::Commit {
chain,
end: end_syntax,
@@ -5333,7 +5390,6 @@ impl fmt::Display for Statement {
Statement::List(command) => write!(f, "LIST {command}"),
Statement::Remove(command) => write!(f, "REMOVE {command}"),
- Statement::SetSessionParam(kind) => write!(f, "SET {kind}"),
}
}
}
@@ -5397,6 +5453,21 @@ impl fmt::Display for SequenceOptions {
}
}
+/// Assignment for a `SET` statement (name [=|TO] value)
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct SetAssignment {
+ pub name: ObjectName,
+ pub value: Expr,
+}
+
+impl fmt::Display for SetAssignment {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{} = {}", self.name, self.value)
+ }
+}
+
/// Target of a `TRUNCATE TABLE` command
///
/// Note this is its own struct because `visit_relation` requires an
`ObjectName` (not a `Vec<ObjectName>`)
diff --git a/src/ast/spans.rs b/src/ast/spans.rs
index 8c3eff3c..fb0fc3f3 100644
--- a/src/ast/spans.rs
+++ b/src/ast/spans.rs
@@ -230,11 +230,7 @@ impl Spanned for Values {
/// - [Statement::Fetch]
/// - [Statement::Flush]
/// - [Statement::Discard]
-/// - [Statement::SetRole]
-/// - [Statement::SetVariable]
-/// - [Statement::SetTimeZone]
-/// - [Statement::SetNames]
-/// - [Statement::SetNamesDefault]
+/// - [Statement::Set]
/// - [Statement::ShowFunctions]
/// - [Statement::ShowVariable]
/// - [Statement::ShowStatus]
@@ -244,7 +240,6 @@ impl Spanned for Values {
/// - [Statement::ShowTables]
/// - [Statement::ShowCollation]
/// - [Statement::StartTransaction]
-/// - [Statement::SetTransaction]
/// - [Statement::Comment]
/// - [Statement::Commit]
/// - [Statement::Rollback]
@@ -445,11 +440,7 @@ impl Spanned for Statement {
Statement::Fetch { .. } => Span::empty(),
Statement::Flush { .. } => Span::empty(),
Statement::Discard { .. } => Span::empty(),
- Statement::SetRole { .. } => Span::empty(),
- Statement::SetVariable { .. } => Span::empty(),
- Statement::SetTimeZone { .. } => Span::empty(),
- Statement::SetNames { .. } => Span::empty(),
- Statement::SetNamesDefault {} => Span::empty(),
+ Statement::Set(_) => Span::empty(),
Statement::ShowFunctions { .. } => Span::empty(),
Statement::ShowVariable { .. } => Span::empty(),
Statement::ShowStatus { .. } => Span::empty(),
@@ -460,7 +451,6 @@ impl Spanned for Statement {
Statement::ShowCollation { .. } => Span::empty(),
Statement::Use(u) => u.span(),
Statement::StartTransaction { .. } => Span::empty(),
- Statement::SetTransaction { .. } => Span::empty(),
Statement::Comment { .. } => Span::empty(),
Statement::Commit { .. } => Span::empty(),
Statement::Rollback { .. } => Span::empty(),
@@ -509,7 +499,6 @@ impl Spanned for Statement {
Statement::RenameTable { .. } => Span::empty(),
Statement::RaisError { .. } => Span::empty(),
Statement::List(..) | Statement::Remove(..) => Span::empty(),
- Statement::SetSessionParam { .. } => Span::empty(),
}
}
}
diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs
index aeb097cf..8d4557e2 100644
--- a/src/dialect/mod.rs
+++ b/src/dialect/mod.rs
@@ -399,6 +399,16 @@ pub trait Dialect: Debug + Any {
false
}
+ /// Returns true if the dialect supports multiple `SET` statements
+ /// in a single statement.
+ ///
+ /// ```sql
+ /// SET variable = expression [, variable = expression];
+ /// ```
+ fn supports_comma_separated_set_assignments(&self) -> bool {
+ false
+ }
+
/// Returns true if the dialect supports an `EXCEPT` clause following a
/// wildcard in a select list.
///
diff --git a/src/dialect/mssql.rs b/src/dialect/mssql.rs
index aeed1eb7..3db34748 100644
--- a/src/dialect/mssql.rs
+++ b/src/dialect/mssql.rs
@@ -82,6 +82,7 @@ impl Dialect for MsSqlDialect {
fn supports_start_transaction_modifier(&self) -> bool {
true
}
+
fn supports_end_transaction_modifier(&self) -> bool {
true
}
diff --git a/src/dialect/mysql.rs b/src/dialect/mysql.rs
index 0bdfc9bf..2077ea19 100644
--- a/src/dialect/mysql.rs
+++ b/src/dialect/mysql.rs
@@ -141,6 +141,10 @@ impl Dialect for MySqlDialect {
fn supports_set_names(&self) -> bool {
true
}
+
+ fn supports_comma_separated_set_assignments(&self) -> bool {
+ true
+ }
}
/// `LOCK TABLES`
diff --git a/src/keywords.rs b/src/keywords.rs
index bda817df..195bbb17 100644
--- a/src/keywords.rs
+++ b/src/keywords.rs
@@ -173,6 +173,7 @@ define_keywords!(
CHANNEL,
CHAR,
CHARACTER,
+ CHARACTERISTICS,
CHARACTERS,
CHARACTER_LENGTH,
CHARSET,
@@ -557,6 +558,7 @@ define_keywords!(
MULTISET,
MUTATION,
NAME,
+ NAMES,
NANOSECOND,
NANOSECONDS,
NATIONAL,
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 400a9480..32a7bccd 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -4314,7 +4314,8 @@ impl<'a> Parser<'a> {
}
/// Run a parser method `f`, reverting back to the current position if
unsuccessful.
- /// Returns `None` if `f` returns an error
+ /// Returns `ParserError::RecursionLimitExceeded` if `f` returns a
`RecursionLimitExceeded`.
+ /// Returns `Ok(None)` if `f` returns any other error.
pub fn maybe_parse<T, F>(&mut self, f: F) -> Result<Option<T>, ParserError>
where
F: FnMut(&mut Parser) -> Result<T, ParserError>,
@@ -10978,47 +10979,108 @@ impl<'a> Parser<'a> {
} else {
Some(self.parse_identifier()?)
};
- Ok(Statement::SetRole {
+ Ok(Statement::Set(Set::SetRole {
context_modifier,
role_name,
- })
+ }))
}
- pub fn parse_set(&mut self) -> Result<Statement, ParserError> {
- let modifier =
- self.parse_one_of_keywords(&[Keyword::SESSION, Keyword::LOCAL,
Keyword::HIVEVAR]);
- if let Some(Keyword::HIVEVAR) = modifier {
- self.expect_token(&Token::Colon)?;
- } else if let Some(set_role_stmt) =
- self.maybe_parse(|parser| parser.parse_set_role(modifier))?
- {
- return Ok(set_role_stmt);
+ fn parse_set_values(
+ &mut self,
+ parenthesized_assignment: bool,
+ ) -> Result<Vec<Expr>, ParserError> {
+ let mut values = vec![];
+
+ if parenthesized_assignment {
+ self.expect_token(&Token::LParen)?;
+ }
+
+ loop {
+ let value = if let Some(expr) = self.try_parse_expr_sub_query()? {
+ expr
+ } else if let Ok(expr) = self.parse_expr() {
+ expr
+ } else {
+ self.expected("variable value", self.peek_token())?
+ };
+
+ values.push(value);
+ if self.consume_token(&Token::Comma) {
+ continue;
+ }
+
+ if parenthesized_assignment {
+ self.expect_token(&Token::RParen)?;
+ }
+ return Ok(values);
}
+ }
- let variables = if self.parse_keywords(&[Keyword::TIME,
Keyword::ZONE]) {
- OneOrManyWithParens::One(ObjectName::from(vec!["TIMEZONE".into()]))
- } else if self.dialect.supports_parenthesized_set_variables()
+ fn parse_set_assignment(
+ &mut self,
+ ) -> Result<(OneOrManyWithParens<ObjectName>, Expr), ParserError> {
+ let variables = if self.dialect.supports_parenthesized_set_variables()
&& self.consume_token(&Token::LParen)
{
- let variables = OneOrManyWithParens::Many(
+ let vars = OneOrManyWithParens::Many(
self.parse_comma_separated(|parser: &mut Parser<'a>|
parser.parse_identifier())?
.into_iter()
.map(|ident| ObjectName::from(vec![ident]))
.collect(),
);
self.expect_token(&Token::RParen)?;
- variables
+ vars
} else {
OneOrManyWithParens::One(self.parse_object_name(false)?)
};
- let names = matches!(&variables, OneOrManyWithParens::One(variable) if
variable.to_string().eq_ignore_ascii_case("NAMES"));
+ if !(self.consume_token(&Token::Eq) ||
self.parse_keyword(Keyword::TO)) {
+ return self.expected("assignment operator", self.peek_token());
+ }
+
+ let values = self.parse_expr()?;
+
+ Ok((variables, values))
+ }
+
+ fn parse_set(&mut self) -> Result<Statement, ParserError> {
+ let modifier =
+ self.parse_one_of_keywords(&[Keyword::SESSION, Keyword::LOCAL,
Keyword::HIVEVAR]);
- if names && self.dialect.supports_set_names() {
+ if let Some(Keyword::HIVEVAR) = modifier {
+ self.expect_token(&Token::Colon)?;
+ }
+
+ if let Some(set_role_stmt) = self.maybe_parse(|parser|
parser.parse_set_role(modifier))? {
+ return Ok(set_role_stmt);
+ }
+
+ // Handle special cases first
+ if self.parse_keywords(&[Keyword::TIME, Keyword::ZONE])
+ || self.parse_keyword(Keyword::TIMEZONE)
+ {
+ if self.consume_token(&Token::Eq) ||
self.parse_keyword(Keyword::TO) {
+ return Ok(Set::SingleAssignment {
+ local: modifier == Some(Keyword::LOCAL),
+ hivevar: modifier == Some(Keyword::HIVEVAR),
+ variable: ObjectName::from(vec!["TIMEZONE".into()]),
+ values: self.parse_set_values(false)?,
+ }
+ .into());
+ } else {
+ // A shorthand alias for SET TIME ZONE that doesn't require
+ // the assignment operator. It's originally PostgreSQL
specific,
+ // but we allow it for all the dialects
+ return Ok(Set::SetTimeZone {
+ local: modifier == Some(Keyword::LOCAL),
+ value: self.parse_expr()?,
+ }
+ .into());
+ }
+ } else if self.dialect.supports_set_names() &&
self.parse_keyword(Keyword::NAMES) {
if self.parse_keyword(Keyword::DEFAULT) {
- return Ok(Statement::SetNamesDefault {});
+ return Ok(Set::SetNamesDefault {}.into());
}
-
let charset_name = self.parse_identifier()?;
let collation_name = if
self.parse_one_of_keywords(&[Keyword::COLLATE]).is_some() {
Some(self.parse_literal_string()?)
@@ -11026,86 +11088,117 @@ impl<'a> Parser<'a> {
None
};
- return Ok(Statement::SetNames {
+ return Ok(Set::SetNames {
charset_name,
collation_name,
- });
- }
-
- let parenthesized_assignment = matches!(&variables,
OneOrManyWithParens::Many(_));
-
- if self.consume_token(&Token::Eq) || self.parse_keyword(Keyword::TO) {
- if parenthesized_assignment {
- self.expect_token(&Token::LParen)?;
- }
-
- let mut values = vec![];
- loop {
- let value = if let Some(expr) =
self.try_parse_expr_sub_query()? {
- expr
- } else if let Ok(expr) = self.parse_expr() {
- expr
- } else {
- self.expected("variable value", self.peek_token())?
- };
-
- values.push(value);
- if self.consume_token(&Token::Comma) {
- continue;
- }
-
- if parenthesized_assignment {
- self.expect_token(&Token::RParen)?;
- }
- return Ok(Statement::SetVariable {
- local: modifier == Some(Keyword::LOCAL),
- hivevar: Some(Keyword::HIVEVAR) == modifier,
- variables,
- value: values,
- });
}
- }
-
- let OneOrManyWithParens::One(variable) = variables else {
- return self.expected("set variable", self.peek_token());
- };
-
- if variable.to_string().eq_ignore_ascii_case("TIMEZONE") {
- // for some db (e.g. postgresql), SET TIME ZONE <value> is an
alias for SET TIMEZONE [TO|=] <value>
- match self.parse_expr() {
- Ok(expr) => Ok(Statement::SetTimeZone {
- local: modifier == Some(Keyword::LOCAL),
- value: expr,
- }),
- _ => self.expected("timezone value", self.peek_token())?,
- }
- } else if variable.to_string() == "CHARACTERISTICS" {
+ .into());
+ } else if self.parse_keyword(Keyword::CHARACTERISTICS) {
self.expect_keywords(&[Keyword::AS, Keyword::TRANSACTION])?;
- Ok(Statement::SetTransaction {
+ return Ok(Set::SetTransaction {
modes: self.parse_transaction_modes()?,
snapshot: None,
session: true,
- })
- } else if variable.to_string() == "TRANSACTION" && modifier.is_none() {
+ }
+ .into());
+ } else if self.parse_keyword(Keyword::TRANSACTION) {
if self.parse_keyword(Keyword::SNAPSHOT) {
let snapshot_id = self.parse_value()?.value;
- return Ok(Statement::SetTransaction {
+ return Ok(Set::SetTransaction {
modes: vec![],
snapshot: Some(snapshot_id),
session: false,
- });
+ }
+ .into());
}
- Ok(Statement::SetTransaction {
+ return Ok(Set::SetTransaction {
modes: self.parse_transaction_modes()?,
snapshot: None,
session: false,
- })
- } else if self.dialect.supports_set_stmt_without_operator() {
- self.prev_token();
- self.parse_set_session_params()
+ }
+ .into());
+ }
+
+ if self.dialect.supports_comma_separated_set_assignments() {
+ if let Some(assignments) = self
+ .maybe_parse(|parser|
parser.parse_comma_separated(Parser::parse_set_assignment))?
+ {
+ return if assignments.len() > 1 {
+ let assignments = assignments
+ .into_iter()
+ .map(|(var, val)| match var {
+ OneOrManyWithParens::One(v) => Ok(SetAssignment {
+ name: v,
+ value: val,
+ }),
+ OneOrManyWithParens::Many(_) => {
+ self.expected("List of single identifiers",
self.peek_token())
+ }
+ })
+ .collect::<Result<_, _>>()?;
+
+ Ok(Set::MultipleAssignments { assignments }.into())
+ } else {
+ let (vars, values): (Vec<_>, Vec<_>) =
assignments.into_iter().unzip();
+
+ let variable = match vars.into_iter().next() {
+ Some(OneOrManyWithParens::One(v)) => Ok(v),
+ Some(OneOrManyWithParens::Many(_)) => self.expected(
+ "Single assignment or list of assignments",
+ self.peek_token(),
+ ),
+ None => self.expected("At least one identifier",
self.peek_token()),
+ }?;
+
+ Ok(Set::SingleAssignment {
+ local: modifier == Some(Keyword::LOCAL),
+ hivevar: modifier == Some(Keyword::HIVEVAR),
+ variable,
+ values,
+ }
+ .into())
+ };
+ }
+ }
+
+ let variables = if self.dialect.supports_parenthesized_set_variables()
+ && self.consume_token(&Token::LParen)
+ {
+ let vars = OneOrManyWithParens::Many(
+ self.parse_comma_separated(|parser: &mut Parser<'a>|
parser.parse_identifier())?
+ .into_iter()
+ .map(|ident| ObjectName::from(vec![ident]))
+ .collect(),
+ );
+ self.expect_token(&Token::RParen)?;
+ vars
} else {
- self.expected("equals sign or TO", self.peek_token())
+ OneOrManyWithParens::One(self.parse_object_name(false)?)
+ };
+
+ if self.consume_token(&Token::Eq) || self.parse_keyword(Keyword::TO) {
+ let stmt = match variables {
+ OneOrManyWithParens::One(var) => Set::SingleAssignment {
+ local: modifier == Some(Keyword::LOCAL),
+ hivevar: modifier == Some(Keyword::HIVEVAR),
+ variable: var,
+ values: self.parse_set_values(false)?,
+ },
+ OneOrManyWithParens::Many(vars) =>
Set::ParenthesizedAssignments {
+ variables: vars,
+ values: self.parse_set_values(true)?,
+ },
+ };
+
+ return Ok(stmt.into());
}
+
+ if self.dialect.supports_set_stmt_without_operator() {
+ self.prev_token();
+ return self.parse_set_session_params();
+ };
+
+ self.expected("equals sign or TO", self.peek_token())
}
pub fn parse_set_session_params(&mut self) -> Result<Statement,
ParserError> {
@@ -11123,15 +11216,20 @@ impl<'a> Parser<'a> {
_ => return self.expected("IO, PROFILE, TIME or XML",
self.peek_token()),
};
let value = self.parse_session_param_value()?;
- Ok(Statement::SetSessionParam(SetSessionParamKind::Statistics(
- SetSessionParamStatistics { topic, value },
- )))
+ Ok(
+
Set::SetSessionParam(SetSessionParamKind::Statistics(SetSessionParamStatistics {
+ topic,
+ value,
+ }))
+ .into(),
+ )
} else if self.parse_keyword(Keyword::IDENTITY_INSERT) {
let obj = self.parse_object_name(false)?;
let value = self.parse_session_param_value()?;
- Ok(Statement::SetSessionParam(
-
SetSessionParamKind::IdentityInsert(SetSessionParamIdentityInsert { obj, value
}),
+ Ok(Set::SetSessionParam(SetSessionParamKind::IdentityInsert(
+ SetSessionParamIdentityInsert { obj, value },
))
+ .into())
} else if self.parse_keyword(Keyword::OFFSETS) {
let keywords = self.parse_comma_separated(|parser| {
let next_token = parser.next_token();
@@ -11141,9 +11239,13 @@ impl<'a> Parser<'a> {
}
})?;
let value = self.parse_session_param_value()?;
- Ok(Statement::SetSessionParam(SetSessionParamKind::Offsets(
- SetSessionParamOffsets { keywords, value },
- )))
+ Ok(
+
Set::SetSessionParam(SetSessionParamKind::Offsets(SetSessionParamOffsets {
+ keywords,
+ value,
+ }))
+ .into(),
+ )
} else {
let names = self.parse_comma_separated(|parser| {
let next_token = parser.next_token();
@@ -11153,9 +11255,13 @@ impl<'a> Parser<'a> {
}
})?;
let value = self.parse_expr()?.to_string();
- Ok(Statement::SetSessionParam(SetSessionParamKind::Generic(
- SetSessionParamGeneric { names, value },
- )))
+ Ok(
+
Set::SetSessionParam(SetSessionParamKind::Generic(SetSessionParamGeneric {
+ names,
+ value,
+ }))
+ .into(),
+ )
}
}
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index 8225d367..c7bf287c 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -8555,11 +8555,11 @@ fn parse_set_transaction() {
// TRANSACTION, so no need to duplicate the tests here. We just do a quick
// sanity check.
match verified_stmt("SET TRANSACTION READ ONLY, READ WRITE, ISOLATION
LEVEL SERIALIZABLE") {
- Statement::SetTransaction {
+ Statement::Set(Set::SetTransaction {
modes,
session,
snapshot,
- } => {
+ }) => {
assert_eq!(
modes,
vec![
@@ -8578,20 +8578,17 @@ fn parse_set_transaction() {
#[test]
fn parse_set_variable() {
match verified_stmt("SET SOMETHING = '1'") {
- Statement::SetVariable {
+ Statement::Set(Set::SingleAssignment {
local,
hivevar,
- variables,
- value,
- } => {
+ variable,
+ values,
+ }) => {
assert!(!local);
assert!(!hivevar);
+ assert_eq!(variable, ObjectName::from(vec!["SOMETHING".into()]));
assert_eq!(
- variables,
-
OneOrManyWithParens::One(ObjectName::from(vec!["SOMETHING".into()]))
- );
- assert_eq!(
- value,
+ values,
vec![Expr::Value(
(Value::SingleQuotedString("1".into())).with_empty_span()
)]
@@ -8603,24 +8600,17 @@ fn parse_set_variable() {
let multi_variable_dialects = all_dialects_where(|d|
d.supports_parenthesized_set_variables());
let sql = r#"SET (a, b, c) = (1, 2, 3)"#;
match multi_variable_dialects.verified_stmt(sql) {
- Statement::SetVariable {
- local,
- hivevar,
- variables,
- value,
- } => {
- assert!(!local);
- assert!(!hivevar);
+ Statement::Set(Set::ParenthesizedAssignments { variables, values }) =>
{
assert_eq!(
variables,
- OneOrManyWithParens::Many(vec![
+ vec![
ObjectName::from(vec!["a".into()]),
ObjectName::from(vec!["b".into()]),
ObjectName::from(vec!["c".into()]),
- ])
+ ]
);
assert_eq!(
- value,
+ values,
vec![
Expr::value(number("1")),
Expr::value(number("2")),
@@ -8680,20 +8670,17 @@ fn parse_set_variable() {
#[test]
fn parse_set_role_as_variable() {
match verified_stmt("SET role = 'foobar'") {
- Statement::SetVariable {
+ Statement::Set(Set::SingleAssignment {
local,
hivevar,
- variables,
- value,
- } => {
+ variable,
+ values,
+ }) => {
assert!(!local);
assert!(!hivevar);
+ assert_eq!(variable, ObjectName::from(vec!["role".into()]));
assert_eq!(
- variables,
- OneOrManyWithParens::One(ObjectName::from(vec!["role".into()]))
- );
- assert_eq!(
- value,
+ values,
vec![Expr::Value(
(Value::SingleQuotedString("foobar".into())).with_empty_span()
)]
@@ -8730,20 +8717,17 @@ fn parse_double_colon_cast_at_timezone() {
#[test]
fn parse_set_time_zone() {
match verified_stmt("SET TIMEZONE = 'UTC'") {
- Statement::SetVariable {
+ Statement::Set(Set::SingleAssignment {
local,
hivevar,
- variables: variable,
- value,
- } => {
+ variable,
+ values,
+ }) => {
assert!(!local);
assert!(!hivevar);
+ assert_eq!(variable, ObjectName::from(vec!["TIMEZONE".into()]));
assert_eq!(
- variable,
-
OneOrManyWithParens::One(ObjectName::from(vec!["TIMEZONE".into()]))
- );
- assert_eq!(
- value,
+ values,
vec![Expr::Value(
(Value::SingleQuotedString("UTC".into())).with_empty_span()
)]
@@ -8755,20 +8739,6 @@ fn parse_set_time_zone() {
one_statement_parses_to("SET TIME ZONE TO 'UTC'", "SET TIMEZONE = 'UTC'");
}
-#[test]
-fn parse_set_time_zone_alias() {
- match verified_stmt("SET TIME ZONE 'UTC'") {
- Statement::SetTimeZone { local, value } => {
- assert!(!local);
- assert_eq!(
- value,
-
Expr::Value((Value::SingleQuotedString("UTC".into())).with_empty_span())
- );
- }
- _ => unreachable!(),
- }
-}
-
#[test]
fn parse_commit() {
match verified_stmt("COMMIT") {
@@ -14681,3 +14651,44 @@ fn parse_set_names() {
dialects.verified_stmt("SET NAMES 'utf8'");
dialects.verified_stmt("SET NAMES UTF8 COLLATE bogus");
}
+
+#[test]
+fn parse_multiple_set_statements() -> Result<(), ParserError> {
+ let dialects = all_dialects_where(|d|
d.supports_comma_separated_set_assignments());
+ let stmt = dialects.verified_stmt("SET @a = 1, b = 2");
+
+ match stmt {
+ Statement::Set(Set::MultipleAssignments { assignments }) => {
+ assert_eq!(
+ assignments,
+ vec![
+ SetAssignment {
+ name: ObjectName::from(vec!["@a".into()]),
+ value: Expr::value(number("1"))
+ },
+ SetAssignment {
+ name: ObjectName::from(vec!["b".into()]),
+ value: Expr::value(number("2"))
+ }
+ ]
+ );
+ }
+ _ => panic!("Expected SetVariable with 2 variables and 2 values"),
+ };
+
+ Ok(())
+}
+
+#[test]
+fn parse_set_time_zone_alias() {
+ match all_dialects().verified_stmt("SET TIME ZONE 'UTC'") {
+ Statement::Set(Set::SetTimeZone { local, value }) => {
+ assert!(!local);
+ assert_eq!(
+ value,
+
Expr::Value((Value::SingleQuotedString("UTC".into())).with_empty_span())
+ );
+ }
+ _ => unreachable!(),
+ }
+}
diff --git a/tests/sqlparser_hive.rs b/tests/sqlparser_hive.rs
index d7f3c014..56fe22a0 100644
--- a/tests/sqlparser_hive.rs
+++ b/tests/sqlparser_hive.rs
@@ -22,9 +22,8 @@
use sqlparser::ast::{
ClusteredBy, CommentDef, CreateFunction, CreateFunctionBody,
CreateFunctionUsing, CreateTable,
- Expr, Function, FunctionArgumentList, FunctionArguments, Ident, ObjectName,
- OneOrManyWithParens, OrderByExpr, OrderByOptions, SelectItem, Statement,
TableFactor,
- UnaryOperator, Use, Value,
+ Expr, Function, FunctionArgumentList, FunctionArguments, Ident,
ObjectName, OrderByExpr,
+ OrderByOptions, SelectItem, Set, Statement, TableFactor, UnaryOperator,
Use, Value,
};
use sqlparser::dialect::{GenericDialect, HiveDialect, MsSqlDialect};
use sqlparser::parser::ParserError;
@@ -92,7 +91,7 @@ fn parse_msck() {
}
#[test]
-fn parse_set() {
+fn parse_set_hivevar() {
let set = "SET HIVEVAR:name = a, b, c_d";
hive().verified_stmt(set);
}
@@ -369,20 +368,20 @@ fn from_cte() {
fn set_statement_with_minus() {
assert_eq!(
hive().verified_stmt("SET hive.tez.java.opts = -Xmx4g"),
- Statement::SetVariable {
+ Statement::Set(Set::SingleAssignment {
local: false,
hivevar: false,
- variables: OneOrManyWithParens::One(ObjectName::from(vec![
+ variable: ObjectName::from(vec![
Ident::new("hive"),
Ident::new("tez"),
Ident::new("java"),
Ident::new("opts")
- ])),
- value: vec![Expr::UnaryOp {
+ ]),
+ values: vec![Expr::UnaryOp {
op: UnaryOperator::Minus,
expr: Box::new(Expr::Identifier(Ident::new("Xmx4g")))
}],
- }
+ })
);
assert_eq!(
diff --git a/tests/sqlparser_mssql.rs b/tests/sqlparser_mssql.rs
index 3f313af4..386bd178 100644
--- a/tests/sqlparser_mssql.rs
+++ b/tests/sqlparser_mssql.rs
@@ -1254,14 +1254,14 @@ fn parse_mssql_declare() {
for_query: None
}]
},
- Statement::SetVariable {
+ Statement::Set(Set::SingleAssignment {
local: false,
hivevar: false,
- variables:
OneOrManyWithParens::One(ObjectName::from(vec![Ident::new("@bar")])),
- value: vec![Expr::Value(
+ variable: ObjectName::from(vec![Ident::new("@bar")]),
+ values: vec![Expr::Value(
(Value::Number("2".parse().unwrap(),
false)).with_empty_span()
)],
- },
+ }),
Statement::Query(Box::new(Query {
with: None,
limit: None,
diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs
index 560ea9da..13a8a6cc 100644
--- a/tests/sqlparser_mysql.rs
+++ b/tests/sqlparser_mysql.rs
@@ -617,12 +617,12 @@ fn parse_set_variables() {
mysql_and_generic().verified_stmt("SET sql_mode = CONCAT(@@sql_mode,
',STRICT_TRANS_TABLES')");
assert_eq!(
mysql_and_generic().verified_stmt("SET LOCAL autocommit = 1"),
- Statement::SetVariable {
+ Statement::Set(Set::SingleAssignment {
local: true,
hivevar: false,
- variables:
OneOrManyWithParens::One(ObjectName::from(vec!["autocommit".into()])),
- value: vec![Expr::value(number("1"))],
- }
+ variable: ObjectName::from(vec!["autocommit".into()]),
+ values: vec![Expr::value(number("1"))],
+ })
);
}
@@ -2705,19 +2705,19 @@ fn parse_set_names() {
let stmt = mysql_and_generic().verified_stmt("SET NAMES utf8mb4");
assert_eq!(
stmt,
- Statement::SetNames {
+ Statement::Set(Set::SetNames {
charset_name: "utf8mb4".into(),
collation_name: None,
- }
+ })
);
let stmt = mysql_and_generic().verified_stmt("SET NAMES utf8mb4 COLLATE
bogus");
assert_eq!(
stmt,
- Statement::SetNames {
+ Statement::Set(Set::SetNames {
charset_name: "utf8mb4".into(),
collation_name: Some("bogus".to_string()),
- }
+ })
);
let stmt = mysql_and_generic()
@@ -2725,14 +2725,14 @@ fn parse_set_names() {
.unwrap();
assert_eq!(
stmt,
- vec![Statement::SetNames {
+ vec![Statement::Set(Set::SetNames {
charset_name: "utf8mb4".into(),
collation_name: Some("bogus".to_string()),
- }]
+ })]
);
let stmt = mysql_and_generic().verified_stmt("SET NAMES DEFAULT");
- assert_eq!(stmt, Statement::SetNamesDefault {});
+ assert_eq!(stmt, Statement::Set(Set::SetNamesDefault {}));
}
#[test]
diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs
index 0dfcc24e..a65c4fa3 100644
--- a/tests/sqlparser_postgres.rs
+++ b/tests/sqlparser_postgres.rs
@@ -1432,81 +1432,77 @@ fn parse_set() {
let stmt = pg_and_generic().verified_stmt("SET a = b");
assert_eq!(
stmt,
- Statement::SetVariable {
+ Statement::Set(Set::SingleAssignment {
local: false,
hivevar: false,
- variables:
OneOrManyWithParens::One(ObjectName::from(vec![Ident::new("a")])),
- value: vec![Expr::Identifier(Ident {
+ variable: ObjectName::from(vec![Ident::new("a")]),
+ values: vec![Expr::Identifier(Ident {
value: "b".into(),
quote_style: None,
span: Span::empty(),
})],
- }
+ })
);
let stmt = pg_and_generic().verified_stmt("SET a = 'b'");
assert_eq!(
stmt,
- Statement::SetVariable {
+ Statement::Set(Set::SingleAssignment {
local: false,
hivevar: false,
- variables:
OneOrManyWithParens::One(ObjectName::from(vec![Ident::new("a")])),
- value: vec![Expr::Value(
+ variable: ObjectName::from(vec![Ident::new("a")]),
+ values: vec![Expr::Value(
(Value::SingleQuotedString("b".into())).with_empty_span()
)],
- }
+ })
);
let stmt = pg_and_generic().verified_stmt("SET a = 0");
assert_eq!(
stmt,
- Statement::SetVariable {
+ Statement::Set(Set::SingleAssignment {
local: false,
hivevar: false,
- variables:
OneOrManyWithParens::One(ObjectName::from(vec![Ident::new("a")])),
- value: vec![Expr::value(number("0"))],
- }
+ variable: ObjectName::from(vec![Ident::new("a")]),
+ values: vec![Expr::value(number("0"))],
+ })
);
let stmt = pg_and_generic().verified_stmt("SET a = DEFAULT");
assert_eq!(
stmt,
- Statement::SetVariable {
+ Statement::Set(Set::SingleAssignment {
local: false,
hivevar: false,
- variables:
OneOrManyWithParens::One(ObjectName::from(vec![Ident::new("a")])),
- value: vec![Expr::Identifier(Ident::new("DEFAULT"))],
- }
+ variable: ObjectName::from(vec![Ident::new("a")]),
+ values: vec![Expr::Identifier(Ident::new("DEFAULT"))],
+ })
);
let stmt = pg_and_generic().verified_stmt("SET LOCAL a = b");
assert_eq!(
stmt,
- Statement::SetVariable {
+ Statement::Set(Set::SingleAssignment {
local: true,
hivevar: false,
- variables:
OneOrManyWithParens::One(ObjectName::from(vec![Ident::new("a")])),
- value: vec![Expr::Identifier("b".into())],
- }
+ variable: ObjectName::from(vec![Ident::new("a")]),
+ values: vec![Expr::Identifier("b".into())],
+ })
);
let stmt = pg_and_generic().verified_stmt("SET a.b.c = b");
assert_eq!(
stmt,
- Statement::SetVariable {
+ Statement::Set(Set::SingleAssignment {
local: false,
hivevar: false,
- variables: OneOrManyWithParens::One(ObjectName::from(vec![
- Ident::new("a"),
- Ident::new("b"),
- Ident::new("c")
- ])),
- value: vec![Expr::Identifier(Ident {
+ variable: ObjectName::from(vec![Ident::new("a"), Ident::new("b"),
Ident::new("c")]),
+ values: vec![Expr::Identifier(Ident {
value: "b".into(),
quote_style: None,
span: Span::empty(),
})],
- }
+ })
);
let stmt = pg_and_generic().one_statement_parses_to(
@@ -1515,18 +1511,18 @@ fn parse_set() {
);
assert_eq!(
stmt,
- Statement::SetVariable {
+ Statement::Set(Set::SingleAssignment {
local: false,
hivevar: false,
- variables: OneOrManyWithParens::One(ObjectName::from(vec![
+ variable: ObjectName::from(vec![
Ident::new("hive"),
Ident::new("tez"),
Ident::new("auto"),
Ident::new("reducer"),
Ident::new("parallelism")
- ])),
- value:
vec![Expr::Value((Value::Boolean(false)).with_empty_span())],
- }
+ ]),
+ values:
vec![Expr::Value((Value::Boolean(false)).with_empty_span())],
+ })
);
pg_and_generic().one_statement_parses_to("SET a TO b", "SET a = b");
@@ -1560,10 +1556,10 @@ fn parse_set_role() {
let stmt = pg_and_generic().verified_stmt(query);
assert_eq!(
stmt,
- Statement::SetRole {
+ Statement::Set(Set::SetRole {
context_modifier: ContextModifier::Session,
role_name: None,
- }
+ })
);
assert_eq!(query, stmt.to_string());
@@ -1571,14 +1567,14 @@ fn parse_set_role() {
let stmt = pg_and_generic().verified_stmt(query);
assert_eq!(
stmt,
- Statement::SetRole {
+ Statement::Set(Set::SetRole {
context_modifier: ContextModifier::Local,
role_name: Some(Ident {
value: "rolename".to_string(),
quote_style: Some('\"'),
span: Span::empty(),
}),
- }
+ })
);
assert_eq!(query, stmt.to_string());
@@ -1586,14 +1582,14 @@ fn parse_set_role() {
let stmt = pg_and_generic().verified_stmt(query);
assert_eq!(
stmt,
- Statement::SetRole {
+ Statement::Set(Set::SetRole {
context_modifier: ContextModifier::None,
role_name: Some(Ident {
value: "rolename".to_string(),
quote_style: Some('\''),
span: Span::empty(),
}),
- }
+ })
);
assert_eq!(query, stmt.to_string());
}
@@ -2982,16 +2978,16 @@ fn test_transaction_statement() {
let statement = pg().verified_stmt("SET TRANSACTION SNAPSHOT
'000003A1-1'");
assert_eq!(
statement,
- Statement::SetTransaction {
+ Statement::Set(Set::SetTransaction {
modes: vec![],
snapshot:
Some(Value::SingleQuotedString(String::from("000003A1-1"))),
session: false
- }
+ })
);
let statement = pg().verified_stmt("SET SESSION CHARACTERISTICS AS
TRANSACTION READ ONLY, READ WRITE, ISOLATION LEVEL SERIALIZABLE");
assert_eq!(
statement,
- Statement::SetTransaction {
+ Statement::Set(Set::SetTransaction {
modes: vec![
TransactionMode::AccessMode(TransactionAccessMode::ReadOnly),
TransactionMode::AccessMode(TransactionAccessMode::ReadWrite),
@@ -2999,7 +2995,7 @@ fn test_transaction_statement() {
],
snapshot: None,
session: true
- }
+ })
);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]