Skip to content

Commit 2203e12

Browse files
committed
HHH-18497 Add xmlelement function
1 parent 2be3000 commit 2203e12

36 files changed

+1044
-2
lines changed

documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
:example-dir-hql: {core-project-dir}/src/test/java/org/hibernate/orm/test/hql
88
:array-example-dir-hql: {core-project-dir}/src/test/java/org/hibernate/orm/test/function/array
99
:json-example-dir-hql: {core-project-dir}/src/test/java/org/hibernate/orm/test/function/json
10+
:xml-example-dir-hql: {core-project-dir}/src/test/java/org/hibernate/orm/test/function/xml
1011
:extrasdir: extras
1112

1213
This chapter describes Hibernate Query Language (HQL) and Jakarta Persistence Query Language (JPQL).
@@ -2158,6 +2159,54 @@ include::{json-example-dir-hql}/JsonArrayInsertTest.java[tags=hql-json-array-ins
21582159
21592160
WARNING: SAP HANA, DB2, H2 and HSQLDB do not support this function.
21602161
2162+
[[hql-functions-xml]]
2163+
==== Functions for dealing with XML
2164+
2165+
The following functions deal with SQL XML types, which are not supported on every database.
2166+
2167+
NOTE: The following functions are incubating/tech-preview and to use them in HQL,
2168+
it is necessary to enable the `hibernate.query.hql.xml_functions_enabled` configuration setting.
2169+
2170+
[[hql-xml-functions]]
2171+
|===
2172+
| Function | Purpose
2173+
2174+
| `xmlelement()` | Constructs an XML element from arguments
2175+
|===
2176+
2177+
2178+
[[hql-xmlelement-function]]
2179+
===== `xmlelement()`
2180+
2181+
Constructs an XML element from the arguments.
2182+
2183+
[[hql-xmlelement-bnf]]
2184+
[source, antlrv4, indent=0]
2185+
----
2186+
include::{extrasdir}/xmlelement_bnf.txt[]
2187+
----
2188+
2189+
The identifier represents the XML element name and can be quoted by using backticks.
2190+
2191+
[[hql-xmlelement-example]]
2192+
====
2193+
[source, java, indent=0]
2194+
----
2195+
include::{xml-example-dir-hql}/XmlElementTest.java[tags=hql-xmlelement-example]
2196+
----
2197+
====
2198+
2199+
XML element attributes can be defined by using the `xmlattributes` function as second argument.
2200+
All following arguments represent the XML content.
2201+
2202+
[[hql-xmlelement-attributes-content-example]]
2203+
====
2204+
[source, java, indent=0]
2205+
----
2206+
include::{xml-example-dir-hql}/XmlElementTest.java[tags=hql-xmlelement-attributes-content-example]
2207+
----
2208+
====
2209+
21612210
[[hql-user-defined-functions]]
21622211
==== Native and user-defined functions
21632212
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
"xmlelement(name " identifier xmlattributes? ("," expressionOrPredicate)* ")"
2+
3+
xmlattributes
4+
: "xmlattributes(" expressionOrPredicate " as " identifier ("," expressionOrPredicate " as " identifier)* ")"
5+
;

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,8 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
440440
functionFactory.jsonObjectAgg_db2();
441441
}
442442
}
443+
444+
functionFactory.xmlelement();
443445
}
444446

445447
@Override

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,8 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
417417
// Use group_concat until 2.x as listagg was buggy
418418
functionFactory.listagg_groupConcat();
419419
}
420+
421+
functionFactory.xmlelement_h2();
420422
}
421423
else {
422424
functionFactory.listagg_groupConcat();

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,8 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
325325
functionFactory.jsonArrayAppend_oracle();
326326
functionFactory.jsonArrayInsert_oracle();
327327
}
328+
329+
functionFactory.xmlelement();
328330
}
329331

330332
@Override

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,8 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
669669
functionFactory.jsonArrayAppend_postgresql( getVersion().isSameOrAfter( 13 ) );
670670
functionFactory.jsonArrayInsert_postgresql();
671671

