@@ -792,6 +792,247 @@ impl fmt::Display for CaseWhen {
792792 }
793793}
794794
795+ /// Modes accepted by XML parsing/serialization clauses.
796+ #[ derive( Debug , Clone , Copy , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
797+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
798+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
799+ pub enum XmlParseMode {
800+ /// `CONTENT`
801+ Content ,
802+ /// `DOCUMENT`
803+ Document ,
804+ }
805+
806+ impl fmt:: Display for XmlParseMode {
807+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
808+ match self {
809+ XmlParseMode :: Content => write ! ( f, "CONTENT" ) ,
810+ XmlParseMode :: Document => write ! ( f, "DOCUMENT" ) ,
811+ }
812+ }
813+ }
814+
815+ /// A named XML argument (for XMLFOREST entries).
816+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
817+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
818+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
819+ pub struct XmlNamedExpr {
820+ /// Value expression.
821+ pub expr : Expr ,
822+ /// Optional explicit XML name.
823+ pub alias : Option < Ident > ,
824+ }
825+
826+ impl fmt:: Display for XmlNamedExpr {
827+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
828+ write ! ( f, "{}" , self . expr) ?;
829+ if let Some ( alias) = & self . alias {
830+ write ! ( f, " AS {alias}" ) ?;
831+ }
832+ Ok ( ( ) )
833+ }
834+ }
835+
836+ /// A single XML attribute expression, optionally named.
837+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
838+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
839+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
840+ pub struct XmlAttribute {
841+ /// Attribute value expression.
842+ pub expr : Expr ,
843+ /// Optional explicit attribute name.
844+ pub alias : Option < Ident > ,
845+ }
846+
847+ impl fmt:: Display for XmlAttribute {
848+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
849+ write ! ( f, "{}" , self . expr) ?;
850+ if let Some ( alias) = & self . alias {
851+ write ! ( f, " AS {alias}" ) ?;
852+ }
853+ Ok ( ( ) )
854+ }
855+ }
856+
857+ /// `XMLELEMENT(NAME ..., [XMLATTRIBUTES(...)], [content ...])`.
858+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
859+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
860+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
861+ pub struct XmlElementExpr {
862+ /// Element name.
863+ pub name : Ident ,
864+ /// Optional XML attributes.
865+ pub attributes : Option < Vec < XmlAttribute > > ,
866+ /// Optional content expressions.
867+ pub content : Vec < Expr > ,
868+ }
869+
870+ impl fmt:: Display for XmlElementExpr {
871+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
872+ write ! ( f, "XMLELEMENT(NAME {}" , self . name) ?;
873+ if let Some ( attrs) = & self . attributes {
874+ write ! ( f, ", XMLATTRIBUTES({})" , display_comma_separated( attrs) ) ?;
875+ }
876+ if !self . content . is_empty ( ) {
877+ write ! ( f, ", {}" , display_comma_separated( & self . content) ) ?;
878+ }
879+ write ! ( f, ")" )
880+ }
881+ }
882+
883+ /// `XMLPARSE(<mode> <expr>)`.
884+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
885+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
886+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
887+ pub struct XmlParseExpr {
888+ /// Parsing mode.
889+ pub mode : XmlParseMode ,
890+ /// Expression to parse as XML.
891+ pub expr : Box < Expr > ,
892+ }
893+
894+ impl fmt:: Display for XmlParseExpr {
895+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
896+ write ! ( f, "XMLPARSE({} {})" , self . mode, self . expr)
897+ }
898+ }
899+
900+ /// `XMLPI(NAME ..., [content])`.
901+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
902+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
903+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
904+ pub struct XmlPiExpr {
905+ /// Processing instruction target name.
906+ pub name : Ident ,
907+ /// Optional processing instruction content.
908+ pub content : Option < Box < Expr > > ,
909+ }
910+
911+ impl fmt:: Display for XmlPiExpr {
912+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
913+ write ! ( f, "XMLPI(NAME {}" , self . name) ?;
914+ if let Some ( content) = & self . content {
915+ write ! ( f, ", {content}" ) ?;
916+ }
917+ write ! ( f, ")" )
918+ }
919+ }
920+
921+ /// Version argument in XMLROOT.
922+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
923+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
924+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
925+ pub enum XmlRootVersion {
926+ /// `VERSION NO VALUE`
927+ NoValue ,
928+ /// `VERSION <expr>`
929+ Value ( Box < Expr > ) ,
930+ }
931+
932+ impl fmt:: Display for XmlRootVersion {
933+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
934+ match self {
935+ XmlRootVersion :: NoValue => write ! ( f, "NO VALUE" ) ,
936+ XmlRootVersion :: Value ( expr) => write ! ( f, "{expr}" ) ,
937+ }
938+ }
939+ }
940+
941+ /// Standalone option in XMLROOT.
942+ #[ derive( Debug , Clone , Copy , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
943+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
944+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
945+ pub enum XmlStandalone {
946+ /// `YES`
947+ Yes ,
948+ /// `NO`
949+ No ,
950+ /// `NO VALUE`
951+ NoValue ,
952+ }
953+
954+ impl fmt:: Display for XmlStandalone {
955+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
956+ match self {
957+ XmlStandalone :: Yes => write ! ( f, "YES" ) ,
958+ XmlStandalone :: No => write ! ( f, "NO" ) ,
959+ XmlStandalone :: NoValue => write ! ( f, "NO VALUE" ) ,
960+ }
961+ }
962+ }
963+
964+ /// `XMLROOT(...)` expression.
965+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
966+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
967+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
968+ pub struct XmlRootExpr {
969+ /// XML expression to rewrite.
970+ pub expr : Box < Expr > ,
971+ /// Required version argument.
972+ pub version : XmlRootVersion ,
973+ /// Optional standalone option.
974+ pub standalone : Option < XmlStandalone > ,
975+ }
976+
977+ impl fmt:: Display for XmlRootExpr {
978+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
979+ write ! ( f, "XMLROOT({}, VERSION {}" , self . expr, self . version) ?;
980+ if let Some ( standalone) = & self . standalone {
981+ write ! ( f, ", STANDALONE {standalone}" ) ?;
982+ }
983+ write ! ( f, ")" )
984+ }
985+ }
986+
987+ /// Optional indentation behavior in XMLSERIALIZE.
988+ #[ derive( Debug , Clone , Copy , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
989+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
990+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
991+ pub enum XmlIndentOption {
992+ /// `INDENT`
993+ Indent ,
994+ /// `NO INDENT`
995+ NoIndent ,
996+ }
997+
998+ impl fmt:: Display for XmlIndentOption {
999+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1000+ match self {
1001+ XmlIndentOption :: Indent => write ! ( f, "INDENT" ) ,
1002+ XmlIndentOption :: NoIndent => write ! ( f, "NO INDENT" ) ,
1003+ }
1004+ }
1005+ }
1006+
1007+ /// `XMLSERIALIZE(<mode> <expr> AS <type> [indent-option])`.
1008+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
1009+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
1010+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
1011+ pub struct XmlSerializeExpr {
1012+ /// Input XML mode.
1013+ pub mode : XmlParseMode ,
1014+ /// Expression to serialize.
1015+ pub expr : Box < Expr > ,
1016+ /// Output SQL data type.
1017+ pub data_type : DataType ,
1018+ /// Optional indentation behavior.
1019+ pub indent : Option < XmlIndentOption > ,
1020+ }
1021+
1022+ impl fmt:: Display for XmlSerializeExpr {
1023+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1024+ write ! (
1025+ f,
1026+ "XMLSERIALIZE({} {} AS {}" ,
1027+ self . mode, self . expr, self . data_type
1028+ ) ?;
1029+ if let Some ( indent) = self . indent {
1030+ write ! ( f, " {indent}" ) ?;
1031+ }
1032+ write ! ( f, ")" )
1033+ }
1034+ }
1035+
7951036/// An SQL expression of any type.
7961037///
7971038/// # Semantics / Type Checking
@@ -1181,6 +1422,20 @@ pub enum Expr {
11811422 /// This can represent ANSI SQL `DATE`, `TIME`, and `TIMESTAMP` literals (such as `DATE '2020-01-01'`),
11821423 /// as well as constants of other types (a non-standard PostgreSQL extension).
11831424 TypedString ( TypedString ) ,
1425+ /// XML concatenation expression: `XMLCONCAT(expr [, ...])`.
1426+ XmlConcat ( Vec < Expr > ) ,
1427+ /// XML element constructor: `XMLELEMENT(NAME ... [, XMLATTRIBUTES(...)] [, content ...])`.
1428+ XmlElement ( XmlElementExpr ) ,
1429+ /// XML forest constructor: `XMLFOREST(expr [AS name] [, ...])`.
1430+ XmlForest ( Vec < XmlNamedExpr > ) ,
1431+ /// XML parse expression: `XMLPARSE(CONTENT|DOCUMENT expr)`.
1432+ XmlParse ( XmlParseExpr ) ,
1433+ /// XML processing instruction constructor: `XMLPI(NAME target [, content])`.
1434+ XmlPi ( XmlPiExpr ) ,
1435+ /// XML root mutator: `XMLROOT(expr, VERSION ... [, STANDALONE ...])`.
1436+ XmlRoot ( XmlRootExpr ) ,
1437+ /// XML serialization expression: `XMLSERIALIZE(CONTENT|DOCUMENT expr AS type [INDENT|NO INDENT])`.
1438+ XmlSerialize ( XmlSerializeExpr ) ,
11841439 /// Scalar function call e.g. `LEFT(foo, 5)`
11851440 Function ( Function ) ,
11861441 /// `CASE [<operand>] WHEN <condition> THEN <result> ... [ELSE <result>] END`
@@ -1970,6 +2225,15 @@ impl fmt::Display for Expr {
19702225 Expr :: Value ( v) => write ! ( f, "{v}" ) ,
19712226 Expr :: Prefixed { prefix, value } => write ! ( f, "{prefix} {value}" ) ,
19722227 Expr :: TypedString ( ts) => ts. fmt ( f) ,
2228+ Expr :: XmlConcat ( exprs) => write ! ( f, "XMLCONCAT({})" , display_comma_separated( exprs) ) ,
2229+ Expr :: XmlElement ( xml_element) => write ! ( f, "{xml_element}" ) ,
2230+ Expr :: XmlForest ( items) => {
2231+ write ! ( f, "XMLFOREST({})" , display_comma_separated( items) )
2232+ }
2233+ Expr :: XmlParse ( xml_parse) => write ! ( f, "{xml_parse}" ) ,
2234+ Expr :: XmlPi ( xml_pi) => write ! ( f, "{xml_pi}" ) ,
2235+ Expr :: XmlRoot ( xml_root) => write ! ( f, "{xml_root}" ) ,
2236+ Expr :: XmlSerialize ( xml_serialize) => write ! ( f, "{xml_serialize}" ) ,
19732237 Expr :: Function ( fun) => fun. fmt ( f) ,
19742238 Expr :: Case {
19752239 case_token : _,
0 commit comments