Consolidate representation of function calls, remove AggregateExpressionWithFilter, ArraySubquery, ListAgg and ArrayAgg (#1247)

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
Joey Hain 2024-05-03 11:46:03 -07:00 committed by GitHub
parent 5ea9c01bb2
commit a14faa36bb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 773 additions and 1040 deletions

View file

@ -1042,13 +1042,15 @@ fn parse_select_count_wildcard() {
assert_eq!(
&Expr::Function(Function {
name: ObjectName(vec![Ident::new("COUNT")]),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Wildcard)],
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: None,
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Wildcard)],
clauses: vec![],
}),
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
within_group: vec![]
}),
expr_from_projection(only(&select.projection))
);
@ -1061,24 +1063,24 @@ fn parse_select_count_distinct() {
assert_eq!(
&Expr::Function(Function {
name: ObjectName(vec![Ident::new("COUNT")]),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::UnaryOp {
op: UnaryOperator::Plus,
expr: Box::new(Expr::Identifier(Ident::new("x"))),
}))],
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: Some(DuplicateTreatment::Distinct),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::UnaryOp {
op: UnaryOperator::Plus,
expr: Box::new(Expr::Identifier(Ident::new("x"))),
}))],
clauses: vec![],
}),
null_treatment: None,
within_group: vec![],
filter: None,
over: None,
distinct: true,
special: false,
order_by: vec![],
over: None
}),
expr_from_projection(only(&select.projection))
);
one_statement_parses_to(
"SELECT COUNT(ALL +x) FROM customer",
"SELECT COUNT(+x) FROM customer",
);
verified_stmt("SELECT COUNT(ALL +x) FROM customer");
verified_stmt("SELECT COUNT(+x) FROM customer");
let sql = "SELECT COUNT(ALL DISTINCT + x) FROM customer";
let res = parse_sql_statements(sql);
@ -2142,13 +2144,15 @@ fn parse_select_having() {
Some(Expr::BinaryOp {
left: Box::new(Expr::Function(Function {
name: ObjectName(vec![Ident::new("COUNT")]),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Wildcard)],
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: None,
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Wildcard)],
clauses: vec![],
}),
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
within_group: vec![]
})),
op: BinaryOperator::Gt,
right: Box::new(Expr::Value(number("1"))),
@ -2169,7 +2173,11 @@ fn parse_select_qualify() {
Some(Expr::BinaryOp {
left: Box::new(Expr::Function(Function {
name: ObjectName(vec![Ident::new("ROW_NUMBER")]),
args: vec![],
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: None,
args: vec![],
clauses: vec![],
}),
null_treatment: None,
filter: None,
over: Some(WindowType::WindowSpec(WindowSpec {
@ -2182,9 +2190,7 @@ fn parse_select_qualify() {
}],
window_frame: None,
})),
distinct: false,
special: false,
order_by: vec![],
within_group: vec![]
})),
op: BinaryOperator::Eq,
right: Box::new(Expr::Value(number("1"))),
@ -2502,9 +2508,57 @@ fn parse_floor_datetime() {
#[test]
fn parse_listagg() {
let sql = "SELECT LISTAGG(DISTINCT dateid, ', ' ON OVERFLOW TRUNCATE '%' WITHOUT COUNT) \
WITHIN GROUP (ORDER BY id, username)";
let select = verified_only_select(sql);
let select = verified_only_select(concat!(
"SELECT LISTAGG(DISTINCT dateid, ', ' ON OVERFLOW TRUNCATE '%' WITHOUT COUNT) ",
"WITHIN GROUP (ORDER BY id, username)",
));
assert_eq!(
&Expr::Function(Function {
name: ObjectName(vec![Ident::new("LISTAGG")]),
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: Some(DuplicateTreatment::Distinct),
args: vec![
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Identifier(Ident::new(
"dateid"
)))),
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
Value::SingleQuotedString(", ".to_owned())
)))
],
clauses: vec![FunctionArgumentClause::OnOverflow(
ListAggOnOverflow::Truncate {
filler: Some(Box::new(Expr::Value(Value::SingleQuotedString(
"%".to_string(),
)))),
with_count: false,
}
)],
}),
filter: None,
null_treatment: None,
over: None,
within_group: vec![
OrderByExpr {
expr: Expr::Identifier(Ident {
value: "id".to_string(),
quote_style: None,
}),
asc: None,
nulls_first: None,
},
OrderByExpr {
expr: Expr::Identifier(Ident {
value: "username".to_string(),
quote_style: None,
}),
asc: None,
nulls_first: None,
},
]
}),
expr_from_projection(only(&select.projection))
);
verified_stmt("SELECT LISTAGG(sellerid) WITHIN GROUP (ORDER BY dateid)");
verified_stmt("SELECT LISTAGG(dateid)");
@ -2512,44 +2566,6 @@ fn parse_listagg() {
verified_stmt("SELECT LISTAGG(dateid ON OVERFLOW ERROR)");
verified_stmt("SELECT LISTAGG(dateid ON OVERFLOW TRUNCATE N'...' WITH COUNT)");
verified_stmt("SELECT LISTAGG(dateid ON OVERFLOW TRUNCATE X'deadbeef' WITH COUNT)");
let expr = Box::new(Expr::Identifier(Ident::new("dateid")));
let on_overflow = Some(ListAggOnOverflow::Truncate {
filler: Some(Box::new(Expr::Value(Value::SingleQuotedString(
"%".to_string(),
)))),
with_count: false,
});
let within_group = vec![
OrderByExpr {
expr: Expr::Identifier(Ident {
value: "id".to_string(),
quote_style: None,
}),
asc: None,
nulls_first: None,
},
OrderByExpr {
expr: Expr::Identifier(Ident {
value: "username".to_string(),
quote_style: None,
}),
asc: None,
nulls_first: None,
},
];
assert_eq!(
&Expr::ListAgg(ListAgg {
distinct: true,
expr,
separator: Some(Box::new(Expr::Value(Value::SingleQuotedString(
", ".to_string()
)))),
on_overflow,
within_group,
}),
expr_from_projection(only(&select.projection))
);
}
#[test]
@ -2575,12 +2591,6 @@ fn parse_array_agg_func() {
] {
supported_dialects.verified_stmt(sql);
}
// follows special-case array_agg code path. fails in everything except postgres
let wc_sql = "SELECT ARRAY_AGG(sections_tbl.*) AS sections FROM sections_tbl";
all_dialects_but_pg()
.parse_sql_statements(wc_sql)
.expect_err("should have failed");
}
#[test]
@ -2664,24 +2674,31 @@ fn parse_window_function_null_treatment_arg() {
unreachable!()
};
assert_eq!(ObjectName(vec![Ident::new("FIRST_VALUE")]), actual.name);
assert!(actual.order_by.is_empty());
assert_eq!(1, actual.args.len());
let FunctionArguments::List(arg_list) = &actual.args else {
panic!("expected argument list")
};
assert!({
arg_list
.clauses
.iter()
.all(|clause| !matches!(clause, FunctionArgumentClause::OrderBy(_)))
});
assert_eq!(1, arg_list.args.len());
let FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Identifier(actual_expr))) =
&actual.args[0]
&arg_list.args[0]
else {
unreachable!()
};
assert_eq!(&Ident::new(expected_expr), actual_expr);
let Some(NullTreatmentType::FunctionArg(actual_null_treatment)) = actual.null_treatment
else {
unreachable!()
};
assert_eq!(expected_null_treatment, actual_null_treatment);
assert_eq!(
Some(expected_null_treatment),
arg_list.clauses.iter().find_map(|clause| match clause {
FunctionArgumentClause::IgnoreOrRespectNulls(nt) => Some(*nt),
_ => None,
})
);
}
let sql = "SELECT FIRST_VALUE(a ORDER BY b IGNORE NULLS) OVER () FROM t1";
dialects.verified_stmt(sql);
let sql = "SELECT LAG(1 IGNORE NULLS) IGNORE NULLS OVER () FROM t1";
assert_eq!(
dialects.parse_sql_statements(sql).unwrap_err(),
@ -4074,18 +4091,7 @@ fn parse_scalar_function_in_projection() {
let sql = dbg!(format!("SELECT {function_name}(id) FROM foo"));
let select = verified_only_select(&sql);
assert_eq!(
&Expr::Function(Function {
name: ObjectName(vec![Ident::new(function_name)]),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
Expr::Identifier(Ident::new("id"))
))],
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
}),
&call(function_name, [Expr::Identifier(Ident::new("id"))]),
expr_from_projection(only(&select.projection))
);
}
@ -4199,28 +4205,30 @@ fn parse_named_argument_function() {
assert_eq!(
&Expr::Function(Function {
name: ObjectName(vec![Ident::new("FUN")]),
args: vec![
FunctionArg::Named {
name: Ident::new("a"),
arg: FunctionArgExpr::Expr(Expr::Value(Value::SingleQuotedString(
"1".to_owned()
))),
operator: FunctionArgOperator::RightArrow
},
FunctionArg::Named {
name: Ident::new("b"),
arg: FunctionArgExpr::Expr(Expr::Value(Value::SingleQuotedString(
"2".to_owned()
))),
operator: FunctionArgOperator::RightArrow
},
],
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: None,
args: vec![
FunctionArg::Named {
name: Ident::new("a"),
arg: FunctionArgExpr::Expr(Expr::Value(Value::SingleQuotedString(
"1".to_owned()
))),
operator: FunctionArgOperator::RightArrow
},
FunctionArg::Named {
name: Ident::new("b"),
arg: FunctionArgExpr::Expr(Expr::Value(Value::SingleQuotedString(
"2".to_owned()
))),
operator: FunctionArgOperator::RightArrow
},
],
clauses: vec![],
}),
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
within_group: vec![]
}),
expr_from_projection(only(&select.projection))
);
@ -4235,28 +4243,30 @@ fn parse_named_argument_function_with_eq_operator() {
assert_eq!(
&Expr::Function(Function {
name: ObjectName(vec![Ident::new("FUN")]),
args: vec![
FunctionArg::Named {
name: Ident::new("a"),
arg: FunctionArgExpr::Expr(Expr::Value(Value::SingleQuotedString(
"1".to_owned()
))),
operator: FunctionArgOperator::Equals
},
FunctionArg::Named {
name: Ident::new("b"),
arg: FunctionArgExpr::Expr(Expr::Value(Value::SingleQuotedString(
"2".to_owned()
))),
operator: FunctionArgOperator::Equals
},
],
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: None,
args: vec![
FunctionArg::Named {
name: Ident::new("a"),
arg: FunctionArgExpr::Expr(Expr::Value(Value::SingleQuotedString(
"1".to_owned()
))),
operator: FunctionArgOperator::Equals
},
FunctionArg::Named {
name: Ident::new("b"),
arg: FunctionArgExpr::Expr(Expr::Value(Value::SingleQuotedString(
"2".to_owned()
))),
operator: FunctionArgOperator::Equals
},
],
clauses: vec![],
}),
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
within_group: vec![],
}),
expr_from_projection(only(&select.projection))
);
@ -4266,22 +4276,14 @@ fn parse_named_argument_function_with_eq_operator() {
assert_eq!(
all_dialects_except(|d| d.supports_named_fn_args_with_eq_operator())
.verified_expr("foo(bar = 42)"),
Expr::Function(Function {
name: ObjectName(vec![Ident::new("foo")]),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("bar"))),
op: BinaryOperator::Eq,
right: Box::new(Expr::Value(number("42"))),
},
))],
filter: None,
null_treatment: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
})
call(
"foo",
[Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("bar"))),
op: BinaryOperator::Eq,
right: Box::new(Expr::Value(number("42"))),
}]
),
);
// TODO: should this parse for all dialects?
@ -4313,7 +4315,11 @@ fn parse_window_functions() {
assert_eq!(
&Expr::Function(Function {
name: ObjectName(vec![Ident::new("row_number")]),
args: vec![],
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: None,
args: vec![],
clauses: vec![],
}),
null_treatment: None,
filter: None,
over: Some(WindowType::WindowSpec(WindowSpec {
@ -4326,9 +4332,7 @@ fn parse_window_functions() {
}],
window_frame: None,
})),
distinct: false,
special: false,
order_by: vec![],
within_group: vec![],
}),
expr_from_projection(&select.projection[0])
);
@ -4439,21 +4443,23 @@ fn test_parse_named_window() {
value: "MIN".to_string(),
quote_style: None,
}]),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
Expr::Identifier(Ident {
value: "c12".to_string(),
quote_style: None,
}),
))],
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: None,
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
Expr::Identifier(Ident {
value: "c12".to_string(),
quote_style: None,
}),
))],
clauses: vec![],
}),
null_treatment: None,
filter: None,
over: Some(WindowType::NamedWindow(Ident {
value: "window1".to_string(),
quote_style: None,
})),
distinct: false,
special: false,
order_by: vec![],
within_group: vec![],
}),
alias: Ident {
value: "min1".to_string(),
@ -4466,21 +4472,23 @@ fn test_parse_named_window() {
value: "MAX".to_string(),
quote_style: None,
}]),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
Expr::Identifier(Ident {
value: "c12".to_string(),
quote_style: None,
}),
))],
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: None,
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
Expr::Identifier(Ident {
value: "c12".to_string(),
quote_style: None,
}),
))],
clauses: vec![],
}),
null_treatment: None,
filter: None,
over: Some(WindowType::NamedWindow(Ident {
value: "window2".to_string(),
quote_style: None,
})),
distinct: false,
special: false,
order_by: vec![],
within_group: vec![],
}),
alias: Ident {
value: "max1".to_string(),
@ -4982,19 +4990,7 @@ fn parse_at_timezone() {
let select = verified_only_select(sql);
assert_eq!(
&Expr::AtTimeZone {
timestamp: Box::new(Expr::Function(Function {
name: ObjectName(vec![Ident {
value: "FROM_UNIXTIME".to_string(),
quote_style: None,
}]),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(zero.clone()))],
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
})),
timestamp: Box::new(call("FROM_UNIXTIME", [zero.clone()])),
time_zone: "UTC-06:00".to_string(),
},
expr_from_projection(only(&select.projection)),
@ -5004,39 +5000,16 @@ fn parse_at_timezone() {
let select = verified_only_select(sql);
assert_eq!(
&SelectItem::ExprWithAlias {
expr: Expr::Function(Function {
name: ObjectName(vec![Ident {
value: "DATE_FORMAT".to_string(),
quote_style: None,
},],),
args: vec![
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::AtTimeZone {
timestamp: Box::new(Expr::Function(Function {
name: ObjectName(vec![Ident {
value: "FROM_UNIXTIME".to_string(),
quote_style: None,
},],),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(zero))],
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
},)),
expr: call(
"DATE_FORMAT",
[
Expr::AtTimeZone {
timestamp: Box::new(call("FROM_UNIXTIME", [zero])),
time_zone: "UTC-06:00".to_string(),
},),),
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
Value::SingleQuotedString("%Y-%m-%dT%H".to_string()),
),),),
],
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
},),
},
Expr::Value(Value::SingleQuotedString("%Y-%m-%dT%H".to_string()),)
]
),
alias: Ident {
value: "hour".to_string(),
quote_style: Some('"'),
@ -5185,19 +5158,13 @@ fn parse_table_function() {
match only(select.from).relation {
TableFactor::TableFunction { expr, alias } => {
let expected_expr = Expr::Function(Function {
name: ObjectName(vec![Ident::new("FUN")]),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
Value::SingleQuotedString("1".to_owned()),
)))],
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
});
assert_eq!(expr, expected_expr);
assert_eq!(
call(
"FUN",
[Expr::Value(Value::SingleQuotedString("1".to_owned()))],
),
expr
);
assert_eq!(alias, table_alias("a"))
}
_ => panic!("Expecting TableFactor::TableFunction"),
@ -5336,20 +5303,14 @@ fn parse_unnest_in_from_clause() {
vec![TableWithJoins {
relation: TableFactor::UNNEST {
alias: None,
array_exprs: vec![Expr::Function(Function {
name: ObjectName(vec![Ident::new("make_array")]),
args: vec![
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(number("1")))),
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(number("2")))),
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(number("3")))),
array_exprs: vec![call(
"make_array",
[
Expr::Value(number("1")),
Expr::Value(number("2")),
Expr::Value(number("3")),
],
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
})],
)],
with_offset: false,
with_offset_alias: None,
},
@ -5367,33 +5328,18 @@ fn parse_unnest_in_from_clause() {
relation: TableFactor::UNNEST {
alias: None,
array_exprs: vec![
Expr::Function(Function {
name: ObjectName(vec![Ident::new("make_array")]),
args: vec![
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(number("1")))),
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(number("2")))),
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(number("3")))),
call(
"make_array",
[
Expr::Value(number("1")),
Expr::Value(number("2")),
Expr::Value(number("3")),
],
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
}),
Expr::Function(Function {
name: ObjectName(vec![Ident::new("make_array")]),
args: vec![
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(number("5")))),
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(number("6")))),
],
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
}),
),
call(
"make_array",
[Expr::Value(number("5")), Expr::Value(number("6"))],
),
],
with_offset: false,
with_offset_alias: None,
@ -8001,13 +7947,15 @@ fn parse_time_functions() {
let select = verified_only_select(&sql);
let select_localtime_func_call_ast = Function {
name: ObjectName(vec![Ident::new(func_name)]),
args: vec![],
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: None,
args: vec![],
clauses: vec![],
}),
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
within_group: vec![],
};
assert_eq!(
&Expr::Function(select_localtime_func_call_ast.clone()),
@ -8017,7 +7965,7 @@ fn parse_time_functions() {
// Validating Parenthesis
let sql_without_parens = format!("SELECT {}", func_name);
let mut ast_without_parens = select_localtime_func_call_ast;
ast_without_parens.special = true;
ast_without_parens.args = FunctionArguments::None;
assert_eq!(
&Expr::Function(ast_without_parens),
expr_from_projection(&verified_only_select(&sql_without_parens).projection[0])
@ -8556,18 +8504,13 @@ fn parse_pivot_table() {
fn expected_function(table: &'static str, alias: Option<&'static str>) -> ExprWithAlias {
ExprWithAlias {
expr: Expr::Function(Function {
name: ObjectName(vec![Ident::new("SUM")]),
args: (vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
Expr::CompoundIdentifier(vec![Ident::new(table), Ident::new("amount")]),
))]),
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
}),
expr: call(
"SUM",
[Expr::CompoundIdentifier(vec![
Ident::new(table),
Ident::new("amount"),
])],
),
alias: alias.map(Ident::new),
}
}
@ -8739,18 +8682,7 @@ fn parse_pivot_unpivot_table() {
}),
}),
aggregate_functions: vec![ExprWithAlias {
expr: Expr::Function(Function {
name: ObjectName(vec![Ident::new("sum")]),
args: (vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
Expr::Identifier(Ident::new("population"))
))]),
null_treatment: None,
filter: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
}),
expr: call("sum", [Expr::Identifier(Ident::new("population"))]),
alias: None
}],
value_column: vec![Ident::new("year")],
@ -8876,16 +8808,18 @@ fn parse_call() {
assert_eq!(
verified_stmt("CALL my_procedure('a')"),
Statement::Call(Function {
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
Value::SingleQuotedString("a".to_string())
))),],
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: None,
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
Value::SingleQuotedString("a".to_string())
)))],
clauses: vec![],
}),
name: ObjectName(vec![Ident::new("my_procedure")]),
filter: None,
null_treatment: None,
over: None,
distinct: false,
special: false,
order_by: vec![]
within_group: vec![],
})
);
}
@ -9085,18 +9019,7 @@ fn parse_map_access_expr() {
syntax: MapAccessSyntax::Bracket,
},
MapAccessKey {
key: Expr::Function(Function {
name: ObjectName(vec![Ident::new("safe_offset")]),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
number("2"),
)))],
filter: None,
null_treatment: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
}),
key: call("safe_offset", [Expr::Value(number("2"))]),
syntax: MapAccessSyntax::Bracket,
},
],
@ -9284,34 +9207,42 @@ fn test_selective_aggregation() {
.verified_only_select(sql)
.projection,
vec![
SelectItem::UnnamedExpr(Expr::AggregateExpressionWithFilter {
expr: Box::new(Expr::ArrayAgg(ArrayAgg {
distinct: false,
expr: Box::new(Expr::Identifier(Ident::new("name"))),
order_by: None,
limit: None,
within_group: false,
})),
filter: Box::new(Expr::IsNotNull(Box::new(Expr::Identifier(Ident::new(
"name"
SelectItem::UnnamedExpr(Expr::Function(Function {
name: ObjectName(vec![Ident::new("ARRAY_AGG")]),
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: None,
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
Expr::Identifier(Ident::new("name"))
))],
clauses: vec![],
}),
filter: Some(Box::new(Expr::IsNotNull(Box::new(Expr::Identifier(
Ident::new("name")
))))),
}),
over: None,
within_group: vec![],
null_treatment: None
})),
SelectItem::ExprWithAlias {
expr: Expr::AggregateExpressionWithFilter {
expr: Box::new(Expr::ArrayAgg(ArrayAgg {
distinct: false,
expr: Box::new(Expr::Identifier(Ident::new("name"))),
order_by: None,
limit: None,
within_group: false,
})),
filter: Box::new(Expr::Like {
expr: Expr::Function(Function {
name: ObjectName(vec![Ident::new("ARRAY_AGG")]),
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: None,
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
Expr::Identifier(Ident::new("name"))
))],
clauses: vec![],
}),
filter: Some(Box::new(Expr::Like {
negated: false,
expr: Box::new(Expr::Identifier(Ident::new("name"))),
pattern: Box::new(Expr::Value(Value::SingleQuotedString("a%".to_owned()))),
escape_char: None,
}),
},
})),
null_treatment: None,
over: None,
within_group: vec![]
}),
alias: Ident::new("agg2")
},
]
@ -9652,18 +9583,7 @@ fn test_select_wildcard_with_replace() {
let expected = SelectItem::Wildcard(WildcardAdditionalOptions {
opt_replace: Some(ReplaceSelectItem {
items: vec![Box::new(ReplaceSelectElement {
expr: Expr::Function(Function {
name: ObjectName(vec![Ident::new("lower")]),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
Expr::Identifier(Ident::new("city")),
))],
filter: None,
null_treatment: None,
over: None,
distinct: false,
special: false,
order_by: vec![],
}),
expr: call("lower", [Expr::Identifier(Ident::new("city"))]),
column_name: Ident::new("city"),
as_keyword: true,
})],
@ -9799,3 +9719,12 @@ fn test_dictionary_syntax() {
]),
)
}
#[test]
fn parse_within_group() {
verified_expr("PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY sales_amount)");
verified_expr(concat!(
"PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY sales_amount) ",
"OVER (PARTITION BY department)",
));
}