@@ -6816,6 +6816,205 @@ fn parse_typed_strings() {
68166816 }
68176817}
68186818
6819+ #[test]
6820+ fn parse_generic_xml_special_expressions() {
6821+ let generic = TestedDialects::new(vec![Box::new(GenericDialect {})]);
6822+
6823+ let select = generic
6824+ .verified_only_select_with_canonical("SELECT xmlconcat(1, 2)", "SELECT XMLCONCAT(1, 2)");
6825+ match &select.projection[0] {
6826+ SelectItem::UnnamedExpr(Expr::XmlConcat(items)) => assert_eq!(items.len(), 2),
6827+ item => panic!("expected XmlConcat expression, got {item:?}"),
6828+ }
6829+
6830+ let select = generic.verified_only_select_with_canonical(
6831+ "SELECT xmlelement(name foo, 'bar')",
6832+ "SELECT XMLELEMENT(NAME foo, 'bar')",
6833+ );
6834+ match &select.projection[0] {
6835+ SelectItem::UnnamedExpr(Expr::XmlElement(XmlElementExpr {
6836+ name,
6837+ attributes,
6838+ content,
6839+ })) => {
6840+ assert_eq!(name.value, "foo");
6841+ assert!(attributes.is_none());
6842+ assert_eq!(content.len(), 1);
6843+ }
6844+ item => panic!("expected XmlElement expression, got {item:?}"),
6845+ }
6846+
6847+ let select = generic.verified_only_select_with_canonical(
6848+ "SELECT xmlforest(1 as one, 2)",
6849+ "SELECT XMLFOREST(1 AS one, 2)",
6850+ );
6851+ match &select.projection[0] {
6852+ SelectItem::UnnamedExpr(Expr::XmlForest(items)) => {
6853+ assert_eq!(items.len(), 2);
6854+ assert_eq!(items[0].alias.as_ref().unwrap().value, "one");
6855+ assert!(items[1].alias.is_none());
6856+ }
6857+ item => panic!("expected XmlForest expression, got {item:?}"),
6858+ }
6859+
6860+ let select = generic.verified_only_select_with_canonical(
6861+ "SELECT xmlparse(content '<a/>')",
6862+ "SELECT XMLPARSE(CONTENT '<a/>')",
6863+ );
6864+ match &select.projection[0] {
6865+ SelectItem::UnnamedExpr(Expr::XmlParse(XmlParseExpr { mode, .. })) => {
6866+ assert_eq!(*mode, XmlParseMode::Content);
6867+ }
6868+ item => panic!("expected XmlParse expression, got {item:?}"),
6869+ }
6870+
6871+ let select = generic.verified_only_select_with_canonical(
6872+ "SELECT xmlpi(name foo, 'bar')",
6873+ "SELECT XMLPI(NAME foo, 'bar')",
6874+ );
6875+ match &select.projection[0] {
6876+ SelectItem::UnnamedExpr(Expr::XmlPi(XmlPiExpr { name, content })) => {
6877+ assert_eq!(name.value, "foo");
6878+ assert!(content.is_some());
6879+ }
6880+ item => panic!("expected XmlPi expression, got {item:?}"),
6881+ }
6882+
6883+ let select = generic.verified_only_select_with_canonical(
6884+ "SELECT xmlserialize(document '<a/>' as text no indent)",
6885+ "SELECT XMLSERIALIZE(DOCUMENT '<a/>' AS TEXT NO INDENT)",
6886+ );
6887+ match &select.projection[0] {
6888+ SelectItem::UnnamedExpr(Expr::XmlSerialize(XmlSerializeExpr { mode, indent, .. })) => {
6889+ assert_eq!(*mode, XmlParseMode::Document);
6890+ assert_eq!(*indent, Some(XmlIndentOption::NoIndent));
6891+ }
6892+ item => panic!("expected XmlSerialize expression, got {item:?}"),
6893+ }
6894+
6895+ let select = generic.verified_only_select_with_canonical(
6896+ "SELECT xmlroot(xml '<foo/>', version no value, standalone yes)",
6897+ "SELECT XMLROOT(xml '<foo/>', VERSION NO VALUE, STANDALONE YES)",
6898+ );
6899+ match &select.projection[0] {
6900+ SelectItem::UnnamedExpr(Expr::XmlRoot(XmlRootExpr {
6901+ version,
6902+ standalone,
6903+ ..
6904+ })) => {
6905+ assert!(matches!(version, XmlRootVersion::NoValue));
6906+ assert_eq!(*standalone, Some(XmlStandalone::Yes));
6907+ }
6908+ item => panic!("expected XmlRoot expression, got {item:?}"),
6909+ }
6910+ }
6911+
6912+ #[test]
6913+ fn parse_generic_xml_special_expressions_reject_invalid_forms() {
6914+ let generic = TestedDialects::new(vec![Box::new(GenericDialect {})]);
6915+
6916+ assert!(
6917+ generic.parse_sql_statements("SELECT xmlparse(1)").is_err(),
6918+ "xmlparse requires DOCUMENT|CONTENT mode"
6919+ );
6920+ assert!(
6921+ generic
6922+ .parse_sql_statements("SELECT xmlroot(xml '<foo/>', standalone yes)")
6923+ .is_err(),
6924+ "xmlroot requires VERSION clause"
6925+ );
6926+ assert!(
6927+ generic
6928+ .parse_sql_statements("SELECT xmlserialize(document '<foo/>' text)")
6929+ .is_err(),
6930+ "xmlserialize requires AS <type>"
6931+ );
6932+ }
6933+
6934+ #[test]
6935+ fn parse_non_pg_dialects_keep_xml_names_as_regular_functions() {
6936+ let cases = [
6937+ ("SELECT xmlparse(1)", "xmlparse", 1usize),
6938+ ("SELECT xmlelement(1, 2)", "xmlelement", 2usize),
6939+ ("SELECT xmlroot(1, 2)", "xmlroot", 2usize),
6940+ ("SELECT xmlserialize(1, 2)", "xmlserialize", 2usize),
6941+ ];
6942+
6943+ let non_pg_dialects =
6944+ all_dialects_except(|d| d.is::<PostgreSqlDialect>() || d.is::<GenericDialect>()).dialects;
6945+
6946+ for dialect in non_pg_dialects {
6947+ let dialect_name = format!("{dialect:?}");
6948+ for (sql, expected_name, expected_arg_count) in cases {
6949+ let statements = Parser::parse_sql(&*dialect, sql)
6950+ .unwrap_or_else(|e| panic!("dialect {dialect_name} failed to parse `{sql}`: {e}"));
6951+ match statements.as_slice() {
6952+ [Statement::Query(query)] => match query.body.as_ref() {
6953+ SetExpr::Select(select) => match select.projection.as_slice() {
6954+ [SelectItem::UnnamedExpr(Expr::Function(function))] => {
6955+ match function.name.0.as_slice() {
6956+ [ObjectNamePart::Identifier(ident)] => {
6957+ assert!(
6958+ ident.value.eq_ignore_ascii_case(expected_name),
6959+ "dialect {dialect_name} parsed `{sql}` as function `{}` instead of `{expected_name}`",
6960+ ident.value
6961+ );
6962+ }
6963+ name_parts => {
6964+ panic!("dialect {dialect_name} expected simple function name, got {name_parts:?}")
6965+ }
6966+ }
6967+ match &function.args {
6968+ FunctionArguments::List(list) => {
6969+ assert_eq!(
6970+ list.args.len(),
6971+ expected_arg_count,
6972+ "dialect {dialect_name} parsed `{sql}` with unexpected argument count"
6973+ );
6974+ }
6975+ args => panic!(
6976+ "dialect {dialect_name} expected positional argument list, got {args:?}"
6977+ ),
6978+ }
6979+ }
6980+ projection => panic!(
6981+ "dialect {dialect_name} expected single function projection for `{sql}`, got {projection:?}"
6982+ ),
6983+ },
6984+ body => panic!(
6985+ "dialect {dialect_name} expected SELECT query body for `{sql}`, got {body:?}"
6986+ ),
6987+ },
6988+ parsed => panic!(
6989+ "dialect {dialect_name} expected a single query statement for `{sql}`, got {parsed:?}"
6990+ ),
6991+ }
6992+ }
6993+ }
6994+ }
6995+
6996+ #[test]
6997+ fn parse_non_pg_dialects_reject_xml_special_syntax() {
6998+ let xml_special_forms = [
6999+ "SELECT xmlparse(content '<a/>')",
7000+ "SELECT xmlelement(name foo, 'bar')",
7001+ "SELECT xmlserialize(document '<a/>' as text)",
7002+ ];
7003+
7004+ let non_pg_dialects =
7005+ all_dialects_except(|d| d.is::<PostgreSqlDialect>() || d.is::<GenericDialect>()).dialects;
7006+
7007+ for dialect in non_pg_dialects {
7008+ let dialect_name = format!("{dialect:?}");
7009+ for sql in xml_special_forms {
7010+ assert!(
7011+ Parser::parse_sql(&*dialect, sql).is_err(),
7012+ "dialect {dialect_name} unexpectedly accepted XML special syntax: `{sql}`"
7013+ );
7014+ }
7015+ }
7016+ }
7017+
68197018#[test]
68207019fn parse_bignumeric_keyword() {
68217020 let sql = r#"SELECT BIGNUMERIC '0'"#;
0 commit comments