You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by gi...@apache.org on 2026/04/10 13:28:35 UTC
(datafusion-sqlparser-rs) branch gh-readonly-queue/main/pr-2299-2b0dc2d6ebeb35fa8dcc40bee04c073450e0dfe0 created (now 6fa3614f)
This is an automated email from the ASF dual-hosted git repository.
github-bot pushed a change to branch gh-readonly-queue/main/pr-2299-2b0dc2d6ebeb35fa8dcc40bee04c073450e0dfe0
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
at 6fa3614f Add xml '...' TypedString support for PostgreSQL (#2299)
This branch includes the following new commits:
new 6fa3614f Add xml '...' TypedString support for PostgreSQL (#2299)
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org
(datafusion-sqlparser-rs) 01/01: Add xml '...' TypedString support for PostgreSQL (#2299)
Posted by gi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
github-bot pushed a commit to branch gh-readonly-queue/main/pr-2299-2b0dc2d6ebeb35fa8dcc40bee04c073450e0dfe0
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
commit 6fa3614fac42f75915e9d7d936583af5c99d8b26
Author: Luca Cappelletti <ca...@gmail.com>
AuthorDate: Fri Apr 10 15:28:10 2026 +0200
Add xml '...' TypedString support for PostgreSQL (#2299)
Co-authored-by: Donovan Schönknecht <do...@tpyo.net>
Co-authored-by: Minjun Kim <48...@users.noreply.github.com>
---
src/dialect/generic.rs | 4 ++++
src/dialect/mod.rs | 11 +++++++++++
src/dialect/postgresql.rs | 4 ++++
src/parser/mod.rs | 26 +++++++++++++++++++++++++-
tests/sqlparser_common.rs | 8 ++++++++
tests/sqlparser_postgres.rs | 19 +++++++++++++++++++
6 files changed, 71 insertions(+), 1 deletion(-)
diff --git a/src/dialect/generic.rs b/src/dialect/generic.rs
index c8f5ce66..674311a9 100644
--- a/src/dialect/generic.rs
+++ b/src/dialect/generic.rs
@@ -300,4 +300,8 @@ impl Dialect for GenericDialect {
fn supports_select_item_multi_column_alias(&self) -> bool {
true
}
+
+ fn supports_xml_expressions(&self) -> bool {
+ true
+ }
}
diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs
index 1a2b9b19..8dae15be 100644
--- a/src/dialect/mod.rs
+++ b/src/dialect/mod.rs
@@ -1702,6 +1702,17 @@ pub trait Dialect: Debug + Any {
fn supports_select_item_multi_column_alias(&self) -> bool {
false
}
+
+ /// Returns true if the dialect supports XML-related expressions
+ /// such as `xml '<foo/>'` typed strings, XML functions like
+ /// `XMLCONCAT`, `XMLELEMENT`, etc.
+ ///
+ /// When this returns false, `xml` is treated as a regular identifier.
+ ///
+ /// [PostgreSQL](https://www.postgresql.org/docs/current/functions-xml.html)
+ fn supports_xml_expressions(&self) -> bool {
+ false
+ }
}
/// Operators for which precedence must be defined.
diff --git a/src/dialect/postgresql.rs b/src/dialect/postgresql.rs
index b99a8b5c..982dc364 100644
--- a/src/dialect/postgresql.rs
+++ b/src/dialect/postgresql.rs
@@ -310,4 +310,8 @@ impl Dialect for PostgreSqlDialect {
fn supports_comma_separated_trim(&self) -> bool {
true
}
+
+ fn supports_xml_expressions(&self) -> bool {
+ true
+ }
}
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index aeac6186..7e29bfa5 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -1687,6 +1687,16 @@ impl<'a> Parser<'a> {
}
}
+ /// Returns true if the given [ObjectName] is a single unquoted
+ /// identifier matching `expected` (case-insensitive).
+ fn is_simple_unquoted_object_name(name: &ObjectName, expected: &str) -> bool {
+ if let [ObjectNamePart::Identifier(ident)] = name.0.as_slice() {
+ ident.quote_style.is_none() && ident.value.eq_ignore_ascii_case(expected)
+ } else {
+ false
+ }
+ }
+
/// Parse an expression prefix.
pub fn parse_prefix(&mut self) -> Result<Expr, ParserError> {
// allow the dialect to override prefix parsing
@@ -1720,7 +1730,21 @@ impl<'a> Parser<'a> {
// so given `NOT 'a' LIKE 'b'`, we'd accept `NOT` as a possible custom data type
// name, resulting in `NOT 'a'` being recognized as a `TypedString` instead of
// an unary negation `NOT ('a' LIKE 'b')`. To solve this, we don't accept the
- // `type 'string'` syntax for the custom data types at all.
+ // `type 'string'` syntax for the custom data types at all ...
+ //
+ // ... with the exception of `xml '...'` on dialects that support XML
+ // expressions, which is a valid PostgreSQL typed string literal.
+ DataType::Custom(ref name, ref modifiers)
+ if modifiers.is_empty()
+ && Self::is_simple_unquoted_object_name(name, "xml")
+ && parser.dialect.supports_xml_expressions() =>
+ {
+ Ok(Expr::TypedString(TypedString {
+ data_type: DataType::Custom(name.clone(), modifiers.clone()),
+ value: parser.parse_value()?,
+ uses_odbc_syntax: false,
+ }))
+ }
DataType::Custom(..) => parser_err!("dummy", loc),
// MySQL supports using the `BINARY` keyword as a cast to binary type.
DataType::Binary(..) if self.dialect.supports_binary_kw_as_cast() => {
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index f5add3a6..4db5edeb 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -18771,3 +18771,11 @@ fn parse_select_item_multi_column_alias() {
.is_err()
);
}
+
+#[test]
+fn parse_non_pg_dialects_keep_xml_names_as_regular_identifiers() {
+ // On dialects that do NOT support XML expressions, bare `xml` should
+ // be treated as a regular column identifier, not a typed-string prefix.
+ let dialects = all_dialects_except(|d| d.supports_xml_expressions());
+ dialects.verified_only_select("SELECT xml FROM t");
+}
diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs
index f39cbc2d..67850987 100644
--- a/tests/sqlparser_postgres.rs
+++ b/tests/sqlparser_postgres.rs
@@ -3750,6 +3750,25 @@ fn parse_on_commit() {
pg_and_generic().verified_stmt("CREATE TEMPORARY TABLE table (COL INT) ON COMMIT DROP");
}
+#[test]
+fn parse_xml_typed_string() {
+ // xml '...' should parse as a TypedString on PostgreSQL and Generic
+ let sql = "SELECT xml '<foo/>'";
+ let select = pg_and_generic().verified_only_select(sql);
+ match expr_from_projection(&select.projection[0]) {
+ Expr::TypedString(TypedString {
+ data_type: DataType::Custom(name, modifiers),
+ value,
+ uses_odbc_syntax: false,
+ }) => {
+ assert_eq!(name.to_string(), "xml");
+ assert!(modifiers.is_empty());
+ assert_eq!(value.value, Value::SingleQuotedString("<foo/>".to_string()));
+ }
+ other => panic!("Expected TypedString, got: {other:?}"),
+ }
+}
+
fn pg() -> TestedDialects {
TestedDialects::new(vec![Box::new(PostgreSqlDialect {})])
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org