Skip to content

Commit c1a6255

Browse files
committed
add support for xml namespaces
1 parent 6c11bb9 commit c1a6255

File tree

5 files changed

+56
-4
lines changed

5 files changed

+56
-4
lines changed

src/ast/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ pub use self::query::{
8181
TableSampleBucket, TableSampleKind, TableSampleMethod, TableSampleModifier,
8282
TableSampleQuantity, TableSampleSeed, TableSampleSeedModifier, TableSampleUnit, TableVersion,
8383
TableWithJoins, Top, TopQuantity, UpdateTableFromKind, ValueTableMode, Values,
84-
WildcardAdditionalOptions, With, WithFill, XmlPassingArgument, XmlPassingClause,
85-
XmlTableColumn, XmlTableColumnOption,
84+
WildcardAdditionalOptions, With, WithFill, XmlNamespaceDefinition, XmlPassingArgument,
85+
XmlPassingClause, XmlTableColumn, XmlTableColumnOption,
8686
};
8787

8888
pub use self::trigger::{

src/ast/query.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,7 +1291,8 @@ pub enum TableFactor {
12911291
/// );
12921292
/// ````
12931293
XmlTable {
1294-
// TODO: Add XMLNAMESPACES clause support
1294+
/// Optional XMLNAMESPACES clause (empty if not present)
1295+
namespaces: Vec<XmlNamespaceDefinition>,
12951296
/// The row-generating XPath expression.
12961297
row_expression: Expr,
12971298
/// The PASSING clause specifying the document expression.
@@ -1971,10 +1972,19 @@ impl fmt::Display for TableFactor {
19711972
passing,
19721973
columns,
19731974
alias,
1975+
namespaces,
19741976
} => {
1977+
write!(f, "XMLTABLE(")?;
1978+
if !namespaces.is_empty() {
1979+
write!(
1980+
f,
1981+
"XMLNAMESPACES({}), ",
1982+
display_comma_separated(namespaces)
1983+
)?;
1984+
}
19751985
write!(
19761986
f,
1977-
"XMLTABLE({row_expression}{passing} COLUMNS {columns})",
1987+
"{row_expression}{passing} COLUMNS {columns})",
19781988
columns = display_comma_separated(columns)
19791989
)?;
19801990
if let Some(alias) = alias {
@@ -3239,3 +3249,22 @@ impl fmt::Display for XmlPassingClause {
32393249
Ok(())
32403250
}
32413251
}
3252+
3253+
/// Represents a single XML namespace definition in the XMLNAMESPACES clause.
3254+
///
3255+
/// `namespace_uri AS namespace_name`
3256+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3257+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3258+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3259+
pub struct XmlNamespaceDefinition {
3260+
/// The namespace URI (a text expression).
3261+
pub uri: Expr,
3262+
/// The alias for the namespace (a simple identifier).
3263+
pub name: Ident,
3264+
}
3265+
3266+
impl fmt::Display for XmlNamespaceDefinition {
3267+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3268+
write!(f, "{} AS {}", self.uri, self.name)
3269+
}
3270+
}

src/keywords.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,7 @@ define_keywords!(
990990
WORK,
991991
WRITE,
992992
XML,
993+
XMLNAMESPACES,
993994
XMLTABLE,
994995
XOR,
995996
YEAR,

src/parser/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12345,20 +12345,37 @@ impl<'a> Parser<'a> {
1234512345

1234612346
fn parse_xml_table_factor(&mut self) -> Result<TableFactor, ParserError> {
1234712347
self.expect_token(&Token::LParen)?;
12348+
let namespaces = if self.parse_keyword(Keyword::XMLNAMESPACES) {
12349+
self.expect_token(&Token::LParen)?;
12350+
let namespaces = self.parse_comma_separated(Parser::parse_xml_namespace_definition)?;
12351+
self.expect_token(&Token::RParen)?;
12352+
self.expect_token(&Token::Comma)?;
12353+
namespaces
12354+
} else {
12355+
vec![]
12356+
};
1234812357
let row_expression = self.parse_expr()?;
1234912358
let passing = self.parse_xml_passing_clause()?;
1235012359
self.expect_keyword_is(Keyword::COLUMNS)?;
1235112360
let columns = self.parse_comma_separated(Parser::parse_xml_table_column)?;
1235212361
self.expect_token(&Token::RParen)?;
1235312362
let alias = self.maybe_parse_table_alias()?;
1235412363
Ok(TableFactor::XmlTable {
12364+
namespaces,
1235512365
row_expression,
1235612366
passing,
1235712367
columns,
1235812368
alias,
1235912369
})
1236012370
}
1236112371

12372+
fn parse_xml_namespace_definition(&mut self) -> Result<XmlNamespaceDefinition, ParserError> {
12373+
let uri = self.parse_expr()?;
12374+
self.expect_keyword_is(Keyword::AS)?;
12375+
let name = self.parse_identifier()?;
12376+
Ok(XmlNamespaceDefinition { uri, name })
12377+
}
12378+
1236212379
fn parse_xml_table_column(&mut self) -> Result<XmlTableColumn, ParserError> {
1236312380
let name = self.parse_identifier()?;
1236412381

tests/sqlparser_common.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11760,6 +11760,11 @@ fn test_xmltable() {
1176011760
all_dialects().verified_only_select(
1176111761
"SELECT X.* FROM T1, XMLTABLE('$CUSTLIST/customers/customerinfo' COLUMNS \"Cid\" BIGINT PATH '@Cid', \"Info\" XML PATH 'document{.}', \"History\" XML PATH 'NULL') AS X"
1176211762
);
11763+
11764+
// Example from PostgreSQL with XMLNAMESPACES
11765+
all_dialects().verified_only_select(
11766+
"SELECT xmltable.* FROM XMLTABLE(XMLNAMESPACES('http://example.com/myns' AS x, 'http://example.com/b' AS \"B\"), '/x:example/x:item' PASSING (SELECT data FROM xmldata) COLUMNS foo INT PATH '@foo', bar INT PATH '@B:bar')"
11767+
);
1176311768
}
1176411769

1176511770
#[test]

0 commit comments

Comments
 (0)