Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,7 @@ pub enum Expr {
expr: Box<Expr>,
},
/// CONVERT a value to a different data type or character encoding. e.g. `CONVERT(foo USING utf8mb4)`
// XXX too big
Convert {
/// CONVERT (false) or TRY_CONVERT (true)
/// <https://learn.microsoft.com/en-us/sql/t-sql/functions/try-convert-transact-sql?view=sql-server-ver16>
Expand All @@ -1032,6 +1033,7 @@ pub enum Expr {
styles: Vec<Expr>,
},
/// `CAST` an expression to a different data type e.g. `CAST(foo AS VARCHAR(123))`
// XXX too big
Cast {
/// The cast kind (e.g., `CAST`, `TRY_CAST`).
kind: CastKind,
Expand Down Expand Up @@ -1181,14 +1183,17 @@ pub enum Expr {
/// A constant of form `<data_type> 'value'`.
/// This can represent ANSI SQL `DATE`, `TIME`, and `TIMESTAMP` literals (such as `DATE '2020-01-01'`),
/// as well as constants of other types (a non-standard PostgreSQL extension).
// XXX too big
TypedString(TypedString),
/// Scalar function call e.g. `LEFT(foo, 5)`
Function(Function),
// XXX too big
Function(Box<Function>),
/// `CASE [<operand>] WHEN <condition> THEN <result> ... [ELSE <result>] END`
///
/// Note we only recognize a complete single expression as `<condition>`,
/// not `< 0` nor `1, 2, 3` as allowed in a `<simple when clause>` per
/// <https://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#simple-when-clause>
// XXX too big
Case {
/// The attached `CASE` token (keeps original spacing/comments).
case_token: AttachedToken,
Expand Down Expand Up @@ -1266,6 +1271,7 @@ pub enum Expr {
/// An array expression e.g. `ARRAY[1, 2]`
Array(Array),
/// An interval expression e.g. `INTERVAL '1' YEAR`
// XXX too big
Interval(Interval),
/// `MySQL` specific text search function [(1)].
///
Expand Down Expand Up @@ -1317,6 +1323,7 @@ pub enum Expr {
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/functions#higher-order-functions---operator-and-lambdaparams-expr-function)
/// [Databricks](https://docs.databricks.com/en/sql/language-manual/sql-ref-lambda-functions.html)
/// [DuckDB](https://duckdb.org/docs/stable/sql/functions/lambda)
// XXX too big
Lambda(LambdaFunction),
/// Checks membership of a value in a JSON array
MemberOf(MemberOf),
Expand All @@ -1327,6 +1334,16 @@ impl Expr {
pub fn value(value: impl Into<ValueWithSpan>) -> Self {
Expr::Value(value.into())
}

/// Convenience method to retrieve `Expr::Function`'s value if `self` is a
/// function expression.
pub fn as_function(&self) -> Option<&Function> {
if let Expr::Function(f) = self {
Some(&**f)
} else {
None
}
}
}

/// The contents inside the `[` and `]` in a subscript expression.
Expand Down Expand Up @@ -10741,7 +10758,7 @@ pub enum TableObject {
/// INSERT INTO TABLE FUNCTION remote('localhost', default.simple_table)
/// ```
/// [Clickhouse](https://clickhouse.com/docs/en/sql-reference/table-functions)
TableFunction(Function),
TableFunction(Box<Function>),
}

impl fmt::Display for TableObject {
Expand Down
2 changes: 1 addition & 1 deletion src/ast/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,7 @@ where
/// over: None,
/// parameters: FunctionArguments::None,
/// within_group: vec![],
/// });
/// }.into());
/// }
/// ControlFlow::<()>::Continue(())
/// });
Expand Down
42 changes: 25 additions & 17 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1516,7 +1516,7 @@ impl<'a> Parser<'a> {
filter: None,
over: None,
within_group: vec![],
})))
}.into())))
}
Keyword::CURRENT_TIMESTAMP
| Keyword::CURRENT_TIME
Expand Down Expand Up @@ -1578,7 +1578,7 @@ impl<'a> Parser<'a> {
null_treatment: None,
over: None,
within_group: vec![],
})))
}.into())))
}
Keyword::NOT => Ok(Some(self.parse_not()?)),
Keyword::MATCH if self.dialect.supports_match_against() => {
Expand Down Expand Up @@ -2404,7 +2404,7 @@ impl<'a> Parser<'a> {
self.parse_function_call(name).map(Expr::Function)
}

fn parse_function_call(&mut self, name: ObjectName) -> Result<Function, ParserError> {
fn parse_function_call(&mut self, name: ObjectName) -> Result<Box<Function>, ParserError> {
self.expect_token(&Token::LParen)?;

// Snowflake permits a subquery to be passed as an argument without
Expand All @@ -2421,7 +2421,8 @@ impl<'a> Parser<'a> {
null_treatment: None,
over: None,
within_group: vec![],
});
}
.into());
}

