Skip to content

Commit

Permalink
HHH-17355 Add array_fill function
Browse files Browse the repository at this point in the history
  • Loading branch information
beikov committed Nov 6, 2023
1 parent 6d392f5 commit 1a5184e
Show file tree
Hide file tree
Showing 37 changed files with 521 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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()`
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
functionFactory.arraySlice_operator();
functionFactory.arrayReplace();
functionFactory.arrayTrim_trim_array();
functionFactory.arrayFill_postgresql();

functionContributions.getFunctionRegistry().register(
"trunc",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
functionFactory.arraySlice();
functionFactory.arrayReplace_h2( getMaximumArraySize() );
functionFactory.arrayTrim_trim_array();
functionFactory.arrayFill_h2();
}
else {
// Use group_concat until 2.x as listagg was buggy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
functionFactory.arraySlice_unnest();
functionFactory.arrayReplace_unnest();
functionFactory.arrayTrim_trim_array();
functionFactory.arrayFill_hsql();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
functionFactory.arraySlice_oracle();
functionFactory.arrayReplace_oracle();
functionFactory.arrayTrim_oracle();
functionFactory.arrayFill_oracle();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
functionFactory.arraySlice_operator();
functionFactory.arrayReplace();
functionFactory.arrayTrim_trim_array();
functionFactory.arrayFill_postgresql();

if ( getVersion().isSameOrAfter( 9, 4 ) ) {
functionFactory.makeDateTimeTimestamp();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
functionFactory.arraySlice_operator();
functionFactory.arrayReplace();
functionFactory.arrayTrim_trim_array();
functionFactory.arrayFill_postgresql();

functionContributions.getFunctionRegistry().register(
"trunc",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
functionFactory.arraySlice();
functionFactory.arrayReplace_h2( getMaximumArraySize() );
functionFactory.arrayTrim_trim_array();
functionFactory.arrayFill_h2();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
functionFactory.arraySlice_unnest();
functionFactory.arrayReplace_unnest();
functionFactory.arrayTrim_trim_array();
functionFactory.arrayFill_hsql();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,28 @@ public void addAuxiliaryDatabaseObjects(
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
functionFactory.arraySlice_oracle();
functionFactory.arrayReplace_oracle();
functionFactory.arrayTrim_oracle();
functionFactory.arrayFill_oracle();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,20 @@
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;
Expand All @@ -54,6 +57,7 @@
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;
Expand Down Expand Up @@ -3091,4 +3095,32 @@ public void arrayTrim_trim_array() {
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() );
}
}
Original file line number Diff line number Diff line change
@@ -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 );
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public ArrayAggFunction(String functionName, boolean withinGroupClause, boolean
FUNCTION_NAME,
FunctionKind.ORDERED_SET_AGGREGATE,
StandardArgumentsValidators.exactly( 1 ),
ArrayViaElementArgumentReturnTypeResolver.INSTANCE,
ArrayViaElementArgumentReturnTypeResolver.VARARGS_INSTANCE,
StandardFunctionArgumentTypeResolvers.NULL
);
this.functionName = functionName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public ArrayConstructorFunction(boolean withKeyword) {
super(
"array",
ArrayConstructorArgumentsValidator.INSTANCE,
ArrayViaElementArgumentReturnTypeResolver.INSTANCE,
ArrayViaElementArgumentReturnTypeResolver.VARARGS_INSTANCE,
StandardFunctionArgumentTypeResolvers.NULL
);
this.withKeyword = withKeyword;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public void render(
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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public void render(
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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@
*/
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
Expand All @@ -47,8 +51,16 @@ else if ( inferredType instanceof BasicValuedMapping ) {
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 );
}
Expand Down

0 comments on commit 1a5184e

Please sign in to comment.