672+
functionFactory.xmlelement();
673+
672674
if ( getVersion().isSameOrAfter( 9, 4 ) ) {
673675
functionFactory.makeDateTimeTimestamp();
674676
// Note that PostgreSQL doesn't support the OVER clause for ordered set-aggregate functions

hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlLexer.g4

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ MINELEMENT : [mM] [iI] [nN] [eE] [lL] [eE] [mM] [eE] [nN] [tT];
258258
MININDEX : [mM] [iI] [nN] [iI] [nN] [dD] [eE] [xX];
259259
MINUTE : [mM] [iI] [nN] [uU] [tT] [eE];
260260
MONTH : [mM] [oO] [nN] [tT] [hH];
261+
NAME : [nN] [aA] [mM] [eE];
261262
NANOSECOND : [nN] [aA] [nN] [oO] [sS] [eE] [cC] [oO] [nN] [dD];
262263
NEW : [nN] [eE] [wW];
263264
NEXT : [nN] [eE] [xX] [tT];
@@ -329,6 +330,8 @@ WITH : [wW] [iI] [tT] [hH];
329330
WITHIN : [wW] [iI] [tT] [hH] [iI] [nN];
330331
WITHOUT : [wW] [iI] [tT] [hH] [oO] [uU] [tT];
331332
WRAPPER : [wW] [rR] [aA] [pP] [pP] [eE] [rR];
333+
XMLATTRIBUTES : [xX] [mM] [lL] [aA] [tT] [tT] [rR] [iI] [bB] [uU] [tT] [eE] [sS];
334+
XMLELEMENT : [xX] [mM] [lL] [eE] [lL] [eE] [mM] [eE] [nN] [tT];
332335
YEAR : [yY] [eE] [aA] [rR];
333336
ZONED : [zZ] [oO] [nN] [eE] [dD];
334337

hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,6 +1110,7 @@ function
11101110
| jpaNonstandardFunction
11111111
| columnFunction
11121112
| jsonFunction
1113+
| xmlFunction
11131114
| genericFunction
11141115
;
11151116

@@ -1716,6 +1717,24 @@ jsonUniqueKeysClause
17161717
: (WITH|WITHOUT) UNIQUE KEYS
17171718
;
17181719

1720+
xmlFunction
1721+
: xmlelementFunction
1722+
;
1723+
1724+
/**
1725+
* The 'xmlelement()' function
1726+
*/
1727+
xmlelementFunction
1728+
: XMLELEMENT LEFT_PAREN NAME identifier (COMMA xmlattributesFunction)? (COMMA expressionOrPredicate)* RIGHT_PAREN
1729+
;
1730+
1731+
/**
1732+
* The 'xmlattributes()' function
1733+
*/
1734+
xmlattributesFunction
1735+
: XMLATTRIBUTES LEFT_PAREN expressionOrPredicate AS identifier (COMMA expressionOrPredicate AS identifier)* RIGHT_PAREN
1736+
;
1737+
17191738
/**
17201739
* Support for "soft" keywords which may be used as identifiers
17211740
*
@@ -1847,6 +1866,7 @@ jsonUniqueKeysClause
18471866
| MININDEX
18481867
| MINUTE
18491868
| MONTH
1869+
| NAME
18501870
| NANOSECOND
18511871
| NATURALID
18521872
| NEW
@@ -1921,6 +1941,8 @@ jsonUniqueKeysClause
19211941
| WITHIN
19221942
| WITHOUT
19231943
| WRAPPER
1944+
| XMLATTRIBUTES
1945+
| XMLELEMENT
19241946
| YEAR
19251947
| ZONED) {
19261948
logUseOfReservedWordAsIdentifier( getCurrentToken() );

hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@
132132
import static org.hibernate.cfg.QuerySettings.DEFAULT_NULL_ORDERING;
133133
import static org.hibernate.cfg.QuerySettings.JSON_FUNCTIONS_ENABLED;
134134
import static org.hibernate.cfg.QuerySettings.PORTABLE_INTEGER_DIVISION;
135+
import static org.hibernate.cfg.QuerySettings.XML_FUNCTIONS_ENABLED;
135136
import static org.hibernate.engine.config.spi.StandardConverters.BOOLEAN;
136137
import static org.hibernate.internal.CoreLogging.messageLogger;
137138
import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER;
@@ -278,6 +279,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
278279

279280
private final boolean portableIntegerDivisionEnabled;
280281
private final boolean jsonFunctionsEnabled;
282+
private final boolean xmlFunctionsEnabled;
281283

282284
private final int queryStatisticsMaxSize;
283285

@@ -622,6 +624,10 @@ else if ( jdbcTimeZoneValue != null ) {
622624
JSON_FUNCTIONS_ENABLED,
623625
configurationSettings
624626
);
627+
this.xmlFunctionsEnabled = getBoolean(
628+
XML_FUNCTIONS_ENABLED,
629+
configurationSettings
630+
);
625631

626632
this.queryStatisticsMaxSize = getInt(
627633
QUERY_STATISTICS_MAX_SIZE,
@@ -1257,6 +1263,11 @@ public boolean isJsonFunctionsEnabled() {
12571263
return jsonFunctionsEnabled;
12581264
}
12591265

1266+
@Override
1267+
public boolean isXmlFunctionsEnabled() {
1268+
return xmlFunctionsEnabled;
1269+
}
1270+
12601271
@Override
12611272
public boolean isPortableIntegerDivisionEnabled() {
12621273
return portableIntegerDivisionEnabled;

hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,11 @@ public boolean isJsonFunctionsEnabled() {
426426
return delegate.isJsonFunctionsEnabled();
427427
}
428428

429+
@Override
430+
public boolean isXmlFunctionsEnabled() {
431+
return delegate.isXmlFunctionsEnabled();
432+
}
433+
429434
@Override
430435
public boolean isPortableIntegerDivisionEnabled() {
431436
return delegate.isPortableIntegerDivisionEnabled();

0 commit comments

Comments
 (0)