HHH-17355 Add array_fill function
This commit is contained in:
parent
6d392f5e20
commit
1a5184e89b
|
@ -1135,6 +1135,7 @@ The following functions deal with SQL array types, which are not supported on ev
|
|||
| `array_slice()` | Creates a sub-array of the based on lower and upper index
|
||||
| `array_replace()` | Creates array copy replacing a given element with another
|
||||
| `array_trim()` | Creates array copy trimming the last _N_ elements
|
||||
| `array_fill()` | Creates array filled with the same element _N_ times
|
||||
|===
|
||||
|
||||
===== `array()`
|
||||
|
@ -1399,6 +1400,19 @@ include::{array-example-dir-hql}/ArrayTrimTest.java[tags=hql-array-trim-example]
|
|||
----
|
||||
====
|
||||
|
||||
===== `array_fill()`
|
||||
|
||||
Creates an array filled with the same element _N_ times as specified by the arguments.
|
||||
It is an error to supply an array length smaller than 0.
|
||||
|
||||
[[hql-array-fill-example]]
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{array-example-dir-hql}/ArrayFillTest.java[tags=hql-array-fill-example]
|
||||
----
|
||||
====
|
||||
|
||||
[[hql-user-defined-functions]]
|
||||
==== Native and user-defined functions
|
||||
|
||||
|
|
|
@ -477,6 +477,7 @@ public class CockroachLegacyDialect extends Dialect {
|
|||
functionFactory.arraySlice_operator();
|
||||
functionFactory.arrayReplace();
|
||||
functionFactory.arrayTrim_trim_array();
|
||||
functionFactory.arrayFill_postgresql();
|
||||
|
||||
functionContributions.getFunctionRegistry().register(
|
||||
"trunc",
|
||||
|
|
|
@ -385,6 +385,7 @@ public class H2LegacyDialect extends Dialect {
|
|||
functionFactory.arraySlice();
|
||||
functionFactory.arrayReplace_h2( getMaximumArraySize() );
|
||||
functionFactory.arrayTrim_trim_array();
|
||||
functionFactory.arrayFill_h2();
|
||||
}
|
||||
else {
|
||||
// Use group_concat until 2.x as listagg was buggy
|
||||
|
|
|
@ -263,6 +263,7 @@ public class HSQLLegacyDialect extends Dialect {
|
|||
functionFactory.arraySlice_unnest();
|
||||
functionFactory.arrayReplace_unnest();
|
||||
functionFactory.arrayTrim_trim_array();
|
||||
functionFactory.arrayFill_hsql();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -299,6 +299,7 @@ public class OracleLegacyDialect extends Dialect {
|
|||
functionFactory.arraySlice_oracle();
|
||||
functionFactory.arrayReplace_oracle();
|
||||
functionFactory.arrayTrim_oracle();
|
||||
functionFactory.arrayFill_oracle();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -597,6 +597,7 @@ public class PostgreSQLLegacyDialect extends Dialect {
|
|||
functionFactory.arraySlice_operator();
|
||||
functionFactory.arrayReplace();
|
||||
functionFactory.arrayTrim_trim_array();
|
||||
functionFactory.arrayFill_postgresql();
|
||||
|
||||
if ( getVersion().isSameOrAfter( 9, 4 ) ) {
|
||||
functionFactory.makeDateTimeTimestamp();
|
||||
|
|
|
@ -464,6 +464,7 @@ public class CockroachDialect extends Dialect {
|
|||
functionFactory.arraySlice_operator();
|
||||
functionFactory.arrayReplace();
|
||||
functionFactory.arrayTrim_trim_array();
|
||||
functionFactory.arrayFill_postgresql();
|
||||
|
||||
functionContributions.getFunctionRegistry().register(
|
||||
"trunc",
|
||||
|
|
|
@ -324,6 +324,7 @@ public class H2Dialect extends Dialect {
|
|||
functionFactory.arraySlice();
|
||||
functionFactory.arrayReplace_h2( getMaximumArraySize() );
|
||||
functionFactory.arrayTrim_trim_array();
|
||||
functionFactory.arrayFill_h2();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -203,6 +203,7 @@ public class HSQLDialect extends Dialect {
|
|||
functionFactory.arraySlice_unnest();
|
||||
functionFactory.arrayReplace_unnest();
|
||||
functionFactory.arrayTrim_trim_array();
|
||||
functionFactory.arrayFill_hsql();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -493,6 +493,28 @@ public class OracleArrayJdbcType extends ArrayJdbcType {
|
|||
false
|
||||
)
|
||||
);
|
||||
database.addAuxiliaryDatabaseObject(
|
||||
new NamedAuxiliaryDatabaseObject(
|
||||
arrayTypeName + "_fill",
|
||||
database.getDefaultNamespace(),
|
||||
new String[]{
|
||||
"create or replace function " + arrayTypeName + "_fill(elem in " + getRawTypeName( elementType ) +
|
||||
", elems number) return " + arrayTypeName + " deterministic is " +
|
||||
"res " + arrayTypeName + ":=" + arrayTypeName + "(); begin " +
|
||||
"if elems is null then return null; end if; " +
|
||||
"if elems<0 then raise_application_error (-20000, 'number of elements must be greater than or equal to 0'); end if;" +
|
||||
"for i in 1 .. elems loop " +
|
||||
"res.extend; " +
|
||||
"res(i) := elem; " +
|
||||
"end loop; " +
|
||||
"return res; " +
|
||||
"end;"
|
||||
},
|
||||
new String[] { "drop function " + arrayTypeName + "_fill" },
|
||||
emptySet(),
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected String createOrReplaceConcatFunction(String arrayTypeName) {
|
||||
|
|
|
@ -328,6 +328,7 @@ public class OracleDialect extends Dialect {
|
|||
functionFactory.arraySlice_oracle();
|
||||
functionFactory.arrayReplace_oracle();
|
||||
functionFactory.arrayTrim_oracle();
|
||||
functionFactory.arrayFill_oracle();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -645,6 +645,7 @@ public class PostgreSQLDialect extends Dialect {
|
|||
functionFactory.arraySlice_operator();
|
||||
functionFactory.arrayReplace();
|
||||
functionFactory.arrayTrim_trim_array();
|
||||
functionFactory.arrayFill_postgresql();
|
||||
|
||||
functionFactory.makeDateTimeTimestamp();
|
||||
// Note that PostgreSQL doesn't support the OVER clause for ordered set-aggregate functions
|
||||
|
|
|
@ -31,17 +31,20 @@ import org.hibernate.dialect.function.array.ArraySliceUnnestFunction;
|
|||
import org.hibernate.dialect.function.array.ArrayViaArgumentReturnTypeResolver;
|
||||
import org.hibernate.dialect.function.array.ElementViaArrayArgumentReturnTypeResolver;
|
||||
import org.hibernate.dialect.function.array.H2ArrayContainsFunction;
|
||||
import org.hibernate.dialect.function.array.H2ArrayFillFunction;
|
||||
import org.hibernate.dialect.function.array.H2ArrayOverlapsFunction;
|
||||
import org.hibernate.dialect.function.array.H2ArrayRemoveFunction;
|
||||
import org.hibernate.dialect.function.array.H2ArrayRemoveIndexFunction;
|
||||
import org.hibernate.dialect.function.array.H2ArrayReplaceFunction;
|
||||
import org.hibernate.dialect.function.array.H2ArraySetFunction;
|
||||
import org.hibernate.dialect.function.array.HSQLArrayConstructorFunction;
|
||||
import org.hibernate.dialect.function.array.HSQLArrayFillFunction;
|
||||
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.OracleArrayFillFunction;
|
||||
import org.hibernate.dialect.function.array.OracleArrayOverlapsFunction;
|
||||
import org.hibernate.dialect.function.array.OracleArrayGetFunction;
|
||||
import org.hibernate.dialect.function.array.OracleArrayLengthFunction;
|
||||
|
@ -54,6 +57,7 @@ import org.hibernate.dialect.function.array.OracleArraySliceFunction;
|
|||
import org.hibernate.dialect.function.array.OracleArrayTrimFunction;
|
||||
import org.hibernate.dialect.function.array.PostgreSQLArrayConcatElementFunction;
|
||||
import org.hibernate.dialect.function.array.PostgreSQLArrayConcatFunction;
|
||||
import org.hibernate.dialect.function.array.PostgreSQLArrayFillFunction;
|
||||
import org.hibernate.dialect.function.array.PostgreSQLArrayPositionFunction;
|
||||
import org.hibernate.dialect.function.array.PostgreSQLArrayConstructorFunction;
|
||||
import org.hibernate.dialect.function.array.OracleArrayAggEmulation;
|
||||
|
@ -3091,4 +3095,32 @@ public class CommonFunctionFactory {
|
|||
public void arrayTrim_oracle() {
|
||||
functionRegistry.register( "array_trim", new OracleArrayTrimFunction() );
|
||||
}
|
||||
|
||||
/**
|
||||
* H2 array_fill() function
|
||||
*/
|
||||
public void arrayFill_h2() {
|
||||
functionRegistry.register( "array_fill", new H2ArrayFillFunction() );
|
||||
}
|
||||
|
||||
/**
|
||||
* HSQLDB array_fill() function
|
||||
*/
|
||||
public void arrayFill_hsql() {
|
||||
functionRegistry.register( "array_fill", new HSQLArrayFillFunction() );
|
||||
}
|
||||
|
||||
/**
|
||||
* PostgreSQL array_fill() function
|
||||
*/
|
||||
public void arrayFill_postgresql() {
|
||||
functionRegistry.register( "array_fill", new PostgreSQLArrayFillFunction() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Oracle array_fill() function
|
||||
*/
|
||||
public void arrayFill_oracle() {
|
||||
functionRegistry.register( "array_fill", new OracleArrayFillFunction() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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 org.hibernate.metamodel.mapping.MappingModelExpressible;
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
|
||||
import org.hibernate.query.sqm.produce.function.FunctionArgumentTypeResolver;
|
||||
import org.hibernate.query.sqm.produce.function.FunctionParameterType;
|
||||
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmFunction;
|
||||
import org.hibernate.type.BasicPluralType;
|
||||
|
||||
/**
|
||||
* Encapsulates the validator, return type and argument type resolvers for the array_contains function.
|
||||
* Subclasses only have to implement the rendering.
|
||||
*/
|
||||
public abstract class AbstractArrayFillFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||
|
||||
public AbstractArrayFillFunction() {
|
||||
super(
|
||||
"array_fill",
|
||||
new ArgumentTypesValidator( null, FunctionParameterType.NO_UNTYPED, FunctionParameterType.INTEGER ),
|
||||
ArrayViaElementArgumentReturnTypeResolver.DEFAULT_INSTANCE,
|
||||
ArrayFillArgumentsValidator.INSTANCE
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgumentListSignature() {
|
||||
return "(OBJECT element, INTEGER elementCount)";
|
||||
}
|
||||
|
||||
private static class ArrayFillArgumentsValidator implements FunctionArgumentTypeResolver {
|
||||
|
||||
public static final FunctionArgumentTypeResolver INSTANCE = new ArrayFillArgumentsValidator();
|
||||
|
||||
private ArrayFillArgumentsValidator() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingModelExpressible<?> resolveFunctionArgumentType(
|
||||
SqmFunction<?> function,
|
||||
int argumentIndex,
|
||||
SqmToSqlAstConverter converter) {
|
||||
if ( argumentIndex == 0 ) {
|
||||
final MappingModelExpressible<?> impliedReturnType = converter.resolveFunctionImpliedReturnType();
|
||||
return impliedReturnType instanceof BasicPluralType<?, ?>
|
||||
? ( (BasicPluralType<?, ?>) impliedReturnType ).getElementType()
|
||||
: null;
|
||||
}
|
||||
else {
|
||||
return converter.getCreationContext().getSessionFactory().getTypeConfiguration().getBasicTypeRegistry()
|
||||
.getRegisteredType( Integer.class );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -39,7 +39,7 @@ public class ArrayAggFunction extends AbstractSqmSelfRenderingFunctionDescriptor
|
|||
FUNCTION_NAME,
|
||||
FunctionKind.ORDERED_SET_AGGREGATE,
|
||||
StandardArgumentsValidators.exactly( 1 ),
|
||||
ArrayViaElementArgumentReturnTypeResolver.INSTANCE,
|
||||
ArrayViaElementArgumentReturnTypeResolver.VARARGS_INSTANCE,
|
||||
StandardFunctionArgumentTypeResolvers.NULL
|
||||
);
|
||||
this.functionName = functionName;
|
||||
|
|
|
@ -33,7 +33,7 @@ public class ArrayConstructorFunction extends AbstractSqmSelfRenderingFunctionDe
|
|||
super(
|
||||
"array",
|
||||
ArrayConstructorArgumentsValidator.INSTANCE,
|
||||
ArrayViaElementArgumentReturnTypeResolver.INSTANCE,
|
||||
ArrayViaElementArgumentReturnTypeResolver.VARARGS_INSTANCE,
|
||||
StandardFunctionArgumentTypeResolvers.NULL
|
||||
);
|
||||
this.withKeyword = withKeyword;
|
||||
|
|
|
@ -61,7 +61,7 @@ public class ArrayRemoveIndexUnnestFunction extends AbstractSqmSelfRenderingFunc
|
|||
sqlAppender.append( "),");
|
||||
if ( castEmptyArrayLiteral ) {
|
||||
sqlAppender.append( "cast(array[] as " );
|
||||
sqlAppender.append( DdlTypeHelper.getCastTypeName( arrayExpression.getExpressionType(), walker ) );
|
||||
sqlAppender.append( DdlTypeHelper.getCastTypeName( returnType, walker ) );
|
||||
sqlAppender.append( ')' );
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -68,7 +68,7 @@ public class ArraySliceUnnestFunction extends AbstractSqmSelfRenderingFunctionDe
|
|||
sqlAppender.append( "),");
|
||||
if ( castEmptyArrayLiteral ) {
|
||||
sqlAppender.append( "cast(array[] as " );
|
||||
sqlAppender.append( DdlTypeHelper.getCastTypeName( arrayExpression.getExpressionType(), walker ) );
|
||||
sqlAppender.append( DdlTypeHelper.getCastTypeName( returnType, walker ) );
|
||||
sqlAppender.append( ')' );
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -24,9 +24,13 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
*/
|
||||
public class ArrayViaElementArgumentReturnTypeResolver implements FunctionReturnTypeResolver {
|
||||
|
||||
public static final FunctionReturnTypeResolver INSTANCE = new ArrayViaElementArgumentReturnTypeResolver();
|
||||
public static final FunctionReturnTypeResolver DEFAULT_INSTANCE = new ArrayViaElementArgumentReturnTypeResolver( 0 );
|
||||
public static final FunctionReturnTypeResolver VARARGS_INSTANCE = new ArrayViaElementArgumentReturnTypeResolver( -1 );
|
||||
|
||||
private ArrayViaElementArgumentReturnTypeResolver() {
|
||||
private final int elementIndex;
|
||||
|
||||
private ArrayViaElementArgumentReturnTypeResolver(int elementIndex) {
|
||||
this.elementIndex = elementIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -47,8 +51,16 @@ public class ArrayViaElementArgumentReturnTypeResolver implements FunctionReturn
|
|||
if ( impliedType != null ) {
|
||||
return impliedType;
|
||||
}
|
||||
for ( SqmTypedNode<?> argument : arguments ) {
|
||||
final DomainType<?> sqmType = argument.getExpressible().getSqmType();
|
||||
if ( elementIndex == -1 ) {
|
||||
for ( SqmTypedNode<?> argument : arguments ) {
|
||||
final DomainType<?> sqmType = argument.getExpressible().getSqmType();
|
||||
if ( sqmType instanceof ReturnableType<?> ) {
|
||||
return DdlTypeHelper.resolveArrayType( sqmType, typeConfiguration );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
final DomainType<?> sqmType = arguments.get( elementIndex ).getExpressible().getSqmType();
|
||||
if ( sqmType instanceof ReturnableType<?> ) {
|
||||
return DdlTypeHelper.resolveArrayType( sqmType, typeConfiguration );
|
||||
}
|
||||
|
|
|
@ -40,21 +40,44 @@ public class DdlTypeHelper {
|
|||
);
|
||||
}
|
||||
|
||||
public static String getTypeName(BasicType<?> type, SqlAstTranslator<?> walker) {
|
||||
return getTypeName( (JdbcMappingContainer) type, walker );
|
||||
}
|
||||
|
||||
public static String getTypeName(JdbcMappingContainer type, SqlAstTranslator<?> walker) {
|
||||
if ( type instanceof SqlTypedMapping ) {
|
||||
return AbstractSqlAstTranslator.getSqlTypeName( (SqlTypedMapping) type, walker.getSessionFactory() );
|
||||
}
|
||||
else {
|
||||
final BasicType<?> jdbcMapping = (BasicType<?>) type.getSingleJdbcMapping();
|
||||
final BasicType<?> basicType = (BasicType<?>) type.getSingleJdbcMapping();
|
||||
final TypeConfiguration typeConfiguration = walker.getSessionFactory().getTypeConfiguration();
|
||||
final DdlTypeRegistry ddlTypeRegistry = typeConfiguration.getDdlTypeRegistry();
|
||||
final DdlType ddlType = ddlTypeRegistry.getDescriptor(
|
||||
jdbcMapping.getJdbcType().getDdlTypeCode()
|
||||
basicType.getJdbcType().getDdlTypeCode()
|
||||
);
|
||||
return ddlType.getTypeName( Size.nil(), jdbcMapping, ddlTypeRegistry );
|
||||
return ddlType.getTypeName( Size.nil(), basicType, ddlTypeRegistry );
|
||||
}
|
||||
}
|
||||
|
||||
public static String getTypeName(ReturnableType<?> type, SqlAstTranslator<?> walker) {
|
||||
if ( type instanceof SqlTypedMapping ) {
|
||||
return AbstractSqlAstTranslator.getSqlTypeName( (SqlTypedMapping) type, walker.getSessionFactory() );
|
||||
}
|
||||
else {
|
||||
final BasicType<?> basicType = (BasicType<?>) ( (JdbcMappingContainer) type ).getSingleJdbcMapping();
|
||||
final TypeConfiguration typeConfiguration = walker.getSessionFactory().getTypeConfiguration();
|
||||
final DdlTypeRegistry ddlTypeRegistry = typeConfiguration.getDdlTypeRegistry();
|
||||
final DdlType ddlType = ddlTypeRegistry.getDescriptor(
|
||||
basicType.getJdbcType().getDdlTypeCode()
|
||||
);
|
||||
return ddlType.getTypeName( Size.nil(), basicType, ddlTypeRegistry );
|
||||
}
|
||||
}
|
||||
|
||||
public static String getCastTypeName(BasicType<?> type, SqlAstTranslator<?> walker) {
|
||||
return getCastTypeName( (JdbcMappingContainer) type, walker );
|
||||
}
|
||||
|
||||
public static String getCastTypeName(JdbcMappingContainer type, SqlAstTranslator<?> walker) {
|
||||
if ( type instanceof SqlTypedMapping ) {
|
||||
return AbstractSqlAstTranslator.getCastTypeName( (SqlTypedMapping) type, walker.getSessionFactory() );
|
||||
|
@ -70,4 +93,19 @@ public class DdlTypeHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public static String getCastTypeName(ReturnableType<?> type, SqlAstTranslator<?> walker) {
|
||||
if ( type instanceof SqlTypedMapping ) {
|
||||
return AbstractSqlAstTranslator.getCastTypeName( (SqlTypedMapping) type, walker.getSessionFactory() );
|
||||
}
|
||||
else {
|
||||
final BasicType<?> basicType = (BasicType<?>) ( (JdbcMappingContainer) type ).getSingleJdbcMapping();
|
||||
final TypeConfiguration typeConfiguration = walker.getSessionFactory().getTypeConfiguration();
|
||||
final DdlTypeRegistry ddlTypeRegistry = typeConfiguration.getDdlTypeRegistry();
|
||||
final DdlType ddlType = ddlTypeRegistry.getDescriptor(
|
||||
basicType.getJdbcType().getDdlTypeCode()
|
||||
);
|
||||
return ddlType.getCastTypeName( Size.nil(), basicType, ddlTypeRegistry );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.ReturnableType;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
|
||||
/**
|
||||
* Implement the array fill function by using {@code system_range}.
|
||||
*/
|
||||
public class H2ArrayFillFunction extends AbstractArrayFillFunction {
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
ReturnableType<?> returnType,
|
||||
SqlAstTranslator<?> walker) {
|
||||
sqlAppender.append( "coalesce((select array_agg(" );
|
||||
sqlAstArguments.get( 0 ).accept( walker );
|
||||
sqlAppender.append( ") from system_range(1," );
|
||||
sqlAstArguments.get( 1 ).accept( walker );
|
||||
sqlAppender.append( ")),array[])" );
|
||||
}
|
||||
}
|
|
@ -32,12 +32,7 @@ public class HSQLArrayConstructorFunction extends ArrayConstructorFunction {
|
|||
SqlAstTranslator<?> walker) {
|
||||
final String castTypeName;
|
||||
if ( returnType != null && hasOnlyBottomArguments( arguments ) ) {
|
||||
if ( returnType instanceof SqlTypedMapping ) {
|
||||
castTypeName = AbstractSqlAstTranslator.getCastTypeName( (SqlTypedMapping) returnType, walker.getSessionFactory() );
|
||||
}
|
||||
else {
|
||||
castTypeName = DdlTypeHelper.getCastTypeName( (JdbcMappingContainer) returnType, walker );
|
||||
}
|
||||
castTypeName = DdlTypeHelper.getCastTypeName( returnType, walker );
|
||||
sqlAppender.append( "cast(" );
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.ReturnableType;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
|
||||
/**
|
||||
* Implement the array fill function by using {@code sequence_array}.
|
||||
*/
|
||||
public class HSQLArrayFillFunction extends AbstractArrayFillFunction {
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
ReturnableType<?> returnType,
|
||||
SqlAstTranslator<?> walker) {
|
||||
sqlAppender.append( "coalesce(case when " );
|
||||
sqlAstArguments.get( 1 ).accept( walker );
|
||||
sqlAppender.append( "<>0 then (select array_agg(" );
|
||||
walker.render( sqlAstArguments.get( 0 ), SqlAstNodeRenderingMode.NO_UNTYPED );
|
||||
sqlAppender.append( ") from unnest(sequence_array(1," );
|
||||
sqlAstArguments.get( 1 ).accept( walker );
|
||||
sqlAppender.append( ",1))) end,array[])" );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.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;
|
||||
|
||||
/**
|
||||
* Oracle array_fill function.
|
||||
*/
|
||||
public class OracleArrayFillFunction extends AbstractArrayFillFunction {
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
ReturnableType<?> returnType,
|
||||
SqlAstTranslator<?> walker) {
|
||||
final String arrayTypeName = DdlTypeHelper.getTypeName( returnType, walker );
|
||||
sqlAppender.append( arrayTypeName );
|
||||
sqlAppender.append( "_fill(" );
|
||||
sqlAstArguments.get( 0 ).accept( walker );
|
||||
sqlAppender.append( ',' );
|
||||
sqlAstArguments.get( 1 ).accept( walker );
|
||||
sqlAppender.append( ')' );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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.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.sql.ast.tree.expression.Literal;
|
||||
|
||||
/**
|
||||
* Implement the array get function by using {@code unnest}.
|
||||
*/
|
||||
public class PostgreSQLArrayFillFunction extends AbstractArrayFillFunction {
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<? extends SqlAstNode> sqlAstArguments,
|
||||
ReturnableType<?> returnType,
|
||||
SqlAstTranslator<?> walker) {
|
||||
sqlAppender.append( "array_fill(" );
|
||||
final String elementCastType;
|
||||
final Expression elementExpression = (Expression) sqlAstArguments.get( 0 );
|
||||
if ( needsElementCasting( elementExpression ) ) {
|
||||
elementCastType = DdlTypeHelper.getCastTypeName( elementExpression.getExpressionType(), walker );
|
||||
sqlAppender.append( "cast(" );
|
||||
}
|
||||
else {
|
||||
elementCastType = null;
|
||||
}
|
||||
sqlAstArguments.get( 0 ).accept( walker );
|
||||
if ( elementCastType != null ) {
|
||||
sqlAppender.append( " as " );
|
||||
sqlAppender.append( elementCastType );
|
||||
sqlAppender.append( ')' );
|
||||
}
|
||||
sqlAppender.append( ",array[" );
|
||||
sqlAstArguments.get( 1 ).accept( walker );
|
||||
sqlAppender.append( "])" );
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -28,23 +28,23 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
public class ResultSetMappingSqlSelection implements SqlSelection, Expression, SqlExpressionAccess {
|
||||
private final int valuesArrayPosition;
|
||||
private final BasicValuedMapping valueMapping;
|
||||
private final JdbcMapping jdbcMapping;
|
||||
private final ValueExtractor valueExtractor;
|
||||
|
||||
public ResultSetMappingSqlSelection(int valuesArrayPosition, BasicValuedMapping valueMapping) {
|
||||
this.valuesArrayPosition = valuesArrayPosition;
|
||||
this.valueMapping = valueMapping;
|
||||
this.jdbcMapping = valueMapping.getJdbcMapping();
|
||||
this.valueExtractor = valueMapping.getJdbcMapping().getJdbcValueExtractor();
|
||||
}
|
||||
|
||||
public ResultSetMappingSqlSelection(int valuesArrayPosition, JdbcMapping jdbcMapping) {
|
||||
this.valuesArrayPosition = valuesArrayPosition;
|
||||
this.jdbcMapping = jdbcMapping;
|
||||
this.valueMapping = null;
|
||||
this.valueExtractor = jdbcMapping.getJdbcValueExtractor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueExtractor getJdbcValueExtractor() {
|
||||
return jdbcMapping.getJdbcValueExtractor();
|
||||
return valueExtractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -852,7 +852,6 @@ public class CteInsertHandler implements InsertHandler {
|
|||
final CteColumn idCteColumn = cteColumns.get( 0 );
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
0,
|
||||
new ColumnReference(
|
||||
"t",
|
||||
idCteColumn.getColumnExpression(),
|
||||
|
@ -867,7 +866,6 @@ public class CteInsertHandler implements InsertHandler {
|
|||
final CteColumn cteColumn = cteColumns.get( j );
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
0,
|
||||
new ColumnReference(
|
||||
"e",
|
||||
cteColumn.getColumnExpression(),
|
||||
|
@ -906,13 +904,11 @@ public class CteInsertHandler implements InsertHandler {
|
|||
);
|
||||
finalResultQuery.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
0,
|
||||
idColumnReference
|
||||
)
|
||||
);
|
||||
finalResultQuery.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
0,
|
||||
SqmInsertStrategyHelper.createRowNumberingExpression(
|
||||
querySpec,
|
||||
sessionFactory
|
||||
|
@ -958,7 +954,6 @@ public class CteInsertHandler implements InsertHandler {
|
|||
);
|
||||
insertSelectSpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
0,
|
||||
new ColumnReference(
|
||||
"e",
|
||||
rootKeyColumns[j],
|
||||
|
@ -991,7 +986,6 @@ public class CteInsertHandler implements InsertHandler {
|
|||
final ColumnReference columnReference = assignmentReferences.get( j );
|
||||
insertSelectSpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
0,
|
||||
new ColumnReference(
|
||||
"e",
|
||||
entry.getKey().get( j ).getColumnExpression(),
|
||||
|
|
|
@ -460,7 +460,7 @@ public class InlineUpdateHandler implements UpdateHandler {
|
|||
)
|
||||
);
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl( 0, valuesColumnReference )
|
||||
new SqlSelectionImpl( valuesColumnReference )
|
||||
);
|
||||
}
|
||||
);
|
||||
|
@ -492,7 +492,7 @@ public class InlineUpdateHandler implements UpdateHandler {
|
|||
)
|
||||
);
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl( 0, valuesColumnReference )
|
||||
new SqlSelectionImpl( valuesColumnReference )
|
||||
);
|
||||
}
|
||||
final ValuesTableGroup valuesTableGroup = new ValuesTableGroup(
|
||||
|
|
|
@ -55,11 +55,7 @@ public final class ExecuteWithoutIdTableHelper {
|
|||
rootTableReference,
|
||||
selection
|
||||
);
|
||||
final SqlSelection sqlSelection = new SqlSelectionImpl(
|
||||
// irrelevant
|
||||
0,
|
||||
columnReference
|
||||
);
|
||||
final SqlSelection sqlSelection = new SqlSelectionImpl( columnReference );
|
||||
matchingIdSelect.getSelectClause().addSqlSelection( sqlSelection );
|
||||
}
|
||||
);
|
||||
|
|
|
@ -340,7 +340,6 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
for ( ColumnReference columnReference : assignable.getColumnReferences() ) {
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
0,
|
||||
new ColumnReference(
|
||||
updatingTableReference.getIdentificationVariable(),
|
||||
columnReference.getColumnExpression(),
|
||||
|
@ -528,7 +527,6 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
);
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
0,
|
||||
new ColumnReference(
|
||||
updatingTableReference.getIdentificationVariable(),
|
||||
idColumnReference.getColumnExpression(),
|
||||
|
@ -688,7 +686,6 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
for ( ColumnReference columnReference : assignment.getAssignable().getColumnReferences() ) {
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
0,
|
||||
new ColumnReference(
|
||||
updatingTableReference.getIdentificationVariable(),
|
||||
columnReference.getColumnExpression(),
|
||||
|
@ -732,7 +729,6 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
);
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
0,
|
||||
new ColumnReference(
|
||||
updatingTableReference.getIdentificationVariable(),
|
||||
identifierMapping
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.hibernate.query.sqm.tree.SqmTypedNode;
|
|||
import org.hibernate.query.sqm.tree.expression.SqmCollation;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmDurationUnit;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteralNull;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmTrimSpecification;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
|
@ -119,6 +120,17 @@ public class ArgumentTypesValidator implements ArgumentsValidator {
|
|||
throwError(type, Object.class, functionName, count);
|
||||
}
|
||||
break;
|
||||
case NO_UNTYPED:
|
||||
if ( argument instanceof SqmLiteralNull<?> ) {
|
||||
throw new FunctionArgumentException(
|
||||
String.format(
|
||||
"Parameter %d of function '%s()' does not permit untyped expressions like null literals. Please cast the expression to a type",
|
||||
count,
|
||||
functionName
|
||||
)
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -87,5 +87,9 @@ public enum FunctionParameterType {
|
|||
* Indicates that the argument should be a spatial type
|
||||
* @see org.hibernate.type.SqlTypes#isSpatialType(int)
|
||||
*/
|
||||
SPATIAL
|
||||
SPATIAL,
|
||||
/**
|
||||
* Indicates a parameter that accepts any type, except untyped expressions like {@code null} literals
|
||||
*/
|
||||
NO_UNTYPED
|
||||
}
|
||||
|
|
|
@ -1498,14 +1498,14 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
if ( versionExpression != null ) {
|
||||
if ( versionSelection == null ) {
|
||||
// The position is irrelevant as this is only needed for insert
|
||||
versionSelection = new SqlSelectionImpl( 0, versionExpression );
|
||||
versionSelection = new SqlSelectionImpl( versionExpression );
|
||||
}
|
||||
selectClause.addSqlSelection( versionSelection );
|
||||
}
|
||||
if ( discriminatorExpression != null ) {
|
||||
if ( discriminatorSelection == null ) {
|
||||
// The position is irrelevant as this is only needed for insert
|
||||
discriminatorSelection = new SqlSelectionImpl( 0, discriminatorExpression );
|
||||
discriminatorSelection = new SqlSelectionImpl( discriminatorExpression );
|
||||
}
|
||||
selectClause.addSqlSelection( discriminatorSelection );
|
||||
}
|
||||
|
@ -1525,7 +1525,6 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
return false;
|
||||
}
|
||||
identifierSelection = new SqlSelectionImpl(
|
||||
0,
|
||||
SqmInsertStrategyHelper.createRowNumberingExpression( querySpec, sessionFactory )
|
||||
);
|
||||
selectClause.addSqlSelection( identifierSelection );
|
||||
|
@ -1538,7 +1537,6 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
);
|
||||
// The position is irrelevant as this is only needed for insert
|
||||
identifierSelection = new SqlSelectionImpl(
|
||||
0,
|
||||
new SelfRenderingSqlFragmentExpression( fragment )
|
||||
);
|
||||
}
|
||||
|
@ -4517,7 +4515,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
integerType,
|
||||
integerType
|
||||
);
|
||||
subQuerySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl( 0, expression ) );
|
||||
subQuerySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl( expression ) );
|
||||
|
||||
subQuerySpec.applyPredicate(
|
||||
pluralAttributeMapping.getKeyDescriptor().generateJoinPredicate(
|
||||
|
@ -4711,7 +4709,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
).getJdbcMapping(),
|
||||
modelPart
|
||||
);
|
||||
subQuerySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl( 0, expression ) );
|
||||
subQuerySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl( expression ) );
|
||||
|
||||
NavigablePath parent = pluralPartPath.getPluralDomainPath().getNavigablePath().getParent();
|
||||
subQuerySpec.applyPredicate(
|
||||
|
@ -4885,10 +4883,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
);
|
||||
|
||||
subQuerySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
0,
|
||||
expression
|
||||
)
|
||||
new SqlSelectionImpl( expression )
|
||||
);
|
||||
resultColumnReferences.add(
|
||||
new ColumnReference(
|
||||
|
@ -7576,9 +7571,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
assert jdbcTypeCount > 0;
|
||||
|
||||
final JdbcLiteral<Integer> jdbcLiteral = new JdbcLiteral<>( 1, basicType( Integer.class ) );
|
||||
subQuerySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl( 0, jdbcLiteral )
|
||||
);
|
||||
subQuerySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl( jdbcLiteral ) );
|
||||
|
||||
return new ExistsPredicate( subQuerySpec, !predicate.isNegated(), getBooleanType() );
|
||||
}
|
||||
|
|
|
@ -5772,12 +5772,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
if ( shouldEmulateLateralWithIntersect( statement.getQueryPart() ) ) {
|
||||
final QuerySpec lhsReferencesQuery = new QuerySpec( false );
|
||||
for ( ColumnReference columnReference : columnReferences ) {
|
||||
lhsReferencesQuery.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
0,
|
||||
columnReference
|
||||
)
|
||||
);
|
||||
lhsReferencesQuery.getSelectClause().addSqlSelection( new SqlSelectionImpl( columnReference ) );
|
||||
}
|
||||
final List<QueryPart> queryParts = new ArrayList<>( 2 );
|
||||
queryParts.add( lhsReferencesQuery );
|
||||
|
@ -5822,10 +5817,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
}
|
||||
final QuerySpec existsQuery = new QuerySpec( false, 1 );
|
||||
existsQuery.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
0,
|
||||
new QueryLiteral<>( 1, getIntegerType() )
|
||||
)
|
||||
new SqlSelectionImpl( new QueryLiteral<>( 1, getIntegerType() ) )
|
||||
);
|
||||
existsQuery.getFromClause().addRoot( subTableGroup );
|
||||
existsQuery.applyPredicate(
|
||||
|
@ -5874,10 +5866,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
existsQuery.setGroupByClauseExpressions( querySpec.getGroupByClauseExpressions() );
|
||||
existsQuery.setHavingClauseRestrictions( querySpec.getHavingClauseRestrictions() );
|
||||
existsQuery.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
0,
|
||||
new QueryLiteral<>( 1, getIntegerType() )
|
||||
)
|
||||
new SqlSelectionImpl( new QueryLiteral<>( 1, getIntegerType() ) )
|
||||
);
|
||||
existsQuery.applyPredicate(
|
||||
new ComparisonPredicate(
|
||||
|
@ -5911,7 +5900,6 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
countQuery.setHavingClauseRestrictions( querySpec.getHavingClauseRestrictions() );
|
||||
countQuery.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
0,
|
||||
new SelfRenderingAggregateFunctionSqlAstExpression(
|
||||
"count",
|
||||
(sqlAppender, sqlAstArguments, returnType, walker) -> sqlAppender.append( "count(*)" ),
|
||||
|
|
|
@ -26,7 +26,7 @@ public class ResolvedSqlSelection extends SqlSelectionImpl {
|
|||
int valuesArrayPosition,
|
||||
Expression sqlExpression,
|
||||
BasicType<Object> resolvedType) {
|
||||
super( valuesArrayPosition + 1, valuesArrayPosition, null, sqlExpression, false );
|
||||
super( valuesArrayPosition + 1, valuesArrayPosition, sqlExpression, null, false, resolvedType.getJdbcValueExtractor() );
|
||||
this.resolvedType = resolvedType;
|
||||
}
|
||||
|
||||
|
@ -35,15 +35,10 @@ public class ResolvedSqlSelection extends SqlSelectionImpl {
|
|||
int valuesArrayPosition,
|
||||
Expression sqlExpression,
|
||||
BasicType<Object> resolvedType) {
|
||||
super( jdbcPosition, valuesArrayPosition, null, sqlExpression, false );
|
||||
super( jdbcPosition, valuesArrayPosition, sqlExpression, null, false, resolvedType.getJdbcValueExtractor() );
|
||||
this.resolvedType = resolvedType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueExtractor getJdbcValueExtractor() {
|
||||
return resolvedType.getJdbcMapping().getJdbcValueExtractor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcMappingContainer getExpressionType() {
|
||||
return resolvedType;
|
||||
|
|
|
@ -47,6 +47,7 @@ public class SqlSelectionImpl implements SqlSelection, SqlExpressionAccess {
|
|||
private final Expression sqlExpression;
|
||||
private final JavaType<?> jdbcJavaType;
|
||||
private final boolean virtual;
|
||||
private transient ValueExtractor valueExtractor;
|
||||
|
||||
public SqlSelectionImpl(Expression sqlExpression) {
|
||||
this( 0, -1, null, sqlExpression, false );
|
||||
|
@ -66,11 +67,39 @@ public class SqlSelectionImpl implements SqlSelection, SqlExpressionAccess {
|
|||
JavaType<?> jdbcJavaType,
|
||||
Expression sqlExpression,
|
||||
boolean virtual) {
|
||||
this(
|
||||
jdbcPosition,
|
||||
valuesArrayPosition,
|
||||
sqlExpression,
|
||||
jdbcJavaType,
|
||||
virtual,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
protected SqlSelectionImpl(
|
||||
int jdbcPosition,
|
||||
int valuesArrayPosition,
|
||||
Expression sqlExpression,
|
||||
JavaType<?> jdbcJavaType,
|
||||
boolean virtual,
|
||||
ValueExtractor valueExtractor) {
|
||||
this.jdbcPosition = jdbcPosition;
|
||||
this.valuesArrayPosition = valuesArrayPosition;
|
||||
this.jdbcJavaType = jdbcJavaType;
|
||||
this.sqlExpression = sqlExpression;
|
||||
this.jdbcJavaType = jdbcJavaType;
|
||||
this.virtual = virtual;
|
||||
this.valueExtractor = valueExtractor;
|
||||
}
|
||||
|
||||
private static ValueExtractor determineValueExtractor(Expression sqlExpression, JavaType<?> jdbcJavaType) {
|
||||
final JdbcMapping jdbcMapping = sqlExpression.getExpressionType().getSingleJdbcMapping();
|
||||
if ( jdbcJavaType == null || jdbcMapping.getMappedJavaType() == jdbcJavaType ) {
|
||||
return jdbcMapping.getJdbcValueExtractor();
|
||||
}
|
||||
else {
|
||||
return jdbcMapping.getJdbcType().getExtractor( jdbcJavaType );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -80,11 +109,11 @@ public class SqlSelectionImpl implements SqlSelection, SqlExpressionAccess {
|
|||
|
||||
@Override
|
||||
public ValueExtractor getJdbcValueExtractor() {
|
||||
final JdbcMapping jdbcMapping = sqlExpression.getExpressionType().getSingleJdbcMapping();
|
||||
if ( jdbcJavaType == null || jdbcMapping.getMappedJavaType() == jdbcJavaType ) {
|
||||
return jdbcMapping.getJdbcValueExtractor();
|
||||
ValueExtractor extractor = valueExtractor;
|
||||
if ( extractor == null ) {
|
||||
valueExtractor = extractor = determineValueExtractor( sqlExpression, jdbcJavaType );
|
||||
}
|
||||
return jdbcMapping.getJdbcType().getExtractor( jdbcJavaType );
|
||||
return extractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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 static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* @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 ArrayFillTest {
|
||||
|
||||
@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 testFill(SessionFactoryScope scope) {
|
||||
scope.inSession( em -> {
|
||||
//tag::hql-array-fill-example[]
|
||||
List<String[]> results = em.createQuery( "select array_fill('aaa', 2)", String[].class )
|
||||
.getResultList();
|
||||
//end::hql-array-fill-example[]
|
||||
assertEquals( 1, results.size() );
|
||||
assertArrayEquals( new String[] { "aaa", "aaa" }, results.get( 0 ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFillEmpty(SessionFactoryScope scope) {
|
||||
scope.inSession( em -> {
|
||||
List<String[]> results = em.createQuery( "select array_fill('aaa', 0)", String[].class )
|
||||
.getResultList();
|
||||
assertEquals( 1, results.size() );
|
||||
assertArrayEquals( new String[0], results.get( 0 ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFillNull(SessionFactoryScope scope) {
|
||||
scope.inSession( em -> {
|
||||
List<String[]> results = em.createQuery( "select array_fill(cast(null as String), 1)", String[].class )
|
||||
.getResultList();
|
||||
assertEquals( 1, results.size() );
|
||||
assertArrayEquals( new String[]{ null }, results.get( 0 ) );
|
||||
} );
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue