HHH-18497 Add xmlexists function
This commit is contained in:
parent
449d002563
commit
af09813ced
|
@ -2177,6 +2177,7 @@ it is necessary to enable the `hibernate.query.hql.xml_functions_enabled` config
|
||||||
| `xmlconcat()` | Concatenates multiple XML fragments to each other
|
| `xmlconcat()` | Concatenates multiple XML fragments to each other
|
||||||
| `xmlpi()` | Constructs an XML processing instruction
|
| `xmlpi()` | Constructs an XML processing instruction
|
||||||
| `xmlquery()` | Extracts content from XML document using XQuery or XPath
|
| `xmlquery()` | Extracts content from XML document using XQuery or XPath
|
||||||
|
| `xmlexists()` | Checks if an XQuery or XPath expression exists in an XML document
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
@ -2325,6 +2326,30 @@ include::{xml-example-dir-hql}/XmlQueryTest.java[tags=hql-xmlquery-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-xmlexists-function]]
|
||||||
|
===== `xmlexists()`
|
||||||
|
|
||||||
|
Checks if an XQuery or XPath expression exists in an XML document.
|
||||||
|
|
||||||
|
[[hql-xmlexists-bnf]]
|
||||||
|
[source, antlrv4, indent=0]
|
||||||
|
----
|
||||||
|
include::{extrasdir}/xmlexists_bnf.txt[]
|
||||||
|
----
|
||||||
|
|
||||||
|
The first argument represents the XQuery or XPath expression.
|
||||||
|
The second argument after the `passing` keyword represents the XML document.
|
||||||
|
|
||||||
|
[[hql-xmlexists-example]]
|
||||||
|
====
|
||||||
|
[source, java, indent=0]
|
||||||
|
----
|
||||||
|
include::{xml-example-dir-hql}/XmlExistsTest.java[tags=hql-xmlexists-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 @@
|
||||||
|
"xmlexists(" expression "passing" expression ")"
|
|
@ -447,6 +447,7 @@ public class DB2LegacyDialect extends Dialect {
|
||||||
functionFactory.xmlconcat();
|
functionFactory.xmlconcat();
|
||||||
functionFactory.xmlpi();
|
functionFactory.xmlpi();
|
||||||
functionFactory.xmlquery_db2();
|
functionFactory.xmlquery_db2();
|
||||||
|
functionFactory.xmlexists();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -332,6 +332,7 @@ public class OracleLegacyDialect extends Dialect {
|
||||||
functionFactory.xmlconcat();
|
functionFactory.xmlconcat();
|
||||||
functionFactory.xmlpi();
|
functionFactory.xmlpi();
|
||||||
functionFactory.xmlquery_oracle();
|
functionFactory.xmlquery_oracle();
|
||||||
|
functionFactory.xmlexists();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -675,6 +675,7 @@ public class PostgreSQLLegacyDialect extends Dialect {
|
||||||
functionFactory.xmlconcat();
|
functionFactory.xmlconcat();
|
||||||
functionFactory.xmlpi();
|
functionFactory.xmlpi();
|
||||||
functionFactory.xmlquery_postgresql();
|
functionFactory.xmlquery_postgresql();
|
||||||
|
functionFactory.xmlexists();
|
||||||
|
|
||||||
if ( getVersion().isSameOrAfter( 9, 4 ) ) {
|
if ( getVersion().isSameOrAfter( 9, 4 ) ) {
|
||||||
functionFactory.makeDateTimeTimestamp();
|
functionFactory.makeDateTimeTimestamp();
|
||||||
|
|
|
@ -419,6 +419,7 @@ public class SQLServerLegacyDialect extends AbstractTransactSQLDialect {
|
||||||
functionFactory.xmlconcat_sqlserver();
|
functionFactory.xmlconcat_sqlserver();
|
||||||
functionFactory.xmlpi_sqlserver();
|
functionFactory.xmlpi_sqlserver();
|
||||||
functionFactory.xmlquery_sqlserver();
|
functionFactory.xmlquery_sqlserver();
|
||||||
|
functionFactory.xmlexists_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 ) );
|
||||||
|
|
|
@ -332,6 +332,7 @@ WITHOUT : [wW] [iI] [tT] [hH] [oO] [uU] [tT];
|
||||||
WRAPPER : [wW] [rR] [aA] [pP] [pP] [eE] [rR];
|
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];
|
||||||
|
XMLEXISTS : [xX] [mM] [lL] [eE] [xX] [iI] [sS] [tT] [sS];
|
||||||
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];
|
XMLPI : [xX] [mM] [lL] [pP] [iI];
|
||||||
XMLQUERY : [xX] [mM] [lL] [qQ] [uU] [eE] [rR] [yY];
|
XMLQUERY : [xX] [mM] [lL] [qQ] [uU] [eE] [rR] [yY];
|
||||||
|
|
|
@ -1722,6 +1722,7 @@ xmlFunction
|
||||||
| xmlforestFunction
|
| xmlforestFunction
|
||||||
| xmlpiFunction
|
| xmlpiFunction
|
||||||
| xmlqueryFunction
|
| xmlqueryFunction
|
||||||
|
| xmlexistsFunction
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1759,6 +1760,13 @@ xmlqueryFunction
|
||||||
: XMLQUERY LEFT_PAREN expression PASSING expression RIGHT_PAREN
|
: XMLQUERY LEFT_PAREN expression PASSING expression RIGHT_PAREN
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The 'xmlexists()' function
|
||||||
|
*/
|
||||||
|
xmlexistsFunction
|
||||||
|
: XMLEXISTS LEFT_PAREN expression PASSING expression RIGHT_PAREN
|
||||||
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Support for "soft" keywords which may be used as identifiers
|
* Support for "soft" keywords which may be used as identifiers
|
||||||
*
|
*
|
||||||
|
@ -1967,6 +1975,7 @@ xmlqueryFunction
|
||||||
| WRAPPER
|
| WRAPPER
|
||||||
| XMLATTRIBUTES
|
| XMLATTRIBUTES
|
||||||
| XMLELEMENT
|
| XMLELEMENT
|
||||||
|
| XMLEXISTS
|
||||||
| XMLFOREST
|
| XMLFOREST
|
||||||
| XMLPI
|
| XMLPI
|
||||||
| XMLQUERY
|
| XMLQUERY
|
||||||
|
|
|
@ -432,6 +432,7 @@ public class DB2Dialect extends Dialect {
|
||||||
functionFactory.xmlconcat();
|
functionFactory.xmlconcat();
|
||||||
functionFactory.xmlpi();
|
functionFactory.xmlpi();
|
||||||
functionFactory.xmlquery_db2();
|
functionFactory.xmlquery_db2();
|
||||||
|
functionFactory.xmlexists();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -422,6 +422,7 @@ public class OracleDialect extends Dialect {
|
||||||
functionFactory.xmlconcat();
|
functionFactory.xmlconcat();
|
||||||
functionFactory.xmlpi();
|
functionFactory.xmlpi();
|
||||||
functionFactory.xmlquery_oracle();
|
functionFactory.xmlquery_oracle();
|
||||||
|
functionFactory.xmlexists();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -636,6 +636,7 @@ public class PostgreSQLDialect extends Dialect {
|
||||||
functionFactory.xmlconcat();
|
functionFactory.xmlconcat();
|
||||||
functionFactory.xmlpi();
|
functionFactory.xmlpi();
|
||||||
functionFactory.xmlquery_postgresql();
|
functionFactory.xmlquery_postgresql();
|
||||||
|
functionFactory.xmlexists();
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -437,6 +437,7 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
||||||
functionFactory.xmlconcat_sqlserver();
|
functionFactory.xmlconcat_sqlserver();
|
||||||
functionFactory.xmlpi_sqlserver();
|
functionFactory.xmlpi_sqlserver();
|
||||||
functionFactory.xmlquery_sqlserver();
|
functionFactory.xmlquery_sqlserver();
|
||||||
|
functionFactory.xmlexists_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 ) );
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* 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.dialect.function.json.ExpressionTypeHelper;
|
||||||
|
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.Expression;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL Server xmlexists function.
|
||||||
|
*/
|
||||||
|
public class SQLServerXmlExistsFunction extends XmlExistsFunction {
|
||||||
|
|
||||||
|
public SQLServerXmlExistsFunction(TypeConfiguration typeConfiguration) {
|
||||||
|
super( typeConfiguration );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(
|
||||||
|
SqlAppender sqlAppender,
|
||||||
|
List<? extends SqlAstNode> sqlAstArguments,
|
||||||
|
ReturnableType<?> returnType,
|
||||||
|
SqlAstTranslator<?> walker) {
|
||||||
|
final Expression xmlDocument = (Expression) sqlAstArguments.get( 1 );
|
||||||
|
final boolean needsCast = !ExpressionTypeHelper.isXml( xmlDocument );
|
||||||
|
sqlAppender.appendSql( '(' );
|
||||||
|
if ( needsCast ) {
|
||||||
|
sqlAppender.appendSql( "cast(" );
|
||||||
|
}
|
||||||
|
sqlAstArguments.get( 1 ).accept( walker );
|
||||||
|
if ( needsCast ) {
|
||||||
|
sqlAppender.appendSql( " as xml)" );
|
||||||
|
}
|
||||||
|
sqlAppender.appendSql( ".exist(" );
|
||||||
|
sqlAstArguments.get( 0 ).accept( walker );
|
||||||
|
sqlAppender.appendSql( ")=1)" );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* 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.dialect.function.json.ExpressionTypeHelper;
|
||||||
|
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.Expression;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
|
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.IMPLICIT_XML;
|
||||||
|
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.STRING;
|
||||||
|
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.XML;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard xmlexists function.
|
||||||
|
*/
|
||||||
|
public class XmlExistsFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||||
|
|
||||||
|
public XmlExistsFunction(TypeConfiguration typeConfiguration) {
|
||||||
|
super(
|
||||||
|
"xmlexists",
|
||||||
|
FunctionKind.NORMAL,
|
||||||
|
StandardArgumentsValidators.composite(
|
||||||
|
new ArgumentTypesValidator( null, STRING, IMPLICIT_XML )
|
||||||
|
),
|
||||||
|
StandardFunctionReturnTypeResolvers.invariant(
|
||||||
|
typeConfiguration.getBasicTypeRegistry().getRegisteredType( Boolean.class )
|
||||||
|
),
|
||||||
|
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, STRING, XML )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPredicate() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(
|
||||||
|
SqlAppender sqlAppender,
|
||||||
|
List<? extends SqlAstNode> sqlAstArguments,
|
||||||
|
ReturnableType<?> returnType,
|
||||||
|
SqlAstTranslator<?> walker) {
|
||||||
|
final Expression xmlDocument = (Expression) sqlAstArguments.get( 1 );
|
||||||
|
final boolean needsCast = !ExpressionTypeHelper.isXml( xmlDocument );
|
||||||
|
sqlAppender.appendSql( "xmlexists(" );
|
||||||
|
sqlAstArguments.get( 0 ).accept( walker );
|
||||||
|
sqlAppender.appendSql( " passing " );
|
||||||
|
if ( needsCast ) {
|
||||||
|
sqlAppender.appendSql( "xmlparse(document " );
|
||||||
|
}
|
||||||
|
sqlAstArguments.get( 1 ).accept( walker );
|
||||||
|
if ( needsCast ) {
|
||||||
|
sqlAppender.appendSql( ')' );
|
||||||
|
}
|
||||||
|
sqlAppender.appendSql( ')' );
|
||||||
|
}
|
||||||
|
}
|
|
@ -4129,6 +4129,22 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
|
||||||
@Incubating
|
@Incubating
|
||||||
JpaExpression<String> xmlquery(Expression<String> query, Expression<?> xmlDocument);
|
JpaExpression<String> xmlquery(Expression<String> query, Expression<?> xmlDocument);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given XPath or XQuery query exists in the given XML document.
|
||||||
|
*
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
@Incubating
|
||||||
|
JpaExpression<Boolean> xmlexists(String query, Expression<?> xmlDocument);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given XPath or XQuery query exists in the given XML document.
|
||||||
|
*
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
@Incubating
|
||||||
|
JpaExpression<Boolean> xmlexists(Expression<String> query, Expression<?> xmlDocument);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
|
|
|
@ -3693,6 +3693,18 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
|
||||||
return criteriaBuilder.xmlquery( query, xmlDocument );
|
return criteriaBuilder.xmlquery( query, xmlDocument );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Incubating
|
||||||
|
public JpaExpression<Boolean> xmlexists(String query, Expression<?> xmlDocument) {
|
||||||
|
return criteriaBuilder.xmlexists( query, xmlDocument );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Incubating
|
||||||
|
public JpaExpression<Boolean> xmlexists(Expression<String> query, Expression<?> xmlDocument) {
|
||||||
|
return criteriaBuilder.xmlexists( query, xmlDocument );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Incubating
|
@Incubating
|
||||||
public <T> JpaExpression<T> named(Expression<T> expression, String name) {
|
public <T> JpaExpression<T> named(Expression<T> expression, String name) {
|
||||||
|
|
|
@ -3051,6 +3051,14 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
||||||
return creationContext.getNodeBuilder().xmlquery( query, xmlDocument );
|
return creationContext.getNodeBuilder().xmlquery( query, xmlDocument );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmExpression<?> visitXmlexistsFunction(HqlParser.XmlexistsFunctionContext ctx) {
|
||||||
|
checkXmlFunctionsEnabled( ctx );
|
||||||
|
final SqmExpression<String> query = (SqmExpression<String>) ctx.expression( 0 ).accept( this );
|
||||||
|
final SqmExpression<?> xmlDocument = (SqmExpression<?>) ctx.expression( 1 ).accept( this );
|
||||||
|
return creationContext.getNodeBuilder().xmlexists( query, xmlDocument );
|
||||||
|
}
|
||||||
|
|
||||||
private void checkXmlFunctionsEnabled(ParserRuleContext ctx) {
|
private void checkXmlFunctionsEnabled(ParserRuleContext ctx) {
|
||||||
if ( !creationOptions.isXmlFunctionsEnabled() ) {
|
if ( !creationOptions.isXmlFunctionsEnabled() ) {
|
||||||
throw new SemanticException(
|
throw new SemanticException(
|
||||||
|
|
|
@ -783,6 +783,12 @@ public interface NodeBuilder extends HibernateCriteriaBuilder, BindingContext {
|
||||||
@Override
|
@Override
|
||||||
SqmExpression<String> xmlquery(Expression<String> query, Expression<?> xmlDocument);
|
SqmExpression<String> xmlquery(Expression<String> query, Expression<?> xmlDocument);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
SqmExpression<Boolean> xmlexists(String query, Expression<?> xmlDocument);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
SqmExpression<Boolean> xmlexists(Expression<String> query, Expression<?> xmlDocument);
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// Covariant overrides
|
// Covariant overrides
|
||||||
|
|
||||||
|
|
|
@ -5778,4 +5778,18 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, Serializable {
|
||||||
queryEngine
|
queryEngine
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmExpression<Boolean> xmlexists(String query, Expression<?> xmlDocument) {
|
||||||
|
return xmlexists( value( query ), xmlDocument );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmExpression<Boolean> xmlexists(Expression<String> query, Expression<?> xmlDocument) {
|
||||||
|
return getFunctionDescriptor( "xmlexists" ).generateSqmExpression(
|
||||||
|
asList( (SqmTypedNode<?>) query, (SqmTypedNode<?>) xmlDocument ),
|
||||||
|
null,
|
||||||
|
queryEngine
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* 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.SupportsXmlexists.class)
|
||||||
|
public class XmlExistsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSimple(SessionFactoryScope scope) {
|
||||||
|
scope.inSession( em -> {
|
||||||
|
//tag::hql-xmlexists-example[]
|
||||||
|
em.createQuery( "select xmlexists('/a/val' passing '<a><val>asd</val></a>')" ).getResultList();
|
||||||
|
//end::hql-xmlexists-example[]
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -49,6 +49,7 @@ import org.xml.sax.InputSource;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
@DomainModel( annotatedClasses = {
|
@DomainModel( annotatedClasses = {
|
||||||
XmlFunctionTests.XmlHolder.class,
|
XmlFunctionTests.XmlHolder.class,
|
||||||
|
@ -215,6 +216,20 @@ public class XmlFunctionTests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsXmlexists.class)
|
||||||
|
public void testXmlexists(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Tuple tuple = session.createQuery(
|
||||||
|
"select xmlexists('/a/val' passing '<a><val>asd</val></a>')",
|
||||||
|
Tuple.class
|
||||||
|
).getSingleResult();
|
||||||
|
assertTrue( tuple.get( 0, Boolean.class ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
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 ) );
|
||||||
|
|
|
@ -874,6 +874,12 @@ abstract public class DialectFeatureChecks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class SupportsXmlexists implements DialectFeatureCheck {
|
||||||
|
public boolean apply(Dialect dialect) {
|
||||||
|
return definesFunction( dialect, "xmlexists" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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