mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-03 20:50:33 +00:00
Merge 61657837af
into b660a3b1ea
This commit is contained in:
commit
d230d9dfb3
4 changed files with 142 additions and 7 deletions
|
@ -7802,11 +7802,16 @@ pub enum FunctionArgumentClause {
|
||||||
///
|
///
|
||||||
/// [`GROUP_CONCAT`]: https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_group-concat
|
/// [`GROUP_CONCAT`]: https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_group-concat
|
||||||
Separator(Value),
|
Separator(Value),
|
||||||
/// The json-null-clause to the [`JSON_ARRAY`]/[`JSON_OBJECT`] function in MSSQL.
|
/// The `ON NULL` clause for some JSON functions in MSSQL and PostgreSQL
|
||||||
///
|
///
|
||||||
/// [`JSON_ARRAY`]: <https://learn.microsoft.com/en-us/sql/t-sql/functions/json-array-transact-sql?view=sql-server-ver16>
|
/// [MSSQL `JSON_ARRAY`](https://learn.microsoft.com/en-us/sql/t-sql/functions/json-array-transact-sql?view=sql-server-ver16)
|
||||||
/// [`JSON_OBJECT`]: <https://learn.microsoft.com/en-us/sql/t-sql/functions/json-object-transact-sql?view=sql-server-ver16>
|
/// [MSSQL `JSON_OBJECT`](https://learn.microsoft.com/en-us/sql/t-sql/functions/json-object-transact-sql?view=sql-server-ver16>)
|
||||||
|
/// [PostgreSQL JSON functions](https://www.postgresql.org/docs/current/functions-json.html#FUNCTIONS-JSON-PROCESSING)
|
||||||
JsonNullClause(JsonNullClause),
|
JsonNullClause(JsonNullClause),
|
||||||
|
/// The `RETURNING` clause for some JSON functions in PostgreSQL
|
||||||
|
///
|
||||||
|
/// [`JSON_OBJECT`](https://www.postgresql.org/docs/current/functions-json.html#:~:text=json_object)
|
||||||
|
JsonReturningClause(JsonReturningClause),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for FunctionArgumentClause {
|
impl fmt::Display for FunctionArgumentClause {
|
||||||
|
@ -7823,6 +7828,9 @@ impl fmt::Display for FunctionArgumentClause {
|
||||||
FunctionArgumentClause::Having(bound) => write!(f, "{bound}"),
|
FunctionArgumentClause::Having(bound) => write!(f, "{bound}"),
|
||||||
FunctionArgumentClause::Separator(sep) => write!(f, "SEPARATOR {sep}"),
|
FunctionArgumentClause::Separator(sep) => write!(f, "SEPARATOR {sep}"),
|
||||||
FunctionArgumentClause::JsonNullClause(null_clause) => write!(f, "{null_clause}"),
|
FunctionArgumentClause::JsonNullClause(null_clause) => write!(f, "{null_clause}"),
|
||||||
|
FunctionArgumentClause::JsonReturningClause(returning_clause) => {
|
||||||
|
write!(f, "{returning_clause}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10071,6 +10079,25 @@ impl Display for JsonNullClause {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// PostgreSQL JSON function RETURNING clause
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```sql
|
||||||
|
/// JSON_OBJECT('a': 1 RETURNING jsonb)
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
|
pub struct JsonReturningClause {
|
||||||
|
pub data_type: DataType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for JsonReturningClause {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "RETURNING {}", self.data_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// rename object definition
|
/// rename object definition
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
|
|
@ -1778,6 +1778,7 @@ impl Spanned for FunctionArgumentClause {
|
||||||
FunctionArgumentClause::Having(HavingBound(_kind, expr)) => expr.span(),
|
FunctionArgumentClause::Having(HavingBound(_kind, expr)) => expr.span(),
|
||||||
FunctionArgumentClause::Separator(value) => value.span(),
|
FunctionArgumentClause::Separator(value) => value.span(),
|
||||||
FunctionArgumentClause::JsonNullClause(_) => Span::empty(),
|
FunctionArgumentClause::JsonNullClause(_) => Span::empty(),
|
||||||
|
FunctionArgumentClause::JsonReturningClause(_) => Span::empty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15341,7 +15341,7 @@ impl<'a> Parser<'a> {
|
||||||
Ok(TableFunctionArgs { args, settings })
|
Ok(TableFunctionArgs { args, settings })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a potentially empty list of arguments to a window function
|
/// Parses a potentially empty list of arguments to a function
|
||||||
/// (including the closing parenthesis).
|
/// (including the closing parenthesis).
|
||||||
///
|
///
|
||||||
/// Examples:
|
/// Examples:
|
||||||
|
@ -15352,11 +15352,18 @@ impl<'a> Parser<'a> {
|
||||||
fn parse_function_argument_list(&mut self) -> Result<FunctionArgumentList, ParserError> {
|
fn parse_function_argument_list(&mut self) -> Result<FunctionArgumentList, ParserError> {
|
||||||
let mut clauses = vec![];
|
let mut clauses = vec![];
|
||||||
|
|
||||||
// For MSSQL empty argument list with json-null-clause case, e.g. `JSON_ARRAY(NULL ON NULL)`
|
// Handle clauses that may exist with an empty argument list
|
||||||
|
|
||||||
if let Some(null_clause) = self.parse_json_null_clause() {
|
if let Some(null_clause) = self.parse_json_null_clause() {
|
||||||
clauses.push(FunctionArgumentClause::JsonNullClause(null_clause));
|
clauses.push(FunctionArgumentClause::JsonNullClause(null_clause));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(json_returning_clause) = self.parse_json_returning_clause()? {
|
||||||
|
clauses.push(FunctionArgumentClause::JsonReturningClause(
|
||||||
|
json_returning_clause,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
if self.consume_token(&Token::RParen) {
|
if self.consume_token(&Token::RParen) {
|
||||||
return Ok(FunctionArgumentList {
|
return Ok(FunctionArgumentList {
|
||||||
duplicate_treatment: None,
|
duplicate_treatment: None,
|
||||||
|
@ -15412,6 +15419,12 @@ impl<'a> Parser<'a> {
|
||||||
clauses.push(FunctionArgumentClause::JsonNullClause(null_clause));
|
clauses.push(FunctionArgumentClause::JsonNullClause(null_clause));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(json_returning_clause) = self.parse_json_returning_clause()? {
|
||||||
|
clauses.push(FunctionArgumentClause::JsonReturningClause(
|
||||||
|
json_returning_clause,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
self.expect_token(&Token::RParen)?;
|
self.expect_token(&Token::RParen)?;
|
||||||
Ok(FunctionArgumentList {
|
Ok(FunctionArgumentList {
|
||||||
duplicate_treatment,
|
duplicate_treatment,
|
||||||
|
@ -15420,7 +15433,6 @@ impl<'a> Parser<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses MSSQL's json-null-clause
|
|
||||||
fn parse_json_null_clause(&mut self) -> Option<JsonNullClause> {
|
fn parse_json_null_clause(&mut self) -> Option<JsonNullClause> {
|
||||||
if self.parse_keywords(&[Keyword::ABSENT, Keyword::ON, Keyword::NULL]) {
|
if self.parse_keywords(&[Keyword::ABSENT, Keyword::ON, Keyword::NULL]) {
|
||||||
Some(JsonNullClause::AbsentOnNull)
|
Some(JsonNullClause::AbsentOnNull)
|
||||||
|
@ -15431,6 +15443,15 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_json_returning_clause(&mut self) -> Result<Option<JsonReturningClause>, ParserError> {
|
||||||
|
if self.parse_keyword(Keyword::RETURNING) {
|
||||||
|
let data_type = self.parse_data_type()?;
|
||||||
|
Ok(Some(JsonReturningClause { data_type }))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_duplicate_treatment(&mut self) -> Result<Option<DuplicateTreatment>, ParserError> {
|
fn parse_duplicate_treatment(&mut self) -> Result<Option<DuplicateTreatment>, ParserError> {
|
||||||
let loc = self.peek_token().span.start;
|
let loc = self.peek_token().span.start;
|
||||||
match (
|
match (
|
||||||
|
|
|
@ -3351,7 +3351,31 @@ fn test_json() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fn_arg_with_value_operator() {
|
fn json_object_colon_syntax() {
|
||||||
|
match pg().verified_expr("JSON_OBJECT('name' : 'value')") {
|
||||||
|
Expr::Function(Function {
|
||||||
|
args: FunctionArguments::List(FunctionArgumentList { args, .. }),
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
assert!(
|
||||||
|
matches!(
|
||||||
|
&args[..],
|
||||||
|
&[FunctionArg::ExprNamed {
|
||||||
|
operator: FunctionArgOperator::Colon,
|
||||||
|
..
|
||||||
|
}]
|
||||||
|
),
|
||||||
|
"Invalid function argument: {args:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
other => panic!(
|
||||||
|
"Expected: JSON_OBJECT('name' : 'value') to be parsed as a function, but got {other:?}"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn json_object_value_syntax() {
|
||||||
match pg().verified_expr("JSON_OBJECT('name' VALUE 'value')") {
|
match pg().verified_expr("JSON_OBJECT('name' VALUE 'value')") {
|
||||||
Expr::Function(Function { args: FunctionArguments::List(FunctionArgumentList { args, .. }), .. }) => {
|
Expr::Function(Function { args: FunctionArguments::List(FunctionArgumentList { args, .. }), .. }) => {
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
|
@ -3363,6 +3387,68 @@ fn test_fn_arg_with_value_operator() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn json_object_with_null_clause() {
|
||||||
|
match pg().verified_expr("JSON_OBJECT('name' VALUE 'value' NULL ON NULL)") {
|
||||||
|
Expr::Function(Function { args: FunctionArguments::List(FunctionArgumentList { args, clauses, .. }), .. }) => {
|
||||||
|
assert!(matches!(
|
||||||
|
&args[..],
|
||||||
|
&[FunctionArg::ExprNamed { operator: FunctionArgOperator::Value, .. }]
|
||||||
|
), "Invalid function argument: {args:?}");
|
||||||
|
assert_eq!(
|
||||||
|
clauses,
|
||||||
|
vec![FunctionArgumentClause::JsonNullClause(JsonNullClause::NullOnNull)],
|
||||||
|
"Expected: NULL ON NULL to be parsed as a null treatment clause, but got {clauses:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
other => panic!("Expected: JSON_OBJECT('name' VALUE 'value' NULL ON NULL) to be parsed as a function, but got {other:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn json_object_with_returning_clause() {
|
||||||
|
match pg().verified_expr("JSON_OBJECT('name' VALUE 'value' RETURNING JSONB)") {
|
||||||
|
Expr::Function(Function { args: FunctionArguments::List(FunctionArgumentList { args, clauses, .. }), .. }) => {
|
||||||
|
assert!(matches!(
|
||||||
|
&args[..],
|
||||||
|
&[FunctionArg::ExprNamed { operator: FunctionArgOperator::Value, .. }]
|
||||||
|
), "Invalid function argument: {args:?}");
|
||||||
|
assert_eq!(
|
||||||
|
clauses,
|
||||||
|
vec![FunctionArgumentClause::JsonReturningClause(JsonReturningClause {
|
||||||
|
data_type: DataType::JSONB
|
||||||
|
})],
|
||||||
|
"Expected: RETURNING JSONB to be parsed as a returning clause, but got {clauses:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
other => panic!("Expected: JSON_OBJECT('name' VALUE 'value' RETURNING jsonb) to be parsed as a function, but got {other:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn json_object_only_returning_clause() {
|
||||||
|
match pg().verified_expr("JSON_OBJECT(RETURNING JSONB)") {
|
||||||
|
Expr::Function(Function {
|
||||||
|
args: FunctionArguments::List(FunctionArgumentList { args, clauses, .. }),
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
assert!(args.is_empty(), "Expected no arguments, got: {args:?}");
|
||||||
|
assert_eq!(
|
||||||
|
clauses,
|
||||||
|
vec![FunctionArgumentClause::JsonReturningClause(
|
||||||
|
JsonReturningClause {
|
||||||
|
data_type: DataType::JSONB
|
||||||
|
}
|
||||||
|
)],
|
||||||
|
"Expected: RETURNING JSONB to be parsed as a returning clause, but got {clauses:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
other => panic!(
|
||||||
|
"Expected: JSON_OBJECT(RETURNING jsonb) to be parsed as a function, but got {other:?}"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_json_table_is_not_reserved() {
|
fn parse_json_table_is_not_reserved() {
|
||||||
// JSON_TABLE is not a reserved keyword in PostgreSQL, even though it is in SQL:2023
|
// JSON_TABLE is not a reserved keyword in PostgreSQL, even though it is in SQL:2023
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue