Skip to content

Commit

Permalink
Support mssql json and xml extensions (#1043)
Browse files Browse the repository at this point in the history
  • Loading branch information
lovasoa authored Nov 18, 2023
1 parent ff8312b commit 953c833
Show file tree
Hide file tree
Showing 9 changed files with 318 additions and 15 deletions.
12 changes: 6 additions & 6 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ pub use self::ddl::{
};
pub use self::operator::{BinaryOperator, UnaryOperator};
pub use self::query::{
Cte, Distinct, ExceptSelectItem, ExcludeSelectItem, Fetch, GroupByExpr, IdentWithAlias, Join,
JoinConstraint, JoinOperator, LateralView, LockClause, LockType, NamedWindowDefinition,
NonBlock, Offset, OffsetRows, OrderByExpr, Query, RenameSelectItem, ReplaceSelectElement,
ReplaceSelectItem, Select, SelectInto, SelectItem, SetExpr, SetOperator, SetQuantifier, Table,
TableAlias, TableFactor, TableVersion, TableWithJoins, Top, Values, WildcardAdditionalOptions,
With,
Cte, Distinct, ExceptSelectItem, ExcludeSelectItem, Fetch, ForClause, ForJson, ForXml,
GroupByExpr, IdentWithAlias, Join, JoinConstraint, JoinOperator, LateralView, LockClause,
LockType, NamedWindowDefinition, NonBlock, Offset, OffsetRows, OrderByExpr, Query,
RenameSelectItem, ReplaceSelectElement, ReplaceSelectItem, Select, SelectInto, SelectItem,
SetExpr, SetOperator, SetQuantifier, Table, TableAlias, TableFactor, TableVersion,
TableWithJoins, Top, Values, WildcardAdditionalOptions, With,
};
pub use self::value::{
escape_quoted_string, DateTimeField, DollarQuotedString, TrimWhereField, Value,
Expand Down
129 changes: 129 additions & 0 deletions src/ast/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ pub struct Query {
pub fetch: Option<Fetch>,
/// `FOR { UPDATE | SHARE } [ OF table_name ] [ SKIP LOCKED | NOWAIT ]`
pub locks: Vec<LockClause>,
/// `FOR XML { RAW | AUTO | EXPLICIT | PATH } [ , ELEMENTS ]`
/// `FOR JSON { AUTO | PATH } [ , INCLUDE_NULL_VALUES ]`
/// (MSSQL-specific)
pub for_clause: Option<ForClause>,
}

impl fmt::Display for Query {
Expand All @@ -71,6 +75,9 @@ impl fmt::Display for Query {
if !self.locks.is_empty() {
write!(f, " {}", display_separated(&self.locks, " "))?;
}
if let Some(ref for_clause) = self.for_clause {
write!(f, " {}", for_clause)?;
}
Ok(())
}
}
Expand Down Expand Up @@ -1315,3 +1322,125 @@ impl fmt::Display for GroupByExpr {
}
}
}

/// FOR XML or FOR JSON clause, specific to MSSQL
/// (formats the output of a query as XML or JSON)
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum ForClause {
Browse,
Json {
for_json: ForJson,
root: Option<String>,
include_null_values: bool,
without_array_wrapper: bool,
},
Xml {
for_xml: ForXml,
elements: bool,
binary_base64: bool,
root: Option<String>,
r#type: bool,
},
}

