HHH-18497 Add xmlpi function
This commit is contained in:
parent
a37ae66a2e
commit
574959a591
|
@ -2175,6 +2175,7 @@ it is necessary to enable the `hibernate.query.hql.xml_functions_enabled` config
|
||||||
| `xmlcomment()` | Constructs an XML comment from the single argument
|
| `xmlcomment()` | Constructs an XML comment from the single argument
|
||||||
| `xmlforest()` | Constructs an XML forest from the arguments
|
| `xmlforest()` | Constructs an XML forest from the arguments
|
||||||
| `xmlconcat()` | Concatenates multiple XML fragments to each other
|
| `xmlconcat()` | Concatenates multiple XML fragments to each other
|
||||||
|
| `xmlpi()` | Constructs an XML processing instruction
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
@ -2266,6 +2267,39 @@ include::{xml-example-dir-hql}/XmlConcatTest.java[tags=hql-xmlconcat-example]
|
||||||
|
|
||||||
WARNING: SAP HANA, MySQL, MariaDB and HSQLDB do not support this function.
|
WARNING: SAP HANA, MySQL, MariaDB and HSQLDB do not support this function.
|
||||||
|
|
||||||
|
[[hql-xmlpi-function]]
|
||||||
|
===== `xmlpi()`
|
||||||
|
|
||||||
|
Constructs an XML processing instruction from the arguments.
|
||||||
|
|
||||||
|
[[hql-xmlpi-bnf]]
|
||||||
|
[source, antlrv4, indent=0]
|
||||||
|
----
|
||||||
|
include::{extrasdir}/xmlpi_bnf.txt[]
|
||||||
|
----
|
||||||
|
|
||||||
|
The identifier represents the XML processing instruction name and can be quoted by using backticks.
|
||||||
|
|
||||||
|
[[hql-xmlpi-example]]
|
||||||
|
====
|
||||||
|
[source, java, indent=0]
|
||||||
|
----
|
||||||
|
include::{xml-example-dir-hql}/XmlPiTest.java[tags=hql-xmlpi-example]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
The optional second argument represents the processing instruction content.
|
||||||
|
|
||||||
|
[[hql-xmlpi-content-example]]
|
||||||
|
====
|
||||||
|
[source, java, indent=0]
|
||||||
|
----
|
||||||
|
include::{xml-example-dir-hql}/XmlPiTest.java[tags=hql-xmlpi-content-example]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
WARNING: SAP HANA, MySQL, MariaDB and HSQLDB do not support this function.
|
||||||
|
|
||||||
[[hql-user-defined-functions]]
|
[[hql-user-defined-functions]]
|
||||||
==== Native and user-defined functions
|
==== Native and user-defined functions
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
"xmlpi(name " identifier ("," expressionOrPredicate)? ")"
|
|
@ -445,6 +445,7 @@ public class DB2LegacyDialect extends Dialect {
|
||||||
functionFactory.xmlcomment();
|
functionFactory.xmlcomment();
|
||||||
functionFactory.xmlforest();
|
functionFactory.xmlforest();
|
||||||
functionFactory.xmlconcat();
|
functionFactory.xmlconcat();
|
||||||
|
functionFactory.xmlpi();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -422,6 +422,7 @@ public class H2LegacyDialect extends Dialect {
|
||||||
functionFactory.xmlcomment();
|
functionFactory.xmlcomment();
|
||||||
functionFactory.xmlforest_h2();
|
functionFactory.xmlforest_h2();
|
||||||
functionFactory.xmlconcat_h2();
|
functionFactory.xmlconcat_h2();
|
||||||
|
functionFactory.xmlpi_h2();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
functionFactory.listagg_groupConcat();
|
functionFactory.listagg_groupConcat();
|
||||||
|
|
|
@ -330,6 +330,7 @@ public class OracleLegacyDialect extends Dialect {
|
||||||
functionFactory.xmlcomment();
|
functionFactory.xmlcomment();
|
||||||
functionFactory.xmlforest();
|
functionFactory.xmlforest();
|
||||||
functionFactory.xmlconcat();
|
functionFactory.xmlconcat();
|
||||||
|
functionFactory.xmlpi();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -673,6 +673,7 @@ public class PostgreSQLLegacyDialect extends Dialect {
|
||||||
functionFactory.xmlcomment();
|
functionFactory.xmlcomment();
|
||||||
functionFactory.xmlforest();
|
functionFactory.xmlforest();
|
||||||
functionFactory.xmlconcat();
|
functionFactory.xmlconcat();
|
||||||
|
functionFactory.xmlpi();
|
||||||
|
|
||||||
if ( getVersion().isSameOrAfter( 9, 4 ) ) {
|
if ( getVersion().isSameOrAfter( 9, 4 ) ) {
|
||||||
functionFactory.makeDateTimeTimestamp();
|
functionFactory.makeDateTimeTimestamp();
|
||||||
|
|
|
@ -417,6 +417,7 @@ public class SQLServerLegacyDialect extends AbstractTransactSQLDialect {
|
||||||
functionFactory.xmlcomment_sqlserver();
|
functionFactory.xmlcomment_sqlserver();
|
||||||
functionFactory.xmlforest_sqlserver();
|
functionFactory.xmlforest_sqlserver();
|
||||||
functionFactory.xmlconcat_sqlserver();
|
functionFactory.xmlconcat_sqlserver();
|
||||||
|
functionFactory.xmlpi_sqlserver();
|
||||||
if ( getVersion().isSameOrAfter( 14 ) ) {
|
if ( getVersion().isSameOrAfter( 14 ) ) {
|
||||||
functionFactory.listagg_stringAggWithinGroup( "varchar(max)" );
|
functionFactory.listagg_stringAggWithinGroup( "varchar(max)" );
|
||||||
functionFactory.jsonArrayAgg_sqlserver( getVersion().isSameOrAfter( 16 ) );
|
functionFactory.jsonArrayAgg_sqlserver( getVersion().isSameOrAfter( 16 ) );
|
||||||
|
|
|
@ -333,6 +333,7 @@ WRAPPER : [wW] [rR] [aA] [pP] [pP] [eE] [rR];
|
||||||
XMLATTRIBUTES : [xX] [mM] [lL] [aA] [tT] [tT] [rR] [iI] [bB] [uU] [tT] [eE] [sS];
|
XMLATTRIBUTES : [xX] [mM] [lL] [aA] [tT] [tT] [rR] [iI] [bB] [uU] [tT] [eE] [sS];
|
||||||
XMLELEMENT : [xX] [mM] [lL] [eE] [lL] [eE] [mM] [eE] [nN] [tT];
|
XMLELEMENT : [xX] [mM] [lL] [eE] [lL] [eE] [mM] [eE] [nN] [tT];
|
||||||
XMLFOREST : [xX] [mM] [lL] [fF] [oO] [rR] [eE] [sS] [tT];
|
XMLFOREST : [xX] [mM] [lL] [fF] [oO] [rR] [eE] [sS] [tT];
|
||||||
|
XMLPI : [xX] [mM] [lL] [pP] [iI];
|
||||||
YEAR : [yY] [eE] [aA] [rR];
|
YEAR : [yY] [eE] [aA] [rR];
|
||||||
ZONED : [zZ] [oO] [nN] [eE] [dD];
|
ZONED : [zZ] [oO] [nN] [eE] [dD];
|
||||||
|
|
||||||
|
|
|
@ -1720,6 +1720,7 @@ jsonUniqueKeysClause
|
||||||
xmlFunction
|
xmlFunction
|
||||||
: xmlelementFunction
|
: xmlelementFunction
|
||||||
| xmlforestFunction
|
| xmlforestFunction
|
||||||
|
| xmlpiFunction
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1743,6 +1744,13 @@ xmlforestFunction
|
||||||
: XMLFOREST LEFT_PAREN expressionOrPredicate (AS identifier)? (COMMA expressionOrPredicate (AS identifier)?)* RIGHT_PAREN
|
: XMLFOREST LEFT_PAREN expressionOrPredicate (AS identifier)? (COMMA expressionOrPredicate (AS identifier)?)* RIGHT_PAREN
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The 'xmlpi()' function
|
||||||
|
*/
|
||||||
|
xmlpiFunction
|
||||||
|
: XMLPI LEFT_PAREN NAME identifier (COMMA expression)? RIGHT_PAREN
|
||||||
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Support for "soft" keywords which may be used as identifiers
|
* Support for "soft" keywords which may be used as identifiers
|
||||||
*
|
*
|
||||||
|
@ -1952,6 +1960,7 @@ xmlforestFunction
|
||||||
| XMLATTRIBUTES
|
| XMLATTRIBUTES
|
||||||
| XMLELEMENT
|
| XMLELEMENT
|
||||||
| XMLFOREST
|
| XMLFOREST
|
||||||
|
| XMLPI
|
||||||
| YEAR
|
| YEAR
|
||||||
| ZONED) {
|
| ZONED) {
|
||||||
logUseOfReservedWordAsIdentifier( getCurrentToken() );
|
logUseOfReservedWordAsIdentifier( getCurrentToken() );
|
||||||
|
|
|
@ -430,6 +430,7 @@ public class DB2Dialect extends Dialect {
|
||||||
functionFactory.xmlcomment();
|
functionFactory.xmlcomment();
|
||||||
functionFactory.xmlforest();
|
functionFactory.xmlforest();
|
||||||
functionFactory.xmlconcat();
|
functionFactory.xmlconcat();
|
||||||
|
functionFactory.xmlpi();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -357,6 +357,7 @@ public class H2Dialect extends Dialect {
|
||||||
functionFactory.xmlcomment();
|
functionFactory.xmlcomment();
|
||||||
functionFactory.xmlforest_h2();
|
functionFactory.xmlforest_h2();
|
||||||
functionFactory.xmlconcat_h2();
|
functionFactory.xmlconcat_h2();
|
||||||
|
functionFactory.xmlpi_h2();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -420,6 +420,7 @@ public class OracleDialect extends Dialect {
|
||||||
functionFactory.xmlcomment();
|
functionFactory.xmlcomment();
|
||||||
functionFactory.xmlforest();
|
functionFactory.xmlforest();
|
||||||
functionFactory.xmlconcat();
|
functionFactory.xmlconcat();
|
||||||
|
functionFactory.xmlpi();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -634,6 +634,7 @@ public class PostgreSQLDialect extends Dialect {
|
||||||
functionFactory.xmlcomment();
|
functionFactory.xmlcomment();
|
||||||
functionFactory.xmlforest();
|
functionFactory.xmlforest();
|
||||||
functionFactory.xmlconcat();
|
functionFactory.xmlconcat();
|
||||||
|
functionFactory.xmlpi();
|
||||||
|
|
||||||
functionFactory.makeDateTimeTimestamp();
|
functionFactory.makeDateTimeTimestamp();
|
||||||
// Note that PostgreSQL doesn't support the OVER clause for ordered set-aggregate functions
|
// Note that PostgreSQL doesn't support the OVER clause for ordered set-aggregate functions
|
||||||
|
|
|
@ -435,6 +435,7 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
||||||
functionFactory.xmlcomment_sqlserver();
|
functionFactory.xmlcomment_sqlserver();
|
||||||
functionFactory.xmlforest_sqlserver();
|
functionFactory.xmlforest_sqlserver();
|
||||||
functionFactory.xmlconcat_sqlserver();
|
functionFactory.xmlconcat_sqlserver();
|
||||||
|
functionFactory.xmlpi_sqlserver();
|
||||||
if ( getVersion().isSameOrAfter( 14 ) ) {
|
if ( getVersion().isSameOrAfter( 14 ) ) {
|
||||||
functionFactory.listagg_stringAggWithinGroup( "varchar(max)" );
|
functionFactory.listagg_stringAggWithinGroup( "varchar(max)" );
|
||||||
functionFactory.jsonArrayAgg_sqlserver( getVersion().isSameOrAfter( 16 ) );
|
functionFactory.jsonArrayAgg_sqlserver( getVersion().isSameOrAfter( 16 ) );
|
||||||
|
|
|
@ -156,12 +156,15 @@ import org.hibernate.dialect.function.json.SQLServerJsonValueFunction;
|
||||||
import org.hibernate.dialect.function.xml.H2XmlConcatFunction;
|
import org.hibernate.dialect.function.xml.H2XmlConcatFunction;
|
||||||
import org.hibernate.dialect.function.xml.H2XmlElementFunction;
|
import org.hibernate.dialect.function.xml.H2XmlElementFunction;
|
||||||
import org.hibernate.dialect.function.xml.H2XmlForestFunction;
|
import org.hibernate.dialect.function.xml.H2XmlForestFunction;
|
||||||
|
import org.hibernate.dialect.function.xml.H2XmlPiFunction;
|
||||||
import org.hibernate.dialect.function.xml.SQLServerXmlConcatFunction;
|
import org.hibernate.dialect.function.xml.SQLServerXmlConcatFunction;
|
||||||
import org.hibernate.dialect.function.xml.SQLServerXmlElementFunction;
|
import org.hibernate.dialect.function.xml.SQLServerXmlElementFunction;
|
||||||
import org.hibernate.dialect.function.xml.SQLServerXmlForestFunction;
|
import org.hibernate.dialect.function.xml.SQLServerXmlForestFunction;
|
||||||
|
import org.hibernate.dialect.function.xml.SQLServerXmlPiFunction;
|
||||||
import org.hibernate.dialect.function.xml.XmlConcatFunction;
|
import org.hibernate.dialect.function.xml.XmlConcatFunction;
|
||||||
import org.hibernate.dialect.function.xml.XmlElementFunction;
|
import org.hibernate.dialect.function.xml.XmlElementFunction;
|
||||||
import org.hibernate.dialect.function.xml.XmlForestFunction;
|
import org.hibernate.dialect.function.xml.XmlForestFunction;
|
||||||
|
import org.hibernate.dialect.function.xml.XmlPiFunction;
|
||||||
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||||
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
|
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
|
||||||
import org.hibernate.query.sqm.produce.function.FunctionParameterType;
|
import org.hibernate.query.sqm.produce.function.FunctionParameterType;
|
||||||
|
@ -4191,4 +4194,25 @@ public class CommonFunctionFactory {
|
||||||
public void xmlconcat_sqlserver() {
|
public void xmlconcat_sqlserver() {
|
||||||
functionRegistry.register( "xmlconcat", new SQLServerXmlConcatFunction( typeConfiguration ) );
|
functionRegistry.register( "xmlconcat", new SQLServerXmlConcatFunction( typeConfiguration ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard xmlpi() function
|
||||||
|
*/
|
||||||
|
public void xmlpi() {
|
||||||
|
functionRegistry.register( "xmlpi", new XmlPiFunction( typeConfiguration ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* H2 xmlpi() function
|
||||||
|
*/
|
||||||
|
public void xmlpi_h2() {
|
||||||
|
functionRegistry.register( "xmlpi", new H2XmlPiFunction( typeConfiguration ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL Server xmlpi() function
|
||||||
|
*/
|
||||||
|
public void xmlpi_sqlserver() {
|
||||||
|
functionRegistry.register( "xmlpi", new SQLServerXmlPiFunction( typeConfiguration ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.dialect.function.xml;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.query.ReturnableType;
|
||||||
|
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||||
|
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||||
|
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* H2 xmlpi function.
|
||||||
|
*/
|
||||||
|
public class H2XmlPiFunction extends XmlPiFunction {
|
||||||
|
|
||||||
|
public H2XmlPiFunction(TypeConfiguration typeConfiguration) {
|
||||||
|
super( typeConfiguration );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(
|
||||||
|
SqlAppender sqlAppender,
|
||||||
|
List<? extends SqlAstNode> sqlAstArguments,
|
||||||
|
ReturnableType<?> returnType,
|
||||||
|
SqlAstTranslator<?> walker) {
|
||||||
|
sqlAppender.appendSql( "'<?" );
|
||||||
|
final Literal literal = (Literal) sqlAstArguments.get( 0 );
|
||||||
|
sqlAppender.appendSql( (String) literal.getLiteralValue() );
|
||||||
|
|
||||||
|
if ( sqlAstArguments.size() > 1 ) {
|
||||||
|
sqlAppender.appendSql( " '||" );
|
||||||
|
sqlAstArguments.get( 1 ).accept( walker );
|
||||||
|
sqlAppender.appendSql( "||'?>'" );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sqlAppender.appendSql( "?>'" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.dialect.function.xml;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.query.ReturnableType;
|
||||||
|
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||||
|
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||||
|
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL Server xmlpi function.
|
||||||
|
*/
|
||||||
|
public class SQLServerXmlPiFunction extends XmlPiFunction {
|
||||||
|
|
||||||
|
public SQLServerXmlPiFunction(TypeConfiguration typeConfiguration) {
|
||||||
|
super( typeConfiguration );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(
|
||||||
|
SqlAppender sqlAppender,
|
||||||
|
List<? extends SqlAstNode> sqlAstArguments,
|
||||||
|
ReturnableType<?> returnType,
|
||||||
|
SqlAstTranslator<?> walker) {
|
||||||
|
sqlAppender.appendSql( "cast('<?" );
|
||||||
|
final Literal literal = (Literal) sqlAstArguments.get( 0 );
|
||||||
|
sqlAppender.appendSql( (String) literal.getLiteralValue() );
|
||||||
|
|
||||||
|
if ( sqlAstArguments.size() > 1 ) {
|
||||||
|
sqlAppender.appendSql( " '+" );
|
||||||
|
sqlAstArguments.get( 1 ).accept( walker );
|
||||||
|
sqlAppender.appendSql( "+'?>'" );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sqlAppender.appendSql( "?>'" );
|
||||||
|
}
|
||||||
|
sqlAppender.appendSql( " as xml)" );
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,7 +22,7 @@ import org.hibernate.type.spi.TypeConfiguration;
|
||||||
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.XML;
|
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.XML;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard XmlConcatFunction function.
|
* Standard xmlconcat function.
|
||||||
*/
|
*/
|
||||||
public class XmlConcatFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
public class XmlConcatFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ public class XmlConcatFunction extends AbstractSqmSelfRenderingFunctionDescripto
|
||||||
"xmlconcat",
|
"xmlconcat",
|
||||||
FunctionKind.NORMAL,
|
FunctionKind.NORMAL,
|
||||||
StandardArgumentsValidators.composite(
|
StandardArgumentsValidators.composite(
|
||||||
new ArgumentTypesValidator( StandardArgumentsValidators.min( 1 ), XML )
|
new ArgumentTypesValidator( StandardArgumentsValidators.min( 2 ), XML )
|
||||||
),
|
),
|
||||||
StandardFunctionReturnTypeResolvers.invariant(
|
StandardFunctionReturnTypeResolvers.invariant(
|
||||||
typeConfiguration.getBasicTypeRegistry().resolve( String.class, SqlTypes.SQLXML )
|
typeConfiguration.getBasicTypeRegistry().resolve( String.class, SqlTypes.SQLXML )
|
||||||
|
|
|
@ -26,7 +26,7 @@ import static java.lang.Character.isLetter;
|
||||||
import static java.lang.Character.isLetterOrDigit;
|
import static java.lang.Character.isLetterOrDigit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard XmlForestFunction function.
|
* Standard xmlforest function.
|
||||||
*/
|
*/
|
||||||
public class XmlForestFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
public class XmlForestFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.dialect.function.xml;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.query.ReturnableType;
|
||||||
|
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||||
|
import org.hibernate.query.sqm.function.FunctionKind;
|
||||||
|
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
|
||||||
|
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||||
|
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
|
||||||
|
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||||
|
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||||
|
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||||
|
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||||
|
import org.hibernate.type.SqlTypes;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
|
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.ANY;
|
||||||
|
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.STRING;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard xmlpi function.
|
||||||
|
*/
|
||||||
|
public class XmlPiFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||||
|
|
||||||
|
public XmlPiFunction(TypeConfiguration typeConfiguration) {
|
||||||
|
super(
|
||||||
|
"xmlpi",
|
||||||
|
FunctionKind.NORMAL,
|
||||||
|
StandardArgumentsValidators.composite(
|
||||||
|
new ArgumentTypesValidator( StandardArgumentsValidators.between( 1, 2 ), STRING, STRING )
|
||||||
|
),
|
||||||
|
StandardFunctionReturnTypeResolvers.invariant(
|
||||||
|
typeConfiguration.getBasicTypeRegistry().resolve( String.class, SqlTypes.SQLXML )
|
||||||
|
),
|
||||||
|
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, ANY, STRING )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(
|
||||||
|
SqlAppender sqlAppender,
|
||||||
|
List<? extends SqlAstNode> sqlAstArguments,
|
||||||
|
ReturnableType<?> returnType,
|
||||||
|
SqlAstTranslator<?> walker) {
|
||||||
|
sqlAppender.appendSql( "xmlpi(name " );
|
||||||
|
final Literal literal = (Literal) sqlAstArguments.get( 0 );
|
||||||
|
sqlAppender.appendDoubleQuoteEscapedString( (String) literal.getLiteralValue() );
|
||||||
|
if ( sqlAstArguments.size() > 1 ) {
|
||||||
|
sqlAppender.appendSql( ',' );
|
||||||
|
sqlAstArguments.get( 1 ).accept( walker );
|
||||||
|
}
|
||||||
|
sqlAppender.appendSql( ')' );
|
||||||
|
}
|
||||||
|
}
|
|
@ -4097,6 +4097,22 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
|
||||||
@Incubating
|
@Incubating
|
||||||
JpaExpression<String> xmlconcat(List<? extends Expression<?>> elements);
|
JpaExpression<String> xmlconcat(List<? extends Expression<?>> elements);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an XML processing with the given name.
|
||||||
|
*
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
@Incubating
|
||||||
|
JpaExpression<String> xmlpi(String elementName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an XML processing with the given name and content.
|
||||||
|
*
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
@Incubating
|
||||||
|
JpaExpression<String> xmlpi(String elementName, Expression<String> content);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a named expression. The name is important for the result of the expression,
|
* Creates a named expression. The name is important for the result of the expression,
|
||||||
* e.g. when building an {@code xmlforest}, the name acts as the XML element name.
|
* e.g. when building an {@code xmlforest}, the name acts as the XML element name.
|
||||||
|
|
|
@ -3669,6 +3669,18 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
|
||||||
return criteriaBuilder.xmlconcat( elements );
|
return criteriaBuilder.xmlconcat( elements );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Incubating
|
||||||
|
public JpaExpression<String> xmlpi(String elementName) {
|
||||||
|
return criteriaBuilder.xmlpi( elementName );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Incubating
|
||||||
|
public JpaExpression<String> xmlpi(String elementName, Expression<String> content) {
|
||||||
|
return criteriaBuilder.xmlpi( elementName, content );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Incubating
|
@Incubating
|
||||||
public <T> JpaExpression<T> named(Expression<T> expression, String name) {
|
public <T> JpaExpression<T> named(Expression<T> expression, String name) {
|
||||||
|
|
|
@ -3032,6 +3032,17 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
||||||
return creationContext.getNodeBuilder().xmlforest( elementExpressions );
|
return creationContext.getNodeBuilder().xmlforest( elementExpressions );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmExpression<?> visitXmlpiFunction(HqlParser.XmlpiFunctionContext ctx) {
|
||||||
|
checkXmlFunctionsEnabled( ctx );
|
||||||
|
final String name = visitIdentifier( ctx.identifier() );
|
||||||
|
final HqlParser.ExpressionContext exprCtx = ctx.expression();
|
||||||
|
//noinspection unchecked
|
||||||
|
return exprCtx == null
|
||||||
|
? creationContext.getNodeBuilder().xmlpi( name )
|
||||||
|
: creationContext.getNodeBuilder().xmlpi( name, (Expression<String>) exprCtx.accept( this ) );
|
||||||
|
}
|
||||||
|
|
||||||
private void checkXmlFunctionsEnabled(ParserRuleContext ctx) {
|
private void checkXmlFunctionsEnabled(ParserRuleContext ctx) {
|
||||||
if ( !creationOptions.isXmlFunctionsEnabled() ) {
|
if ( !creationOptions.isXmlFunctionsEnabled() ) {
|
||||||
throw new SemanticException(
|
throw new SemanticException(
|
||||||
|
|
|
@ -771,6 +771,12 @@ public interface NodeBuilder extends HibernateCriteriaBuilder, BindingContext {
|
||||||
@Override
|
@Override
|
||||||
SqmExpression<String> xmlconcat(List<? extends Expression<?>> elements);
|
SqmExpression<String> xmlconcat(List<? extends Expression<?>> elements);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
SqmExpression<String> xmlpi(String elementName);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
SqmExpression<String> xmlpi(String elementName, Expression<String> content);
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// Covariant overrides
|
// Covariant overrides
|
||||||
|
|
||||||
|
|
|
@ -5746,4 +5746,22 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, Serializable {
|
||||||
queryEngine
|
queryEngine
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmExpression<String> xmlpi(String elementName) {
|
||||||
|
return getFunctionDescriptor( "xmlpi" ).generateSqmExpression(
|
||||||
|
asList( literal( elementName ) ),
|
||||||
|
null,
|
||||||
|
queryEngine
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmExpression<String> xmlpi(String elementName, Expression<String> content) {
|
||||||
|
return getFunctionDescriptor( "xmlpi" ).generateSqmExpression(
|
||||||
|
asList( literal( elementName ), (SqmTypedNode<?>) content ),
|
||||||
|
null,
|
||||||
|
queryEngine
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.function.xml;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.QuerySettings;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christian Beikov
|
||||||
|
*/
|
||||||
|
@DomainModel
|
||||||
|
@SessionFactory
|
||||||
|
@ServiceRegistry(settings = @Setting(name = QuerySettings.XML_FUNCTIONS_ENABLED, value = "true"))
|
||||||
|
@RequiresDialectFeature( feature = DialectFeatureChecks.SupportsXmlpi.class)
|
||||||
|
public class XmlPiTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSimple(SessionFactoryScope scope) {
|
||||||
|
scope.inSession( em -> {
|
||||||
|
//tag::hql-xmlpi-example[]
|
||||||
|
em.createQuery( "select xmlpi(name php)" ).getResultList();
|
||||||
|
//end::hql-xmlpi-example[]
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testContent(SessionFactoryScope scope) {
|
||||||
|
scope.inSession( em -> {
|
||||||
|
//tag::hql-xmlpi-content-example[]
|
||||||
|
em.createQuery("select xmlpi(name `php`, 'echo \"test\"')" ).getResultList();
|
||||||
|
//end::hql-xmlpi-content-example[]
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -187,6 +187,20 @@ public class XmlFunctionTests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsXmlpi.class)
|
||||||
|
public void testXmlpi(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Tuple tuple = session.createQuery(
|
||||||
|
"select xmlpi(name test, 'abc')",
|
||||||
|
Tuple.class
|
||||||
|
).getSingleResult();
|
||||||
|
assertEquals( "<?test abc?>", tuple.get( 0, String.class ).trim() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private void assertXmlEquals(String expected, String actual) {
|
private void assertXmlEquals(String expected, String actual) {
|
||||||
final Document expectedDoc = parseXml( xmlNormalize( expected ) );
|
final Document expectedDoc = parseXml( xmlNormalize( expected ) );
|
||||||
final Document actualDoc = parseXml( xmlNormalize( actual ) );
|
final Document actualDoc = parseXml( xmlNormalize( actual ) );
|
||||||
|
|
|
@ -862,6 +862,12 @@ abstract public class DialectFeatureChecks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class SupportsXmlpi implements DialectFeatureCheck {
|
||||||
|
public boolean apply(Dialect dialect) {
|
||||||
|
return definesFunction( dialect, "xmlpi" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class IsJtds implements DialectFeatureCheck {
|
public static class IsJtds implements DialectFeatureCheck {
|
||||||
public boolean apply(Dialect dialect) {
|
public boolean apply(Dialect dialect) {
|
||||||
return dialect instanceof SybaseDialect && ( (SybaseDialect) dialect ).getDriverKind() == SybaseDriverKind.JTDS;
|
return dialect instanceof SybaseDialect && ( (SybaseDialect) dialect ).getDriverKind() == SybaseDriverKind.JTDS;
|
||||||
|
|
Loading…
Reference in New Issue