Skip to content
Open
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
9 changes: 4 additions & 5 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1285,13 +1285,12 @@ pub enum Expr {
/// Struct field definitions.
fields: Vec<StructField>,
},
/// `BigQuery` specific: An named expression in a typeless struct [1]
/// A named expression: `1 AS A`. Used in `BigQuery` typeless structs [1]
/// and in aliased function arguments, e.g. `XMLFOREST(a AS x)` in
/// PostgreSQL [2].
///
/// Syntax
/// ```sql
/// 1 AS A
/// ```
/// [1]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#struct_type
/// [2]: https://www.postgresql.org/docs/current/functions-xml.html#FUNCTIONS-PRODUCING-XML-XMLFOREST
Named {
/// The expression being named.
expr: Box<Expr>,
Expand Down
4 changes: 4 additions & 0 deletions src/dialect/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,4 +312,8 @@ impl Dialect for GenericDialect {
fn supports_xml_expressions(&self) -> bool {
true
}

fn supports_aliased_function_args(&self) -> bool {
true
}
}
6 changes: 6 additions & 0 deletions src/dialect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1767,6 +1767,12 @@ pub trait Dialect: Debug + Any {
false
}

/// Returns true if the dialect supports aliased function arguments,
/// e.g. `XMLFOREST(a AS x)` in PostgreSQL.
fn supports_aliased_function_args(&self) -> bool {
false
}

/// Returns true if the dialect supports `USING <format>` in `CREATE TABLE`.
///
/// Example:
Expand Down
4 changes: 4 additions & 0 deletions src/dialect/postgresql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,10 @@ impl Dialect for PostgreSqlDialect {
true
}

fn supports_aliased_function_args(&self) -> bool {
true
}

/// Postgres supports query optimizer hints via the `pg_hint_plan` extension,
/// using the same comment-prefixed-with-`+` syntax as MySQL and Oracle.
///
Expand Down
13 changes: 13 additions & 0 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18496,6 +18496,19 @@ impl<'a> Parser<'a> {
}
other => other.into(),
};
// Aliased argument, e.g. `XMLFOREST(a AS x)` in PostgreSQL
let arg_expr = match arg_expr {
FunctionArgExpr::Expr(expr)
if self.dialect.supports_aliased_function_args()
&& self.parse_keyword(Keyword::AS) =>
{
FunctionArgExpr::Expr(Expr::Named {
expr: expr.into(),
name: self.parse_identifier()?,
})
}
other => other,
};
Ok(FunctionArg::Unnamed(arg_expr))
}

Expand Down
14 changes: 14 additions & 0 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19000,6 +19000,20 @@ fn parse_non_pg_dialects_keep_xml_names_as_regular_identifiers() {
dialects.verified_only_select("SELECT xml FROM t");
}

#[test]
fn parse_aliased_function_args() {
let dialects = all_dialects_where(|d| d.supports_aliased_function_args());
dialects.verified_only_select("SELECT foo(a AS x, b)");
dialects.verified_only_select("SELECT foo('bar' AS x)");
dialects.verified_only_select("SELECT foo(1 + 2 AS x)");
dialects.verified_only_select("SELECT foo(lower(a) AS x, b AS y)");
dialects.verified_only_select(r#"SELECT foo(a AS "x y")"#);
dialects.verified_only_select("SELECT foo(bar(a AS x) AS y)");
assert!(all_dialects_except(|d| d.supports_aliased_function_args())
.parse_sql_statements("SELECT foo(a AS x)")
.is_err());
}

/// Regression test for the 2^N parse-time blowup in `parse_compound_expr` on
/// inputs like `IF a0.a1...aN.#`. The parse is run on a worker thread and the
/// main thread asserts that it reports back within a generous timeout. Post-fix
Expand Down
18 changes: 18 additions & 0 deletions tests/sqlparser_postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3933,6 +3933,24 @@ fn parse_on_commit() {
pg_and_generic().verified_stmt("CREATE TEMPORARY TABLE table (COL INT) ON COMMIT DROP");
}

#[test]
fn parse_xmlforest_aliased_arguments() {
let select = pg_and_generic().verified_only_select("SELECT XMLFOREST(a AS x, b)");
assert_eq!(
expr_from_projection(&select.projection[0]),
&call(
"XMLFOREST",
[
Expr::Named {
expr: Expr::Identifier(Ident::new("a")).into(),
name: Ident::new("x"),
},
Expr::Identifier(Ident::new("b")),
]
)
);
}

#[test]
fn parse_xml_typed_string() {
// xml '...' should parse as a TypedString on PostgreSQL and Generic
Expand Down
Loading