Skip to content

Commit

Permalink
HHH-17355 Test array functions with NodeBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
beikov committed Nov 6, 2023
1 parent e4d8181 commit d7bdb5c
Show file tree
Hide file tree
Showing 40 changed files with 3,543 additions and 2,420 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,7 @@ The following functions deal with SQL array types, which are not supported on ev
| Function | Purpose
| `array()` | Creates an array based on the passed arguments
| `array_list()` | Like `array`, but returns the result as `List<?>`
| `array_agg()` | Aggregates row values into an array
| `array_position()` | Determines the position of an element in an array
| `array_positions()` | Determines all positions of an element in an array
Expand All @@ -1138,12 +1139,15 @@ The following functions deal with SQL array types, which are not supported on ev
| `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_fill_list()` | Like `array_fill`, but returns the result as `List<?>`
| `array_to_string()` | String representation of non-null array elements
|===
===== `array()`
[[hql-array-constructor-functions]]
===== `array()` and `array_list()`
Creates an array based on the passed arguments, and infers the array type from the context if possible.
To retrieve the result as `List<?>`, use the `array_list()` function.
[[hql-array-constructor-example]]
====
Expand All @@ -1153,6 +1157,7 @@ include::{array-example-dir-hql}/ArrayConstructorTest.java[tags=hql-array-exampl
----
====
[[hql-array-aggregate-functions]]
===== `array_agg()`
An <<hql-aggregate-functions-orderedset,ordered set aggregate function>> that aggregates values to an array.
Expand Down Expand Up @@ -1404,6 +1409,7 @@ include::{array-example-dir-hql}/ArrayReplaceTest.java[tags=hql-array-replace-ex
----
====
[[hql-array-trim-functions]]
===== `array_trim()`
Returns an array copy without the last _N_ elements, specified by the second argument.
Expand All @@ -1417,10 +1423,12 @@ include::{array-example-dir-hql}/ArrayTrimTest.java[tags=hql-array-trim-example]
----
====
===== `array_fill()`
[[hql-array-fill-functions]]
===== `array_fill()` and `array_fill_list()`
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.
To retrieve the result as `List<?>`, use the `array_fill_list()` function.
[[hql-array-fill-example]]
====
Expand All @@ -1430,6 +1438,7 @@ include::{array-example-dir-hql}/ArrayFillTest.java[tags=hql-array-fill-example]
----
====
[[hql-array-to-string-functions]]
===== `array_to_string()`
Concatenates the non-null array elements with a separator, as specified by the arguments.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,9 @@
*/
package org.hibernate.dialect.function;

import java.lang.reflect.Type;
import java.util.Date;
import java.util.Arrays;
import java.util.List;

import org.hibernate.annotations.common.reflection.java.generics.ParameterizedTypeImpl;
import org.hibernate.boot.model.FunctionContributions;
import org.hibernate.dialect.Dialect;

Expand Down Expand Up @@ -2604,35 +2601,40 @@ public void dateTrunc_datetrunc() {
* H2, HSQL array() constructor function
*/
public void array() {
functionRegistry.register( "array", new ArrayConstructorFunction( true ) );
functionRegistry.register( "array", new ArrayConstructorFunction( false, true ) );
functionRegistry.register( "array_list", new ArrayConstructorFunction( true, true ) );
}

/**
* H2, HSQL array() constructor function
*/
public void array_hsql() {
functionRegistry.register( "array", new HSQLArrayConstructorFunction() );
functionRegistry.register( "array", new HSQLArrayConstructorFunction( false ) );
functionRegistry.register( "array_list", new HSQLArrayConstructorFunction( true ) );
}

/**
* CockroachDB and PostgreSQL array() constructor function
*/
public void array_postgresql() {
functionRegistry.register( "array", new PostgreSQLArrayConstructorFunction() );
functionRegistry.register( "array", new PostgreSQLArrayConstructorFunction( false ) );
functionRegistry.register( "array_list", new PostgreSQLArrayConstructorFunction( true ) );
}

/**
* Google Spanner array() constructor function
*/
public void array_spanner() {
functionRegistry.register( "array", new ArrayConstructorFunction( false ) );
functionRegistry.register( "array", new ArrayConstructorFunction( false, false ) );
functionRegistry.register( "array_list", new ArrayConstructorFunction( true, false ) );
}

/**
* Oracle array() constructor function
*/
public void array_oracle() {
functionRegistry.register( "array", new OracleArrayConstructorFunction() );
functionRegistry.register( "array", new OracleArrayConstructorFunction( false ) );
functionRegistry.register( "array_list", new OracleArrayConstructorFunction( true ) );
}

/**
Expand Down Expand Up @@ -3175,28 +3177,32 @@ public void arrayTrim_oracle() {
* H2 array_fill() function
*/
public void arrayFill_h2() {
functionRegistry.register( "array_fill", new H2ArrayFillFunction() );
functionRegistry.register( "array_fill", new H2ArrayFillFunction( false ) );
functionRegistry.register( "array_fill_list", new H2ArrayFillFunction( true ) );
}

/**
* HSQLDB array_fill() function
*/
public void arrayFill_hsql() {
functionRegistry.register( "array_fill", new HSQLArrayFillFunction() );
functionRegistry.register( "array_fill", new HSQLArrayFillFunction( false ) );
functionRegistry.register( "array_fill_list", new HSQLArrayFillFunction( true ) );
}

/**
* PostgreSQL array_fill() function
*/
public void arrayFill_postgresql() {
functionRegistry.register( "array_fill", new PostgreSQLArrayFillFunction() );
functionRegistry.register( "array_fill", new PostgreSQLArrayFillFunction( false ) );
functionRegistry.register( "array_fill_list", new PostgreSQLArrayFillFunction( true ) );
}

/**
* Oracle array_fill() function
*/
public void arrayFill_oracle() {
functionRegistry.register( "array_fill", new OracleArrayFillFunction() );
functionRegistry.register( "array_fill", new OracleArrayFillFunction( false ) );
functionRegistry.register( "array_fill_list", new OracleArrayFillFunction( true ) );
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@
*/
public abstract class AbstractArrayFillFunction extends AbstractSqmSelfRenderingFunctionDescriptor {

public AbstractArrayFillFunction() {
public AbstractArrayFillFunction(boolean list) {
super(
"array_fill",
"array_fill" + ( list ? "_list" : "" ),
new ArgumentTypesValidator( null, FunctionParameterType.NO_UNTYPED, FunctionParameterType.INTEGER ),
ArrayViaElementArgumentReturnTypeResolver.DEFAULT_INSTANCE,
list
? ArrayViaElementArgumentReturnTypeResolver.VARARGS_LIST_INSTANCE
: ArrayViaElementArgumentReturnTypeResolver.VARARGS_INSTANCE,
ArrayFillArgumentsValidator.INSTANCE
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ public class ArrayConstructorFunction extends AbstractSqmSelfRenderingFunctionDe

private final boolean withKeyword;

public ArrayConstructorFunction(boolean withKeyword) {
public ArrayConstructorFunction(boolean list, boolean withKeyword) {
super(
"array",
"array" + ( list ? "_list" : "" ),
ArrayConstructorArgumentsValidator.INSTANCE,
ArrayViaElementArgumentReturnTypeResolver.VARARGS_INSTANCE,
list
? ArrayViaElementArgumentReturnTypeResolver.VARARGS_LIST_INSTANCE
: ArrayViaElementArgumentReturnTypeResolver.VARARGS_INSTANCE,
StandardFunctionArgumentTypeResolvers.NULL
);
this.withKeyword = withKeyword;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,17 @@
*/
public class ArrayViaElementArgumentReturnTypeResolver implements FunctionReturnTypeResolver {

public static final FunctionReturnTypeResolver DEFAULT_INSTANCE = new ArrayViaElementArgumentReturnTypeResolver( 0 );
public static final FunctionReturnTypeResolver VARARGS_INSTANCE = new ArrayViaElementArgumentReturnTypeResolver( -1 );
public static final FunctionReturnTypeResolver DEFAULT_INSTANCE = new ArrayViaElementArgumentReturnTypeResolver( false, 0 );

public static final FunctionReturnTypeResolver DEFAULT_LIST_INSTANCE = new ArrayViaElementArgumentReturnTypeResolver( true, 0 );
public static final FunctionReturnTypeResolver VARARGS_INSTANCE = new ArrayViaElementArgumentReturnTypeResolver( false, -1 );
public static final FunctionReturnTypeResolver VARARGS_LIST_INSTANCE = new ArrayViaElementArgumentReturnTypeResolver( true, -1 );

private final boolean list;
private final int elementIndex;

private ArrayViaElementArgumentReturnTypeResolver(int elementIndex) {
private ArrayViaElementArgumentReturnTypeResolver(boolean list, int elementIndex) {
this.list = list;
this.elementIndex = elementIndex;
}

Expand All @@ -55,14 +60,18 @@ else if ( inferredType instanceof BasicValuedMapping ) {
for ( SqmTypedNode<?> argument : arguments ) {
final DomainType<?> sqmType = argument.getExpressible().getSqmType();
if ( sqmType instanceof ReturnableType<?> ) {
return DdlTypeHelper.resolveArrayType( sqmType, typeConfiguration );
return list
? DdlTypeHelper.resolveListType( sqmType, typeConfiguration )
: DdlTypeHelper.resolveArrayType( sqmType, typeConfiguration );
}
}
}
else {
final DomainType<?> sqmType = arguments.get( elementIndex ).getExpressible().getSqmType();
if ( sqmType instanceof ReturnableType<?> ) {
return DdlTypeHelper.resolveArrayType( sqmType, typeConfiguration );
return list
? DdlTypeHelper.resolveListType( sqmType, typeConfiguration )
: DdlTypeHelper.resolveArrayType( sqmType, typeConfiguration );
}
}
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package org.hibernate.dialect.function.array;

import java.util.List;
import java.util.Objects;

import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.query.sqm.SqmExpressible;
Expand Down Expand Up @@ -46,7 +47,7 @@ public void validate(
}
arrayType = (BasicPluralType<?, ?>) sqmType;
}
else if ( !arrayType.equals( sqmType ) ) {
else if ( !isCompatible( arrayType, sqmType ) ) {
throw new FunctionArgumentException(
String.format(
"Parameter %d of function '%s()' requires an array type %s, but argument is of type '%s'",
Expand All @@ -61,6 +62,11 @@ else if ( !arrayType.equals( sqmType ) ) {
}
}

private static boolean isCompatible(BasicPluralType<?,?> arrayType, DomainType<?> sqmType) {
return arrayType == sqmType || sqmType instanceof BasicPluralType<?, ?>
&& Objects.equals( arrayType.getElementType(), ( (BasicPluralType<?, ?>) sqmType ).getElementType() );
}

@Override
public String getSignature() {
return "(ARRAY array0, ARRAY array1[, ARRAY array2, ...])";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
package org.hibernate.dialect.function.array;

import java.lang.reflect.Array;
import java.lang.reflect.Type;
import java.util.List;

import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.Size;
Expand All @@ -16,11 +18,11 @@
import org.hibernate.query.ReturnableType;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.type.BasicPluralType;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.BasicPluralJavaType;
import org.hibernate.type.descriptor.sql.DdlType;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
import org.hibernate.type.internal.ParameterizedTypeImpl;
import org.hibernate.type.spi.TypeConfiguration;

public class DdlTypeHelper {
Expand All @@ -40,6 +42,24 @@ public static BasicType<?> resolveArrayType(DomainType<?> elementType, TypeConfi
);
}

@SuppressWarnings("unchecked")
public static BasicType<?> resolveListType(DomainType<?> elementType, TypeConfiguration typeConfiguration) {
@SuppressWarnings("unchecked") final BasicPluralJavaType<Object> arrayJavaType = (BasicPluralJavaType<Object>) typeConfiguration.getJavaTypeRegistry()
.getDescriptor( List.class )
.createJavaType(
new ParameterizedTypeImpl( List.class, new Type[]{ elementType.getBindableJavaType() }, null ),
typeConfiguration
);
final Dialect dialect = typeConfiguration.getCurrentBaseSqlTypeIndicators().getDialect();
return arrayJavaType.resolveType(
typeConfiguration,
dialect,
(BasicType<Object>) elementType,
null,
typeConfiguration.getCurrentBaseSqlTypeIndicators()
);
}

public static String getTypeName(BasicType<?> type, SqlAstTranslator<?> walker) {
return getTypeName( (JdbcMappingContainer) type, walker );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
*/
public class H2ArrayFillFunction extends AbstractArrayFillFunction {

public H2ArrayFillFunction(boolean list) {
super( list );
}

@Override
public void render(
SqlAppender sqlAppender,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,17 @@

import java.util.List;

import org.hibernate.metamodel.mapping.JdbcMappingContainer;
import org.hibernate.metamodel.mapping.SqlTypedMapping;
import org.hibernate.query.ReturnableType;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.type.BottomType;

public class HSQLArrayConstructorFunction extends ArrayConstructorFunction {

public HSQLArrayConstructorFunction() {
super( true );
public HSQLArrayConstructorFunction(boolean list) {
super( list, true );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
*/
public class HSQLArrayFillFunction extends AbstractArrayFillFunction {

public HSQLArrayFillFunction(boolean list) {
super( list );
}

@Override
public void render(
SqlAppender sqlAppender,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@

public class OracleArrayConstructorFunction extends ArrayConstructorFunction {

public OracleArrayConstructorFunction() {
super( false );
public OracleArrayConstructorFunction(boolean list) {
super( list, false );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
*/
public class OracleArrayFillFunction extends AbstractArrayFillFunction {

public OracleArrayFillFunction(boolean list) {
super( list );
}

@Override
public void render(
SqlAppender sqlAppender,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
*/
public class PostgreSQLArrayConstructorFunction extends ArrayConstructorFunction {

public PostgreSQLArrayConstructorFunction() {
super( true );
public PostgreSQLArrayConstructorFunction(boolean list) {
super( list, true );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
*/
public class PostgreSQLArrayFillFunction extends AbstractArrayFillFunction {

public PostgreSQLArrayFillFunction(boolean list) {
super( list );
}

@Override
public void render(
SqlAppender sqlAppender,
Expand Down

0 comments on commit d7bdb5c

Please sign in to comment.