HHH-17335 Add array_prepend and array_append functions
This commit is contained in:
parent
24fa18f954
commit
ae3c88ab66
|
@ -1123,6 +1123,8 @@ The following functions deal with SQL array types, which are not supported on ev
|
|||
| `array_position()` | Determines the position of an element in an array
|
||||
| `array_length()` | Determines the length of an array
|
||||
| `array_concat()` | Concatenates array with each other in order
|
||||
| `array_prepend()` | Prepends element to array
|
||||
| `array_append()` | Appends element to array
|
||||
| `array_contains_all()` | Determines if one array holds all elements of another array
|
||||
| `array_contains_all_nullable()` | Determines if one array holds all elements of another array, supporting null elements
|
||||
| `array_contains_any()` | Determines if one array holds at least one element of another array
|
||||
|
@ -1204,6 +1206,32 @@ include::{array-example-dir-hql}/ArrayConcatTest.java[tags=hql-array-concat-exam
|
|||
----
|
||||
====
|
||||
|
||||
[[hql-array-prepend-functions]]
|
||||
===== `array_prepend()`
|
||||
|
||||
Prepends element to array. Returns `null` if the array argument is `null`.
|
||||
|
||||
[[hql-array-prepend-example]]
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{array-example-dir-hql}/ArrayPrependTest.java[tags=hql-array-prepend-example]
|
||||
----
|
||||
====
|
||||
|
||||
[[hql-array-append-functions]]
|
||||
===== `array_append()`
|
||||
|
||||
Appends element to array. Returns `null` if the array argument is `null`.
|
||||
|
||||
[[hql-array-append-example]]
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{array-example-dir-hql}/ArrayAppendTest.java[tags=hql-array-append-example]
|
||||
----
|
||||
====
|
||||
|
||||
[[hql-array-contains-quantified-functions]]
|
||||
===== `array_contains_all()` and `array_contains_any()`
|
||||
|
||||
|
|
|
@ -468,6 +468,8 @@ public class CockroachLegacyDialect extends Dialect {
|
|||
functionFactory.arrayPosition_postgresql();
|
||||
functionFactory.arrayLength_cardinality();
|
||||
functionFactory.arrayConcat_postgresql();
|
||||
functionFactory.arrayPrepend_postgresql();
|
||||
functionFactory.arrayAppend_postgresql();
|
||||
functionFactory.arrayContainsAll_operator();
|
||||
functionFactory.arrayContainsAny_operator();
|
||||
functionFactory.arrayContainsAllNullable_operator();
|
||||
|
|
|
@ -376,6 +376,8 @@ public class H2LegacyDialect extends Dialect {
|
|||
functionFactory.arrayContainsNull();
|
||||
functionFactory.arrayLength_cardinality();
|
||||
functionFactory.arrayConcat_operator();
|
||||
functionFactory.arrayPrepend_operator();
|
||||
functionFactory.arrayAppend_operator();
|
||||
functionFactory.arrayContainsAll_h2();
|
||||
functionFactory.arrayContainsAny_h2();
|
||||
functionFactory.arrayContainsAllNullable_h2();
|
||||
|
|
|
@ -254,6 +254,8 @@ public class HSQLLegacyDialect extends Dialect {
|
|||
functionFactory.arrayPosition_hsql();
|
||||
functionFactory.arrayLength_cardinality();
|
||||
functionFactory.arrayConcat_operator();
|
||||
functionFactory.arrayPrepend_operator();
|
||||
functionFactory.arrayAppend_operator();
|
||||
functionFactory.arrayContainsAll_hsql();
|
||||
functionFactory.arrayContainsAny_hsql();
|
||||
functionFactory.arrayContainsAllNullable_hsql();
|
||||
|
|
|
@ -290,6 +290,8 @@ public class OracleLegacyDialect extends Dialect {
|
|||
functionFactory.arrayPosition_oracle();
|
||||
functionFactory.arrayLength_oracle();
|
||||
functionFactory.arrayConcat_oracle();
|
||||
functionFactory.arrayPrepend_oracle();
|
||||
functionFactory.arrayAppend_oracle();
|
||||
functionFactory.arrayContainsAll_oracle();
|
||||
functionFactory.arrayContainsAny_oracle();
|
||||
functionFactory.arrayContainsAllNullable_oracle();
|
||||
|
|
|
@ -588,6 +588,8 @@ public class PostgreSQLLegacyDialect extends Dialect {
|
|||
functionFactory.arrayPosition_postgresql();
|
||||
functionFactory.arrayLength_cardinality();
|
||||
functionFactory.arrayConcat_postgresql();
|
||||
functionFactory.arrayPrepend_postgresql();
|
||||
functionFactory.arrayAppend_postgresql();
|
||||
functionFactory.arrayContainsAll_operator();
|
||||
functionFactory.arrayContainsAny_operator();
|
||||
functionFactory.arrayContainsAllNullable_operator();
|
||||
|
|
|
@ -455,6 +455,8 @@ public class CockroachDialect extends Dialect {
|
|||
functionFactory.arrayPosition_postgresql();
|
||||
functionFactory.arrayLength_cardinality();
|
||||
functionFactory.arrayConcat_postgresql();
|
||||
functionFactory.arrayPrepend_postgresql();
|
||||
functionFactory.arrayAppend_postgresql();
|
||||
functionFactory.arrayContainsAll_operator();
|
||||
functionFactory.arrayContainsAny_operator();
|
||||
functionFactory.arrayContainsAllNullable_operator();
|
||||
|
|
|
@ -315,6 +315,8 @@ public class H2Dialect extends Dialect {
|
|||
functionFactory.arrayContainsNull();
|
||||
functionFactory.arrayLength_cardinality();
|
||||
functionFactory.arrayConcat_operator();
|
||||
functionFactory.arrayPrepend_operator();
|
||||
functionFactory.arrayAppend_operator();
|
||||
functionFactory.arrayContainsAll_h2();
|
||||
functionFactory.arrayContainsAny_h2();
|
||||
functionFactory.arrayContainsAllNullable_h2();
|
||||
|
|
|
@ -194,6 +194,8 @@ public class HSQLDialect extends Dialect {
|
|||
functionFactory.arrayPosition_hsql();
|
||||
functionFactory.arrayLength_cardinality();
|
||||
functionFactory.arrayConcat_operator();
|
||||
functionFactory.arrayPrepend_operator();
|
||||
functionFactory.arrayAppend_operator();
|
||||
functionFactory.arrayContainsAll_hsql();
|
||||
functionFactory.arrayContainsAny_hsql();
|
||||
functionFactory.arrayContainsAllNullable_hsql();
|
||||
|
|
|
@ -46,7 +46,7 @@ public class MySQLSqlAstTranslator<T extends JdbcOperation> extends AbstractSqlA
|
|||
}
|
||||
|
||||
public static String getSqlType(CastTarget castTarget, SessionFactoryImplementor factory) {
|
||||
final String sqlType = getSqlTypeName( castTarget, factory );
|
||||
final String sqlType = getCastTypeName( castTarget, factory );
|
||||
return getSqlType( castTarget, sqlType, factory.getJdbcServices().getDialect() );
|
||||
}
|
||||
|
||||
|
|
|
@ -319,6 +319,8 @@ public class OracleDialect extends Dialect {
|
|||
functionFactory.arrayPosition_oracle();
|
||||
functionFactory.arrayLength_oracle();
|
||||
functionFactory.arrayConcat_oracle();
|
||||
functionFactory.arrayPrepend_oracle();
|
||||
functionFactory.arrayAppend_oracle();
|
||||
functionFactory.arrayContainsAll_oracle();
|
||||
functionFactory.arrayContainsAny_oracle();
|
||||
functionFactory.arrayContainsAllNullable_oracle();
|
||||
|
|
|
@ -636,6 +636,8 @@ public class PostgreSQLDialect extends Dialect {
|
|||
functionFactory.arrayPosition_postgresql();
|
||||
functionFactory.arrayLength_cardinality();
|
||||
functionFactory.arrayConcat_postgresql();
|
||||
functionFactory.arrayPrepend_postgresql();
|
||||
functionFactory.arrayAppend_postgresql();
|
||||
functionFactory.arrayContainsAll_operator();
|
||||
functionFactory.arrayContainsAny_operator();
|
||||
functionFactory.arrayContainsAllNullable_operator();
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.hibernate.dialect.function.array.ArrayAggFunction;
|
|||
import org.hibernate.dialect.function.array.ArrayAndElementArgumentTypeResolver;
|
||||
import org.hibernate.dialect.function.array.ArrayAndElementArgumentValidator;
|
||||
import org.hibernate.dialect.function.array.ArrayArgumentValidator;
|
||||
import org.hibernate.dialect.function.array.ArrayConcatElementFunction;
|
||||
import org.hibernate.dialect.function.array.ArrayConcatFunction;
|
||||
import org.hibernate.dialect.function.array.ArrayConstructorFunction;
|
||||
import org.hibernate.dialect.function.array.ArrayContainsQuantifiedOperatorFunction;
|
||||
|
@ -36,6 +37,7 @@ import org.hibernate.dialect.function.array.H2ArraySetFunction;
|
|||
import org.hibernate.dialect.function.array.HSQLArrayPositionFunction;
|
||||
import org.hibernate.dialect.function.array.HSQLArrayRemoveFunction;
|
||||
import org.hibernate.dialect.function.array.HSQLArraySetFunction;
|
||||
import org.hibernate.dialect.function.array.OracleArrayConcatElementFunction;
|
||||
import org.hibernate.dialect.function.array.OracleArrayConcatFunction;
|
||||
import org.hibernate.dialect.function.array.OracleArrayContainsAllFunction;
|
||||
import org.hibernate.dialect.function.array.OracleArrayContainsAnyFunction;
|
||||
|
@ -47,6 +49,7 @@ import org.hibernate.dialect.function.array.OracleArrayRemoveIndexFunction;
|
|||
import org.hibernate.dialect.function.array.OracleArrayReplaceFunction;
|
||||
import org.hibernate.dialect.function.array.OracleArraySetFunction;
|
||||
import org.hibernate.dialect.function.array.OracleArraySliceFunction;
|
||||
import org.hibernate.dialect.function.array.PostgreSQLArrayConcatElementFunction;
|
||||
import org.hibernate.dialect.function.array.PostgreSQLArrayConcatFunction;
|
||||
import org.hibernate.dialect.function.array.PostgreSQLArrayPositionFunction;
|
||||
import org.hibernate.dialect.function.array.CastingArrayConstructorFunction;
|
||||
|
@ -2946,6 +2949,48 @@ public class CommonFunctionFactory {
|
|||
functionRegistry.register( "array_concat", new OracleArrayConcatFunction() );
|
||||
}
|
||||
|
||||
/**
|
||||
* H2 and HSQLDB array_prepend() function
|
||||
*/
|
||||
public void arrayPrepend_operator() {
|
||||
functionRegistry.register( "array_prepend", new ArrayConcatElementFunction( "", "||", "", true ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* CockroachDB and PostgreSQL array_prepend() function
|
||||
*/
|
||||
public void arrayPrepend_postgresql() {
|
||||
functionRegistry.register( "array_prepend", new PostgreSQLArrayConcatElementFunction( true ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Oracle array_prepend() function
|
||||
*/
|
||||
public void arrayPrepend_oracle() {
|
||||
functionRegistry.register( "array_prepend", new OracleArrayConcatElementFunction( true ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* H2 and HSQLDB array_append() function
|
||||
*/
|
||||
public void arrayAppend_operator() {
|
||||
functionRegistry.register( "array_append", new ArrayConcatElementFunction( "", "||", "", false ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* CockroachDB and PostgreSQL array_append() function
|
||||
*/
|
||||
public void arrayAppend_postgresql() {
|
||||
functionRegistry.register( "array_append", new PostgreSQLArrayConcatElementFunction( false ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Oracle array_append() function
|
||||
*/
|
||||
public void arrayAppend_oracle() {
|
||||
functionRegistry.register( "array_append", new OracleArrayConcatElementFunction( false ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* H2 array_get() function via bracket syntax
|
||||
*/
|
||||
|
|
|
@ -43,7 +43,7 @@ public class ArrayAndElementArgumentTypeResolver implements FunctionArgumentType
|
|||
final SqmTypedNode<?> argument = function.getArguments().get( elementIndex );
|
||||
final DomainType<?> sqmType = argument.getExpressible().getSqmType();
|
||||
if ( sqmType instanceof ReturnableType<?> ) {
|
||||
return ArrayTypeHelper.resolveArrayType(
|
||||
return DdlTypeHelper.resolveArrayType(
|
||||
sqmType,
|
||||
converter.getCreationContext().getSessionFactory().getTypeConfiguration()
|
||||
);
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.dialect.function.array;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
|
||||
/**
|
||||
* Concatenation function for array and an element.
|
||||
*/
|
||||
public class ArrayConcatElementFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||
|
||||
private final String prefix;
|
||||
private final String separator;
|
||||
private final String suffix;
|
||||
protected final boolean prepend;
|
||||
|
||||
public ArrayConcatElementFunction(String prefix, String separator, String suffix, boolean prepend) {
|
||||
super(
|
||||
"array_" + ( prepend ? "prepend" : "append" ),
|
||||
StandardArgumentsValidators.composite(
|
||||
StandardArgumentsValidators.exactly( 2 ),
|
||||
prepend ? new ArrayAndElementArgumentValidator( 1, 0 )
|
||||
: ArrayAndElementArgumentValidator.DEFAULT_INSTANCE
|
||||
),
|
||||
prepend ? new ArrayViaArgumentReturnTypeResolver( 1 )
|
||||
: ArrayViaArgumentReturnTypeResolver.DEFAULT_INSTANCE,
|
||||
prepend ? new ArrayAndElementArgumentTypeResolver( 1, 0 )
|
||||
: ArrayAndElementArgumentTypeResolver.DEFAULT_INSTANCE
|
||||
);
|
||||
this.prefix = prefix;
|
||||
this.separator = separator;
|
||||
this.suffix = suffix;
|
||||
this.prepend = prepend;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final SqlAstNode firstArgument = sqlAstArguments.get( 0 );
|
||||
final SqlAstNode secondArgument = sqlAstArguments.get( 1 );
|
||||
sqlAppender.append( prefix );
|
||||
if ( prepend ) {
|
||||
sqlAppender.append( "array[" );
|
||||
firstArgument.accept( walker );
|
||||
sqlAppender.append( ']' );
|
||||
}
|
||||
else {
|
||||
firstArgument.accept( walker );
|
||||
}
|
||||
sqlAppender.append( separator );
|
||||
if ( prepend ) {
|
||||
secondArgument.accept( walker );
|
||||
}
|
||||
else {
|
||||
sqlAppender.append( "array[" );
|
||||
secondArgument.accept( walker );
|
||||
sqlAppender.append( ']' );
|
||||
}
|
||||
sqlAppender.append( suffix );
|
||||
}
|
||||
}
|
|
@ -48,7 +48,7 @@ public class ArrayContainsOperatorFunction extends AbstractSqmSelfRenderingFunct
|
|||
sqlAppender.append( "cast(array[" );
|
||||
elementExpression.accept( walker );
|
||||
sqlAppender.append( "] as " );
|
||||
sqlAppender.append( ArrayTypeHelper.getArrayTypeName( arrayExpression.getExpressionType(), walker ) );
|
||||
sqlAppender.append( DdlTypeHelper.getCastTypeName( arrayExpression.getExpressionType(), walker ) );
|
||||
sqlAppender.append( ')' );
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -59,7 +59,7 @@ public class ArrayRemoveIndexUnnestFunction extends AbstractSqmSelfRenderingFunc
|
|||
sqlAppender.append( "),");
|
||||
if ( castEmptyArrayLiteral ) {
|
||||
sqlAppender.append( "cast(array[] as " );
|
||||
sqlAppender.append( ArrayTypeHelper.getArrayTypeName( arrayExpression.getExpressionType(), walker ) );
|
||||
sqlAppender.append( DdlTypeHelper.getCastTypeName( arrayExpression.getExpressionType(), walker ) );
|
||||
sqlAppender.append( ')' );
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -66,7 +66,7 @@ public class ArraySliceUnnestFunction extends AbstractSqmSelfRenderingFunctionDe
|
|||
sqlAppender.append( "),");
|
||||
if ( castEmptyArrayLiteral ) {
|
||||
sqlAppender.append( "cast(array[] as " );
|
||||
sqlAppender.append( ArrayTypeHelper.getArrayTypeName( arrayExpression.getExpressionType(), walker ) );
|
||||
sqlAppender.append( DdlTypeHelper.getCastTypeName( arrayExpression.getExpressionType(), walker ) );
|
||||
sqlAppender.append( ')' );
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -30,7 +30,7 @@ public class ArrayViaArgumentReturnTypeResolver implements FunctionReturnTypeRes
|
|||
|
||||
private final int arrayIndex;
|
||||
|
||||
private ArrayViaArgumentReturnTypeResolver(int arrayIndex) {
|
||||
public ArrayViaArgumentReturnTypeResolver(int arrayIndex) {
|
||||
this.arrayIndex = arrayIndex;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ public class ArrayViaElementArgumentReturnTypeResolver implements FunctionReturn
|
|||
for ( SqmTypedNode<?> argument : arguments ) {
|
||||
final DomainType<?> sqmType = argument.getExpressible().getSqmType();
|
||||
if ( sqmType instanceof ReturnableType<?> ) {
|
||||
return ArrayTypeHelper.resolveArrayType( sqmType, typeConfiguration );
|
||||
return DdlTypeHelper.resolveArrayType( sqmType, typeConfiguration );
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -22,7 +22,7 @@ import org.hibernate.type.descriptor.sql.DdlType;
|
|||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
public class ArrayTypeHelper {
|
||||
public class DdlTypeHelper {
|
||||
@SuppressWarnings("unchecked")
|
||||
public static BasicType<?> resolveArrayType(DomainType<?> elementType, TypeConfiguration typeConfiguration) {
|
||||
@SuppressWarnings("unchecked") final BasicPluralJavaType<Object> arrayJavaType = (BasicPluralJavaType<Object>) typeConfiguration.getJavaTypeRegistry()
|
||||
|
@ -39,18 +39,34 @@ public class ArrayTypeHelper {
|
|||
);
|
||||
}
|
||||
|
||||
public static String getArrayTypeName(JdbcMappingContainer arrayType, SqlAstTranslator<?> walker) {
|
||||
if ( arrayType instanceof SqlTypedMapping ) {
|
||||
return AbstractSqlAstTranslator.getSqlTypeName( (SqlTypedMapping) arrayType, walker.getSessionFactory() );
|
||||
public static String getTypeName(JdbcMappingContainer type, SqlAstTranslator<?> walker) {
|
||||
if ( type instanceof SqlTypedMapping ) {
|
||||
return AbstractSqlAstTranslator.getSqlTypeName( (SqlTypedMapping) type, walker.getSessionFactory() );
|
||||
}
|
||||
else {
|
||||
final BasicPluralType<?, ?> pluralType = (BasicPluralType<?, ?>) arrayType.getSingleJdbcMapping();
|
||||
final BasicType<?> jdbcMapping = (BasicType<?>) type.getSingleJdbcMapping();
|
||||
final TypeConfiguration typeConfiguration = walker.getSessionFactory().getTypeConfiguration();
|
||||
final DdlTypeRegistry ddlTypeRegistry = typeConfiguration.getDdlTypeRegistry();
|
||||
final DdlType ddlType = ddlTypeRegistry.getDescriptor(
|
||||
pluralType.getJdbcType().getDdlTypeCode()
|
||||
jdbcMapping.getJdbcType().getDdlTypeCode()
|
||||
);
|
||||
return ddlType.getCastTypeName( Size.nil(), pluralType, ddlTypeRegistry );
|
||||
return ddlType.getTypeName( Size.nil(), jdbcMapping, ddlTypeRegistry );
|
||||
}
|
||||
}
|
||||
|
||||
public static String getCastTypeName(JdbcMappingContainer type, SqlAstTranslator<?> walker) {
|
||||
if ( type instanceof SqlTypedMapping ) {
|
||||
return AbstractSqlAstTranslator.getCastTypeName( (SqlTypedMapping) type, walker.getSessionFactory() );
|
||||
}
|
||||
else {
|
||||
final BasicType<?> jdbcMapping = (BasicType<?>) type.getSingleJdbcMapping();
|
||||
final TypeConfiguration typeConfiguration = walker.getSessionFactory().getTypeConfiguration();
|
||||
final DdlTypeRegistry ddlTypeRegistry = typeConfiguration.getDdlTypeRegistry();
|
||||
final DdlType ddlType = ddlTypeRegistry.getDescriptor(
|
||||
jdbcMapping.getJdbcType().getDdlTypeCode()
|
||||
);
|
||||
return ddlType.getCastTypeName( Size.nil(), jdbcMapping, ddlTypeRegistry );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.dialect.function.array;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Oracle concatenation function for array and an element.
|
||||
*/
|
||||
public class OracleArrayConcatElementFunction extends ArrayConcatElementFunction {
|
||||
|
||||
public OracleArrayConcatElementFunction(boolean prepend) {
|
||||
super( "(", ",", ")", prepend );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final Expression firstArgument = (Expression) sqlAstArguments.get( 0 );
|
||||
final Expression secondArgument = (Expression) sqlAstArguments.get( 1 );
|
||||
final String arrayTypeName = DdlTypeHelper.getTypeName(
|
||||
prepend ? secondArgument.getExpressionType()
|
||||
: firstArgument.getExpressionType(),
|
||||
walker
|
||||
);
|
||||
sqlAppender.append( arrayTypeName );
|
||||
sqlAppender.append( "_concat(" );
|
||||
if ( prepend ) {
|
||||
sqlAppender.append( arrayTypeName );
|
||||
sqlAppender.append( '(' );
|
||||
firstArgument.accept( walker );
|
||||
sqlAppender.append( ')' );
|
||||
}
|
||||
else {
|
||||
firstArgument.accept( walker );
|
||||
}
|
||||
sqlAppender.append( ',' );
|
||||
if ( prepend ) {
|
||||
secondArgument.accept( walker );
|
||||
}
|
||||
else {
|
||||
sqlAppender.append( arrayTypeName );
|
||||
sqlAppender.append( '(' );
|
||||
secondArgument.accept( walker );
|
||||
sqlAppender.append( ')' );
|
||||
}
|
||||
sqlAppender.append( ')' );
|
||||
}
|
||||
}
|
|
@ -36,7 +36,7 @@ public class OracleArrayConcatFunction extends ArrayConcatFunction {
|
|||
}
|
||||
}
|
||||
|
||||
final String arrayTypeName = ArrayTypeHelper.getArrayTypeName( expressionType, walker );
|
||||
final String arrayTypeName = DdlTypeHelper.getTypeName( expressionType, walker );
|
||||
sqlAppender.append( arrayTypeName );
|
||||
sqlAppender.append( "_concat" );
|
||||
super.render( sqlAppender, sqlAstArguments, walker );
|
||||
|
|
|
@ -29,7 +29,7 @@ public class OracleArrayContainsAllFunction extends AbstractArrayContainsQuantif
|
|||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 );
|
||||
final String arrayTypeName = ArrayTypeHelper.getArrayTypeName( haystackExpression.getExpressionType(), walker );
|
||||
final String arrayTypeName = DdlTypeHelper.getTypeName( haystackExpression.getExpressionType(), walker );
|
||||
sqlAppender.appendSql( arrayTypeName );
|
||||
sqlAppender.append( "_contains_all(" );
|
||||
haystackExpression.accept( walker );
|
||||
|
|
|
@ -29,7 +29,7 @@ public class OracleArrayContainsAnyFunction extends AbstractArrayContainsQuantif
|
|||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 );
|
||||
final String arrayTypeName = ArrayTypeHelper.getArrayTypeName( haystackExpression.getExpressionType(), walker );
|
||||
final String arrayTypeName = DdlTypeHelper.getTypeName( haystackExpression.getExpressionType(), walker );
|
||||
sqlAppender.appendSql( arrayTypeName );
|
||||
sqlAppender.append( "_contains_any(" );
|
||||
haystackExpression.accept( walker );
|
||||
|
|
|
@ -37,7 +37,7 @@ public class OracleArrayContainsFunction extends AbstractSqmSelfRenderingFunctio
|
|||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 );
|
||||
final String arrayTypeName = ArrayTypeHelper.getArrayTypeName( arrayExpression.getExpressionType(), walker );
|
||||
final String arrayTypeName = DdlTypeHelper.getTypeName( arrayExpression.getExpressionType(), walker );
|
||||
sqlAppender.appendSql( arrayTypeName );
|
||||
sqlAppender.append( "_position(" );
|
||||
arrayExpression.accept( walker );
|
||||
|
|
|
@ -37,7 +37,7 @@ public class OracleArrayContainsNullFunction extends AbstractSqmSelfRenderingFun
|
|||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 );
|
||||
final String arrayTypeName = ArrayTypeHelper.getArrayTypeName( arrayExpression.getExpressionType(), walker );
|
||||
final String arrayTypeName = DdlTypeHelper.getTypeName( arrayExpression.getExpressionType(), walker );
|
||||
sqlAppender.appendSql( arrayTypeName );
|
||||
sqlAppender.append( "_position(" );
|
||||
arrayExpression.accept( walker );
|
||||
|
|
|
@ -26,7 +26,7 @@ public class OracleArrayGetFunction extends ArrayGetUnnestFunction {
|
|||
SqlAppender sqlAppender,
|
||||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final String arrayTypeName = ArrayTypeHelper.getArrayTypeName(
|
||||
final String arrayTypeName = DdlTypeHelper.getTypeName(
|
||||
( (Expression) sqlAstArguments.get( 0 ) ).getExpressionType(),
|
||||
walker
|
||||
);
|
||||
|
|
|
@ -37,7 +37,7 @@ public class OracleArrayLengthFunction extends AbstractSqmSelfRenderingFunctionD
|
|||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 );
|
||||
final String arrayTypeName = ArrayTypeHelper.getArrayTypeName( arrayExpression.getExpressionType(), walker );
|
||||
final String arrayTypeName = DdlTypeHelper.getTypeName( arrayExpression.getExpressionType(), walker );
|
||||
sqlAppender.appendSql( arrayTypeName );
|
||||
sqlAppender.append( "_length(" );
|
||||
arrayExpression.accept( walker );
|
||||
|
|
|
@ -26,7 +26,7 @@ public class OracleArrayPositionFunction extends AbstractArrayPositionFunction {
|
|||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 );
|
||||
final String arrayTypeName = ArrayTypeHelper.getArrayTypeName( arrayExpression.getExpressionType(), walker );
|
||||
final String arrayTypeName = DdlTypeHelper.getTypeName( arrayExpression.getExpressionType(), walker );
|
||||
sqlAppender.appendSql( arrayTypeName );
|
||||
sqlAppender.append( "_position(" );
|
||||
arrayExpression.accept( walker );
|
||||
|
|
|
@ -26,7 +26,7 @@ public class OracleArrayRemoveFunction extends AbstractArrayRemoveFunction {
|
|||
SqlAppender sqlAppender,
|
||||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final String arrayTypeName = ArrayTypeHelper.getArrayTypeName(
|
||||
final String arrayTypeName = DdlTypeHelper.getTypeName(
|
||||
( (Expression) sqlAstArguments.get( 0 ) ).getExpressionType(),
|
||||
walker
|
||||
);
|
||||
|
|
|
@ -27,7 +27,7 @@ public class OracleArrayRemoveIndexFunction extends ArrayRemoveIndexUnnestFuncti
|
|||
SqlAppender sqlAppender,
|
||||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final String arrayTypeName = ArrayTypeHelper.getArrayTypeName(
|
||||
final String arrayTypeName = DdlTypeHelper.getTypeName(
|
||||
( (Expression) sqlAstArguments.get( 0 ) ).getExpressionType(),
|
||||
walker
|
||||
);
|
||||
|
|
|
@ -23,7 +23,7 @@ public class OracleArrayReplaceFunction extends ArrayReplaceUnnestFunction {
|
|||
SqlAppender sqlAppender,
|
||||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final String arrayTypeName = ArrayTypeHelper.getArrayTypeName(
|
||||
final String arrayTypeName = DdlTypeHelper.getTypeName(
|
||||
( (Expression) sqlAstArguments.get( 0 ) ).getExpressionType(),
|
||||
walker
|
||||
);
|
||||
|
|
|
@ -26,7 +26,7 @@ public class OracleArraySetFunction extends ArraySetUnnestFunction {
|
|||
SqlAppender sqlAppender,
|
||||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final String arrayTypeName = ArrayTypeHelper.getArrayTypeName(
|
||||
final String arrayTypeName = DdlTypeHelper.getTypeName(
|
||||
( (Expression) sqlAstArguments.get( 0 ) ).getExpressionType(),
|
||||
walker
|
||||
);
|
||||
|
|
|
@ -27,7 +27,7 @@ public class OracleArraySliceFunction extends ArraySliceUnnestFunction {
|
|||
SqlAppender sqlAppender,
|
||||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final String arrayTypeName = ArrayTypeHelper.getArrayTypeName(
|
||||
final String arrayTypeName = DdlTypeHelper.getTypeName(
|
||||
( (Expression) sqlAstArguments.get( 0 ) ).getExpressionType(),
|
||||
walker
|
||||
);
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.dialect.function.array;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
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.sql.ast.tree.expression.Literal;
|
||||
import org.hibernate.type.BasicPluralType;
|
||||
import org.hibernate.type.BottomType;
|
||||
|
||||
/**
|
||||
* PostgreSQL variant of the function to properly return {@code null} when the array argument is null.
|
||||
*/
|
||||
public class PostgreSQLArrayConcatElementFunction extends ArrayConcatElementFunction {
|
||||
|
||||
public PostgreSQLArrayConcatElementFunction(boolean prepend) {
|
||||
super( "", "||", "", prepend );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final Expression firstArgument = (Expression) sqlAstArguments.get( 0 );
|
||||
final Expression secondArgument = (Expression) sqlAstArguments.get( 1 );
|
||||
final Expression arrayArgument;
|
||||
final Expression elementArgument;
|
||||
if ( prepend ) {
|
||||
elementArgument = firstArgument;
|
||||
arrayArgument = secondArgument;
|
||||
}
|
||||
else {
|
||||
arrayArgument = firstArgument;
|
||||
elementArgument = secondArgument;
|
||||
}
|
||||
final String elementCastType;
|
||||
if ( needsElementCasting( elementArgument ) ) {
|
||||
final JdbcMapping elementType = elementArgument.getExpressionType().getSingleJdbcMapping();
|
||||
if ( elementType instanceof BottomType ) {
|
||||
elementCastType = DdlTypeHelper.getCastTypeName(
|
||||
( (BasicPluralType<?, ?>) arrayArgument.getExpressionType().getSingleJdbcMapping() )
|
||||
.getElementType(),
|
||||
walker
|
||||
);
|
||||
}
|
||||
else {
|
||||
elementCastType = DdlTypeHelper.getCastTypeName( elementType, walker );
|
||||
}
|
||||
}
|
||||
else {
|
||||
elementCastType = null;
|
||||
}
|
||||
sqlAppender.append( "case when " );
|
||||
arrayArgument.accept( walker );
|
||||
sqlAppender.append( " is not null then " );
|
||||
if ( prepend && elementCastType != null) {
|
||||
sqlAppender.append( "cast(" );
|
||||
firstArgument.accept( walker );
|
||||
sqlAppender.append( " as " );
|
||||
sqlAppender.append( elementCastType );
|
||||
sqlAppender.append( ')' );
|
||||
}
|
||||
else {
|
||||
firstArgument.accept( walker );
|
||||
}
|
||||
sqlAppender.append( "||" );
|
||||
if ( !prepend && elementCastType != null) {
|
||||
sqlAppender.append( "cast(" );
|
||||
secondArgument.accept( walker );
|
||||
sqlAppender.append( " as " );
|
||||
sqlAppender.append( elementCastType );
|
||||
sqlAppender.append( ')' );
|
||||
}
|
||||
else {
|
||||
secondArgument.accept( walker );
|
||||
}
|
||||
sqlAppender.append( " end" );
|
||||
}
|
||||
|
||||
private static boolean needsElementCasting(Expression elementExpression) {
|
||||
// PostgreSQL needs casting of null and string literal expressions
|
||||
return elementExpression instanceof Literal && (
|
||||
elementExpression.getExpressionType().getSingleJdbcMapping().getJdbcType().isString()
|
||||
|| ( (Literal) elementExpression ).getLiteralValue() == null
|
||||
);
|
||||
}
|
||||
}
|
|
@ -6263,7 +6263,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
|
||||
@Override
|
||||
public void visitCastTarget(CastTarget castTarget) {
|
||||
appendSql( getSqlTypeName( castTarget, sessionFactory ) );
|
||||
appendSql( getCastTypeName( castTarget, sessionFactory ) );
|
||||
}
|
||||
|
||||
public static String getSqlTypeName(SqlTypedMapping castTarget, SessionFactoryImplementor factory) {
|
||||
|
@ -6273,7 +6273,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
else {
|
||||
final Size castTargetSize = castTarget.toSize();
|
||||
final DdlTypeRegistry ddlTypeRegistry = factory.getTypeConfiguration().getDdlTypeRegistry();
|
||||
final SqlExpressible expressionType = (SqlExpressible) castTarget.getJdbcMapping();
|
||||
final BasicType<?> expressionType = (BasicType<?>) castTarget.getJdbcMapping();
|
||||
if ( expressionType instanceof BasicPluralType<?, ?> ) {
|
||||
final BasicPluralType<?, ?> containerType = (BasicPluralType<?, ?>) expressionType;
|
||||
final BasicPluralJavaType<?> javaTypeDescriptor = (BasicPluralJavaType<?>) containerType.getJavaTypeDescriptor();
|
||||
|
@ -6293,19 +6293,52 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
return arrayTypeName;
|
||||
}
|
||||
}
|
||||
DdlType ddlType = ddlTypeRegistry
|
||||
.getDescriptor( expressionType.getJdbcMapping().getJdbcType().getDdlTypeCode() );
|
||||
DdlType ddlType = ddlTypeRegistry.getDescriptor( expressionType.getJdbcType().getDdlTypeCode() );
|
||||
if ( ddlType == null ) {
|
||||
// this may happen when selecting a null value like `SELECT null from ...`
|
||||
// some dbs need the value to be cast so not knowing the real type we fall back to INTEGER
|
||||
ddlType = ddlTypeRegistry.getDescriptor( SqlTypes.INTEGER );
|
||||
}
|
||||
|
||||
return ddlType.getCastTypeName(
|
||||
return ddlType.getTypeName( castTargetSize, expressionType, ddlTypeRegistry );
|
||||
}
|
||||
}
|
||||
|
||||
public static String getCastTypeName(SqlTypedMapping castTarget, SessionFactoryImplementor factory) {
|
||||
if ( castTarget.getColumnDefinition() != null ) {
|
||||
return castTarget.getColumnDefinition();
|
||||
}
|
||||
else {
|
||||
final Size castTargetSize = castTarget.toSize();
|
||||
final DdlTypeRegistry ddlTypeRegistry = factory.getTypeConfiguration().getDdlTypeRegistry();
|
||||
final BasicType<?> expressionType = (BasicType<?>) castTarget.getJdbcMapping();
|
||||
if ( expressionType instanceof BasicPluralType<?, ?> ) {
|
||||
final BasicPluralType<?, ?> containerType = (BasicPluralType<?, ?>) expressionType;
|
||||
final BasicPluralJavaType<?> javaTypeDescriptor = (BasicPluralJavaType<?>) containerType.getJavaTypeDescriptor();
|
||||
final BasicType<?> elementType = containerType.getElementType();
|
||||
final String elementTypeName = ddlTypeRegistry.getDescriptor( elementType.getJdbcType().getDdlTypeCode() )
|
||||
.getCastTypeName(
|
||||
castTargetSize,
|
||||
expressionType,
|
||||
elementType,
|
||||
ddlTypeRegistry
|
||||
);
|
||||
final String arrayTypeName = factory.getJdbcServices().getDialect().getArrayTypeName(
|
||||
javaTypeDescriptor.getElementJavaType().getJavaTypeClass().getSimpleName(),
|
||||
elementTypeName,
|
||||
null
|
||||
);
|
||||
if ( arrayTypeName != null ) {
|
||||
return arrayTypeName;
|
||||
}
|
||||
}
|
||||
DdlType ddlType = ddlTypeRegistry.getDescriptor( expressionType.getJdbcType().getDdlTypeCode() );
|
||||
if ( ddlType == null ) {
|
||||
// this may happen when selecting a null value like `SELECT null from ...`
|
||||
// some dbs need the value to be cast so not knowing the real type we fall back to INTEGER
|
||||
ddlType = ddlTypeRegistry.getDescriptor( SqlTypes.INTEGER );
|
||||
}
|
||||
|
||||
return ddlType.getCastTypeName( castTargetSize, expressionType, ddlTypeRegistry );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.orm.test.function.array;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
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.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Tuple;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
@DomainModel(annotatedClasses = EntityWithArrays.class)
|
||||
@SessionFactory
|
||||
@RequiresDialectFeature( feature = DialectFeatureChecks.SupportsStructuralArrays.class)
|
||||
// Make sure this stuff runs on a dedicated connection pool,
|
||||
// otherwise we might run into ORA-21700: object does not exist or is marked for delete
|
||||
// because the JDBC connection or database session caches something that should have been invalidated
|
||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.CONNECTION_PROVIDER, value = ""))
|
||||
public class ArrayAppendTest {
|
||||
|
||||
@BeforeEach
|
||||
public void prepareData(SessionFactoryScope scope) {
|
||||
scope.inTransaction( em -> {
|
||||
em.persist( new EntityWithArrays( 1L, new String[]{} ) );
|
||||
em.persist( new EntityWithArrays( 2L, new String[]{ "abc", null, "def" } ) );
|
||||
em.persist( new EntityWithArrays( 3L, null ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void cleanup(SessionFactoryScope scope) {
|
||||
scope.inTransaction( em -> {
|
||||
em.createMutationQuery( "delete from EntityWithArrays" ).executeUpdate();
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAppend(SessionFactoryScope scope) {
|
||||
scope.inSession( em -> {
|
||||
//tag::hql-array-append-example[]
|
||||
List<Tuple> results = em.createQuery( "select e.id, array_append(e.theArray, 'xyz') from EntityWithArrays e order by e.id", Tuple.class )
|
||||
.getResultList();
|
||||
//end::hql-array-append-example[]
|
||||
assertEquals( 3, results.size() );
|
||||
assertEquals( 1L, results.get( 0 ).get( 0 ) );
|
||||
assertArrayEquals( new String[]{ "xyz" }, results.get( 0 ).get( 1, String[].class ) );
|
||||
assertEquals( 2L, results.get( 1 ).get( 0 ) );
|
||||
assertArrayEquals( new String[]{ "abc", null, "def", "xyz" }, results.get( 1 ).get( 1, String[].class ) );
|
||||
assertEquals( 3L, results.get( 2 ).get( 0 ) );
|
||||
assertNull( results.get( 2 ).get( 1, String[].class ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAppendNull(SessionFactoryScope scope) {
|
||||
scope.inSession( em -> {
|
||||
List<Tuple> results = em.createQuery( "select e.id, array_append(e.theArray, null) from EntityWithArrays e order by e.id", Tuple.class )
|
||||
.getResultList();
|
||||
assertEquals( 3, results.size() );
|
||||
assertEquals( 1L, results.get( 0 ).get( 0 ) );
|
||||
assertArrayEquals( new String[]{ null }, results.get( 0 ).get( 1, String[].class ) );
|
||||
assertEquals( 2L, results.get( 1 ).get( 0 ) );
|
||||
assertArrayEquals( new String[]{ "abc", null, "def", null }, results.get( 1 ).get( 1, String[].class ) );
|
||||
assertEquals( 3L, results.get( 2 ).get( 0 ) );
|
||||
assertNull( results.get( 2 ).get( 1, String[].class ) );
|
||||
} );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.orm.test.function.array;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
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.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Tuple;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
@DomainModel(annotatedClasses = EntityWithArrays.class)
|
||||
@SessionFactory
|
||||
@RequiresDialectFeature( feature = DialectFeatureChecks.SupportsStructuralArrays.class)
|
||||
// Make sure this stuff runs on a dedicated connection pool,
|
||||
// otherwise we might run into ORA-21700: object does not exist or is marked for delete
|
||||
// because the JDBC connection or database session caches something that should have been invalidated
|
||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.CONNECTION_PROVIDER, value = ""))
|
||||
public class ArrayPrependTest {
|
||||
|
||||
@BeforeEach
|
||||
public void prepareData(SessionFactoryScope scope) {
|
||||
scope.inTransaction( em -> {
|
||||
em.persist( new EntityWithArrays( 1L, new String[]{} ) );
|
||||
em.persist( new EntityWithArrays( 2L, new String[]{ "abc", null, "def" } ) );
|
||||
em.persist( new EntityWithArrays( 3L, null ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void cleanup(SessionFactoryScope scope) {
|
||||
scope.inTransaction( em -> {
|
||||
em.createMutationQuery( "delete from EntityWithArrays" ).executeUpdate();
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrepend(SessionFactoryScope scope) {
|
||||
scope.inSession( em -> {
|
||||
//tag::hql-array-prepend-example[]
|
||||
List<Tuple> results = em.createQuery( "select e.id, array_prepend('xyz', e.theArray) from EntityWithArrays e order by e.id", Tuple.class )
|
||||
.getResultList();
|
||||
//end::hql-array-prepend-example[]
|
||||
assertEquals( 3, results.size() );
|
||||
assertEquals( 1L, results.get( 0 ).get( 0 ) );
|
||||
assertArrayEquals( new String[]{ "xyz" }, results.get( 0 ).get( 1, String[].class ) );
|
||||
assertEquals( 2L, results.get( 1 ).get( 0 ) );
|
||||
assertArrayEquals( new String[]{ "xyz", "abc", null, "def" }, results.get( 1 ).get( 1, String[].class ) );
|
||||
assertEquals( 3L, results.get( 2 ).get( 0 ) );
|
||||
assertNull( results.get( 2 ).get( 1, String[].class ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrependNull(SessionFactoryScope scope) {
|
||||
scope.inSession( em -> {
|
||||
List<Tuple> results = em.createQuery( "select e.id, array_prepend(null, e.theArray) from EntityWithArrays e order by e.id", Tuple.class )
|
||||
.getResultList();
|
||||
assertEquals( 3, results.size() );
|
||||
assertEquals( 1L, results.get( 0 ).get( 0 ) );
|
||||
assertArrayEquals( new String[]{ null }, results.get( 0 ).get( 1, String[].class ) );
|
||||
assertEquals( 2L, results.get( 1 ).get( 0 ) );
|
||||
assertArrayEquals( new String[]{ null, "abc", null, "def" }, results.get( 1 ).get( 1, String[].class ) );
|
||||
assertEquals( 3L, results.get( 2 ).get( 0 ) );
|
||||
assertNull( results.get( 2 ).get( 1, String[].class ) );
|
||||
} );
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue