mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-04 06:18:17 +00:00
Support mssql json and xml extensions (#1043)
This commit is contained in:
parent
ff8312bfd8
commit
953c833a4a
9 changed files with 318 additions and 15 deletions
|
@ -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,
|
||||
|
|
129
src/ast/query.rs
129
src/ast/query.rs
|
@ -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 {
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
@ -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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,11 +97,13 @@ define_keywords!(
|
|||
ATOMIC,
|
||||
ATTACH,
|
||||
AUTHORIZATION,
|
||||
AUTO,
|
||||
AUTOINCREMENT,
|
||||
AUTO_INCREMENT,
|
||||
AVG,
|
||||
AVRO,
|
||||
BACKWARD,
|
||||
BASE64,
|
||||
BEGIN,
|
||||
BEGIN_FRAME,
|
||||
BEGIN_PARTITION,
|
||||
|
@ -116,6 +118,7 @@ define_keywords!(
|
|||
BOOL,
|
||||
BOOLEAN,
|
||||
BOTH,
|
||||
BROWSE,
|
||||
BTREE,
|
||||
BY,
|
||||
BYPASSRLS,
|
||||
|
@ -232,6 +235,7 @@ define_keywords!(
|
|||
DYNAMIC,
|
||||
EACH,
|
||||
ELEMENT,
|
||||
ELEMENTS,
|
||||
ELSE,
|
||||
ENCODING,
|
||||
ENCRYPTION,
|
||||
|
@ -256,6 +260,7 @@ define_keywords!(
|
|||
EXP,
|
||||
EXPANSION,
|
||||
EXPLAIN,
|
||||
EXPLICIT,
|
||||
EXTENDED,
|
||||
EXTERNAL,
|
||||
EXTRACT,
|
||||
|
@ -319,6 +324,7 @@ define_keywords!(
|
|||
IMMUTABLE,
|
||||
IN,
|
||||
INCLUDE,
|
||||
INCLUDE_NULL_VALUES,
|
||||
INCREMENT,
|
||||
INDEX,
|
||||
INDICATOR,
|
||||
|
@ -463,6 +469,7 @@ define_keywords!(
|
|||
PARTITIONED,
|
||||
PARTITIONS,
|
||||
PASSWORD,
|
||||
PATH,
|
||||
PATTERN,
|
||||
PERCENT,
|
||||
PERCENTILE_CONT,
|
||||
|
@ -494,6 +501,7 @@ define_keywords!(
|
|||
QUOTE,
|
||||
RANGE,
|
||||
RANK,
|
||||
RAW,
|
||||
RCFILE,
|
||||
READ,
|
||||
READS,
|
||||
|
@ -535,6 +543,7 @@ define_keywords!(
|
|||
ROLE,
|
||||
ROLLBACK,
|
||||
ROLLUP,
|
||||
ROOT,
|
||||
ROW,
|
||||
ROWID,
|
||||
ROWS,
|
||||
|
@ -682,8 +691,10 @@ define_keywords!(
|
|||
WITH,
|
||||
WITHIN,
|
||||
WITHOUT,
|
||||
WITHOUT_ARRAY_WRAPPER,
|
||||
WORK,
|
||||
WRITE,
|
||||
XML,
|
||||
XOR,
|
||||
YEAR,
|
||||
ZONE,
|
||||
|
@ -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,
|
||||
];
|
||||
|
|
|
@ -5825,6 +5825,7 @@ impl<'a> Parser<'a> {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
})
|
||||
} else if self.parse_keyword(Keyword::UPDATE) {
|
||||
let update = self.parse_update()?;
|
||||
|
@ -5837,6 +5838,7 @@ impl<'a> Parser<'a> {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
})
|
||||
} else {
|
||||
let body = Box::new(self.parse_query_body(0)?);
|
||||
|
@ -5888,9 +5890,15 @@ impl<'a> Parser<'a> {
|
|||
None
|
||||
};
|
||||
|
||||
let mut for_clause = None;
|
||||
let mut locks = Vec::new();
|
||||
while self.parse_keyword(Keyword::FOR) {
|
||||
locks.push(self.parse_lock()?);
|
||||
if let Some(parsed_for_clause) = self.parse_for_clause()? {
|
||||
for_clause = Some(parsed_for_clause);
|
||||
break;
|
||||
} else {
|
||||
locks.push(self.parse_lock()?);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Query {
|
||||
|
@ -5902,10 +5910,113 @@ impl<'a> Parser<'a> {
|
|||
offset,
|
||||
fetch,
|
||||
locks,
|
||||
for_clause,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a mssql `FOR [XML | JSON | BROWSE]` clause
|
||||
pub fn parse_for_clause(&mut self) -> Result<Option<ForClause>, ParserError> {
|
||||
if self.parse_keyword(Keyword::XML) {
|
||||
Ok(Some(self.parse_for_xml()?))
|
||||
} else if self.parse_keyword(Keyword::JSON) {
|
||||
Ok(Some(self.parse_for_json()?))
|
||||
} else if self.parse_keyword(Keyword::BROWSE) {
|
||||
Ok(Some(ForClause::Browse))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a mssql `FOR XML` clause
|
||||
pub fn parse_for_xml(&mut self) -> Result<ForClause, ParserError> {
|
||||
let for_xml = if self.parse_keyword(Keyword::RAW) {
|
||||
let mut element_name = None;
|
||||
if self.peek_token().token == Token::LParen {
|
||||
self.expect_token(&Token::LParen)?;
|
||||
element_name = Some(self.parse_literal_string()?);
|
||||
self.expect_token(&Token::RParen)?;
|
||||
}
|
||||
ForXml::Raw(element_name)
|
||||
} else if self.parse_keyword(Keyword::AUTO) {
|
||||
ForXml::Auto
|
||||
} else if self.parse_keyword(Keyword::EXPLICIT) {
|
||||
ForXml::Explicit
|
||||
} else if self.parse_keyword(Keyword::PATH) {
|
||||
let mut element_name = None;
|
||||
if self.peek_token().token == Token::LParen {
|
||||
self.expect_token(&Token::LParen)?;
|
||||
element_name = Some(self.parse_literal_string()?);
|
||||
self.expect_token(&Token::RParen)?;
|
||||
}
|
||||
ForXml::Path(element_name)
|
||||
} else {
|
||||
return Err(ParserError::ParserError(
|
||||
"Expected FOR XML [RAW | AUTO | EXPLICIT | PATH ]".to_string(),
|
||||
));
|
||||
};
|
||||
let mut elements = false;
|
||||
let mut binary_base64 = false;
|
||||
let mut root = None;
|
||||
let mut r#type = false;
|
||||
while self.peek_token().token == Token::Comma {
|
||||
self.next_token();
|
||||
if self.parse_keyword(Keyword::ELEMENTS) {
|
||||
elements = true;
|
||||
} else if self.parse_keyword(Keyword::BINARY) {
|
||||
self.expect_keyword(Keyword::BASE64)?;
|
||||
binary_base64 = true;
|
||||
} else if self.parse_keyword(Keyword::ROOT) {
|
||||
self.expect_token(&Token::LParen)?;
|
||||
root = Some(self.parse_literal_string()?);
|
||||
self.expect_token(&Token::RParen)?;
|
||||
} else if self.parse_keyword(Keyword::TYPE) {
|
||||
r#type = true;
|
||||
}
|
||||
}
|
||||
Ok(ForClause::Xml {
|
||||
for_xml,
|
||||
elements,
|
||||
binary_base64,
|
||||
root,
|
||||
r#type,
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse a mssql `FOR JSON` clause
|
||||
pub fn parse_for_json(&mut self) -> Result<ForClause, ParserError> {
|
||||
let for_json = if self.parse_keyword(Keyword::AUTO) {
|
||||
ForJson::Auto
|
||||
} else if self.parse_keyword(Keyword::PATH) {
|
||||
ForJson::Path
|
||||
} else {
|
||||
return Err(ParserError::ParserError(
|
||||
"Expected FOR JSON [AUTO | PATH ]".to_string(),
|
||||
));
|
||||
};
|
||||
let mut root = None;
|
||||
let mut include_null_values = false;
|
||||
let mut without_array_wrapper = false;
|
||||
while self.peek_token().token == Token::Comma {
|
||||
self.next_token();
|
||||
if self.parse_keyword(Keyword::ROOT) {
|
||||
self.expect_token(&Token::LParen)?;
|
||||
root = Some(self.parse_literal_string()?);
|
||||
self.expect_token(&Token::RParen)?;
|
||||
} else if self.parse_keyword(Keyword::INCLUDE_NULL_VALUES) {
|
||||
include_null_values = true;
|
||||
} else if self.parse_keyword(Keyword::WITHOUT_ARRAY_WRAPPER) {
|
||||
without_array_wrapper = true;
|
||||
}
|
||||
}
|
||||
Ok(ForClause::Json {
|
||||
for_json,
|
||||
root,
|
||||
include_null_values,
|
||||
without_array_wrapper,
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse a CTE (`alias [( col1, col2, ... )] AS (subquery)`)
|
||||
pub fn parse_cte(&mut self) -> Result<Cte, ParserError> {
|
||||
let name = self.parse_identifier()?;
|
||||
|
|
|
@ -534,13 +534,7 @@ impl<'a> Tokenizer<'a> {
|
|||
/// Tokenize the statement and produce a vector of tokens
|
||||
pub fn tokenize(&mut self) -> Result<Vec<Token>, TokenizerError> {
|
||||
let twl = self.tokenize_with_location()?;
|
||||
|
||||
let mut tokens: Vec<Token> = vec![];
|
||||
tokens.reserve(twl.len());
|
||||
for token_with_location in twl {
|
||||
tokens.push(token_with_location.token);
|
||||
}
|
||||
Ok(tokens)
|
||||
Ok(twl.into_iter().map(|t| t.token).collect())
|
||||
}
|
||||
|
||||
/// Tokenize the statement and produce a vector of tokens with location information
|
||||
|
|
|
@ -270,6 +270,7 @@ fn parse_update_set_from() {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
}),
|
||||
alias: Some(TableAlias {
|
||||
name: Ident::new("t2"),
|
||||
|
@ -2756,6 +2757,7 @@ fn parse_create_table_as_table() {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
});
|
||||
|
||||
match verified_stmt(sql1) {
|
||||
|
@ -2780,6 +2782,7 @@ fn parse_create_table_as_table() {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
});
|
||||
|
||||
match verified_stmt(sql2) {
|
||||
|
@ -4082,6 +4085,7 @@ fn parse_interval_and_or_xor() {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
}))];
|
||||
|
||||
assert_eq!(actual_ast, expected_ast);
|
||||
|
@ -6656,6 +6660,7 @@ fn parse_merge() {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
}),
|
||||
alias: Some(TableAlias {
|
||||
name: Ident {
|
||||
|
|
|
@ -96,6 +96,7 @@ fn parse_create_procedure() {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
order_by: vec![],
|
||||
body: Box::new(SetExpr::Select(Box::new(Select {
|
||||
distinct: None,
|
||||
|
@ -431,6 +432,44 @@ fn parse_like() {
|
|||
chk(true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_for_clause() {
|
||||
ms_and_generic().verified_stmt("SELECT a FROM t FOR JSON PATH");
|
||||
ms_and_generic().verified_stmt("SELECT b FROM t FOR JSON AUTO");
|
||||
ms_and_generic().verified_stmt("SELECT c FROM t FOR JSON AUTO, WITHOUT_ARRAY_WRAPPER");
|
||||
ms_and_generic().verified_stmt("SELECT 1 FROM t FOR JSON PATH, ROOT('x'), INCLUDE_NULL_VALUES");
|
||||
ms_and_generic().verified_stmt("SELECT 2 FROM t FOR XML AUTO");
|
||||
ms_and_generic().verified_stmt("SELECT 3 FROM t FOR XML AUTO, TYPE, ELEMENTS");
|
||||
ms_and_generic().verified_stmt("SELECT * FROM t WHERE x FOR XML AUTO, ELEMENTS");
|
||||
ms_and_generic().verified_stmt("SELECT x FROM t ORDER BY y FOR XML AUTO, ELEMENTS");
|
||||
ms_and_generic().verified_stmt("SELECT y FROM t FOR XML PATH('x'), ROOT('y'), ELEMENTS");
|
||||
ms_and_generic().verified_stmt("SELECT z FROM t FOR XML EXPLICIT, BINARY BASE64");
|
||||
ms_and_generic().verified_stmt("SELECT * FROM t FOR XML RAW('x')");
|
||||
ms_and_generic().verified_stmt("SELECT * FROM t FOR BROWSE");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dont_parse_trailing_for() {
|
||||
assert!(ms()
|
||||
.run_parser_method("SELECT * FROM foo FOR", |p| p.parse_query())
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_for_json_expect_ast() {
|
||||
assert_eq!(
|
||||
ms().verified_query("SELECT * FROM t FOR JSON PATH, ROOT('root')")
|
||||
.for_clause
|
||||
.unwrap(),
|
||||
ForClause::Json {
|
||||
for_json: ForJson::Path,
|
||||
root: Some("root".into()),
|
||||
without_array_wrapper: false,
|
||||
include_null_values: false,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_cast_varchar_max() {
|
||||
ms_and_generic().verified_expr("CAST('foo' AS VARCHAR(MAX))");
|
||||
|
@ -545,6 +584,7 @@ fn parse_substring_in_select() {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
}),
|
||||
query
|
||||
);
|
||||
|
|
|
@ -566,6 +566,7 @@ fn parse_escaped_quote_identifiers_with_escape() {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
@ -609,6 +610,7 @@ fn parse_escaped_quote_identifiers_with_no_escape() {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
@ -649,6 +651,7 @@ fn parse_escaped_backticks_with_escape() {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
@ -689,6 +692,7 @@ fn parse_escaped_backticks_with_no_escape() {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
@ -964,6 +968,7 @@ fn parse_simple_insert() {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
}),
|
||||
source
|
||||
);
|
||||
|
@ -1004,7 +1009,8 @@ fn parse_ignore_insert() {
|
|||
limit_by: vec![],
|
||||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![]
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
}),
|
||||
source
|
||||
);
|
||||
|
@ -1041,6 +1047,7 @@ fn parse_empty_row_insert() {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
}),
|
||||
source
|
||||
);
|
||||
|
@ -1100,6 +1107,7 @@ fn parse_insert_with_on_duplicate_update() {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
}),
|
||||
source
|
||||
);
|
||||
|
@ -1490,6 +1498,7 @@ fn parse_substring_in_select() {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
}),
|
||||
query
|
||||
);
|
||||
|
@ -1785,6 +1794,7 @@ fn parse_hex_string_introducer() {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
}))
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1010,6 +1010,7 @@ fn parse_copy_to() {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
})),
|
||||
to: true,
|
||||
target: CopyTarget::File {
|
||||
|
@ -2060,6 +2061,7 @@ fn parse_array_subquery_expr() {
|
|||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
})),
|
||||
expr_from_projection(only(&select.projection)),
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue