mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-10-30 06:47:17 +00:00
Support parametric arguments to FUNCTION for ClickHouse dialect (#1315)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
parent
7a9793b72e
commit
a685e11993
13 changed files with 119 additions and 5 deletions
|
|
@ -4695,6 +4695,16 @@ impl fmt::Display for CloseCursor {
|
|||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||
pub struct Function {
|
||||
pub name: ObjectName,
|
||||
/// The parameters to the function, including any options specified within the
|
||||
/// delimiting parentheses.
|
||||
///
|
||||
/// Example:
|
||||
/// ```plaintext
|
||||
/// HISTOGRAM(0.5, 0.6)(x, y)
|
||||
/// ```
|
||||
///
|
||||
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/aggregate-functions/parametric-functions)
|
||||
pub parameters: FunctionArguments,
|
||||
/// The arguments to the function, including any options specified within the
|
||||
/// delimiting parentheses.
|
||||
pub args: FunctionArguments,
|
||||
|
|
@ -4723,7 +4733,7 @@ pub struct Function {
|
|||
|
||||
impl fmt::Display for Function {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}{}", self.name, self.args)?;
|
||||
write!(f, "{}{}{}", self.name, self.parameters, self.args)?;
|
||||
|
||||
if !self.within_group.is_empty() {
|
||||
write!(
|
||||
|
|
|
|||
|
|
@ -533,6 +533,7 @@ where
|
|||
/// null_treatment: None,
|
||||
/// filter: None,
|
||||
/// over: None,
|
||||
/// parameters: FunctionArguments::None,
|
||||
/// within_group: vec![],
|
||||
/// });
|
||||
/// }
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ use core::{
|
|||
|
||||
use log::debug;
|
||||
|
||||
use recursion::RecursionCounter;
|
||||
use IsLateral::*;
|
||||
use IsOptional::*;
|
||||
|
||||
|
|
@ -146,8 +147,6 @@ mod recursion {
|
|||
pub struct DepthGuard {}
|
||||
}
|
||||
|
||||
use recursion::RecursionCounter;
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum IsOptional {
|
||||
Optional,
|
||||
|
|
@ -1002,6 +1001,7 @@ impl<'a> Parser<'a> {
|
|||
{
|
||||
Ok(Expr::Function(Function {
|
||||
name: ObjectName(vec![w.to_ident()]),
|
||||
parameters: FunctionArguments::None,
|
||||
args: FunctionArguments::None,
|
||||
null_treatment: None,
|
||||
filter: None,
|
||||
|
|
@ -1058,6 +1058,7 @@ impl<'a> Parser<'a> {
|
|||
self.expect_token(&Token::RParen)?;
|
||||
Ok(Expr::Function(Function {
|
||||
name: ObjectName(vec![w.to_ident()]),
|
||||
parameters: FunctionArguments::None,
|
||||
args: FunctionArguments::Subquery(query),
|
||||
filter: None,
|
||||
null_treatment: None,
|
||||
|
|
@ -1293,6 +1294,7 @@ impl<'a> Parser<'a> {
|
|||
self.expect_token(&Token::RParen)?;
|
||||
return Ok(Expr::Function(Function {
|
||||
name,
|
||||
parameters: FunctionArguments::None,
|
||||
args: FunctionArguments::Subquery(subquery),
|
||||
filter: None,
|
||||
null_treatment: None,
|
||||
|
|
@ -1301,7 +1303,16 @@ impl<'a> Parser<'a> {
|
|||
}));
|
||||
}
|
||||
|
||||
let args = self.parse_function_argument_list()?;
|
||||
let mut args = self.parse_function_argument_list()?;
|
||||
let mut parameters = FunctionArguments::None;
|
||||
// ClickHouse aggregations support parametric functions like `HISTOGRAM(0.5, 0.6)(x, y)`
|
||||
// which (0.5, 0.6) is a parameter to the function.
|
||||
if dialect_of!(self is ClickHouseDialect | GenericDialect)
|
||||
&& self.consume_token(&Token::LParen)
|
||||
{
|
||||
parameters = FunctionArguments::List(args);
|
||||
args = self.parse_function_argument_list()?;
|
||||
}
|
||||
|
||||
let within_group = if self.parse_keywords(&[Keyword::WITHIN, Keyword::GROUP]) {
|
||||
self.expect_token(&Token::LParen)?;
|
||||
|
|
@ -1350,6 +1361,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
Ok(Expr::Function(Function {
|
||||
name,
|
||||
parameters,
|
||||
args: FunctionArguments::List(args),
|
||||
null_treatment,
|
||||
filter,
|
||||
|
|
@ -1382,6 +1394,7 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
Ok(Expr::Function(Function {
|
||||
name,
|
||||
parameters: FunctionArguments::None,
|
||||
args,
|
||||
filter: None,
|
||||
over: None,
|
||||
|
|
@ -6470,6 +6483,7 @@ impl<'a> Parser<'a> {
|
|||
} else {
|
||||
Ok(Statement::Call(Function {
|
||||
name: object_name,
|
||||
parameters: FunctionArguments::None,
|
||||
args: FunctionArguments::None,
|
||||
over: None,
|
||||
filter: None,
|
||||
|
|
@ -8092,7 +8106,7 @@ impl<'a> Parser<'a> {
|
|||
pub fn parse_query_body(&mut self, precedence: u8) -> Result<SetExpr, ParserError> {
|
||||
// We parse the expression using a Pratt parser, as in `parse_expr()`.
|
||||
// Start by parsing a restricted SELECT or a `(subquery)`:
|
||||
let mut expr = if self.parse_keyword(Keyword::SELECT) {
|
||||
let expr = if self.parse_keyword(Keyword::SELECT) {
|
||||
SetExpr::Select(self.parse_select().map(Box::new)?)
|
||||
} else if self.consume_token(&Token::LParen) {
|
||||
// CTEs are not allowed here, but the parser currently accepts them
|
||||
|
|
@ -8111,6 +8125,17 @@ impl<'a> Parser<'a> {
|
|||
);
|
||||
};
|
||||
|
||||
self.parse_remaining_set_exprs(expr, precedence)
|
||||
}
|
||||
|
||||
/// Parse any extra set expressions that may be present in a query body
|
||||
///
|
||||
/// (this is its own function to reduce required stack size in debug builds)
|
||||
fn parse_remaining_set_exprs(
|
||||
&mut self,
|
||||
mut expr: SetExpr,
|
||||
precedence: u8,
|
||||
) -> Result<SetExpr, ParserError> {
|
||||
loop {
|
||||
// The query can be optionally followed by a set operator:
|
||||
let op = self.parse_set_operator(&self.peek_token().token);
|
||||
|
|
|
|||
|
|
@ -336,6 +336,7 @@ pub fn join(relation: TableFactor) -> Join {
|
|||
pub fn call(function: &str, args: impl IntoIterator<Item = Expr>) -> Expr {
|
||||
Expr::Function(Function {
|
||||
name: ObjectName(vec![Ident::new(function)]),
|
||||
parameters: FunctionArguments::None,
|
||||
args: FunctionArguments::List(FunctionArgumentList {
|
||||
duplicate_treatment: None,
|
||||
args: args
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue