Skip to content

Commit 274a1a3

Browse files
Merge branch 'main' into alter-operator-class
2 parents 4f86af6 + d4fb5c3 commit 274a1a3

File tree

6 files changed

+97
-6
lines changed

6 files changed

+97
-6
lines changed

src/ast/mod.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11171,12 +11171,15 @@ impl fmt::Display for CreateUser {
1117111171

1117211172
/// Modifies the properties of a user
1117311173
///
11174-
/// Syntax:
11174+
/// [Snowflake Syntax:](https://docs.snowflake.com/en/sql-reference/sql/alter-user)
1117511175
/// ```sql
1117611176
/// ALTER USER [ IF EXISTS ] [ <name> ] [ OPTIONS ]
1117711177
/// ```
1117811178
///
11179-
/// [Snowflake](https://docs.snowflake.com/en/sql-reference/sql/alter-user)
11179+
/// [PostgreSQL Syntax:](https://www.postgresql.org/docs/current/sql-alteruser.html)
11180+
/// ```sql
11181+
/// ALTER USER <role_specification> [ WITH ] option [ ... ]
11182+
/// ```
1118011183
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1118111184
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1118211185
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
@@ -11218,6 +11221,8 @@ pub struct AlterUser {
1121811221
pub set_props: KeyValueOptions,
1121911222
/// Properties to unset on the user.
1122011223
pub unset_props: Vec<String>,
11224+
/// The following options are PostgreSQL-specific: <https://www.postgresql.org/docs/current/sql-alteruser.html>
11225+
pub password: Option<AlterUserPassword>,
1122111226
}
1122211227

1122311228
/// ```sql
@@ -11409,6 +11414,34 @@ impl fmt::Display for AlterUser {
1140911414
if !self.unset_props.is_empty() {
1141011415
write!(f, " UNSET {}", display_comma_separated(&self.unset_props))?;
1141111416
}
11417+
if let Some(password) = &self.password {
11418+
write!(f, " {}", password)?;
11419+
}
11420+
Ok(())
11421+
}
11422+
}
11423+
11424+
/// ```sql
11425+
/// ALTER USER <role_specification> [ WITH ] PASSWORD { 'password' | NULL }``
11426+
/// ```
11427+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
11428+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11429+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
11430+
pub struct AlterUserPassword {
11431+
pub encrypted: bool,
11432+
pub password: Option<String>,
11433+
}
11434+
11435+
impl Display for AlterUserPassword {
11436+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
11437+
if self.encrypted {
11438+
write!(f, "ENCRYPTED ")?;
11439+
}
11440+
write!(f, "PASSWORD")?;
11441+
match &self.password {
11442+
None => write!(f, " NULL")?,
11443+
Some(password) => write!(f, " '{}'", value::escape_single_quote_string(password))?,
11444+
}
1141211445
Ok(())
1141311446
}
1141411447
}

src/dialect/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,11 @@ pub trait Dialect: Debug + Any {
12321232
fn supports_quote_delimited_string(&self) -> bool {
12331233
false
12341234
}
1235+
1236+
/// Returns true if the dialect considers the `&&` operator as a boolean AND operator.
1237+
fn supports_double_ampersand_operator(&self) -> bool {
1238+
false
1239+
}
12351240
}
12361241

12371242
/// Operators for which precedence must be defined.

src/dialect/mysql.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,11 @@ impl Dialect for MySqlDialect {
171171
fn supports_cross_join_constraint(&self) -> bool {
172172
true
173173
}
174+
175+
/// See: <https://dev.mysql.com/doc/refman/8.4/en/expressions.html>
176+
fn supports_double_ampersand_operator(&self) -> bool {
177+
true
178+
}
174179
}
175180

176181
/// `LOCK TABLES`

