@@ -1271,6 +1271,37 @@ pub enum TableFactor {
1271
1271
symbols : Vec < SymbolDefinition > ,
1272
1272
alias : Option < TableAlias > ,
1273
1273
} ,
1274
+ /// The `XMLTABLE` table-valued function.
1275
+ /// Part of the SQL standard, supported by PostgreSQL, Oracle, and DB2.
1276
+ ///
1277
+ /// <https://www.postgresql.org/docs/15/functions-xml.html#FUNCTIONS-XML-PROCESSING>
1278
+ ///
1279
+ /// ```sql
1280
+ /// SELECT xmltable.*
1281
+ /// FROM xmldata,
1282
+ /// XMLTABLE('//ROWS/ROW'
1283
+ /// PASSING data
1284
+ /// COLUMNS id int PATH '@id',
1285
+ /// ordinality FOR ORDINALITY,
1286
+ /// "COUNTRY_NAME" text,
1287
+ /// country_id text PATH 'COUNTRY_ID',
1288
+ /// size_sq_km float PATH 'SIZE[@unit = "sq_km"]',
1289
+ /// size_other text PATH 'concat(SIZE[@unit!="sq_km"], " ", SIZE[@unit!="sq_km"]/@unit)',
1290
+ /// premier_name text PATH 'PREMIER_NAME' DEFAULT 'not specified'
1291
+ /// );
1292
+ /// ````
1293
+ XmlTable {
1294
+ /// Optional XMLNAMESPACES clause (empty if not present)
1295
+ namespaces : Vec < XmlNamespaceDefinition > ,
1296
+ /// The row-generating XPath expression.
1297
+ row_expression : Expr ,
1298
+ /// The PASSING clause specifying the document expression.
1299
+ passing : XmlPassingClause ,
1300
+ /// The columns to be extracted from each generated row.
1301
+ columns : Vec < XmlTableColumn > ,
1302
+ /// The alias for the table.
1303
+ alias : Option < TableAlias > ,
1304
+ } ,
1274
1305
}
1275
1306
1276
1307
/// The table sample modifier options
@@ -1936,6 +1967,31 @@ impl fmt::Display for TableFactor {
1936
1967
}
1937
1968
Ok ( ( ) )
1938
1969
}
1970
+ TableFactor :: XmlTable {
1971
+ row_expression,
1972
+ passing,
1973
+ columns,
1974
+ alias,
1975
+ namespaces,
1976
+ } => {
1977
+ write ! ( f, "XMLTABLE(" ) ?;
1978
+ if !namespaces. is_empty ( ) {
1979
+ write ! (
1980
+ f,
1981
+ "XMLNAMESPACES({}), " ,
1982
+ display_comma_separated( namespaces)
1983
+ ) ?;
1984
+ }
1985
+ write ! (
1986
+ f,
1987
+ "{row_expression}{passing} COLUMNS {columns})" ,
1988
+ columns = display_comma_separated( columns)
1989
+ ) ?;
1990
+ if let Some ( alias) = alias {
1991
+ write ! ( f, " AS {alias}" ) ?;
1992
+ }
1993
+ Ok ( ( ) )
1994
+ }
1939
1995
}
1940
1996
}
1941
1997
}
@@ -3082,3 +3138,133 @@ pub enum UpdateTableFromKind {
3082
3138
/// For Example: `UPDATE SET t1.name='aaa' FROM t1`
3083
3139
AfterSet ( Vec < TableWithJoins > ) ,
3084
3140
}
3141
+
3142
+ /// Defines the options for an XmlTable column: Named or ForOrdinality
3143
+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
3144
+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
3145
+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
3146
+ pub enum XmlTableColumnOption {
3147
+ /// A named column with a type, optional path, and default value.
3148
+ NamedInfo {
3149
+ /// The type of the column to be extracted.
3150
+ r#type : DataType ,
3151
+ /// The path to the column to be extracted. If None, defaults to the column name.
3152
+ path : Option < Expr > ,
3153
+ /// Default value if path does not match
3154
+ default : Option < Expr > ,
3155
+ /// Whether the column is nullable (NULL=true, NOT NULL=false)
3156
+ nullable : bool ,
3157
+ } ,
3158
+ /// The FOR ORDINALITY marker
3159
+ ForOrdinality ,
3160
+ }
3161
+
3162
+ /// A single column definition in XMLTABLE
3163
+ ///
3164
+ /// ```sql
3165
+ /// COLUMNS
3166
+ /// id int PATH '@id',
3167
+ /// ordinality FOR ORDINALITY,
3168
+ /// "COUNTRY_NAME" text,
3169
+ /// country_id text PATH 'COUNTRY_ID',
3170
+ /// size_sq_km float PATH 'SIZE[@unit = "sq_km"]',
3171
+ /// size_other text PATH 'concat(SIZE[@unit!="sq_km"], " ", SIZE[@unit!="sq_km"]/@unit)',
3172
+ /// premier_name text PATH 'PREMIER_NAME' DEFAULT 'not specified'
3173
+ /// ```
3174
+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
3175
+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
3176
+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
3177
+ pub struct XmlTableColumn {
3178
+ /// The name of the column.
3179
+ pub name : Ident ,
3180
+ /// Column options: type/path/default or FOR ORDINALITY
3181
+ pub option : XmlTableColumnOption ,
3182
+ }
3183
+
3184
+ impl fmt:: Display for XmlTableColumn {
3185
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
3186
+ write ! ( f, "{}" , self . name) ?;
3187
+ match & self . option {
3188
+ XmlTableColumnOption :: NamedInfo {
3189
+ r#type,
3190
+ path,
3191
+ default,
3192
+ nullable,
3193
+ } => {
3194
+ write ! ( f, " {}" , r#type) ?;
3195
+ if let Some ( p) = path {
3196
+ write ! ( f, " PATH {}" , p) ?;
3197
+ }
3198
+ if let Some ( d) = default {
3199
+ write ! ( f, " DEFAULT {}" , d) ?;
3200
+ }
3201
+ if !* nullable {
3202
+ write ! ( f, " NOT NULL" ) ?;
3203
+ }
3204
+ Ok ( ( ) )
3205
+ }
3206
+ XmlTableColumnOption :: ForOrdinality => {
3207
+ write ! ( f, " FOR ORDINALITY" )
3208
+ }
3209
+ }
3210
+ }
3211
+ }
3212
+
3213
+ /// Argument passed in the XMLTABLE PASSING clause
3214
+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
3215
+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
3216
+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
3217
+ pub struct XmlPassingArgument {
3218
+ pub expr : Expr ,
3219
+ pub alias : Option < Ident > ,
3220
+ pub by_value : bool , // True if BY VALUE is specified
3221
+ }
3222
+
3223
+ impl fmt:: Display for XmlPassingArgument {
3224
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
3225
+ if self . by_value {
3226
+ write ! ( f, "BY VALUE " ) ?;
3227
+ }
3228
+ write ! ( f, "{}" , self . expr) ?;
3229
+ if let Some ( alias) = & self . alias {
3230
+ write ! ( f, " AS {}" , alias) ?;
3231
+ }
3232
+ Ok ( ( ) )
3233
+ }
3234
+ }
3235
+
3236
+ /// The PASSING clause for XMLTABLE
3237
+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
3238
+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
3239
+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
3240
+ pub struct XmlPassingClause {
3241
+ pub arguments : Vec < XmlPassingArgument > ,
3242
+ }
3243
+
3244
+ impl fmt:: Display for XmlPassingClause {
3245
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
3246
+ if !self . arguments . is_empty ( ) {
3247
+ write ! ( f, " PASSING {}" , display_comma_separated( & self . arguments) ) ?;
3248
+ }
3249
+ Ok ( ( ) )
3250
+ }
3251
+ }
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
+ }
0 commit comments