Skip to content

Commit b31ef53

Browse files
Support aliased function arguments (expr AS name)
1 parent 20b9849 commit b31ef53

7 files changed

Lines changed: 63 additions & 5 deletions

File tree

src/ast/mod.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,13 +1285,12 @@ pub enum Expr {
12851285
/// Struct field definitions.
12861286
fields: Vec<StructField>,
12871287
},
1288-
/// `BigQuery` specific: An named expression in a typeless struct [1]
1288+
/// A named expression: `1 AS A`. Used in `BigQuery` typeless structs [1]
1289+
/// and in aliased function arguments, e.g. `XMLFOREST(a AS x)` in
1290+
/// PostgreSQL [2].
12891291
///
1290-
/// Syntax
1291-
/// ```sql
1292-
/// 1 AS A
1293-
/// ```
12941292
/// [1]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#struct_type
1293+
/// [2]: https://www.postgresql.org/docs/current/functions-xml.html#FUNCTIONS-PRODUCING-XML-XMLFOREST
12951294
Named {
12961295
/// The expression being named.
12971296
expr: Box<Expr>,

src/dialect/generic.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,4 +312,8 @@ impl Dialect for GenericDialect {
312312
fn supports_xml_expressions(&self) -> bool {
313313
true
314314
}
315+
316+
fn supports_aliased_function_args(&self) -> bool {
317+
true
318+
}
315319
}

src/dialect/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1767,6 +1767,12 @@ pub trait Dialect: Debug + Any {
17671767
false
17681768
}
17691769

1770+
/// Returns true if the dialect supports aliased function arguments,
1771+
/// e.g. `XMLFOREST(a AS x)` in PostgreSQL.
1772+
fn supports_aliased_function_args(&self) -> bool {
1773+
false
1774+
}
1775+
17701776
/// Returns true if the dialect supports `USING <format>` in `CREATE TABLE`.
17711777
///
17721778
/// Example:

src/dialect/postgresql.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,10 @@ impl Dialect for PostgreSqlDialect {
323323
true
324324
}
325325

326+
fn supports_aliased_function_args(&self) -> bool {
327+
true
328+
}
329+
326330
/// Postgres supports query optimizer hints via the `pg_hint_plan` extension,
327331
/// using the same comment-prefixed-with-`+` syntax as MySQL and Oracle.
328332
///

src/parser/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18496,6 +18496,19 @@ impl<'a> Parser<'a> {
1849618496
}
1849718497
other => other.into(),
1849818498
};
18499+
// Aliased argument, e.g. `XMLFOREST(a AS x)` in PostgreSQL
18500+
let arg_expr = match arg_expr {
18501+
FunctionArgExpr::Expr(expr)
18502+
if self.dialect.supports_aliased_function_args()
18503+
&& self.parse_keyword(Keyword::AS) =>
18504+
{
18505+
FunctionArgExpr::Expr(Expr::Named {
18506+
expr: expr.into(),
18507+
name: self.parse_identifier()?,
18508+
})
18509+
}
18510+
other => other,
18511+
};
1849918512
Ok(FunctionArg::Unnamed(arg_expr))
1850018513
}
1850118514

tests/sqlparser_common.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19000,6 +19000,20 @@ fn parse_non_pg_dialects_keep_xml_names_as_regular_identifiers() {
1900019000
dialects.verified_only_select("SELECT xml FROM t");
1900119001
}
1900219002

19003+
#[test]
19004+
fn parse_aliased_function_args() {
19005+
let dialects = all_dialects_where(|d| d.supports_aliased_function_args());
19006+
dialects.verified_only_select("SELECT foo(a AS x, b)");
19007+
dialects.verified_only_select("SELECT foo('bar' AS x)");
19008+
dialects.verified_only_select("SELECT foo(1 + 2 AS x)");
19009+
dialects.verified_only_select("SELECT foo(lower(a) AS x, b AS y)");
19010+
dialects.verified_only_select(r#"SELECT foo(a AS "x y")"#);
19011+
dialects.verified_only_select("SELECT foo(bar(a AS x) AS y)");
19012+
assert!(all_dialects_except(|d| d.supports_aliased_function_args())
19013+
.parse_sql_statements("SELECT foo(a AS x)")
19014+
.is_err());
19015+
}
19016+
1900319017
/// Regression test for the 2^N parse-time blowup in `parse_compound_expr` on
1900419018
/// inputs like `IF a0.a1...aN.#`. The parse is run on a worker thread and the
1900519019
/// main thread asserts that it reports back within a generous timeout. Post-fix

tests/sqlparser_postgres.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3933,6 +3933,24 @@ fn parse_on_commit() {
39333933
pg_and_generic().verified_stmt("CREATE TEMPORARY TABLE table (COL INT) ON COMMIT DROP");
39343934
}
39353935

3936+
#[test]
3937+
fn parse_xmlforest_aliased_arguments() {
3938+
let select = pg_and_generic().verified_only_select("SELECT XMLFOREST(a AS x, b)");
3939+
assert_eq!(
3940+
expr_from_projection(&select.projection[0]),
3941+
&call(
3942+
"XMLFOREST",
3943+
[
3944+
Expr::Named {
3945+
expr: Expr::Identifier(Ident::new("a")).into(),
3946+
name: Ident::new("x"),
3947+
},
3948+
Expr::Identifier(Ident::new("b")),
3949+
]
3950+
)
3951+
);
3952+
}
3953+
39363954
#[test]
39373955
fn parse_xml_typed_string() {
39383956
// xml '...' should parse as a TypedString on PostgreSQL and Generic

0 commit comments

Comments
 (0)