impl fmt::Display for ForClause {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ForClause::Browse => write!(f, "FOR BROWSE"),
ForClause::Json {
for_json,
root,
include_null_values,
without_array_wrapper,
} => {
write!(f, "FOR JSON ")?;
write!(f, "{}", for_json)?;
if let Some(root) = root {
write!(f, ", ROOT('{}')", root)?;
}
if *include_null_values {
write!(f, ", INCLUDE_NULL_VALUES")?;
}
if *without_array_wrapper {
write!(f, ", WITHOUT_ARRAY_WRAPPER")?;
}
Ok(())
}
ForClause::Xml {
for_xml,
elements,
binary_base64,
root,
r#type,
} => {
write!(f, "FOR XML ")?;
write!(f, "{}", for_xml)?;
if *binary_base64 {
write!(f, ", BINARY BASE64")?;
}
if *r#type {
write!(f, ", TYPE")?;
}
if let Some(root) = root {
write!(f, ", ROOT('{}')", root)?;
}
if *elements {
write!(f, ", ELEMENTS")?;
}
Ok(())
}
}
}
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum ForXml {
Raw(Option<String>),
Auto,
Explicit,
Path(Option<String>),
}

impl fmt::Display for ForXml {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ForXml::Raw(root) => {
write!(f, "RAW")?;
if let Some(root) = root {
write!(f, "('{}')", root)?;
}
Ok(())
}
ForXml::Auto => write!(f, "AUTO"),
ForXml::Explicit => write!(f, "EXPLICIT"),
ForXml::Path(root) => {
write!(f, "PATH")?;
if let Some(root) = root {
write!(f, "('{}')", root)?;
}
Ok(())
}
}
}
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ForJson {
Auto,
Path,
}

impl fmt::Display for ForJson {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ForJson::Auto => write!(f, "AUTO"),
ForJson::Path => write!(f, "PATH"),
}
}
}
12 changes: 12 additions & 0 deletions src/keywords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,13 @@ define_keywords!(
ATOMIC,
ATTACH,
AUTHORIZATION,
AUTO,
AUTOINCREMENT,
AUTO_INCREMENT,
AVG,
AVRO,
BACKWARD,
BASE64,
BEGIN,
BEGIN_FRAME,
BEGIN_PARTITION,
Expand All @@ -116,6 +118,7 @@ define_keywords!(
BOOL,
BOOLEAN,
BOTH,
BROWSE,
BTREE,
BY,
BYPASSRLS,
Expand Down Expand Up @@ -232,6 +235,7 @@ define_keywords!(
DYNAMIC,
EACH,
ELEMENT,
ELEMENTS,
ELSE,
ENCODING,
ENCRYPTION,
Expand All @@ -256,6 +260,7 @@ define_keywords!(
EXP,
EXPANSION,
EXPLAIN,
EXPLICIT,
EXTENDED,
EXTERNAL,
EXTRACT,
Expand Down Expand Up @@ -319,6 +324,7 @@ define_keywords!(
IMMUTABLE,
IN,
INCLUDE,
INCLUDE_NULL_VALUES,
INCREMENT,
INDEX,
INDICATOR,
Expand Down Expand Up @@ -463,6 +469,7 @@ define_keywords!(
PARTITIONED,
PARTITIONS,
PASSWORD,
PATH,
PATTERN,
PERCENT,
PERCENTILE_CONT,
Expand Down Expand Up @@ -494,6 +501,7 @@ define_keywords!(
QUOTE,
RANGE,
RANK,
RAW,
RCFILE,
READ,
READS,
Expand Down Expand Up @@ -535,6 +543,7 @@ define_keywords!(
ROLE,
ROLLBACK,
ROLLUP,
ROOT,
ROW,
ROWID,
ROWS,
Expand Down Expand Up @@ -682,8 +691,10 @@ define_keywords!(
WITH,
WITHIN,
WITHOUT,
WITHOUT_ARRAY_WRAPPER,
WORK,
WRITE,
XML,
XOR,
YEAR,
ZONE,
Expand Down Expand Up @@ -732,6 +743,7 @@ pub const RESERVED_FOR_TABLE_ALIAS: &[Keyword] = &[
Keyword::QUALIFY,
Keyword::WINDOW,
Keyword::END,
Keyword::FOR,
// for MYSQL PARTITION SELECTION
Keyword::PARTITION,
];
Expand Down
Loading

0 comments on commit 953c833

Please sign in to comment.