let mut args = self.parse_function_argument_list()?;
Expand Down Expand Up @@ -2489,7 +2490,8 @@ impl<'a> Parser<'a> {
filter,
over,
within_group,
})
}
.into())
}

/// Optionally parses a null treatment clause.
Expand All @@ -2515,16 +2517,19 @@ impl<'a> Parser<'a> {
} else {
FunctionArguments::None
};
Ok(Expr::Function(Function {
name,
uses_odbc_syntax: false,
parameters: FunctionArguments::None,
args,
filter: None,
over: None,
null_treatment: None,
within_group: vec![],
}))
Ok(Expr::Function(
Function {
name,
uses_odbc_syntax: false,
parameters: FunctionArguments::None,
args,
filter: None,
over: None,
null_treatment: None,
within_group: vec![],
}
.into(),
))
}

/// Parse window frame `UNITS` clause: `ROWS`, `RANGE`, or `GROUPS`.
Expand Down Expand Up @@ -11036,7 +11041,7 @@ impl<'a> Parser<'a> {
let object_name = self.parse_object_name(false)?;
if self.peek_token_ref().token == Token::LParen {
match self.parse_function(object_name)? {
Expr::Function(f) => Ok(Statement::Call(f)),
Expr::Function(f) => Ok(Statement::Call(*f)),
other => parser_err!(
format!("Expected a simple procedure call but found: {other}"),
self.peek_token_ref().span.start
Expand Down Expand Up @@ -13780,7 +13785,10 @@ impl<'a> Parser<'a> {
let function_expr = self.parse_function(function_name)?;
if let Expr::Function(function) = function_expr {
let alias = self.parse_identifier_optional_alias()?;
pipe_operators.push(PipeOperator::Call { function, alias });
pipe_operators.push(PipeOperator::Call {
function: *function,
alias,
});
} else {
return Err(ParserError::ParserError(
"Expected function call after CALL".to_string(),
Expand Down
37 changes: 20 additions & 17 deletions src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,23 +435,26 @@ pub fn join(relation: TableFactor) -> Join {
}

pub fn call(function: &str, args: impl IntoIterator<Item = Expr>) -> Expr {
Expr::Function(Function {
name: ObjectName::from(vec![Ident::new(function)]),
uses_odbc_syntax: false,
parameters: FunctionArguments::None,
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: None,
args: args
.into_iter()
.map(|arg| FunctionArg::Unnamed(FunctionArgExpr::Expr(arg)))
.collect(),
clauses: vec![],
}),
filter: None,
null_treatment: None,
over: None,
within_group: vec![],
})
Expr::Function(
Function {
name: ObjectName::from(vec![Ident::new(function)]),
uses_odbc_syntax: false,
parameters: FunctionArguments::None,
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: None,
args: args
.into_iter()
.map(|arg| FunctionArg::Unnamed(FunctionArgExpr::Expr(arg)))
.collect(),
clauses: vec![],
}),
filter: None,
null_treatment: None,
over: None,
within_group: vec![],
}
.into(),
)
}

/// Gets the first index column (mysql calls it a key part) of the first index found in a
Expand Down
41 changes: 22 additions & 19 deletions tests/sqlparser_bigquery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2219,25 +2219,28 @@ fn parse_map_access_expr() {
},
}),
AccessExpr::Subscript(Subscript::Index {
index: Expr::Function(Function {
name: ObjectName::from(vec![Ident::with_span(
Span::new(Location::of(1, 11), Location::of(1, 22)),
"safe_offset",
)]),
parameters: FunctionArguments::None,
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: None,
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
number("2").with_empty_span(),
)))],
clauses: vec![],
}),
filter: None,
null_treatment: None,
over: None,
within_group: vec![],
uses_odbc_syntax: false,
}),
index: Expr::Function(
Function {
name: ObjectName::from(vec![Ident::with_span(
Span::new(Location::of(1, 11), Location::of(1, 22)),
"safe_offset",
)]),
parameters: FunctionArguments::None,
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: None,
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
number("2").with_empty_span(),
)))],
clauses: vec![],
}),
filter: None,
null_treatment: None,
over: None,
within_group: vec![],
uses_odbc_syntax: false,
}
.into(),
),
}),
AccessExpr::Dot(Expr::Identifier(Ident::with_span(
Span::new(Location::of(1, 24), Location::of(1, 25)),
Expand Down
68 changes: 36 additions & 32 deletions tests/sqlparser_clickhouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ fn parse_delimited_identifiers() {
expr_from_projection(&select.projection[0]),
);
assert_eq!(
&Expr::Function(Function {
Some(&Function {
name: ObjectName::from(vec![Ident::with_quote('"', "myfun")]),
uses_odbc_syntax: false,
parameters: FunctionArguments::None,
Expand All @@ -205,7 +205,7 @@ fn parse_delimited_identifiers() {
over: None,
within_group: vec![],
}),
expr_from_projection(&select.projection[1]),
expr_from_projection(&select.projection[1]).as_function(),
);
match &select.projection[2] {
SelectItem::ExprWithAlias { expr, alias } => {
Expand Down Expand Up @@ -826,41 +826,45 @@ fn parse_create_table_with_variant_default_expressions() {
data_type: DataType::Datetime(None),
options: vec![ColumnOptionDef {
name: None,
option: ColumnOption::Materialized(Expr::Function(Function {
name: ObjectName::from(vec![Ident::new("now")]),
uses_odbc_syntax: false,
args: FunctionArguments::List(FunctionArgumentList {
args: vec![],
duplicate_treatment: None,
clauses: vec![],
}),
parameters: FunctionArguments::None,
null_treatment: None,
filter: None,
over: None,
within_group: vec![],
}))
option: ColumnOption::Materialized(Expr::Function(Box::new(
Function {
name: ObjectName::from(vec![Ident::new("now")]),
uses_odbc_syntax: false,
args: FunctionArguments::List(FunctionArgumentList {
args: vec![],
duplicate_treatment: None,
clauses: vec![],
}),
parameters: FunctionArguments::None,
null_treatment: None,
filter: None,
over: None,
within_group: vec![],
}
)))
}],
},
ColumnDef {
name: Ident::new("b"),
data_type: DataType::Datetime(None),
options: vec![ColumnOptionDef {
name: None,
option: ColumnOption::Ephemeral(Some(Expr::Function(Function {
name: ObjectName::from(vec![Ident::new("now")]),
uses_odbc_syntax: false,
args: FunctionArguments::List(FunctionArgumentList {
args: vec![],
duplicate_treatment: None,
clauses: vec![],
}),
parameters: FunctionArguments::None,
null_treatment: None,
filter: None,
over: None,
within_group: vec![],
})))
option: ColumnOption::Ephemeral(Some(Expr::Function(Box::new(
Function {
name: ObjectName::from(vec![Ident::new("now")]),
uses_odbc_syntax: false,
args: FunctionArguments::List(FunctionArgumentList {
args: vec![],
duplicate_treatment: None,
clauses: vec![],
}),
parameters: FunctionArguments::None,
null_treatment: None,
filter: None,
over: None,
within_group: vec![],
}
))))
}],
},
ColumnDef {
Expand All @@ -876,7 +880,7 @@ fn parse_create_table_with_variant_default_expressions() {
data_type: DataType::String(None),
options: vec![ColumnOptionDef {
name: None,
option: ColumnOption::Alias(Expr::Function(Function {
option: ColumnOption::Alias(Expr::Function(Box::new(Function {
name: ObjectName::from(vec![Ident::new("toString")]),
uses_odbc_syntax: false,
args: FunctionArguments::List(FunctionArgumentList {
Expand All @@ -891,7 +895,7 @@ fn parse_create_table_with_variant_default_expressions() {
filter: None,
over: None,
within_group: vec![],
}))
})))
}],
}
]
Expand Down
Loading
Loading