src/parser/alter.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ use crate::{
2121
helpers::key_value_options::{KeyValueOptions, KeyValueOptionsDelimiter},
2222
AlterConnectorOwner, AlterPolicyOperation, AlterRoleOperation, AlterUser,
2323
AlterUserAddMfaMethodOtp, AlterUserAddRoleDelegation, AlterUserModifyMfaMethod,
24-
AlterUserRemoveRoleDelegation, AlterUserSetPolicy, Expr, MfaMethodKind, Password,
25-
ResetConfig, RoleOption, SetConfigValue, Statement, UserPolicyKind,
24+
AlterUserPassword, AlterUserRemoveRoleDelegation, AlterUserSetPolicy, Expr, MfaMethodKind,
25+
Password, ResetConfig, RoleOption, SetConfigValue, Statement, UserPolicyKind,
2626
},
2727
dialect::{MsSqlDialect, PostgreSqlDialect},
2828
keywords::Keyword,
@@ -151,6 +151,7 @@ impl Parser<'_> {
151151
pub fn parse_alter_user(&mut self) -> Result<Statement, ParserError> {
152152
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
153153
let name = self.parse_identifier()?;
154+
let _ = self.parse_keyword(Keyword::WITH);
154155
let rename_to = if self.parse_keywords(&[Keyword::RENAME, Keyword::TO]) {
155156
Some(self.parse_identifier()?)
156157
} else {
@@ -293,6 +294,21 @@ impl Parser<'_> {
293294
vec![]
294295
};
295296

297+
let encrypted = self.parse_keyword(Keyword::ENCRYPTED);
298+
let password = if self.parse_keyword(Keyword::PASSWORD) {
299+
let password = if self.parse_keyword(Keyword::NULL) {
300+
None
301+
} else {
302+
Some(self.parse_literal_string()?)
303+
};
304+
Some(AlterUserPassword {
305+
encrypted,
306+
password,
307+
})
308+
} else {
309+
None
310+
};
311+
296312
Ok(Statement::AlterUser(AlterUser {
297313
if_exists,
298314
name,
@@ -312,6 +328,7 @@ impl Parser<'_> {
312328
unset_tag,
313329
set_props,
314330
unset_props,
331+
password,
315332
}))
316333
}
317334

src/parser/mod.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3557,6 +3557,9 @@ impl<'a> Parser<'a> {
35573557
Token::Overlap if dialect_is!(dialect is PostgreSqlDialect | GenericDialect) => {
35583558
Some(BinaryOperator::PGOverlap)
35593559
}
3560+
Token::Overlap if dialect.supports_double_ampersand_operator() => {
3561+
Some(BinaryOperator::And)
3562+
}
35603563
Token::CaretAt if dialect_is!(dialect is PostgreSqlDialect | GenericDialect) => {
35613564
Some(BinaryOperator::PGStartsWith)
35623565
}
@@ -18995,7 +18998,7 @@ impl<'a> Parser<'a> {
1899518998
return self.expected(" another option or EOF", self.peek_token());
1899618999
}
1899719000
}
18998-
Token::EOF => break,
19001+
Token::EOF | Token::SemiColon => break,
1899919002
Token::Comma => {
1900019003
delimiter = KeyValueOptionsDelimiter::Comma;
1900119004
continue;
@@ -19007,7 +19010,12 @@ impl<'a> Parser<'a> {
1900719010
self.prev_token();
1900819011
break;
1900919012
}
19010-
_ => return self.expected("another option, EOF, Comma or ')'", self.peek_token()),
19013+
_ => {
19014+
return self.expected(
19015+
"another option, EOF, SemiColon, Comma or ')'",
19016+
self.peek_token(),
19017+
)
19018+
}
1901119019
};
1901219020
}
1901319021

tests/sqlparser_common.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17950,6 +17950,15 @@ fn test_parse_alter_user() {
1795017950
_ => unreachable!(),
1795117951
}
1795217952
verified_stmt("ALTER USER u1 SET DEFAULT_SECONDARY_ROLES=('ALL'), PASSWORD='secret', WORKLOAD_IDENTITY=(TYPE=AWS, ARN='arn:aws:iam::123456789:r1/')");
17953+
17954+
verified_stmt("ALTER USER u1 PASSWORD 'AAA'");
17955+
verified_stmt("ALTER USER u1 ENCRYPTED PASSWORD 'AAA'");
17956+
verified_stmt("ALTER USER u1 PASSWORD NULL");
17957+
17958+
one_statement_parses_to(
17959+
"ALTER USER u1 WITH PASSWORD 'AAA'",
17960+
"ALTER USER u1 PASSWORD 'AAA'",
17961+
);
1795317962
}
1795417963

1795517964
#[test]
@@ -18037,3 +18046,17 @@ fn parse_select_parenthesized_wildcard() {
1803718046
assert_eq!(select2.projection.len(), 1);
1803818047
assert!(matches!(select2.projection[0], SelectItem::Wildcard(_)));
1803918048
}
18049+
18050+
#[test]
18051+
fn parse_overlap_as_bool_and() {
18052+
let dialects = all_dialects_where(|d| d.supports_double_ampersand_operator());
18053+
dialects.one_statement_parses_to("SELECT x && y", "SELECT x AND y");
18054+
}
18055+
18056+
#[test]
18057+
fn test_parse_key_value_options_trailing_semicolon() {
18058+
one_statement_parses_to(
18059+
"CREATE USER u1 option1='value1' option2='value2';",
18060+
"CREATE USER u1 option1='value1' option2='value2'",
18061+
);
18062+
}

0 commit comments

Comments
 (0)