Skip to content

Commit

Permalink
Merge ab6c2fd into a9939b0
Browse files Browse the repository at this point in the history
  • Loading branch information
AugustoFKL committed Oct 9, 2022
2 parents a9939b0 + ab6c2fd commit 39c744d
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 39 deletions.
75 changes: 47 additions & 28 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,6 @@
// limitations under the License.

//! SQL Abstract Syntax Tree (AST) types
mod data_type;
mod ddl;
pub mod helpers;
mod operator;
mod query;
mod value;

#[cfg(not(feature = "std"))]
use alloc::{
boxed::Box,
Expand All @@ -44,6 +37,13 @@ pub use self::query::{
};
pub use self::value::{DateTimeField, TrimWhereField, Value};

mod data_type;
mod ddl;
pub mod helpers;
mod operator;
mod query;
mod value;

struct DisplaySeparated<'a, T>
where
T: fmt::Display,
Expand Down Expand Up @@ -1227,14 +1227,16 @@ pub enum Statement {
/// Note: this is a PostgreSQL-specific statement,
/// but may also compatible with other SQL.
Discard { object_type: DiscardObject },
/// SET [ SESSION | LOCAL ] ROLE role_name
/// SET `[ SESSION | LOCAL ]` ROLE role_name. Examples: [ANSI][1], [Postgresql][2], [MySQL][3], and [Oracle][4].
///
/// Note: this is a PostgreSQL-specific statement,
/// but may also compatible with other SQL.
/// [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 {
local: bool,
// SESSION is the default if neither SESSION nor LOCAL appears.
session: bool,
/// 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>,
},
/// SET <variable>
Expand Down Expand Up @@ -2136,23 +2138,12 @@ impl fmt::Display for Statement {
write!(f, "DISCARD {object_type}", object_type = object_type)?;
Ok(())
}
Statement::SetRole {
local,
session,
Self::SetRole {
context_modifier,
role_name,
} => {
write!(
f,
"SET {local}{session}ROLE",
local = if *local { "LOCAL " } else { "" },
session = if *session { "SESSION " } else { "" },
)?;
if let Some(role_name) = role_name {
write!(f, " {}", role_name)?;
} else {
f.write_str(" NONE")?;
}
Ok(())
let role_name = role_name.clone().unwrap_or_else(|| Ident::new("NONE"));
write!(f, "SET{context_modifier} ROLE {role_name}")
}
Statement::SetVariable {
local,
Expand Down Expand Up @@ -3283,6 +3274,34 @@ impl fmt::Display for DiscardObject {
}
}

/// Optional context modifier for statements that can be or `LOCAL`, or `SESSION`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ContextModifier {
/// No context defined. Each dialect defines the default in this scenario.
None,
/// `LOCAL` identifier, usually related to transactional states.
Local,
/// `SESSION` identifier
Session,
}

impl fmt::Display for ContextModifier {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::None => {
write!(f, "")
}
Self::Local => {
write!(f, " LOCAL")
}
Self::Session => {
write!(f, " SESSION")
}
}
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum CreateFunctionUsing {
Expand Down
9 changes: 7 additions & 2 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4113,14 +4113,19 @@ impl<'a> Parser<'a> {
if let Some(Keyword::HIVEVAR) = modifier {
self.expect_token(&Token::Colon)?;
} else if self.parse_keyword(Keyword::ROLE) {
let context_modifier = match modifier {
Some(keyword) if keyword == Keyword::LOCAL => ContextModifier::Local,
Some(keyword) if keyword == Keyword::SESSION => ContextModifier::Session,
_ => ContextModifier::None,
};

let role_name = if self.parse_keyword(Keyword::NONE) {
None
} else {
Some(self.parse_identifier()?)
};
return Ok(Statement::SetRole {
local: modifier == Some(Keyword::LOCAL),
session: modifier == Some(Keyword::SESSION),
context_modifier,
role_name,
});
}
Expand Down
21 changes: 12 additions & 9 deletions tests/sqlparser_postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -902,41 +902,44 @@ fn parse_set() {

#[test]
fn parse_set_role() {
let stmt = pg_and_generic().verified_stmt("SET SESSION ROLE NONE");
let query = "SET SESSION ROLE NONE";
let stmt = pg_and_generic().verified_stmt(query);
assert_eq!(
stmt,
Statement::SetRole {
local: false,
session: true,
context_modifier: ContextModifier::Session,
role_name: None,
}
);
assert_eq!(query, stmt.to_string());

let stmt = pg_and_generic().verified_stmt("SET LOCAL ROLE \"rolename\"");
let query = "SET LOCAL ROLE \"rolename\"";
let stmt = pg_and_generic().verified_stmt(query);
assert_eq!(
stmt,
Statement::SetRole {
local: true,
session: false,
context_modifier: ContextModifier::Local,
role_name: Some(Ident {
value: "rolename".to_string(),
quote_style: Some('\"'),
}),
}
);
assert_eq!(query, stmt.to_string());

let stmt = pg_and_generic().verified_stmt("SET ROLE 'rolename'");
let query = "SET ROLE 'rolename'";
let stmt = pg_and_generic().verified_stmt(query);
assert_eq!(
stmt,
Statement::SetRole {
local: false,
session: false,
context_modifier: ContextModifier::None,
role_name: Some(Ident {
value: "rolename".to_string(),
quote_style: Some('\''),
}),
}
);
assert_eq!(query, stmt.to_string());
}

#[test]
Expand Down

0 comments on commit 39c744d

Please sign in to comment.