mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-27 22:39:13 +00:00
HHH-18497 Add xmlconcat function
This commit is contained in:
parent
1abfd4eea6
commit
a37ae66a2e
@ -2173,7 +2173,8 @@ it is necessary to enable the `hibernate.query.hql.xml_functions_enabled` config
|
|||||||
|
|
||||||
| `xmlelement()` | Constructs an XML element from arguments
|
| `xmlelement()` | Constructs an XML element from arguments
|
||||||
| `xmlcomment()` | Constructs an XML comment from the single argument
|
| `xmlcomment()` | Constructs an XML comment from the single argument
|
||||||
| `xmlforest()` | Constructs an XML forest from thearguments
|
| `xmlforest()` | Constructs an XML forest from the arguments
|
||||||
|
| `xmlconcat()` | Concatenates multiple XML fragments to each other
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
|
||||||
@ -2250,6 +2251,21 @@ include::{xml-example-dir-hql}/XmlForestTest.java[tags=hql-xmlforest-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-xmlconcat-function]]
|
||||||
|
===== `xmlconcat()`
|
||||||
|
|
||||||
|
Concatenates multiple XML fragments to each other.
|
||||||
|
|
||||||
|
[[hql-xmlconcat-example]]
|
||||||
|
====
|
||||||
|
[source, java, indent=0]
|
||||||
|
----
|
||||||
|
include::{xml-example-dir-hql}/XmlConcatTest.java[tags=hql-xmlconcat-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
|
||||||
|
|
||||||
|
@ -444,6 +444,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
|
|||||||
functionFactory.xmlelement();
|
functionFactory.xmlelement();
|
||||||
functionFactory.xmlcomment();
|
functionFactory.xmlcomment();
|
||||||
functionFactory.xmlforest();
|
functionFactory.xmlforest();
|
||||||
|
functionFactory.xmlconcat();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -421,6 +421,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
|
|||||||
functionFactory.xmlelement_h2();
|
functionFactory.xmlelement_h2();
|
||||||
functionFactory.xmlcomment();
|
functionFactory.xmlcomment();
|
||||||
functionFactory.xmlforest_h2();
|
functionFactory.xmlforest_h2();
|
||||||
|
functionFactory.xmlconcat_h2();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
functionFactory.listagg_groupConcat();
|
functionFactory.listagg_groupConcat();
|
||||||
|
@ -329,6 +329,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
|
|||||||
functionFactory.xmlelement();
|
functionFactory.xmlelement();
|
||||||
functionFactory.xmlcomment();
|
functionFactory.xmlcomment();
|
||||||
functionFactory.xmlforest();
|
functionFactory.xmlforest();
|
||||||
|
functionFactory.xmlconcat();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -672,6 +672,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
|
|||||||
functionFactory.xmlelement();
|
functionFactory.xmlelement();
|
||||||
functionFactory.xmlcomment();
|
functionFactory.xmlcomment();
|
||||||
functionFactory.xmlforest();
|
functionFactory.xmlforest();
|
||||||
|
functionFactory.xmlconcat();
|
||||||
|
|
||||||
if ( getVersion().isSameOrAfter( 9, 4 ) ) {
|
if ( getVersion().isSameOrAfter( 9, 4 ) ) {
|
||||||
functionFactory.makeDateTimeTimestamp();
|
functionFactory.makeDateTimeTimestamp();
|
||||||
|
@ -416,6 +416,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
|
|||||||
functionFactory.xmlelement_sqlserver();
|
functionFactory.xmlelement_sqlserver();
|
||||||
functionFactory.xmlcomment_sqlserver();
|
functionFactory.xmlcomment_sqlserver();
|
||||||
functionFactory.xmlforest_sqlserver();
|
functionFactory.xmlforest_sqlserver();
|
||||||
|
functionFactory.xmlconcat_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 ) );
|
||||||
|
@ -429,6 +429,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
|
|||||||
functionFactory.xmlelement();
|
functionFactory.xmlelement();
|
||||||
functionFactory.xmlcomment();
|
functionFactory.xmlcomment();
|
||||||
functionFactory.xmlforest();
|
functionFactory.xmlforest();
|
||||||
|
functionFactory.xmlconcat();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -356,6 +356,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
|
|||||||
functionFactory.xmlelement_h2();
|
functionFactory.xmlelement_h2();
|
||||||
functionFactory.xmlcomment();
|
functionFactory.xmlcomment();
|
||||||
functionFactory.xmlforest_h2();
|
functionFactory.xmlforest_h2();
|
||||||
|
functionFactory.xmlconcat_h2();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -419,6 +419,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
|
|||||||
functionFactory.xmlelement();
|
functionFactory.xmlelement();
|
||||||
functionFactory.xmlcomment();
|
functionFactory.xmlcomment();
|
||||||
functionFactory.xmlforest();
|
functionFactory.xmlforest();
|
||||||
|
functionFactory.xmlconcat();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -633,6 +633,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
|
|||||||
functionFactory.xmlelement();
|
functionFactory.xmlelement();
|
||||||
functionFactory.xmlcomment();
|
functionFactory.xmlcomment();
|
||||||
functionFactory.xmlforest();
|
functionFactory.xmlforest();
|
||||||
|
functionFactory.xmlconcat();
|
||||||
|
|
||||||
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
|
||||||
|
@ -434,6 +434,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
|
|||||||
functionFactory.xmlelement_sqlserver();
|
functionFactory.xmlelement_sqlserver();
|
||||||
functionFactory.xmlcomment_sqlserver();
|
functionFactory.xmlcomment_sqlserver();
|
||||||
functionFactory.xmlforest_sqlserver();
|
functionFactory.xmlforest_sqlserver();
|
||||||
|
functionFactory.xmlconcat_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 ) );
|
||||||
|
@ -153,10 +153,13 @@
|
|||||||
import org.hibernate.dialect.function.json.SQLServerJsonReplaceFunction;
|
import org.hibernate.dialect.function.json.SQLServerJsonReplaceFunction;
|
||||||
import org.hibernate.dialect.function.json.SQLServerJsonSetFunction;
|
import org.hibernate.dialect.function.json.SQLServerJsonSetFunction;
|
||||||
import org.hibernate.dialect.function.json.SQLServerJsonValueFunction;
|
import org.hibernate.dialect.function.json.SQLServerJsonValueFunction;
|
||||||
|
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.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.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.query.sqm.function.SqmFunctionRegistry;
|
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||||
@ -4167,4 +4170,25 @@ public void xmlforest_h2() {
|
|||||||
public void xmlforest_sqlserver() {
|
public void xmlforest_sqlserver() {
|
||||||
functionRegistry.register( "xmlforest", new SQLServerXmlForestFunction( typeConfiguration ) );
|
functionRegistry.register( "xmlforest", new SQLServerXmlForestFunction( typeConfiguration ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard xmlconcat() function
|
||||||
|
*/
|
||||||
|
public void xmlconcat() {
|
||||||
|
functionRegistry.register( "xmlconcat", new XmlConcatFunction( typeConfiguration ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* H2 xmlconcat() function
|
||||||
|
*/
|
||||||
|
public void xmlconcat_h2() {
|
||||||
|
functionRegistry.register( "xmlconcat", new H2XmlConcatFunction( typeConfiguration ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL Server xmlconcat() function
|
||||||
|
*/
|
||||||
|
public void xmlconcat_sqlserver() {
|
||||||
|
functionRegistry.register( "xmlconcat", new SQLServerXmlConcatFunction( typeConfiguration ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* H2 xmlconcat function.
|
||||||
|
*/
|
||||||
|
public class H2XmlConcatFunction extends XmlConcatFunction {
|
||||||
|
|
||||||
|
public H2XmlConcatFunction(TypeConfiguration typeConfiguration) {
|
||||||
|
super( typeConfiguration );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(
|
||||||
|
SqlAppender sqlAppender,
|
||||||
|
List<? extends SqlAstNode> sqlAstArguments,
|
||||||
|
ReturnableType<?> returnType,
|
||||||
|
SqlAstTranslator<?> walker) {
|
||||||
|
String separator = "";
|
||||||
|
sqlAppender.appendSql( '(' );
|
||||||
|
for ( SqlAstNode sqlAstArgument : sqlAstArguments ) {
|
||||||
|
sqlAppender.appendSql( separator );
|
||||||
|
sqlAstArgument.accept( walker );
|
||||||
|
separator = "||";
|
||||||
|
}
|
||||||
|
sqlAppender.appendSql( ')' );
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL Server xmlconcat function.
|
||||||
|
*/
|
||||||
|
public class SQLServerXmlConcatFunction extends XmlConcatFunction {
|
||||||
|
|
||||||
|
public SQLServerXmlConcatFunction(TypeConfiguration typeConfiguration) {
|
||||||
|
super( typeConfiguration );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(
|
||||||
|
SqlAppender sqlAppender,
|
||||||
|
List<? extends SqlAstNode> sqlAstArguments,
|
||||||
|
ReturnableType<?> returnType,
|
||||||
|
SqlAstTranslator<?> walker) {
|
||||||
|
sqlAppender.appendSql( "cast" );
|
||||||
|
char separator = '(';
|
||||||
|
for ( SqlAstNode sqlAstArgument : sqlAstArguments ) {
|
||||||
|
sqlAppender.appendSql( separator );
|
||||||
|
sqlAppender.appendSql( "cast(" );
|
||||||
|
sqlAstArgument.accept( walker );
|
||||||
|
sqlAppender.appendSql( " as nvarchar(max))" );
|
||||||
|
separator = '+';
|
||||||
|
}
|
||||||
|
sqlAppender.appendSql( " as xml)" );
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* 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.type.SqlTypes;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
|
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.XML;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard XmlConcatFunction function.
|
||||||
|
*/
|
||||||
|
public class XmlConcatFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||||
|
|
||||||
|
public XmlConcatFunction(TypeConfiguration typeConfiguration) {
|
||||||
|
super(
|
||||||
|
"xmlconcat",
|
||||||
|
FunctionKind.NORMAL,
|
||||||
|
StandardArgumentsValidators.composite(
|
||||||
|
new ArgumentTypesValidator( StandardArgumentsValidators.min( 1 ), XML )
|
||||||
|
),
|
||||||
|
StandardFunctionReturnTypeResolvers.invariant(
|
||||||
|
typeConfiguration.getBasicTypeRegistry().resolve( String.class, SqlTypes.SQLXML )
|
||||||
|
),
|
||||||
|
StandardFunctionArgumentTypeResolvers.impliedOrInvariant( typeConfiguration, XML )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(
|
||||||
|
SqlAppender sqlAppender,
|
||||||
|
List<? extends SqlAstNode> sqlAstArguments,
|
||||||
|
ReturnableType<?> returnType,
|
||||||
|
SqlAstTranslator<?> walker) {
|
||||||
|
sqlAppender.appendSql( "xmlconcat" );
|
||||||
|
char separator = '(';
|
||||||
|
for ( SqlAstNode sqlAstArgument : sqlAstArguments ) {
|
||||||
|
sqlAppender.appendSql( separator );
|
||||||
|
sqlAstArgument.accept( walker );
|
||||||
|
separator = ',';
|
||||||
|
}
|
||||||
|
sqlAppender.appendSql( ')' );
|
||||||
|
}
|
||||||
|
}
|
@ -4067,6 +4067,7 @@ default <E> JpaPredicate collectionOverlapsNullable(Collection<E> collection1, E
|
|||||||
* Creates an XML forest from the given XML element expressions.
|
* Creates an XML forest from the given XML element expressions.
|
||||||
*
|
*
|
||||||
* @since 7.0
|
* @since 7.0
|
||||||
|
* @see #named(Expression, String)
|
||||||
*/
|
*/
|
||||||
@Incubating
|
@Incubating
|
||||||
JpaExpression<String> xmlforest(Expression<?>... elements);
|
JpaExpression<String> xmlforest(Expression<?>... elements);
|
||||||
@ -4075,10 +4076,27 @@ default <E> JpaPredicate collectionOverlapsNullable(Collection<E> collection1, E
|
|||||||
* Creates an XML forest from the given XML element expressions.
|
* Creates an XML forest from the given XML element expressions.
|
||||||
*
|
*
|
||||||
* @since 7.0
|
* @since 7.0
|
||||||
|
* @see #named(Expression, String)
|
||||||
*/
|
*/
|
||||||
@Incubating
|
@Incubating
|
||||||
JpaExpression<String> xmlforest(List<? extends Expression<?>> elements);
|
JpaExpression<String> xmlforest(List<? extends Expression<?>> elements);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concatenates the given XML element expressions.
|
||||||
|
*
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
@Incubating
|
||||||
|
JpaExpression<String> xmlconcat(Expression<?>... elements);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concatenates the given XML element expressions.
|
||||||
|
*
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
@Incubating
|
||||||
|
JpaExpression<String> xmlconcat(List<? extends Expression<?>> elements);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
|
@ -3657,6 +3657,18 @@ public JpaExpression<String> xmlforest(List<? extends Expression<?>> elements) {
|
|||||||
return criteriaBuilder.xmlforest( elements );
|
return criteriaBuilder.xmlforest( elements );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Incubating
|
||||||
|
public JpaExpression<String> xmlconcat(Expression<?>... elements) {
|
||||||
|
return criteriaBuilder.xmlconcat( elements );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Incubating
|
||||||
|
public JpaExpression<String> xmlconcat(List<? extends Expression<?>> elements) {
|
||||||
|
return criteriaBuilder.xmlconcat( elements );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Incubating
|
@Incubating
|
||||||
public <T> JpaExpression<T> named(Expression<T> expression, String name) {
|
public <T> JpaExpression<T> named(Expression<T> expression, String name) {
|
||||||
|
@ -765,6 +765,12 @@ <T> SqmJsonValueExpression<T> jsonValue(
|
|||||||
@Override
|
@Override
|
||||||
SqmExpression<String> xmlforest(Expression<?>... elements);
|
SqmExpression<String> xmlforest(Expression<?>... elements);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
SqmExpression<String> xmlconcat(Expression<?>... elements);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
SqmExpression<String> xmlconcat(List<? extends Expression<?>> elements);
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// Covariant overrides
|
// Covariant overrides
|
||||||
|
|
||||||
|
@ -5732,4 +5732,18 @@ public SqmExpression<String> xmlforest(List<? extends Expression<?>> elements) {
|
|||||||
queryEngine
|
queryEngine
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmExpression<String> xmlconcat(Expression<?>... elements) {
|
||||||
|
return xmlconcat( Arrays.asList( elements ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmExpression<String> xmlconcat(List<? extends Expression<?>> elements) {
|
||||||
|
return getFunctionDescriptor( "xmlforest" ).generateSqmExpression(
|
||||||
|
(List<? extends SqmTypedNode<?>>) elements,
|
||||||
|
null,
|
||||||
|
queryEngine
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,6 +251,8 @@ private static boolean isCompatible(FunctionParameterType type, JdbcType jdbcTyp
|
|||||||
case SPATIAL -> jdbcType.isSpatial();
|
case SPATIAL -> jdbcType.isSpatial();
|
||||||
case JSON -> jdbcType.isJson();
|
case JSON -> jdbcType.isJson();
|
||||||
case IMPLICIT_JSON -> jdbcType.isImplicitJson();
|
case IMPLICIT_JSON -> jdbcType.isImplicitJson();
|
||||||
|
case XML -> jdbcType.isXml();
|
||||||
|
case IMPLICIT_XML -> jdbcType.isImplicitXml();
|
||||||
default -> true; // TODO: should we throw here?
|
default -> true; // TODO: should we throw here?
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,18 @@ public enum FunctionParameterType {
|
|||||||
* @since 7.0
|
* @since 7.0
|
||||||
*/
|
*/
|
||||||
IMPLICIT_JSON,
|
IMPLICIT_JSON,
|
||||||
|
/**
|
||||||
|
* Indicates that the argument should be a XML type
|
||||||
|
* @see org.hibernate.type.SqlTypes#isXmlType(int)
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
XML,
|
||||||
|
/**
|
||||||
|
* Indicates that the argument should be a XML or String type
|
||||||
|
* @see org.hibernate.type.SqlTypes#isImplicitXmlType(int)
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
IMPLICIT_XML,
|
||||||
/**
|
/**
|
||||||
* Indicates a parameter that accepts any type, except untyped expressions like {@code null} literals
|
* Indicates a parameter that accepts any type, except untyped expressions like {@code null} literals
|
||||||
*/
|
*/
|
||||||
|
@ -1021,4 +1021,36 @@ public static boolean isImplicitJsonType(int typeCode) {
|
|||||||
return isCharacterOrClobType( typeCode );
|
return isCharacterOrClobType( typeCode );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the typecode represent a XML type.
|
||||||
|
*
|
||||||
|
* @param typeCode - a JDBC type code
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
public static boolean isXmlType(int typeCode) {
|
||||||
|
switch ( typeCode ) {
|
||||||
|
case SQLXML:
|
||||||
|
case XML_ARRAY:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the typecode represent an XML type or a type that can be implicitly cast to XML.
|
||||||
|
*
|
||||||
|
* @param typeCode - a JDBC type code
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
public static boolean isImplicitXmlType(int typeCode) {
|
||||||
|
switch ( typeCode ) {
|
||||||
|
case SQLXML:
|
||||||
|
case XML_ARRAY:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return isCharacterOrClobType( typeCode );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -435,6 +435,16 @@ default boolean isImplicitJson() {
|
|||||||
return isImplicitJsonType( getDefaultSqlTypeCode() );
|
return isImplicitJsonType( getDefaultSqlTypeCode() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Incubating
|
||||||
|
default boolean isXml() {
|
||||||
|
return isXmlType( getDefaultSqlTypeCode() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Incubating
|
||||||
|
default boolean isImplicitXml() {
|
||||||
|
return isImplicitXmlType( getDefaultSqlTypeCode() );
|
||||||
|
}
|
||||||
|
|
||||||
@Incubating
|
@Incubating
|
||||||
default boolean isBoolean() {
|
default boolean isBoolean() {
|
||||||
return getDefaultSqlTypeCode() == BOOLEAN;
|
return getDefaultSqlTypeCode() == BOOLEAN;
|
||||||
|
@ -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.SupportsXmlconcat.class)
|
||||||
|
public class XmlConcatTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSimple(SessionFactoryScope scope) {
|
||||||
|
scope.inSession( em -> {
|
||||||
|
//tag::hql-xmlconcat-example[]
|
||||||
|
em.createQuery( "select xmlconcat(xmlelement(name e1, 123), xmlelement(name e2, 'text'))" ).getResultList();
|
||||||
|
//end::hql-xmlconcat-example[]
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -170,6 +170,23 @@ public void testXmlforest(SessionFactoryScope scope) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsXmlconcat.class)
|
||||||
|
public void testXmlconcat(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Tuple tuple = session.createQuery(
|
||||||
|
"select xmlconcat(xmlelement(name e1, 123), xmlelement(name e2, 'text'))," +
|
||||||
|
"xmlconcat(xmlelement(name id, e.id), xmlelement(name theString, e.theString)) " +
|
||||||
|
"from EntityOfBasics e where e.id = 1",
|
||||||
|
Tuple.class
|
||||||
|
).getSingleResult();
|
||||||
|
assertXmlEquals( "<r><e1>123</e1><e2>text</e2></r>", "<r>" + tuple.get( 0, String.class ) + "</r>" );
|
||||||
|
assertXmlEquals( "<r><id>1</id><theString>Dog</theString></r>", "<r>" + tuple.get( 1, String.class ) + "</r>" );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
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 ) );
|
||||||
|
@ -856,6 +856,12 @@ public boolean apply(Dialect dialect) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class SupportsXmlconcat implements DialectFeatureCheck {
|
||||||
|
public boolean apply(Dialect dialect) {
|
||||||
|
return definesFunction( dialect, "xmlconcat" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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…
x
Reference in New Issue
Block a user