Skip to content

Commit

Permalink
fix(sqlparser): fix subclause order when parsing function calls (#18130)
Browse files Browse the repository at this point in the history
Signed-off-by: Richard Chien <[email protected]>
  • Loading branch information
stdrc authored Aug 22, 2024
1 parent 4a5bc4c commit c101a30
Show file tree
Hide file tree
Showing 11 changed files with 193 additions and 87 deletions.
32 changes: 16 additions & 16 deletions src/frontend/planner_test/tests/testdata/output/agg.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@
create table t(a int, b int);
select avg(a) FILTER (WHERE abs(a)) AS avga from t;
binder_error: |
Failed to bind expression: avg(a) FILTER(WHERE abs(a))
Failed to bind expression: avg(a) FILTER (WHERE abs(a))
Caused by:
argument of FILTER must be boolean, not type Int32
Expand All @@ -778,7 +778,7 @@
create table t(a int, b int);
select avg(a) FILTER (WHERE 0 < (select max(a) from t)) AS avga from t;
binder_error: |
Failed to bind expression: avg(a) FILTER(WHERE 0 < (SELECT max(a) FROM t))
Failed to bind expression: avg(a) FILTER (WHERE 0 < (SELECT max(a) FROM t))
Caused by:
Feature is not yet implemented: subquery in filter clause
Expand All @@ -788,7 +788,7 @@
create table t(a int, b int);
select avg(a) FILTER (WHERE a < avg(b)) AS avga from t;
binder_error: |
Failed to bind expression: avg(a) FILTER(WHERE a < avg(b))
Failed to bind expression: avg(a) FILTER (WHERE a < avg(b))
Caused by:
Feature is not yet implemented: aggregation function in filter clause
Expand All @@ -798,7 +798,7 @@
create table t(a int, b int);
select abs(a) FILTER (WHERE a > 0) AS avga from t;
binder_error: |
Failed to bind expression: abs(a) FILTER(WHERE a > 0)
Failed to bind expression: abs(a) FILTER (WHERE a > 0)
Caused by:
Invalid input syntax: DISTINCT, ORDER BY or FILTER is only allowed in aggregation functions, but `abs` is not an aggregation function
Expand Down Expand Up @@ -1096,7 +1096,7 @@
create table a (a1 int, a2 int);
select count(a1) filter (where (select true)) from a;
binder_error: |
Failed to bind expression: count(a1) FILTER(WHERE (SELECT true))
Failed to bind expression: count(a1) FILTER (WHERE (SELECT true))
Caused by:
Feature is not yet implemented: subquery in filter clause
Expand All @@ -1110,10 +1110,10 @@
select count(b1) filter (where min(a1) < 3) from b
);
binder_error: |
Failed to bind expression: EXISTS (SELECT count(b1) FILTER(WHERE min(a1) < 3) FROM b)
Failed to bind expression: EXISTS (SELECT count(b1) FILTER (WHERE min(a1) < 3) FROM b)
Caused by these errors (recent errors listed first):
1: Failed to bind expression: count(b1) FILTER(WHERE min(a1) < 3)
1: Failed to bind expression: count(b1) FILTER (WHERE min(a1) < 3)
2: Feature is not yet implemented: aggregation function in filter clause
No tracking issue yet. Feel free to submit a feature request at https://github.com/risingwavelabs/risingwave/issues/new?labels=type%2Ffeature&template=feature_request.yml
- name: agg filter - table function
Expand All @@ -1122,7 +1122,7 @@
create table a (a1 int, a2 int);
select count(a1) filter (where unnest(array[1]) < 1) from a;
binder_error: |
Failed to bind expression: count(a1) FILTER(WHERE unnest(ARRAY[1]) < 1)
Failed to bind expression: count(a1) FILTER (WHERE unnest(ARRAY[1]) < 1)
Caused by:
Invalid input syntax: table functions are not allowed in FILTER
Expand Down Expand Up @@ -1551,7 +1551,7 @@
create table t (x int, y int);
select percentile_cont(x) within group (order by y) from t;
binder_error: |
Failed to bind expression: percentile_cont(x)
Failed to bind expression: percentile_cont(x) WITHIN GROUP (ORDER BY y)
Caused by:
Feature is not yet implemented: variable as direct argument of ordered-set aggregate
Expand All @@ -1560,7 +1560,7 @@
create table t (x int, y int);
select percentile_cont('abc') within group (order by y) from t;
binder_error: |
Failed to bind expression: percentile_cont('abc')
Failed to bind expression: percentile_cont('abc') WITHIN GROUP (ORDER BY y)
Caused by:
Feature is not yet implemented: variable as direct argument of ordered-set aggregate
Expand All @@ -1569,23 +1569,23 @@
create table t (x int, y int);
select percentile_cont(1.3) within group (order by y) from t;
binder_error: |
Failed to bind expression: percentile_cont(1.3)
Failed to bind expression: percentile_cont(1.3) WITHIN GROUP (ORDER BY y)
Caused by:
Invalid input syntax: direct arg in `percentile_cont` must between 0.0 and 1.0
- sql: |
create table t (x int, y int);
select percentile_cont(0, 0) within group (order by y) from t;
binder_error: |
Failed to bind expression: percentile_cont(0, 0)
Failed to bind expression: percentile_cont(0, 0) WITHIN GROUP (ORDER BY y)
Caused by:
Invalid input syntax: invalid direct args or within group argument for `percentile_cont` aggregation
- sql: |
create table t (x int, y varchar);
select percentile_cont(0) within group (order by y) from t;
binder_error: |
Failed to bind expression: percentile_cont(0)
Failed to bind expression: percentile_cont(0) WITHIN GROUP (ORDER BY y)
Caused by:
Invalid input syntax: arg in `percentile_cont` must be castable to float64
Expand Down Expand Up @@ -1625,15 +1625,15 @@
create table t (x int, y int);
select percentile_cont(0.8 + 0.8) within group (order by y) from t;
binder_error: |
Failed to bind expression: percentile_cont(0.8 + 0.8)
Failed to bind expression: percentile_cont(0.8 + 0.8) WITHIN GROUP (ORDER BY y)
Caused by:
Invalid input syntax: direct arg in `percentile_cont` must between 0.0 and 1.0
- sql: |
create table t (x int, y int);
select percentile_cont(0.2 + x) within group (order by y) from t group by x;
binder_error: |
Failed to bind expression: percentile_cont(0.2 + x)
Failed to bind expression: percentile_cont(0.2 + x) WITHIN GROUP (ORDER BY y)
Caused by:
Feature is not yet implemented: variable as direct argument of ordered-set aggregate
Expand All @@ -1656,7 +1656,7 @@
create table t (x int, y varchar);
select mode(1) within group (order by y desc) from t;
binder_error: |
Failed to bind expression: mode(1)
Failed to bind expression: mode(1) WITHIN GROUP (ORDER BY y DESC)
Caused by:
Invalid input syntax: invalid direct args or within group argument for `mode` aggregation
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/planner_test/tests/testdata/output/expr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@
create table t (v1 timestamp with time zone, v2 int);
select sum(v2) filter (where v1 >= now()) as sum_v2 from t;
stream_error: |
Failed to bind expression: sum(v2) FILTER(WHERE v1 >= now())
Failed to bind expression: sum(v2) FILTER (WHERE v1 >= now())
Caused by:
Invalid input syntax: For streaming queries, `NOW()` function is only allowed in `WHERE`, `HAVING`, `ON` and `FROM`. Found in clause: Some(Filter). Please please refer to https://www.risingwave.dev/docs/current/sql-pattern-temporal-filters/ for more information
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
create table t(x int);
select sum(x) filter (where row_number() over () > 1) from t;
binder_error: |
Failed to bind expression: sum(x) FILTER(WHERE row_number() OVER () > 1)
Failed to bind expression: sum(x) FILTER (WHERE row_number() OVER () > 1)
Caused by:
Invalid input syntax: window functions are not allowed in FILTER
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@
sql: |
with a(a1) as (values (array[2]), (null)) select count(*) filter(where unnest(a1) < 3) from a;
binder_error: |
Failed to bind expression: count(*) FILTER(WHERE unnest(a1) < 3)
Failed to bind expression: count(*) FILTER (WHERE unnest(a1) < 3)
Caused by:
Invalid input syntax: table functions are not allowed in FILTER
Expand Down
4 changes: 2 additions & 2 deletions src/frontend/src/binder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -816,8 +816,6 @@ mod tests {
order_by: [],
ignore_nulls: false,
},
over: None,
filter: None,
within_group: Some(
OrderByExpr {
expr: Identifier(
Expand All @@ -830,6 +828,8 @@ mod tests {
nulls_first: None,
},
),
filter: None,
over: None,
},
),
),
Expand Down
25 changes: 17 additions & 8 deletions src/sqlparser/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2567,13 +2567,19 @@ impl FunctionArgList {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Function {
/// Whether the function is prefixed with `aggregate:`
/// Whether the function is prefixed with `AGGREGATE:`
pub scalar_as_agg: bool,
/// Function name.
pub name: ObjectName,
/// Argument list of the function call, i.e. things in `()`.
pub arg_list: FunctionArgList,
pub over: Option<WindowSpec>,
pub filter: Option<Box<Expr>>,
/// `WITHIN GROUP` clause of the function call, for ordered-set aggregate functions.
/// FIXME(rc): why we only support one expression here?
pub within_group: Option<Box<OrderByExpr>>,
/// `FILTER` clause of the function call, for aggregate and window (not supported yet) functions.
pub filter: Option<Box<Expr>>,
/// `OVER` clause of the function call, for window functions.
pub over: Option<WindowSpec>,
}

impl Function {
Expand All @@ -2582,9 +2588,9 @@ impl Function {
scalar_as_agg: false,
name,
arg_list: FunctionArgList::empty(),
over: None,
filter: None,
within_group: None,
filter: None,
over: None,
}
}
}
Expand All @@ -2595,11 +2601,14 @@ impl fmt::Display for Function {
write!(f, "AGGREGATE:")?;
}
write!(f, "{}{}", self.name, self.arg_list)?;
if let Some(o) = &self.over {
write!(f, " OVER ({})", o)?;
if let Some(within_group) = &self.within_group {
write!(f, " WITHIN GROUP (ORDER BY {})", within_group)?;
}
if let Some(filter) = &self.filter {
write!(f, " FILTER(WHERE {})", filter)?;
write!(f, " FILTER (WHERE {})", filter)?;
}
if let Some(o) = &self.over {
write!(f, " OVER ({})", o)?;
}
Ok(())
}
Expand Down
45 changes: 23 additions & 22 deletions src/sqlparser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,27 @@ impl Parser<'_> {
};
let name = self.parse_object_name()?;
let arg_list = self.parse_argument_list()?;

let within_group = if self.parse_keywords(&[Keyword::WITHIN, Keyword::GROUP]) {
self.expect_token(&Token::LParen)?;
self.expect_keywords(&[Keyword::ORDER, Keyword::BY])?;
let order_by = self.parse_order_by_expr()?;
self.expect_token(&Token::RParen)?;
Some(Box::new(order_by.clone()))
} else {
None
};

let filter = if self.parse_keyword(Keyword::FILTER) {
self.expect_token(&Token::LParen)?;
self.expect_keyword(Keyword::WHERE)?;
let filter_expr = self.parse_expr()?;
self.expect_token(&Token::RParen)?;
Some(Box::new(filter_expr))
} else {
None
};

let over = if self.parse_keyword(Keyword::OVER) {
// TODO: support window names (`OVER mywin`) in place of inline specification
self.expect_token(&Token::LParen)?;
Expand Down Expand Up @@ -855,33 +876,13 @@ impl Parser<'_> {
None
};

let filter = if self.parse_keyword(Keyword::FILTER) {
self.expect_token(&Token::LParen)?;
self.expect_keyword(Keyword::WHERE)?;
let filter_expr = self.parse_expr()?;
self.expect_token(&Token::RParen)?;
Some(Box::new(filter_expr))
} else {
None
};

let within_group = if self.parse_keywords(&[Keyword::WITHIN, Keyword::GROUP]) {
self.expect_token(&Token::LParen)?;
self.expect_keywords(&[Keyword::ORDER, Keyword::BY])?;
let order_by = self.parse_order_by_expr()?;
self.expect_token(&Token::RParen)?;
Some(Box::new(order_by.clone()))
} else {
None
};

Ok(Expr::Function(Function {
scalar_as_agg,
name,
arg_list,
over,
filter,
within_group,
filter,
over,
}))
}

Expand Down
Loading

0 comments on commit c101a30

Please sign in to comment.