HHH-10463 Implement function argument type inference

This commit is contained in:
Christian Beikov 2022-02-10 13:25:17 +01:00
parent 260c738a5a
commit dc6ad33cfc
69 changed files with 820 additions and 213 deletions

View File

@ -173,7 +173,8 @@ public class CacheDialect extends Dialect {
queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ),
"$find(?2,?1)",
"$find(?2,?1,?3)",
STRING, STRING, INTEGER
STRING, STRING, INTEGER,
queryEngine.getTypeConfiguration()
).setArgumentListSignature("(pattern, string[, start])");
functionFactory.bitLength_pattern( "($length(?1)*8)" );

View File

@ -284,7 +284,8 @@ public class FirebirdDialect extends Dialect {
integerType,
"position(?1 in ?2)",
"position(?1,?2,?3)",
STRING, STRING, INTEGER
STRING, STRING, INTEGER,
queryEngine.getTypeConfiguration()
).setArgumentListSignature( "(pattern, string[, start])" );
functionRegistry.namedDescriptorBuilder( "ascii_val" )
.setExactArgumentCount( 1 )

View File

@ -288,7 +288,8 @@ public class IngresDialect extends Dialect {
integerType,
"position(?1 in ?2)",
"(position(?1 in substring(?2 from ?3))+(?3)-1)",
STRING, STRING, INTEGER
STRING, STRING, INTEGER,
queryEngine.getTypeConfiguration()
).setArgumentListSignature("(pattern, string[, start])");
queryEngine.getSqmFunctionRegistry().registerPattern( "extract", "date_part('?1',?2)", integerType );

View File

@ -168,7 +168,8 @@ public class MaxDBDialect extends Dialect {
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
integerType, "index(?2,?1)", "index(?2,?1,?3)",
STRING, STRING, INTEGER
STRING, STRING, INTEGER,
queryEngine.getTypeConfiguration()
).setArgumentListSignature("(pattern, string[, start])");
}

View File

@ -277,21 +277,24 @@ public class SQLiteDialect extends Dialect {
integerType,
"instr(?2,?1)",
"instr(?2,?1,?3)",
STRING, STRING, INTEGER
STRING, STRING, INTEGER,
queryEngine.getTypeConfiguration()
).setArgumentListSignature("(pattern, string[, start])");
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"lpad",
stringType,
"(substr(replace(hex(zeroblob(?2)),'00',' '),1,?2-length(?1))||?1)",
"(substr(replace(hex(zeroblob(?2)),'00',?3),1,?2-length(?1))||?1)",
STRING, INTEGER, STRING
STRING, INTEGER, STRING,
queryEngine.getTypeConfiguration()
).setArgumentListSignature("(string, length[, padding])");
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"rpad",
stringType,
"(?1||substr(replace(hex(zeroblob(?2)),'00',' '),1,?2-length(?1)))",
"(?1||substr(replace(hex(zeroblob(?2)),'00',?3),1,?2-length(?1)))",
STRING, INTEGER, STRING
STRING, INTEGER, STRING,
queryEngine.getTypeConfiguration()
).setArgumentListSignature("(string, length[, padding])");
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("format", "strftime")

View File

@ -168,7 +168,8 @@ public class TimesTenDialect extends Dialect {
queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ),
"instr(?2,?1)",
"instr(?2,?1,?3)",
STRING, STRING, INTEGER
STRING, STRING, INTEGER,
queryEngine.getTypeConfiguration()
).setArgumentListSignature("(pattern, string[, start])");
}

View File

@ -79,6 +79,7 @@ import java.util.regex.Pattern;
import jakarta.persistence.TemporalType;
import org.hibernate.query.sqm.produce.function.FunctionParameterType;
import org.hibernate.type.spi.TypeConfiguration;
/**
* An abstract base class for SAP HANA dialects.
@ -274,13 +275,15 @@ public abstract class AbstractHANADialect extends Dialect {
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
final TypeConfiguration typeConfiguration = queryEngine.getTypeConfiguration();
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ),
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ),
"locate(?2,?1)",
"locate(?2,?1,?3)",
FunctionParameterType.STRING, FunctionParameterType.STRING, FunctionParameterType.INTEGER
FunctionParameterType.STRING, FunctionParameterType.STRING, FunctionParameterType.INTEGER,
typeConfiguration
).setArgumentListSignature("(pattern, string[, start])");
CommonFunctionFactory functionFactory = new CommonFunctionFactory(queryEngine);
@ -317,7 +320,7 @@ public abstract class AbstractHANADialect extends Dialect {
functionFactory.hypotheticalOrderedSetAggregates_windowEmulation();
queryEngine.getSqmFunctionRegistry().register( "timestampadd",
new IntegralTimestampaddFunction( this, queryEngine.getTypeConfiguration() ) );
new IntegralTimestampaddFunction( this, typeConfiguration ) );
}
@Override

View File

@ -142,7 +142,6 @@ public abstract class AbstractTransactSQLDialect extends Dialect {
functionFactory.yearMonthDay();
functionFactory.ascii();
functionFactory.chr_char();
functionFactory.concat_plusOperator();
functionFactory.trim1();
functionFactory.repeat_replicate();
functionFactory.characterLength_len();

View File

@ -160,6 +160,7 @@ import org.hibernate.type.descriptor.jdbc.NCharJdbcType;
import org.hibernate.type.descriptor.jdbc.NClobJdbcType;
import org.hibernate.type.descriptor.jdbc.NVarcharJdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration;
import jakarta.persistence.TemporalType;
@ -769,7 +770,8 @@ public abstract class Dialect implements ConversionContext {
* same names.
*/
public void initializeFunctionRegistry(QueryEngine queryEngine) {
final BasicTypeRegistry basicTypeRegistry = queryEngine.getTypeConfiguration().getBasicTypeRegistry();
final TypeConfiguration typeConfiguration = queryEngine.getTypeConfiguration();
final BasicTypeRegistry basicTypeRegistry = typeConfiguration.getBasicTypeRegistry();
final BasicType<Date> timestampType = basicTypeRegistry.resolve( StandardBasicTypes.TIMESTAMP );
final BasicType<Date> dateType = basicTypeRegistry.resolve( StandardBasicTypes.DATE );
final BasicType<Date> timeType = basicTypeRegistry.resolve( StandardBasicTypes.TIME );
@ -842,20 +844,20 @@ public abstract class Dialect implements ConversionContext {
//define it here as an alias for locate()
queryEngine.getSqmFunctionRegistry().register( "position",
new LocatePositionEmulation( queryEngine.getTypeConfiguration() ) );
new LocatePositionEmulation( typeConfiguration ) );
//very few databases support ANSI-style overlay() function, so emulate
//it here in terms of either insert() or concat()/substring()
queryEngine.getSqmFunctionRegistry().register( "overlay",
new InsertSubstringOverlayEmulation( queryEngine.getTypeConfiguration(), false ) );
new InsertSubstringOverlayEmulation( typeConfiguration, false ) );
//ANSI SQL trim() function is supported on almost all of the databases
//we care about, but on some it must be emulated using ltrim(), rtrim(),
//and replace()
queryEngine.getSqmFunctionRegistry().register( "trim",
new TrimFunction( this, queryEngine.getTypeConfiguration() ) );
new TrimFunction( this, typeConfiguration ) );
//ANSI SQL cast() function is supported on the databases we care most
//about but in certain cases it doesn't allow some useful typecasts,
@ -883,7 +885,7 @@ public abstract class Dialect implements ConversionContext {
//a very dialect-specific way
queryEngine.getSqmFunctionRegistry().register( "extract",
new ExtractFunction( this ) );
new ExtractFunction( this, typeConfiguration ) );
//comparison functions supported on most databases, emulated on others
//using a case expression
@ -905,13 +907,13 @@ public abstract class Dialect implements ConversionContext {
//pad() is a function we've designed to look like ANSI trim()
queryEngine.getSqmFunctionRegistry().register( "pad",
new LpadRpadPadEmulation( queryEngine.getTypeConfiguration() ) );
new LpadRpadPadEmulation( typeConfiguration ) );
//legacy Hibernate convenience function for casting to string, defined
//here as an alias for cast(arg as String)
queryEngine.getSqmFunctionRegistry().register( "str",
new CastStrEmulation( queryEngine.getTypeConfiguration() ) );
new CastStrEmulation( typeConfiguration ) );
//format() function for datetimes, emulated on many databases using the
//Oracle-style to_char() function, and on others using their native
@ -923,9 +925,9 @@ public abstract class Dialect implements ConversionContext {
//since there is a great variety of different ways to emulate them
queryEngine.getSqmFunctionRegistry().register( "timestampadd",
new TimestampaddFunction( this ) );
new TimestampaddFunction( this, typeConfiguration ) );
queryEngine.getSqmFunctionRegistry().register( "timestampdiff",
new TimestampdiffFunction( this, queryEngine.getTypeConfiguration() ) );
new TimestampdiffFunction( this, typeConfiguration ) );
queryEngine.getSqmFunctionRegistry().registerAlternateKey( "dateadd", "timestampadd" );
queryEngine.getSqmFunctionRegistry().registerAlternateKey( "datediff", "timestampdiff" );

View File

@ -19,6 +19,7 @@ import org.hibernate.dialect.temptable.TemporaryTableKind;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.ANY;
@ -102,20 +103,22 @@ public class HANAColumnStoreDialect extends AbstractHANADialect {
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
final TypeConfiguration typeConfiguration = queryEngine.getTypeConfiguration();
// full-text search functions
queryEngine.getSqmFunctionRegistry().registerNamed(
"score",
queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE )
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE )
);
queryEngine.getSqmFunctionRegistry().registerNamed( "snippets" );
queryEngine.getSqmFunctionRegistry().registerNamed( "highlighted" );
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"contains",
queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.BOOLEAN ),
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.BOOLEAN ),
"contains(?1,?2)",
"contains(?1,?2,?3)",
ANY, ANY, ANY
ANY, ANY, ANY,
typeConfiguration
);
}

View File

@ -93,6 +93,8 @@ import static org.hibernate.query.sqm.TemporalUnit.SECOND;
import static org.hibernate.query.sqm.TemporalUnit.YEAR;
import org.hibernate.query.sqm.produce.function.FunctionParameterType;
import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.type.SqlTypes.*;
/**
@ -136,6 +138,7 @@ public class OracleDialect extends Dialect {
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
final TypeConfiguration typeConfiguration = queryEngine.getTypeConfiguration();
CommonFunctionFactory functionFactory = new CommonFunctionFactory(queryEngine);
functionFactory.cosh();
@ -185,10 +188,11 @@ public class OracleDialect extends Dialect {
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ),
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ),
"instr(?2,?1)",
"instr(?2,?1,?3)",
FunctionParameterType.STRING, FunctionParameterType.STRING, FunctionParameterType.INTEGER
FunctionParameterType.STRING, FunctionParameterType.STRING, FunctionParameterType.INTEGER,
typeConfiguration
).setArgumentListSignature("(pattern, string[, start])");
// The within group clause became optional in 18
if ( getVersion().isSameOrAfter( 18 ) ) {
@ -203,7 +207,7 @@ public class OracleDialect extends Dialect {
// Oracle has a regular aggregate function named stats_mode
queryEngine.getSqmFunctionRegistry().register(
"mode",
new ModeStatsModeEmulation( queryEngine.getTypeConfiguration() )
new ModeStatsModeEmulation( typeConfiguration )
);
}

View File

@ -15,7 +15,9 @@ import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescript
import org.hibernate.query.sqm.function.FunctionKind;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
@ -49,7 +51,8 @@ public class AvgFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 1 ), NUMERIC ),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE )
)
),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, NUMERIC )
);
this.defaultArgumentRenderingMode = defaultArgumentRenderingMode;
doubleType = typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE );
@ -80,8 +83,10 @@ public class AvgFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
arg = (Expression) sqlAstArguments.get( 0 );
}
if ( caseWrapper ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( "case when " );
filter.accept( translator );
translator.getCurrentClauseStack().pop();
sqlAppender.appendSql( " then " );
renderArgument( sqlAppender, translator, arg );
sqlAppender.appendSql( " else null end)" );
@ -90,9 +95,11 @@ public class AvgFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
renderArgument( sqlAppender, translator, arg );
sqlAppender.appendSql( ')' );
if ( filter != null ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( " filter (where " );
filter.accept( translator );
sqlAppender.appendSql( ')' );
translator.getCurrentClauseStack().pop();
}
}
}

View File

@ -11,6 +11,7 @@ import java.util.List;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
@ -33,7 +34,8 @@ public class CaseLeastGreatestEmulation
super(
least ? "least" : "greatest",
new ArgumentTypesValidator( StandardArgumentsValidators.min( 2 ), COMPARABLE, COMPARABLE ),
StandardFunctionReturnTypeResolvers.useFirstNonNull()
StandardFunctionReturnTypeResolvers.useFirstNonNull(),
StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE
);
this.operator = least ? "<=" : ">=";
}

View File

@ -14,6 +14,7 @@ import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.query.sqm.CastType;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
import org.hibernate.sql.ast.SqlAstTranslator;
@ -38,7 +39,8 @@ public class CastFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
super(
"cast",
StandardArgumentsValidators.exactly( 2 ),
StandardFunctionReturnTypeResolvers.useArgType( 2 )
StandardFunctionReturnTypeResolvers.useArgType( 2 ),
StandardFunctionArgumentTypeResolvers.IMPLIED_RESULT_TYPE
);
this.dialect = dialect;
this.booleanCastType = getBooleanCastType( preferredSqlTypeCodeForBoolean );

View File

@ -37,7 +37,8 @@ public class CastStrEmulation
StandardArgumentsValidators.exactly( 1 ),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
)
),
null
);
}
@ -45,7 +46,7 @@ public class CastStrEmulation
String name,
ArgumentsValidator argumentsValidator,
FunctionReturnTypeResolver returnTypeResolver) {
super( name, argumentsValidator, returnTypeResolver );
super( name, argumentsValidator, returnTypeResolver, null );
}
@Override

View File

@ -15,6 +15,7 @@ import org.hibernate.query.sqm.CastType;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
@ -42,10 +43,11 @@ public class CastingConcatFunction extends AbstractSqmSelfRenderingFunctionDescr
TypeConfiguration typeConfiguration) {
super(
"concat",
new ArgumentTypesValidator( StandardArgumentsValidators.min( 1 ), STRING ),
StandardArgumentsValidators.min( 1 ),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
)
),
StandardFunctionArgumentTypeResolvers.impliedOrInvariant( typeConfiguration, STRING )
);
this.dialect = dialect;
this.concatOperator = concatOperator;

View File

@ -11,6 +11,7 @@ import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SelfRenderingSqmFunction;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.type.spi.TypeConfiguration;
@ -25,7 +26,8 @@ public class CoalesceIfnullEmulation
public CoalesceIfnullEmulation() {
super(
"ifnull",
StandardArgumentsValidators.exactly( 2 )
StandardArgumentsValidators.exactly( 2 ),
StandardFunctionArgumentTypeResolvers.IMPLIED_RESULT_TYPE
);
}

View File

@ -16,6 +16,7 @@ import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.type.BasicType;
import org.hibernate.type.BasicTypeRegistry;
@ -454,14 +455,16 @@ public class CommonFunctionFactory {
stringType,
"lpad(?1,?2,' ')",
"lpad(?1,?2,?3)",
STRING, INTEGER, STRING
STRING, INTEGER, STRING,
typeConfiguration
).setArgumentListSignature( "(string, length[, padding])" );
functionRegistry.registerBinaryTernaryPattern(
"rpad",
stringType,
"rpad(?1,?2,' ')",
"rpad(?1,?2,?3)",
STRING, INTEGER, STRING
STRING, INTEGER, STRING,
typeConfiguration
).setArgumentListSignature( "(string, length[, padding])" );
}
@ -474,14 +477,16 @@ public class CommonFunctionFactory {
stringType,
"(space(?2-len(?1))+?1)",
"(replicate(?3,?2-len(?1))+?1)",
STRING, INTEGER, STRING
STRING, INTEGER, STRING,
typeConfiguration
).setArgumentListSignature( "(string, length[, padding])" );
functionRegistry.registerBinaryTernaryPattern(
"rpad",
stringType,
"(?1+space(?2-len(?1)))",
"(?1+replicate(?3,?2-len(?1)))",
STRING, INTEGER, STRING
STRING, INTEGER, STRING,
typeConfiguration
).setArgumentListSignature( "(string, length[, padding])" );
}
@ -491,14 +496,16 @@ public class CommonFunctionFactory {
stringType,
"(repeat(' ',?2-character_length(?1))||?1)",
"(repeat(?3,?2-character_length(?1))||?1)",
STRING, INTEGER, STRING
STRING, INTEGER, STRING,
typeConfiguration
).setArgumentListSignature( "(string, length[, padding])" );
functionRegistry.registerBinaryTernaryPattern(
"rpad",
stringType,
"(?1||repeat(' ',?2-character_length(?1)))",
"(?1||repeat(?3,?2-character_length(?1)))",
STRING, INTEGER, STRING
STRING, INTEGER, STRING,
typeConfiguration
).setArgumentListSignature( "(string, length[, padding])" );
}
@ -511,14 +518,16 @@ public class CommonFunctionFactory {
stringType,
"lfill(?1,' ',?2)",
"lfill(?1,?3,?2)",
STRING, INTEGER, STRING
STRING, INTEGER, STRING,
typeConfiguration
).setArgumentListSignature( "(string, length[, padding])" );
functionRegistry.registerBinaryTernaryPattern(
"rpad",
stringType,
"rfill(?1,' ',?2)",
"rfill(?1,?3,?2)",
STRING, INTEGER, STRING
STRING, INTEGER, STRING,
typeConfiguration
).setArgumentListSignature( "(string, length[, padding])" );
}
@ -606,6 +615,7 @@ public class CommonFunctionFactory {
functionRegistry.namedDescriptorBuilder( "md5" )
.setInvariantType(stringType)
.setExactArgumentCount( 1 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.IMPLIED_RESULT_TYPE )
.register();
}
@ -613,6 +623,7 @@ public class CommonFunctionFactory {
functionRegistry.namedDescriptorBuilder( "initcap" )
.setInvariantType(stringType)
.setExactArgumentCount( 1 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.IMPLIED_RESULT_TYPE )
.register();
}
@ -638,30 +649,35 @@ public class CommonFunctionFactory {
functionRegistry.namedDescriptorBuilder( "translate" )
.setInvariantType(stringType)
.setExactArgumentCount( 3 )
.setParameterTypes( STRING, STRING, STRING )
.register();
}
public void bitand() {
functionRegistry.namedDescriptorBuilder( "bitand" )
.setExactArgumentCount( 2 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
}
public void bitor() {
functionRegistry.namedDescriptorBuilder( "bitor" )
.setExactArgumentCount( 2 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
}
public void bitxor() {
functionRegistry.namedDescriptorBuilder( "bitxor" )
.setExactArgumentCount( 2 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
}
public void bitnot() {
functionRegistry.namedDescriptorBuilder( "bitnot" )
.setExactArgumentCount( 1 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.IMPLIED_RESULT_TYPE )
.register();
}
@ -671,21 +687,25 @@ public class CommonFunctionFactory {
public void bitandorxornot_bitAndOrXorNot() {
functionRegistry.namedDescriptorBuilder( "bit_and" )
.setExactArgumentCount( 2 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
functionRegistry.registerAlternateKey( "bitand", "bit_and" );
functionRegistry.namedDescriptorBuilder( "bit_or" )
.setExactArgumentCount( 2 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
functionRegistry.registerAlternateKey( "bitor", "bit_or" );
functionRegistry.namedDescriptorBuilder( "bit_xor" )
.setExactArgumentCount( 2 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
functionRegistry.registerAlternateKey( "bitxor", "bit_xor" );
functionRegistry.namedDescriptorBuilder( "bit_not" )
.setExactArgumentCount( 1 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.IMPLIED_RESULT_TYPE )
.register();
functionRegistry.registerAlternateKey( "bitnot", "bit_not" );
}
@ -696,21 +716,25 @@ public class CommonFunctionFactory {
public void bitandorxornot_binAndOrXorNot() {
functionRegistry.namedDescriptorBuilder( "bin_and" )
.setMinArgumentCount( 1 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
functionRegistry.registerAlternateKey( "bitand", "bin_and" );
functionRegistry.namedDescriptorBuilder( "bin_or" )
.setMinArgumentCount( 1 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
functionRegistry.registerAlternateKey( "bitor", "bin_or" );
functionRegistry.namedDescriptorBuilder( "bin_xor" )
.setMinArgumentCount( 1 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
functionRegistry.registerAlternateKey( "bitxor", "bin_xor" );
functionRegistry.namedDescriptorBuilder( "bin_not" )
.setExactArgumentCount( 1 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.IMPLIED_RESULT_TYPE )
.register();
functionRegistry.registerAlternateKey( "bitnot", "bin_not" );
}
@ -721,18 +745,22 @@ public class CommonFunctionFactory {
public void bitandorxornot_operator() {
functionRegistry.patternDescriptorBuilder( "bitand", "(?1&?2)" )
.setExactArgumentCount( 2 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
functionRegistry.patternDescriptorBuilder( "bitor", "(?1|?2)" )
.setExactArgumentCount( 2 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
functionRegistry.patternDescriptorBuilder( "bitxor", "(?1^?2)" )
.setExactArgumentCount( 2 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
functionRegistry.patternDescriptorBuilder( "bitnot", "~?1" )
.setExactArgumentCount( 1 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.IMPLIED_RESULT_TYPE )
.register();
}
@ -742,10 +770,12 @@ public class CommonFunctionFactory {
public void bitAndOr() {
functionRegistry.namedAggregateDescriptorBuilder( "bit_and" )
.setExactArgumentCount( 1 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
functionRegistry.namedAggregateDescriptorBuilder( "bit_or" )
.setExactArgumentCount( 1 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
//MySQL has it but how is that even useful?
@ -978,21 +1008,25 @@ public class CommonFunctionFactory {
functionRegistry.namedDescriptorBuilder( "to_number" )
//always 1 arg on HSQL and Cache, always 2 on Postgres
.setArgumentCountBetween( 1, 3 )
.setParameterTypes( STRING, STRING, STRING )
.setInvariantType(doubleType)
.register();
functionRegistry.namedDescriptorBuilder( "to_char" )
.setArgumentCountBetween( 1, 3 )
.setParameterTypes( ANY, STRING, STRING )
//always 2 args on HSQL and Postgres
.setInvariantType(stringType)
.register();
functionRegistry.namedDescriptorBuilder( "to_date" )
//always 2 args on HSQL and Postgres
.setArgumentCountBetween( 1, 3 )
.setParameterTypes( STRING, STRING, STRING )
.setInvariantType(dateType)
.register();
functionRegistry.namedDescriptorBuilder( "to_timestamp" )
//always 2 args on HSQL and Postgres
.setArgumentCountBetween( 1, 3 )
.setParameterTypes( STRING, STRING, STRING )
.setInvariantType(timestampType)
.register();
}
@ -1073,19 +1107,9 @@ public class CommonFunctionFactory {
functionRegistry.patternDescriptorBuilder( "concat", "(?1||?2...)" )
.setInvariantType(stringType)
.setMinArgumentCount( 1 )
.setParameterTypes(STRING)
.setArgumentListSignature( "(STRING string0[, STRING string1[, ...]])" )
.register();
}
/**
* Transact SQL-style
*/
public void concat_plusOperator() {
functionRegistry.patternDescriptorBuilder( "concat", "(?1+?2...)" )
.setInvariantType(stringType)
.setMinArgumentCount( 1 )
.setParameterTypes(STRING)
.setArgumentTypeResolver(
StandardFunctionArgumentTypeResolvers.impliedOrInvariant( typeConfiguration, STRING )
)
.setArgumentListSignature( "(STRING string0[, STRING string1[, ...]])" )
.register();
}
@ -1297,6 +1321,7 @@ public class CommonFunctionFactory {
public void coalesce() {
functionRegistry.namedDescriptorBuilder( "coalesce" )
.setMinArgumentCount( 1 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
}
@ -1306,6 +1331,7 @@ public class CommonFunctionFactory {
public void coalesce_value() {
functionRegistry.namedDescriptorBuilder( "value" )
.setMinArgumentCount( 1 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
functionRegistry.registerAlternateKey( "coalesce", "value" );
}
@ -1313,6 +1339,7 @@ public class CommonFunctionFactory {
public void nullif() {
functionRegistry.namedDescriptorBuilder( "nullif" )
.setExactArgumentCount( 2 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
}
@ -1420,7 +1447,8 @@ public class CommonFunctionFactory {
"locate",
integerType,
"position(?1 in ?2)", "(position(?1 in substring(?2 from ?3))+(?3)-1)",
STRING, STRING, INTEGER
STRING, STRING, INTEGER,
typeConfiguration
)
.setArgumentListSignature( "(STRING pattern, STRING string[, INTEGER start])" );
}
@ -1432,7 +1460,8 @@ public class CommonFunctionFactory {
"substring",
stringType,
"substring(?1 from ?2)", "substring(?1 from ?2 for ?3)",
STRING, INTEGER, INTEGER
STRING, INTEGER, INTEGER,
typeConfiguration
)
.setArgumentListSignature( "(STRING string{ from|,} INTEGER start[{ for|,} INTEGER length])" );
}
@ -1459,7 +1488,8 @@ public class CommonFunctionFactory {
stringType,
"substring(?1,?2,len(?1)-?2+1)",
"substring(?1,?2,?3)",
STRING, INTEGER, INTEGER
STRING, INTEGER, INTEGER,
typeConfiguration
)
.setArgumentListSignature( "(STRING string{ from|,} INTEGER start[{ for|,} INTEGER length])" );
}
@ -1508,7 +1538,8 @@ public class CommonFunctionFactory {
stringType,
"overlay(?1 placing ?2 from ?3)",
"overlay(?1 placing ?2 from ?3 for ?4)",
STRING, STRING, INTEGER, INTEGER
STRING, STRING, INTEGER, INTEGER,
typeConfiguration
)
.setArgumentListSignature( "(string placing replacement from start[ for length])" );
}
@ -1524,7 +1555,8 @@ public class CommonFunctionFactory {
//because DB2 doesn't like "length(?)"
"overlay(?1 placing ?2 from ?3 for character_length(?2))",
"overlay(?1 placing ?2 from ?3 for ?4)",
STRING, STRING, INTEGER, INTEGER
STRING, STRING, INTEGER, INTEGER,
typeConfiguration
)
.setArgumentListSignature( "(string placing replacement from start[ for length])" );
}
@ -1555,7 +1587,9 @@ public class CommonFunctionFactory {
functionRegistry.namedDescriptorBuilder( "concat" )
.setInvariantType(stringType)
.setMinArgumentCount( 1 )
.setParameterTypes(STRING)
.setArgumentTypeResolver(
StandardFunctionArgumentTypeResolvers.impliedOrInvariant( typeConfiguration, STRING )
)
.setArgumentListSignature( "(STRING string0[, STRING string1[, ...]])" )
.register();
}
@ -1644,10 +1678,12 @@ public class CommonFunctionFactory {
functionRegistry.namedDescriptorBuilder( "least" )
.setMinArgumentCount( 2 )
.setParameterTypes(COMPARABLE, COMPARABLE)
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
functionRegistry.namedDescriptorBuilder( "greatest" )
.setMinArgumentCount( 2 )
.setParameterTypes(COMPARABLE, COMPARABLE)
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
}
@ -1655,10 +1691,12 @@ public class CommonFunctionFactory {
functionRegistry.namedDescriptorBuilder( "least", "min" )
.setMinArgumentCount( 2 )
.setParameterTypes(COMPARABLE, COMPARABLE)
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
functionRegistry.namedDescriptorBuilder( "greatest", "max" )
.setMinArgumentCount( 2 )
.setParameterTypes(COMPARABLE, COMPARABLE)
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
}
@ -1666,10 +1704,12 @@ public class CommonFunctionFactory {
functionRegistry.namedDescriptorBuilder( "least", "minvalue" )
.setMinArgumentCount( 2 )
.setParameterTypes(COMPARABLE, COMPARABLE)
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
functionRegistry.namedDescriptorBuilder( "greatest", "maxvalue" )
.setMinArgumentCount( 2 )
.setParameterTypes(COMPARABLE, COMPARABLE)
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();
}
@ -1682,12 +1722,14 @@ public class CommonFunctionFactory {
.setArgumentRenderingMode( inferenceArgumentRenderingMode )
.setExactArgumentCount( 1 )
.setParameterTypes(COMPARABLE)
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.IMPLIED_RESULT_TYPE )
.register();
functionRegistry.namedAggregateDescriptorBuilder( "min" )
.setArgumentRenderingMode( inferenceArgumentRenderingMode )
.setExactArgumentCount( 1 )
.setParameterTypes(COMPARABLE)
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.IMPLIED_RESULT_TYPE )
.register();
functionRegistry.namedAggregateDescriptorBuilder( "sum" )
@ -1835,26 +1877,43 @@ public class CommonFunctionFactory {
functionRegistry.namedWindowDescriptorBuilder( "lag" )
.setArgumentCountBetween( 1, 3 )
.setParameterTypes( ANY, INTEGER, ANY )
.setArgumentTypeResolver(
StandardFunctionArgumentTypeResolvers.composite(
StandardFunctionArgumentTypeResolvers.argumentsOrImplied( 2 ),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, INTEGER ),
StandardFunctionArgumentTypeResolvers.argumentsOrImplied( 0 )
)
)
.setArgumentListSignature( "ANY value[, INTEGER offset[, ANY default]]" )
.register();
functionRegistry.namedWindowDescriptorBuilder( "lead" )
.setArgumentCountBetween( 1, 3 )
.setParameterTypes( ANY, INTEGER, ANY )
.setArgumentTypeResolver(
StandardFunctionArgumentTypeResolvers.composite(
StandardFunctionArgumentTypeResolvers.argumentsOrImplied( 2 ),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, INTEGER ),
StandardFunctionArgumentTypeResolvers.argumentsOrImplied( 0 )
)
)
.setArgumentListSignature( "ANY value[, INTEGER offset[, ANY default]]" )
.register();
functionRegistry.namedWindowDescriptorBuilder( "first_value" )
.setExactArgumentCount( 1 )
.setParameterTypes( ANY )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.IMPLIED_RESULT_TYPE )
.setArgumentListSignature( "ANY value" )
.register();
functionRegistry.namedWindowDescriptorBuilder( "last_value" )
.setExactArgumentCount( 1 )
.setParameterTypes( ANY )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.IMPLIED_RESULT_TYPE )
.setArgumentListSignature( "ANY value" )
.register();
functionRegistry.namedWindowDescriptorBuilder( "nth_value" )
.setExactArgumentCount( 2 )
.setParameterTypes( ANY, INTEGER )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.IMPLIED_RESULT_TYPE )
.setArgumentListSignature( "ANY value, INTEGER nth" )
.register();
}
@ -1969,6 +2028,7 @@ public class CommonFunctionFactory {
public void crc32() {
functionRegistry.namedDescriptorBuilder( "crc32" )
.setInvariantType(integerType)
.setParameterTypes( STRING )
.setExactArgumentCount( 1 )
.register();
}
@ -1976,6 +2036,7 @@ public class CommonFunctionFactory {
public void sha1() {
functionRegistry.namedDescriptorBuilder( "sha1" )
.setInvariantType(stringType)
.setParameterTypes( STRING )
.setExactArgumentCount( 1 )
.register();
}
@ -1983,6 +2044,7 @@ public class CommonFunctionFactory {
public void sha2() {
functionRegistry.namedDescriptorBuilder( "sha2" )
.setInvariantType(stringType)
.setParameterTypes( STRING, INTEGER )
.setExactArgumentCount( 2 )
.register();
}
@ -1990,6 +2052,7 @@ public class CommonFunctionFactory {
public void sha() {
functionRegistry.namedDescriptorBuilder( "sha" )
.setInvariantType(stringType)
.setParameterTypes( STRING )
.setExactArgumentCount( 1 )
.register();
}
@ -2156,6 +2219,7 @@ public class CommonFunctionFactory {
public void format_formatdatetime() {
functionRegistry.namedDescriptorBuilder( "format", "formatdatetime" )
.setInvariantType(stringType)
.setParameterTypes( TEMPORAL, STRING )
.setArgumentsValidator( formatValidator() )
.setArgumentListSignature( "(TEMPORAL datetime as STRING pattern)" )
.register();
@ -2169,6 +2233,7 @@ public class CommonFunctionFactory {
public void format_toChar() {
functionRegistry.namedDescriptorBuilder( "format", "to_char" )
.setInvariantType(stringType)
.setParameterTypes( TEMPORAL, STRING )
.setArgumentsValidator( formatValidator() )
.setArgumentListSignature( "(TEMPORAL datetime as STRING pattern)" )
.register();
@ -2182,6 +2247,7 @@ public class CommonFunctionFactory {
public void format_dateFormat() {
functionRegistry.namedDescriptorBuilder( "format", "date_format" )
.setInvariantType(stringType)
.setParameterTypes( TEMPORAL, STRING )
.setArgumentsValidator( formatValidator() )
.setArgumentListSignature( "(TEMPORAL datetime as STRING pattern)" )
.register();
@ -2195,6 +2261,7 @@ public class CommonFunctionFactory {
public void format_toVarchar() {
functionRegistry.namedDescriptorBuilder( "format", "to_varchar" )
.setInvariantType(stringType)
.setParameterTypes( TEMPORAL, STRING )
.setArgumentsValidator( formatValidator() )
.setArgumentListSignature( "(TEMPORAL datetime as STRING pattern)" )
.register();
@ -2223,7 +2290,7 @@ public class CommonFunctionFactory {
functionRegistry.patternDescriptorBuilder("collate", "(?1 collate '?2')")
.setInvariantType(stringType)
.setExactArgumentCount( 2 )
.setParameterTypes(STRING, ANY)
.setParameterTypes(STRING, COLLATION)
.setArgumentListSignature("(STRING string as COLLATION collation)")
.register();
}

View File

@ -20,6 +20,7 @@ import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
import org.hibernate.query.sqm.sql.internal.AbstractSqmPathInterpretation;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
@ -58,7 +59,8 @@ public class CountFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
StandardArgumentsValidators.exactly( 1 ),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.LONG )
)
),
null
);
this.dialect = dialect;
this.defaultArgumentRenderingMode = defaultArgumentRenderingMode;
@ -102,9 +104,11 @@ public class CountFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
// In the end, the expression looks like the following:
// count(distinct coalesce(nullif(coalesce(col1 || '', '\0'), ''), '\01') || '\0' || coalesce(nullif(coalesce(col2 || '', '\0'), ''), '\02'))
if ( caseWrapper ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( "case when " );
filter.accept( translator );
sqlAppender.appendSql( " then " );
translator.getCurrentClauseStack().pop();
}
sqlAppender.appendSql( "coalesce(nullif(coalesce(" );
renderCastedArgument( sqlAppender, translator, expressions.get( 0 ) );
@ -162,7 +166,9 @@ public class CountFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
else if ( !dialect.supportsTupleCounts() ) {
sqlAppender.appendSql( "case when " );
if ( caseWrapper ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
filter.accept( translator );
translator.getCurrentClauseStack().pop();
sqlAppender.appendSql( " and " );
}
translator.render( expressions.get( 0 ), defaultArgumentRenderingMode );
@ -193,9 +199,11 @@ public class CountFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
}
sqlAppender.appendSql( ')' );
if ( filter != null && !caseWrapper ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( " filter (where " );
filter.accept( translator );
sqlAppender.appendSql( ')' );
translator.getCurrentClauseStack().pop();
}
}
@ -250,8 +258,10 @@ public class CountFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
boolean caseWrapper,
SqlAstNode realArg) {
if ( caseWrapper ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( "case when " );
filter.accept( translator );
translator.getCurrentClauseStack().pop();
sqlAppender.appendSql( " then " );
if ( realArg instanceof Star ) {
sqlAppender.appendSql( "1" );

View File

@ -31,7 +31,8 @@ public class CurrentFunction
super(
name,
StandardArgumentsValidators.NO_ARGS,
StandardFunctionReturnTypeResolvers.invariant( type )
StandardFunctionReturnTypeResolvers.invariant( type ),
null
);
this.sql = sql;
}

View File

@ -8,6 +8,7 @@ package org.hibernate.dialect.function;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
@ -20,6 +21,9 @@ import org.hibernate.type.spi.TypeConfiguration;
import java.util.List;
import jakarta.persistence.TemporalType;
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.STRING;
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEMPORAL;
/**
* DB2's varchar_format() can't handle quoted literal strings in
* the format pattern. So just split the pattern into bits, call
@ -37,7 +41,8 @@ public class DB2FormatEmulation
CommonFunctionFactory.formatValidator(),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
)
),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, TEMPORAL, STRING )
);
}

View File

@ -11,6 +11,7 @@ import java.util.List;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator;
@ -36,7 +37,8 @@ public class DerbyLpadEmulation
new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 2 ), STRING, INTEGER ),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
)
),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, STRING, INTEGER )
);
}

View File

@ -11,6 +11,7 @@ import java.util.List;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator;
@ -36,7 +37,8 @@ public class DerbyRpadEmulation
new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 2 ), STRING, INTEGER ),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
)
),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, STRING, INTEGER )
);
}

View File

@ -12,7 +12,9 @@ import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescript
import org.hibernate.query.sqm.function.FunctionKind;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
@ -43,7 +45,8 @@ public class EveryAnyEmulation extends AbstractSqmSelfRenderingFunctionDescripto
new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 1 ), BOOLEAN ),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.BOOLEAN )
)
),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, BOOLEAN )
);
this.every = every;
}
@ -56,7 +59,9 @@ public class EveryAnyEmulation extends AbstractSqmSelfRenderingFunctionDescripto
SqlAstTranslator<?> walker) {
sqlAppender.appendSql( "(sum(case when " );
if ( filter != null ) {
walker.getCurrentClauseStack().push( Clause.WHERE );
filter.accept( walker );
walker.getCurrentClauseStack().pop();
sqlAppender.appendSql( " then case when " );
sqlAstArguments.get( 0 ).accept( walker );
if ( every ) {

View File

@ -16,6 +16,7 @@ import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SelfRenderingSqmFunction;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.*;
@ -44,14 +45,15 @@ public class ExtractFunction
private final Dialect dialect;
public ExtractFunction(Dialect dialect) {
public ExtractFunction(Dialect dialect, TypeConfiguration typeConfiguration) {
super(
"extract",
new ArgumentTypesValidator(
StandardArgumentsValidators.exactly( 2 ),
TEMPORAL_UNIT, TEMPORAL
),
StandardFunctionReturnTypeResolvers.useArgType( 1 )
StandardFunctionReturnTypeResolvers.useArgType( 1 ),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, TEMPORAL_UNIT, TEMPORAL )
);
this.dialect = dialect;
}

View File

@ -12,6 +12,7 @@ import java.util.List;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.function.FunctionKind;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
@ -32,7 +33,8 @@ public class HypotheticalSetFunction extends AbstractSqmSelfRenderingFunctionDes
null,
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( returnType )
)
),
null
);
}
@ -74,6 +76,7 @@ public class HypotheticalSetFunction extends AbstractSqmSelfRenderingFunctionDes
}
sqlAppender.appendSql( ')' );
if ( withinGroup != null && !withinGroup.isEmpty() ) {
translator.getCurrentClauseStack().push( Clause.WITHIN_GROUP );
sqlAppender.appendSql( " within group (order by " );
withinGroup.get( 0 ).accept( translator );
for ( int i = 1; i < withinGroup.size(); i++ ) {
@ -81,11 +84,14 @@ public class HypotheticalSetFunction extends AbstractSqmSelfRenderingFunctionDes
withinGroup.get( i ).accept( translator );
}
sqlAppender.appendSql( ')' );
translator.getCurrentClauseStack().pop();
}
if ( filter != null ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( " filter (where " );
filter.accept( translator );
sqlAppender.appendSql( ')' );
translator.getCurrentClauseStack().pop();
}
}

View File

@ -15,6 +15,7 @@ import org.hibernate.query.sqm.function.SelfRenderingSqmFunction;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic;
@ -54,7 +55,8 @@ public class InsertSubstringOverlayEmulation
),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
)
),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, STRING, STRING, INTEGER, INTEGER )
);
this.strictSubstring = strictSubstring;
}

View File

@ -41,7 +41,7 @@ public class IntegralTimestampaddFunction
private final BasicType<Integer> integerType;
public IntegralTimestampaddFunction(Dialect dialect, TypeConfiguration typeConfiguration) {
super( dialect );
super( dialect, typeConfiguration );
this.dialect = dialect;
this.integerType = typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER );
//This is kinda wrong, we're supposed to use findFunctionDescriptor("cast"), not instantiate CastFunction

View File

@ -20,10 +20,12 @@ import org.hibernate.query.sqm.function.SelfRenderingSqmOrderedSetAggregateFunct
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.FunctionParameterType;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.select.SqmOrderByClause;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
@ -44,7 +46,10 @@ public class InverseDistributionFunction extends AbstractSqmSelfRenderingFunctio
parameterType == null
? StandardArgumentsValidators.exactly( 0 )
: new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 1 ), parameterType ),
null
null,
parameterType == null
? null
: StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, parameterType )
);
}
@ -103,6 +108,7 @@ public class InverseDistributionFunction extends AbstractSqmSelfRenderingFunctio
}
sqlAppender.appendSql( ')' );
if ( withinGroup != null && !withinGroup.isEmpty() ) {
translator.getCurrentClauseStack().push( Clause.WITHIN_GROUP );
sqlAppender.appendSql( " within group (order by " );
withinGroup.get( 0 ).accept( translator );
for ( int i = 1; i < withinGroup.size(); i++ ) {
@ -110,11 +116,14 @@ public class InverseDistributionFunction extends AbstractSqmSelfRenderingFunctio
withinGroup.get( i ).accept( translator );
}
sqlAppender.appendSql( ')' );
translator.getCurrentClauseStack().pop();
}
if ( filter != null ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( " filter (where " );
filter.accept( translator );
sqlAppender.appendSql( ')' );
translator.getCurrentClauseStack().pop();
}
}

View File

@ -13,7 +13,9 @@ import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescript
import org.hibernate.query.sqm.function.FunctionKind;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
@ -40,7 +42,8 @@ public class ListaggFunction extends AbstractSqmSelfRenderingFunctionDescriptor
new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 2 ), STRING, STRING ),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
)
),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, STRING, STRING )
);
this.emptyWithinReplacement = emptyWithinReplacement;
}
@ -82,7 +85,9 @@ public class ListaggFunction extends AbstractSqmSelfRenderingFunctionDescriptor
}
if ( caseWrapper ) {
sqlAppender.appendSql( "case when " );
translator.getCurrentClauseStack().push( Clause.WHERE );
filter.accept( translator );
translator.getCurrentClauseStack().pop();
sqlAppender.appendSql( " then " );
arg.accept( translator );
sqlAppender.appendSql( " else null end" );
@ -96,6 +101,7 @@ public class ListaggFunction extends AbstractSqmSelfRenderingFunctionDescriptor
}
sqlAppender.appendSql( ')' );
if ( withinGroup != null && !withinGroup.isEmpty() ) {
translator.getCurrentClauseStack().push( Clause.WITHIN_GROUP );
sqlAppender.appendSql( " within group (order by " );
withinGroup.get( 0 ).accept( translator );
for ( int i = 1; i < withinGroup.size(); i++ ) {
@ -103,15 +109,18 @@ public class ListaggFunction extends AbstractSqmSelfRenderingFunctionDescriptor
withinGroup.get( i ).accept( translator );
}
sqlAppender.appendSql( ')' );
translator.getCurrentClauseStack().pop();
}
else if ( emptyWithinReplacement != null ) {
sqlAppender.appendSql( ' ' );
sqlAppender.appendSql( emptyWithinReplacement );
}
if ( !caseWrapper && filter != null ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( " filter (where " );
filter.accept( translator );
sqlAppender.appendSql( ')' );
translator.getCurrentClauseStack().pop();
}
}

View File

@ -13,7 +13,9 @@ import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescript
import org.hibernate.query.sqm.function.FunctionKind;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
@ -41,7 +43,8 @@ public class ListaggGroupConcatEmulation extends AbstractSqmSelfRenderingFunctio
new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 2 ), STRING, STRING ),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
)
),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, STRING, STRING )
);
}
@ -81,22 +84,26 @@ public class ListaggGroupConcatEmulation extends AbstractSqmSelfRenderingFunctio
arg = (Expression) firstArg;
}
if ( caseWrapper ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( "case when " );
filter.accept( translator );
sqlAppender.appendSql( " then " );
arg.accept( translator );
sqlAppender.appendSql( " else null end" );
translator.getCurrentClauseStack().pop();
}
else {
arg.accept( translator );
}
if ( withinGroup != null && !withinGroup.isEmpty() ) {
translator.getCurrentClauseStack().push( Clause.WITHIN_GROUP );
sqlAppender.appendSql( " order by " );
withinGroup.get( 0 ).accept( translator );
for ( int i = 1; i < withinGroup.size(); i++ ) {
sqlAppender.appendSql( ',' );
withinGroup.get( i ).accept( translator );
}
translator.getCurrentClauseStack().pop();
}
if ( sqlAstArguments.size() != 1 ) {
SqlAstNode separator = sqlAstArguments.get( 1 );
@ -109,9 +116,11 @@ public class ListaggGroupConcatEmulation extends AbstractSqmSelfRenderingFunctio
}
sqlAppender.appendSql( ')' );
if ( !caseWrapper && filter != null ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( " filter (where " );
filter.accept( translator );
sqlAppender.appendSql( ')' );
translator.getCurrentClauseStack().pop();
}
}

View File

@ -15,7 +15,9 @@ import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescript
import org.hibernate.query.sqm.function.FunctionKind;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
@ -51,7 +53,8 @@ public class ListaggStringAggEmulation extends AbstractSqmSelfRenderingFunctionD
new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 2 ), STRING, STRING ),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
)
),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, STRING, STRING )
);
this.functionName = functionName;
this.stringType = stringType;
@ -95,11 +98,13 @@ public class ListaggStringAggEmulation extends AbstractSqmSelfRenderingFunctionD
arg = (Expression) firstArg;
}
if ( caseWrapper ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( "case when " );
filter.accept( translator );
sqlAppender.appendSql( " then " );
renderAsString( sqlAppender, translator, arg );
sqlAppender.appendSql( " else null end" );
translator.getCurrentClauseStack().pop();
}
else {
renderAsString( sqlAppender, translator, arg );
@ -113,16 +118,19 @@ public class ListaggStringAggEmulation extends AbstractSqmSelfRenderingFunctionD
sqlAppender.appendSql( ',' );
separator.accept( translator );
if ( !withinGroupClause && withinGroup != null && !withinGroup.isEmpty() ) {
translator.getCurrentClauseStack().push( Clause.WITHIN_GROUP );
sqlAppender.appendSql( " order by " );
withinGroup.get( 0 ).accept( translator );
for ( int i = 1; i < withinGroup.size(); i++ ) {
sqlAppender.appendSql( ',' );
withinGroup.get( i ).accept( translator );
}
translator.getCurrentClauseStack().pop();
}
}
sqlAppender.appendSql( ')' );
if ( withinGroupClause && withinGroup != null && !withinGroup.isEmpty() ) {
translator.getCurrentClauseStack().push( Clause.WITHIN_GROUP );
sqlAppender.appendSql( " within group (order by " );
withinGroup.get( 0 ).accept( translator );
for ( int i = 1; i < withinGroup.size(); i++ ) {
@ -130,11 +138,14 @@ public class ListaggStringAggEmulation extends AbstractSqmSelfRenderingFunctionD
withinGroup.get( i ).accept( translator );
}
sqlAppender.appendSql( ')' );
translator.getCurrentClauseStack().pop();
}
if ( !caseWrapper && filter != null ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( " filter (where " );
filter.accept( translator );
sqlAppender.appendSql( ')' );
translator.getCurrentClauseStack().pop();
}
}

View File

@ -12,6 +12,7 @@ import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SelfRenderingSqmFunction;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.type.StandardBasicTypes;
@ -34,7 +35,8 @@ public class LocatePositionEmulation extends AbstractSqmFunctionDescriptor {
new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 2 ), STRING, STRING ),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER )
)
),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, STRING, STRING )
);
}

View File

@ -13,6 +13,7 @@ import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SelfRenderingSqmFunction;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.SqmTrimSpecification;
@ -47,7 +48,8 @@ public class LpadRpadPadEmulation
),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
)
),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, STRING, INTEGER, TRIM_SPEC, STRING )
);
}

View File

@ -13,7 +13,9 @@ import org.hibernate.query.sqm.function.FunctionKind;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.FunctionParameterType;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
@ -41,7 +43,8 @@ public class MinMaxCaseEveryAnyEmulation extends AbstractSqmSelfRenderingFunctio
new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 1 ), FunctionParameterType.BOOLEAN ),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.BOOLEAN )
)
),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, FunctionParameterType.BOOLEAN )
);
this.every = every;
}
@ -59,7 +62,9 @@ public class MinMaxCaseEveryAnyEmulation extends AbstractSqmSelfRenderingFunctio
sqlAppender.appendSql( "max(case when " );
}
if ( filter != null ) {
walker.getCurrentClauseStack().push( Clause.WHERE );
filter.accept( walker );
walker.getCurrentClauseStack().pop();
sqlAppender.appendSql( " then case when " );
sqlAstArguments.get( 0 ).accept( walker );
sqlAppender.appendSql( " then 1 else 0 end else null end)" );

View File

@ -8,6 +8,7 @@ package org.hibernate.dialect.function;
import java.util.List;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
@ -43,19 +44,27 @@ public class ModeStatsModeEmulation extends InverseDistributionFunction {
throw new IllegalArgumentException( "MODE function requires a WITHIN GROUP clause with exactly one order by item!" );
}
if ( caseWrapper ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( "case when " );
filter.accept( translator );
translator.getCurrentClauseStack().pop();
sqlAppender.appendSql( " then " );
translator.getCurrentClauseStack().push( Clause.WITHIN_GROUP );
withinGroup.get( 0 ).accept( translator );
sqlAppender.appendSql( " else null end)" );
translator.getCurrentClauseStack().pop();
}
else {
translator.getCurrentClauseStack().push( Clause.WITHIN_GROUP );
withinGroup.get( 0 ).accept( translator );
translator.getCurrentClauseStack().pop();
sqlAppender.appendSql( ')' );
if ( filter != null ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( " filter (where " );
filter.accept( translator );
sqlAppender.appendSql( ')' );
translator.getCurrentClauseStack().pop();
}
}
}

View File

@ -12,6 +12,7 @@ import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SelfRenderingSqmFunction;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
@ -35,7 +36,8 @@ public class NvlCoalesceEmulation
super(
"coalesce",
StandardArgumentsValidators.min( 2 ),
StandardFunctionReturnTypeResolvers.useFirstNonNull()
StandardFunctionReturnTypeResolvers.useFirstNonNull(),
StandardFunctionArgumentTypeResolvers.IMPLIED_RESULT_TYPE
);
}

View File

@ -11,6 +11,7 @@ import java.util.List;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
@ -32,7 +33,8 @@ public class QuantifiedLeastGreatestEmulation
super(
least ? "least" : "greatest",
new ArgumentTypesValidator( StandardArgumentsValidators.min( 2 ), COMPARABLE, COMPARABLE ),
StandardFunctionReturnTypeResolvers.useFirstNonNull()
StandardFunctionReturnTypeResolvers.useFirstNonNull(),
StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE
);
this.operator = least ? "<=" : ">=";
}

View File

@ -11,8 +11,11 @@ import java.util.List;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.function.FunctionKind;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.FunctionParameterType;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
@ -42,7 +45,8 @@ public class SQLServerEveryAnyEmulation extends AbstractSqmSelfRenderingFunction
new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 1 ), BOOLEAN ),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.BOOLEAN )
)
),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, FunctionParameterType.BOOLEAN )
);
this.every = every;
}
@ -60,7 +64,9 @@ public class SQLServerEveryAnyEmulation extends AbstractSqmSelfRenderingFunction
sqlAppender.appendSql( "max(iif(" );
}
if ( filter != null ) {
walker.getCurrentClauseStack().push( Clause.WHERE );
filter.accept( walker );
walker.getCurrentClauseStack().pop();
sqlAppender.appendSql( ",iif(" );
sqlAstArguments.get( 0 ).accept( walker );
sqlAppender.appendSql( ",1,0),null))" );

View File

@ -11,6 +11,7 @@ import jakarta.persistence.TemporalType;
import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
@ -20,6 +21,9 @@ import org.hibernate.sql.ast.tree.expression.Format;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.STRING;
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEMPORAL;
/**
* SQL Server behaves strangely when the first argument to format is of the type time, so we cast to datetime.
*
@ -35,7 +39,8 @@ public class SQLServerFormatEmulation extends AbstractSqmSelfRenderingFunctionDe
CommonFunctionFactory.formatValidator(),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
)
),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, TEMPORAL, STRING )
);
this.dialect = dialect;
}

View File

@ -29,7 +29,8 @@ public class SqlFunction
super(
"sql",
StandardArgumentsValidators.min( 1 ),
StandardFunctionReturnTypeResolvers.invariant( JavaObjectType.INSTANCE )
StandardFunctionReturnTypeResolvers.invariant( JavaObjectType.INSTANCE ),
null
);
}

View File

@ -15,6 +15,7 @@ import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescript
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
import org.hibernate.sql.ast.SqlAstTranslator;
@ -22,6 +23,7 @@ import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.expression.DurationUnit;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.type.spi.TypeConfiguration;
import java.util.List;
@ -46,14 +48,15 @@ public class TimestampaddFunction
private final Dialect dialect;
public TimestampaddFunction(Dialect dialect) {
public TimestampaddFunction(Dialect dialect, TypeConfiguration typeConfiguration) {
super(
"timestampadd",
new ArgumentTypesValidator(
StandardArgumentsValidators.exactly( 3 ),
TEMPORAL_UNIT, INTEGER, TEMPORAL
),
StandardFunctionReturnTypeResolvers.useArgType( 3 )
StandardFunctionReturnTypeResolvers.useArgType( 3 ),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, TEMPORAL_UNIT, INTEGER, TEMPORAL )
);
this.dialect = dialect;
}

View File

@ -8,7 +8,6 @@ package org.hibernate.dialect.function;
import java.util.List;
import jakarta.persistence.TemporalType;
import org.hibernate.dialect.Dialect;
import org.hibernate.query.ReturnableType;
import org.hibernate.query.sqm.TemporalUnit;
@ -16,6 +15,7 @@ import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescript
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
import org.hibernate.sql.ast.SqlAstTranslator;
@ -26,6 +26,8 @@ import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration;
import jakarta.persistence.TemporalType;
import static java.util.Arrays.asList;
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEMPORAL;
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEMPORAL_UNIT;
@ -54,7 +56,8 @@ public class TimestampdiffFunction
),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.LONG )
)
),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, TEMPORAL_UNIT, TEMPORAL, TEMPORAL )
);
this.dialect = dialect;
}

View File

@ -11,6 +11,7 @@ import org.hibernate.query.sqm.TrimSpec;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
import org.hibernate.sql.ast.SqlAstTranslator;
@ -50,7 +51,8 @@ public class TrimFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
),
StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
)
),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, TRIM_SPEC, STRING, STRING )
);
this.dialect = dialect;
}

View File

@ -3191,7 +3191,8 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
null,
StandardFunctionReturnTypeResolvers.invariant(
resolveExpressibleTypeBasic( Object.class )
)
),
null
);
}
return functionTemplate.generateSqmExpression(
@ -3262,6 +3263,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
StandardFunctionReturnTypeResolvers.invariant(
resolveExpressibleTypeBasic( Object.class )
),
null,
functionName,
functionKind,
null,

View File

@ -6,45 +6,52 @@
*/
package org.hibernate.query.sqm.function;
import java.util.List;
import org.hibernate.query.ReturnableType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.FunctionArgumentTypeResolver;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.select.SqmOrderByClause;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.type.spi.TypeConfiguration;
import java.util.ArrayList;
import java.util.List;
import static java.util.Collections.emptyList;
/**
* @author Steve Ebersole
*/
public abstract class AbstractSqmFunctionDescriptor implements SqmFunctionDescriptor {
private final ArgumentsValidator argumentsValidator;
private final FunctionReturnTypeResolver returnTypeResolver;
private final FunctionArgumentTypeResolver functionArgumentTypeResolver;
private final String name;
public AbstractSqmFunctionDescriptor(String name) {
this( name, null, null );
this( name, null, null, null );
}
public AbstractSqmFunctionDescriptor(String name, ArgumentsValidator argumentsValidator) {
this( name, argumentsValidator, null );
public AbstractSqmFunctionDescriptor(
String name,
ArgumentsValidator argumentsValidator) {
this( name, argumentsValidator, null, null );
}
public AbstractSqmFunctionDescriptor(
String name,
ArgumentsValidator argumentsValidator,
FunctionReturnTypeResolver returnTypeResolver) {
FunctionArgumentTypeResolver argumentTypeResolver) {
this( name, argumentsValidator, null, argumentTypeResolver );
}
public AbstractSqmFunctionDescriptor(
String name,
ArgumentsValidator argumentsValidator,
FunctionReturnTypeResolver returnTypeResolver,
FunctionArgumentTypeResolver argumentTypeResolver) {
this.name = name;
this.argumentsValidator = argumentsValidator == null
? StandardArgumentsValidators.NONE
@ -52,6 +59,9 @@ public abstract class AbstractSqmFunctionDescriptor implements SqmFunctionDescri
this.returnTypeResolver = returnTypeResolver == null
? StandardFunctionReturnTypeResolvers.useFirstNonNull()
: returnTypeResolver;
this.functionArgumentTypeResolver = argumentTypeResolver == null
? StandardFunctionArgumentTypeResolvers.NULL
: argumentTypeResolver;
}
public String getName() {
@ -71,6 +81,10 @@ public abstract class AbstractSqmFunctionDescriptor implements SqmFunctionDescri
return returnTypeResolver;
}
public FunctionArgumentTypeResolver getArgumentTypeResolver() {
return functionArgumentTypeResolver;
}
public String getReturnSignature() {
String result = returnTypeResolver.getReturnType();
return result.isEmpty() ? "" : result + " ";
@ -81,23 +95,6 @@ public abstract class AbstractSqmFunctionDescriptor implements SqmFunctionDescri
return alwaysIncludesParentheses() ? args : "()".equals(args) ? "" : "[" + args + "]";
}
private static SqlAstNode toSqlAstNode(Object arg, SqmToSqlAstConverter walker) {
return (SqlAstNode) arg;
}
public static List<SqlAstNode> resolveSqlAstArguments(List<? extends SqmTypedNode<?>> sqmArguments, SqmToSqlAstConverter walker) {
if ( sqmArguments == null || sqmArguments.isEmpty() ) {
return emptyList();
}
final ArrayList<SqlAstNode> sqlAstArguments = new ArrayList<>();
for ( SqmTypedNode<?> sqmArgument : sqmArguments ) {
sqlAstArguments.add( toSqlAstNode( ((SqmVisitableNode) sqmArgument).accept( walker ), walker ) );
}
return sqlAstArguments;
}
@Override
public final <T> SelfRenderingSqmFunction<T> generateSqmExpression(
List<? extends SqmTypedNode<?>> arguments,

View File

@ -9,6 +9,7 @@ package org.hibernate.query.sqm.function;
import org.hibernate.query.ReturnableType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.FunctionArgumentTypeResolver;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
@ -33,8 +34,9 @@ public abstract class AbstractSqmSelfRenderingFunctionDescriptor
public AbstractSqmSelfRenderingFunctionDescriptor(
String name,
ArgumentsValidator argumentsValidator,
FunctionReturnTypeResolver returnTypeResolver) {
super( name, argumentsValidator, returnTypeResolver );
FunctionReturnTypeResolver returnTypeResolver,
FunctionArgumentTypeResolver argumentTypeResolver) {
super( name, argumentsValidator, returnTypeResolver, argumentTypeResolver );
this.functionKind = FunctionKind.NORMAL;
}
@ -42,8 +44,9 @@ public abstract class AbstractSqmSelfRenderingFunctionDescriptor
String name,
FunctionKind functionKind,
ArgumentsValidator argumentsValidator,
FunctionReturnTypeResolver returnTypeResolver) {
super( name, argumentsValidator, returnTypeResolver );
FunctionReturnTypeResolver returnTypeResolver,
FunctionArgumentTypeResolver argumentTypeResolver) {
super( name, argumentsValidator, returnTypeResolver, argumentTypeResolver );
this.functionKind = functionKind;
}

View File

@ -11,6 +11,7 @@ import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.FunctionParameterType;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.type.BasicType;
@ -60,6 +61,7 @@ public class MultipatternSqmFunctionDescriptor extends AbstractSqmFunctionDescri
String name,
SqmFunctionDescriptor[] functions,
BasicType<?> type,
TypeConfiguration typeConfiguration,
FunctionParameterType... parameterTypes) {
super(
name,
@ -70,7 +72,8 @@ public class MultipatternSqmFunctionDescriptor extends AbstractSqmFunctionDescri
),
parameterTypes
),
StandardFunctionReturnTypeResolvers.invariant( type )
StandardFunctionReturnTypeResolvers.invariant( type ),
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, parameterTypes )
);
this.functions = functions;
}

View File

@ -7,7 +7,9 @@
package org.hibernate.query.sqm.function;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.FunctionArgumentTypeResolver;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
@ -47,6 +49,7 @@ public class NamedSqmFunctionDescriptor
useParenthesesWhenNoArgs,
argumentsValidator,
returnTypeResolver,
null,
functionName,
FunctionKind.NORMAL,
null,
@ -59,11 +62,31 @@ public class NamedSqmFunctionDescriptor
boolean useParenthesesWhenNoArgs,
ArgumentsValidator argumentsValidator,
FunctionReturnTypeResolver returnTypeResolver,
FunctionArgumentTypeResolver argumentTypeResolver) {
this(
functionName,
useParenthesesWhenNoArgs,
argumentsValidator,
returnTypeResolver,
argumentTypeResolver,
functionName,
FunctionKind.NORMAL,
null,
SqlAstNodeRenderingMode.DEFAULT
);
}
public NamedSqmFunctionDescriptor(
String functionName,
boolean useParenthesesWhenNoArgs,
ArgumentsValidator argumentsValidator,
FunctionReturnTypeResolver returnTypeResolver,
FunctionArgumentTypeResolver argumentTypeResolver,
String name,
FunctionKind functionKind,
String argumentListSignature,
SqlAstNodeRenderingMode argumentRenderingMode) {
super( name, functionKind, argumentsValidator, returnTypeResolver );
super( name, functionKind, argumentsValidator, returnTypeResolver, argumentTypeResolver );
this.functionName = functionName;
this.useParenthesesWhenNoArgs = useParenthesesWhenNoArgs;
@ -150,8 +173,10 @@ public class NamedSqmFunctionDescriptor
sqlAppender.appendSql( "," );
}
if ( caseWrapper && !( arg instanceof Distinct ) ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( "case when " );
filter.accept( translator );
translator.getCurrentClauseStack().pop();
sqlAppender.appendSql( " then " );
if ( ( arg instanceof Star ) ) {
sqlAppender.appendSql( "1" );
@ -172,6 +197,7 @@ public class NamedSqmFunctionDescriptor
}
if ( withinGroup != null && !withinGroup.isEmpty() ) {
translator.getCurrentClauseStack().push( Clause.WITHIN_GROUP );
sqlAppender.appendSql( " within group (order by" );
translator.render( withinGroup.get( 0 ), argumentRenderingMode );
for ( int i = 1; i < withinGroup.size(); i++ ) {
@ -179,6 +205,7 @@ public class NamedSqmFunctionDescriptor
translator.render( withinGroup.get( 0 ), argumentRenderingMode );
}
sqlAppender.appendSql( ')' );
translator.getCurrentClauseStack().pop();
}
if ( fromFirst != null ) {
@ -199,9 +226,11 @@ public class NamedSqmFunctionDescriptor
}
if ( filter != null && !caseWrapper ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( " filter (where " );
filter.accept( translator );
sqlAppender.appendSql( ')' );
translator.getCurrentClauseStack().pop();
}
}

View File

@ -7,6 +7,7 @@
package org.hibernate.query.sqm.function;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.FunctionArgumentTypeResolver;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
@ -48,6 +49,7 @@ public class PatternBasedSqmFunctionDescriptor
PatternRenderer renderer,
ArgumentsValidator argumentsValidator,
FunctionReturnTypeResolver returnTypeResolver,
FunctionArgumentTypeResolver argumentTypeResolver,
String name,
FunctionKind functionKind,
String argumentListSignature) {
@ -63,7 +65,8 @@ public class PatternBasedSqmFunctionDescriptor
: renderer.hasVarargs()
? StandardArgumentsValidators.min( renderer.getParamCount() )
: StandardArgumentsValidators.exactly( renderer.getParamCount() ),
returnTypeResolver
returnTypeResolver,
argumentTypeResolver
);
this.renderer = renderer;
this.argumentListSignature = argumentListSignature;

View File

@ -8,6 +8,7 @@ package org.hibernate.query.sqm.function;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.MappingModelExpressible;
@ -16,7 +17,9 @@ import org.hibernate.query.ReturnableType;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.FunctionArgumentTypeResolver;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmTypedNode;
@ -97,14 +100,38 @@ public class SelfRenderingSqmFunction<T> extends SqmFunction<T> {
return returnTypeResolver;
}
protected static List<SqlAstNode> resolveSqlAstArguments(List<? extends SqmTypedNode<?>> sqmArguments, SqmToSqlAstConverter walker) {
protected List<SqlAstNode> resolveSqlAstArguments(List<? extends SqmTypedNode<?>> sqmArguments, SqmToSqlAstConverter walker) {
if ( sqmArguments == null || sqmArguments.isEmpty() ) {
return emptyList();
}
final FunctionArgumentTypeResolver argumentTypeResolver;
if ( getFunctionDescriptor() instanceof AbstractSqmFunctionDescriptor ) {
argumentTypeResolver = ( (AbstractSqmFunctionDescriptor) getFunctionDescriptor() ).getArgumentTypeResolver();
}
else {
argumentTypeResolver = null;
}
if ( argumentTypeResolver == null ) {
final ArrayList<SqlAstNode> sqlAstArguments = new ArrayList<>( sqmArguments.size() );
for ( int i = 0; i < sqmArguments.size(); i++ ) {
sqlAstArguments.add(
(SqlAstNode) ( (SqmVisitableNode) sqmArguments.get( i ) ).accept( walker )
);
}
return sqlAstArguments;
}
final FunctionArgumentTypeResolverTypeAccess typeAccess = new FunctionArgumentTypeResolverTypeAccess(
walker,
this,
argumentTypeResolver
);
final ArrayList<SqlAstNode> sqlAstArguments = new ArrayList<>( sqmArguments.size() );
for ( SqmTypedNode<?> sqmArgument : sqmArguments ) {
sqlAstArguments.add( (SqlAstNode) ( (SqmVisitableNode) sqmArgument ).accept( walker ) );
for ( int i = 0; i < sqmArguments.size(); i++ ) {
typeAccess.argumentIndex = i;
sqlAstArguments.add(
(SqlAstNode) walker.visitWithInferredType( (SqmVisitableNode) sqmArguments.get( i ), typeAccess )
);
}
return sqlAstArguments;
}
@ -184,4 +211,26 @@ public class SelfRenderingSqmFunction<T> extends SqmFunction<T> {
return mapping;
}
private static class FunctionArgumentTypeResolverTypeAccess implements Supplier<MappingModelExpressible<?>> {
private final SqmToSqlAstConverter converter;
private final SqmFunction<?> function;
private final FunctionArgumentTypeResolver argumentTypeResolver;
private int argumentIndex;
public FunctionArgumentTypeResolverTypeAccess(
SqmToSqlAstConverter converter,
SqmFunction<?> function,
FunctionArgumentTypeResolver argumentTypeResolver) {
this.converter = converter;
this.function = function;
this.argumentTypeResolver = argumentTypeResolver;
}
@Override
public MappingModelExpressible<?> get() {
return argumentTypeResolver.resolveFunctionArgumentType( function, argumentIndex, converter );
}
}
}

View File

@ -107,7 +107,7 @@ public class SelfRenderingSqmOrderedSetAggregateFunction<T> extends SelfRenderin
withinGroup = Collections.emptyList();
}
else {
walker.getCurrentClauseStack().push( Clause.ORDER );
walker.getCurrentClauseStack().push( Clause.WITHIN_GROUP );
try {
final List<SqmSortSpecification> sortSpecifications = this.withinGroup.getSortSpecifications();
withinGroup = new ArrayList<>( sortSpecifications.size() );

View File

@ -15,6 +15,7 @@ import org.hibernate.query.sqm.produce.function.FunctionParameterType;
import org.hibernate.query.sqm.produce.function.NamedFunctionDescriptorBuilder;
import org.hibernate.query.sqm.produce.function.PatternFunctionDescriptorBuilder;
import org.hibernate.type.BasicType;
import org.hibernate.type.spi.TypeConfiguration;
import org.jboss.logging.Logger;
@ -305,8 +306,16 @@ public class SqmFunctionRegistry {
BasicType type,
String pattern0,
String pattern1,
FunctionParameterType parameterType) {
return registerPatterns( name, type, new FunctionParameterType[]{parameterType}, pattern0, pattern1 );
FunctionParameterType parameterType,
TypeConfiguration typeConfiguration) {
return registerPatterns(
name,
type,
new FunctionParameterType[] { parameterType },
typeConfiguration,
pattern0,
pattern1
);
}
/**
@ -320,10 +329,17 @@ public class SqmFunctionRegistry {
String pattern1,
String pattern2,
FunctionParameterType parameterType1,
FunctionParameterType parameterType2) {
return registerPatterns( name, type,
new FunctionParameterType[]{parameterType1,parameterType2},
null, pattern1, pattern2 );
FunctionParameterType parameterType2,
TypeConfiguration typeConfiguration) {
return registerPatterns(
name,
type,
new FunctionParameterType[] { parameterType1, parameterType2 },
typeConfiguration,
null,
pattern1,
pattern2
);
}
/**
@ -338,10 +354,18 @@ public class SqmFunctionRegistry {
String pattern3,
FunctionParameterType parameterType1,
FunctionParameterType parameterType2,
FunctionParameterType parameterType3) {
return registerPatterns( name, type,
new FunctionParameterType[]{parameterType1,parameterType2,parameterType3},
null, null, pattern2, pattern3 );
FunctionParameterType parameterType3,
TypeConfiguration typeConfiguration) {
return registerPatterns(
name,
type,
new FunctionParameterType[] { parameterType1, parameterType2, parameterType3 },
typeConfiguration,
null,
null,
pattern2,
pattern3
);
}
/**
@ -357,16 +381,31 @@ public class SqmFunctionRegistry {
FunctionParameterType parameterType1,
FunctionParameterType parameterType2,
FunctionParameterType parameterType3,
FunctionParameterType parameterType4) {
return registerPatterns( name, type,
new FunctionParameterType[]{parameterType1,parameterType2,parameterType3, parameterType4},
null, null, null, pattern3, pattern4 );
FunctionParameterType parameterType4,
TypeConfiguration typeConfiguration) {
return registerPatterns(
name,
type,
new FunctionParameterType[] {
parameterType1,
parameterType2,
parameterType3,
parameterType4
},
typeConfiguration,
null,
null,
null,
pattern3,
pattern4
);
}
private MultipatternSqmFunctionDescriptor registerPatterns(
String name,
BasicType<?> type,
FunctionParameterType[] parameterTypes,
TypeConfiguration typeConfiguration,
String... patterns) {
SqmFunctionDescriptor[] descriptors =
new SqmFunctionDescriptor[patterns.length];
@ -383,7 +422,7 @@ public class SqmFunctionRegistry {
}
MultipatternSqmFunctionDescriptor function =
new MultipatternSqmFunctionDescriptor( name, descriptors, type, parameterTypes );
new MultipatternSqmFunctionDescriptor( name, descriptors, type, typeConfiguration, parameterTypes );
register( name, function );
return function;
}

View File

@ -1340,7 +1340,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
name,
true,
null,
StandardFunctionReturnTypeResolvers.invariant( resultType )
StandardFunctionReturnTypeResolvers.invariant( resultType ),
null
);
}

View File

@ -402,18 +402,18 @@ public class SqmUtil {
List<SqmParameter<?>> sqmParameters,
SqmParameterMappingModelResolutionAccess mappingModelResolutionAccess,
SessionFactoryImplementor sessionFactory) {
if ( binding.getType() != null ) {
return binding.getType();
}
if ( binding.getBindType() != null && binding.getBindType() instanceof Bindable ) {
if ( binding.getBindType() instanceof Bindable ) {
return (Bindable) binding.getBindType();
}
if ( parameter.getHibernateType() != null && parameter.getHibernateType() instanceof Bindable ) {
if ( parameter.getHibernateType() instanceof Bindable ) {
return (Bindable) parameter.getHibernateType();
}
if ( binding.getType() != null ) {
return binding.getType();
}
for ( int i = 0; i < sqmParameters.size(); i++ ) {
final MappingModelExpressible<?> mappingModelType = mappingModelResolutionAccess
.getResolvedMappingModelType( sqmParameters.get( i ) );
@ -425,8 +425,7 @@ public class SqmUtil {
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
// assume we have (or can create) a mapping for the parameter's Java type
BasicType basicType = typeConfiguration.standardBasicTypeForJavaType( parameter.getParameterType() );
return basicType;
return typeConfiguration.standardBasicTypeForJavaType( parameter.getParameterType() );
}
public static SqmStatement.ParameterResolutions resolveParameters(SqmStatement<?> statement) {

View File

@ -0,0 +1,32 @@
/*
* 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.query.sqm.produce.function;
import org.hibernate.metamodel.mapping.MappingModelExpressible;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.expression.SqmFunction;
/**
* Pluggable strategy for resolving a function argument type for a specific call.
*
* @author Christian Beikov
*/
public interface FunctionArgumentTypeResolver {
/**
* Resolve the argument type for a function given its context-implied return type.
* <p/>
* NOTE : the _context-implied_ type is the type implied by where the function's
* occurs in the query. E.g., for an equality predicate (`something = some_function`)
* the implied type would be defined by the type of `something`.
*
* @return The resolved type.
*/
MappingModelExpressible<?> resolveFunctionArgumentType(
SqmFunction<?> function,
int argumentIndex,
SqmToSqlAstConverter converter);
}

View File

@ -26,6 +26,7 @@ public class NamedFunctionDescriptorBuilder {
private ArgumentsValidator argumentsValidator;
private FunctionReturnTypeResolver returnTypeResolver;
private FunctionArgumentTypeResolver argumentTypeResolver;
private boolean useParenthesesWhenNoArgs = true;
private String argumentListSignature;
@ -47,6 +48,11 @@ public class NamedFunctionDescriptorBuilder {
return this;
}
public NamedFunctionDescriptorBuilder setArgumentTypeResolver(FunctionArgumentTypeResolver argumentTypeResolver) {
this.argumentTypeResolver = argumentTypeResolver;
return this;
}
public NamedFunctionDescriptorBuilder setArgumentCountBetween(int min, int max) {
return setArgumentsValidator( StandardArgumentsValidators.between( min, max ) );
}
@ -71,6 +77,7 @@ public class NamedFunctionDescriptorBuilder {
public NamedFunctionDescriptorBuilder setParameterTypes(FunctionParameterType... types) {
setArgumentsValidator( new ArgumentTypesValidator(argumentsValidator, types) );
setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.invariant( types ) );
return this;
}
@ -99,6 +106,7 @@ public class NamedFunctionDescriptorBuilder {
useParenthesesWhenNoArgs,
argumentsValidator,
returnTypeResolver,
argumentTypeResolver,
registrationKey,
functionKind,
argumentListSignature,

View File

@ -26,6 +26,7 @@ public class PatternFunctionDescriptorBuilder {
private ArgumentsValidator argumentsValidator;
private FunctionReturnTypeResolver returnTypeResolver;
private FunctionArgumentTypeResolver argumentTypeResolver;
private SqlAstNodeRenderingMode argumentRenderingMode = SqlAstNodeRenderingMode.DEFAULT;
public PatternFunctionDescriptorBuilder(
@ -44,8 +45,14 @@ public class PatternFunctionDescriptorBuilder {
return this;
}
public PatternFunctionDescriptorBuilder setArgumentTypeResolver(FunctionArgumentTypeResolver argumentTypeResolver) {
this.argumentTypeResolver = argumentTypeResolver;
return this;
}
public PatternFunctionDescriptorBuilder setParameterTypes(FunctionParameterType... types) {
setArgumentsValidator( new ArgumentTypesValidator(argumentsValidator, types) );
setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.invariant( types ) );
return this;
}
@ -62,7 +69,7 @@ public class PatternFunctionDescriptorBuilder {
return this;
}
public PatternFunctionDescriptorBuilder setInvariantType(BasicType invariantType) {
public PatternFunctionDescriptorBuilder setInvariantType(BasicType<?> invariantType) {
setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant( invariantType ) );
return this;
}
@ -86,6 +93,7 @@ public class PatternFunctionDescriptorBuilder {
new PatternRenderer( pattern, argumentRenderingMode ),
argumentsValidator,
returnTypeResolver,
argumentTypeResolver,
registrationKey,
functionKind,
argumentListSignature

View File

@ -0,0 +1,161 @@
/*
* 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.query.sqm.produce.function;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.List;
import org.hibernate.metamodel.mapping.MappingModelExpressible;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.type.spi.TypeConfiguration;
/**
* @author Christian Beikov
*/
public final class StandardFunctionArgumentTypeResolvers {
/**
* Disallow instantiation
*/
private StandardFunctionArgumentTypeResolvers() {
}
public static final FunctionArgumentTypeResolver NULL = (function, argumentIndex, converter) -> {
return null;
};
public static final FunctionArgumentTypeResolver IMPLIED_RESULT_TYPE = (function, argumentIndex, converter) -> {
return converter.resolveFunctionImpliedReturnType();
};
public static final FunctionArgumentTypeResolver ARGUMENT_OR_IMPLIED_RESULT_TYPE = (function, argumentIndex, converter) -> {
final List<? extends SqmTypedNode<?>> arguments = function.getArguments();
final int argumentsSize = arguments.size();
for ( int i = 0 ; i < argumentIndex; i++ ) {
final SqmTypedNode<?> node = arguments.get( i );
if ( node instanceof SqmExpression<?> ) {
final MappingModelExpressible<?> expressible = converter.determineValueMapping( (SqmExpression<?>) node );
if ( expressible != null ) {
return expressible;
}
}
}
for ( int i = argumentIndex + 1 ; i < argumentsSize; i++ ) {
final SqmTypedNode<?> node = arguments.get( i );
if ( node instanceof SqmExpression<?> ) {
final MappingModelExpressible<?> expressible = converter.determineValueMapping( (SqmExpression<?>) node );
if ( expressible != null ) {
return expressible;
}
}
}
return converter.resolveFunctionImpliedReturnType();
};
public static FunctionArgumentTypeResolver invariant(
TypeConfiguration typeConfiguration,
FunctionParameterType type) {
final MappingModelExpressible<?> expressible = getMappingModelExpressible( typeConfiguration, type );
return (function, argumentIndex, converter) -> expressible;
}
public static FunctionArgumentTypeResolver invariant(
TypeConfiguration typeConfiguration,
FunctionParameterType... types) {
final MappingModelExpressible<?>[] expressibles = new MappingModelExpressible[types.length];
for ( int i = 0; i < types.length; i++ ) {
expressibles[i] = getMappingModelExpressible( typeConfiguration, types[i] );
}
return (function, argumentIndex, converter) -> expressibles[argumentIndex];
}
public static FunctionArgumentTypeResolver invariant(FunctionParameterType... types) {
return (function, argumentIndex, converter) -> getMappingModelExpressible(
function.nodeBuilder().getTypeConfiguration(),
types[argumentIndex]
);
}
public static FunctionArgumentTypeResolver impliedOrInvariant(
TypeConfiguration typeConfiguration,
FunctionParameterType type) {
final MappingModelExpressible<?> expressible = getMappingModelExpressible( typeConfiguration, type );
return (function, argumentIndex, converter) -> {
final MappingModelExpressible<?> mappingModelExpressible = converter.resolveFunctionImpliedReturnType();
if ( mappingModelExpressible != null ) {
return mappingModelExpressible;
}
return expressible;
};
}
public static FunctionArgumentTypeResolver argumentsOrImplied(int... indices) {
return (function, argumentIndex, converter) -> {
final List<? extends SqmTypedNode<?>> arguments = function.getArguments();
final int argumentsSize = arguments.size();
for ( int index : indices ) {
if ( index >= argumentIndex || index >= argumentsSize ) {
break;
}
final SqmTypedNode<?> node = arguments.get( index );
if ( node instanceof SqmExpression<?> ) {
final MappingModelExpressible<?> expressible = converter.determineValueMapping( (SqmExpression<?>) node );
if ( expressible != null ) {
return expressible;
}
}
}
for ( int index : indices ) {
if ( index <= argumentIndex || index >= argumentsSize ) {
break;
}
final SqmTypedNode<?> node = arguments.get( index );
if ( node instanceof SqmExpression<?> ) {
final MappingModelExpressible<?> expressible = converter.determineValueMapping( (SqmExpression<?>) node );
if ( expressible != null ) {
return expressible;
}
}
}
return converter.resolveFunctionImpliedReturnType();
};
}
public static FunctionArgumentTypeResolver composite(FunctionArgumentTypeResolver... resolvers) {
return (function, argumentIndex, converter) -> {
return resolvers[argumentIndex].resolveFunctionArgumentType( function, argumentIndex, converter );
};
}
private static MappingModelExpressible<?> getMappingModelExpressible(
TypeConfiguration typeConfiguration,
FunctionParameterType type) {
switch ( type ) {
case STRING:
return typeConfiguration.getBasicTypeForJavaType( String.class );
case NUMERIC:
return typeConfiguration.getBasicTypeForJavaType( BigDecimal.class );
case INTEGER:
return typeConfiguration.getBasicTypeForJavaType( Integer.class );
case TEMPORAL:
return typeConfiguration.getBasicTypeForJavaType( Timestamp.class );
case DATE:
return typeConfiguration.getBasicTypeForJavaType( Date.class );
case TIME:
return typeConfiguration.getBasicTypeForJavaType( Time.class );
case BOOLEAN:
return typeConfiguration.getBasicTypeForJavaType( Boolean.class );
}
return null;
}
}

View File

@ -8,6 +8,7 @@ package org.hibernate.query.sqm.produce.function.internal;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
@ -189,8 +190,10 @@ public class PatternRenderer {
if ( arg != null ) {
sqlAppender.appendSql( chunks[i] );
if ( caseWrapper && !( arg instanceof Distinct ) && !( arg instanceof Star ) ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( "case when " );
filter.accept( translator );
translator.getCurrentClauseStack().pop();
sqlAppender.appendSql( " then " );
translator.render( arg, argumentRenderingMode );
sqlAppender.appendSql( " else null end" );
@ -209,8 +212,10 @@ public class PatternRenderer {
}
if ( arg != null ) {
if ( caseWrapper && !( arg instanceof Distinct ) && !( arg instanceof Star ) ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( "case when " );
filter.accept( translator );
translator.getCurrentClauseStack().pop();
sqlAppender.appendSql( " then " );
translator.render( arg, argumentRenderingMode );
sqlAppender.appendSql( " else null end" );
@ -226,6 +231,7 @@ public class PatternRenderer {
}
if ( withinGroup != null && !withinGroup.isEmpty() ) {
translator.getCurrentClauseStack().push( Clause.WITHIN_GROUP );
sqlAppender.appendSql( " within group (order by" );
translator.render( withinGroup.get( 0 ), argumentRenderingMode );
for ( int i = 1; i < withinGroup.size(); i++ ) {
@ -233,6 +239,7 @@ public class PatternRenderer {
translator.render( withinGroup.get( 0 ), argumentRenderingMode );
}
sqlAppender.appendSql( ')' );
translator.getCurrentClauseStack().pop();
}
if ( fromFirst != null ) {
@ -253,9 +260,11 @@ public class PatternRenderer {
}
if ( filter != null && !caseWrapper ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
sqlAppender.appendSql( " filter (where " );
filter.accept( translator );
sqlAppender.appendSql( ')' );
translator.getCurrentClauseStack().pop();
}
}
}

View File

@ -140,6 +140,7 @@ import org.hibernate.query.sqm.sql.internal.SqmPathInterpretation;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.query.sqm.tree.cte.SqmCteContainer;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.cte.SqmCteTable;
@ -393,6 +394,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
private final QueryOptions queryOptions;
private final LoadQueryInfluencers loadQueryInfluencers;
private final Map<SqmParameter<?>, List<List<JdbcParameter>>> jdbcParamsBySqmParam = new IdentityHashMap<>();
private final JdbcParameters jdbcParameters = new JdbcParametersImpl();
private final DomainParameterXref domainParameterXref;
private final QueryParameterBindings domainParameterBindings;
private final Map<SqmParameter<?>, MappingModelExpressible<?>> sqmParameterMappingModelTypes = new LinkedHashMap<>();
@ -407,6 +410,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
private ForeignKeyDescriptor.Nature currentlyResolvingForeignKeySide;
private SqmQueryPart<?> currentSqmQueryPart;
private boolean containsCollectionFetches;
private boolean trackSelectionsForGroup;
private final Map<String, PredicateCollector> collectionFilterPredicates = new HashMap<>();
private List<Map.Entry<OrderByFragment, TableGroup>> orderByFragments;
@ -436,6 +440,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
);
private final Stack<List<QueryTransformer>> queryTransformers = new StandardStack<>();
private boolean inTypeInference;
private Supplier<MappingModelExpressible<?>> functionImpliedResultTypeAccess;
private SqmByUnit appliedByUnit;
private Expression adjustedTimestamp;
@ -1573,8 +1578,6 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return cteContainer;
}
private boolean trackSelectionsForGroup;
@Override
public QueryPart visitQueryPart(SqmQueryPart<?> queryPart) {
return (QueryPart) super.visitQueryPart( queryPart );
@ -4079,6 +4082,17 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return inferredType;
}
@Override
public MappingModelExpressible<?> resolveFunctionImpliedReturnType() {
if ( inTypeInference || functionImpliedResultTypeAccess == null ) {
return null;
}
inTypeInference = true;
final MappingModelExpressible<?> inferredType = functionImpliedResultTypeAccess.get();
inTypeInference = false;
return inferredType;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// General expressions
@ -4284,9 +4298,6 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
}
}
private final Map<SqmParameter<?>, List<List<JdbcParameter>>> jdbcParamsBySqmParam = new IdentityHashMap<>();
private final JdbcParameters jdbcParameters = new JdbcParametersImpl();
@Override
public Map<SqmParameter<?>, List<List<JdbcParameter>>> getJdbcParamsBySqmParam() {
return jdbcParamsBySqmParam;
@ -4434,7 +4445,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
);
}
protected MappingModelExpressible<?> determineValueMapping(SqmExpression<?> sqmExpression) {
@Override
public MappingModelExpressible<?> determineValueMapping(SqmExpression<?> sqmExpression) {
if ( sqmExpression instanceof SqmParameter ) {
return determineValueMapping( (SqmParameter<?>) sqmExpression );
}
@ -4562,16 +4574,6 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final QueryParameterImplementor<?> queryParameter = domainParameterXref.getQueryParameter( sqmParameter );
final QueryParameterBinding<?> binding = domainParameterBindings.getBinding( queryParameter );
if ( sqmParameter.getAnticipatedType() == null ) {
// this should indicate the condition that the user query did not define an
// explicit type in regard to this parameter. Here we should prefer the
// inferrable type and fallback to the binding type
final MappingModelExpressible<?> inferredValueMapping = getInferredValueMapping();
if ( inferredValueMapping != null ) {
return inferredValueMapping;
}
}
BindableType<?> paramType = binding.getBindType();
if ( paramType == null ) {
paramType = queryParameter.getHibernateType();
@ -4581,12 +4583,25 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
}
if ( paramType == null ) {
final MappingModelExpressible<?> inferredValueMapping = getInferredValueMapping();
if ( inferredValueMapping != null ) {
return inferredValueMapping;
}
// Default to the Object type
return basicType( Object.class );
}
else if ( paramType instanceof MappingModelExpressible<?> && paramType.getBindableJavaType() == Object.class ) {
else if ( paramType instanceof MappingModelExpressible<?> ) {
return (MappingModelExpressible<?>) paramType;
}
else if ( sqmParameter.getAnticipatedType() == null ) {
// this should indicate the condition that the user query did not define an
// explicit type in regard to this parameter. Here we should prefer the
// inferrable type and fallback to resolving the binding type
final MappingModelExpressible<?> inferredValueMapping = getInferredValueMapping();
if ( inferredValueMapping != null ) {
return inferredValueMapping;
}
}
final SqmExpressible<?> paramSqmType = paramType.resolveExpressible( creationContext.getSessionFactory() );
@ -4742,12 +4757,15 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
@Override
public Expression visitFunction(SqmFunction<?> sqmFunction) {
final Supplier<MappingModelExpressible<?>> oldFunctionImpliedResultTypeAccess = functionImpliedResultTypeAccess;
functionImpliedResultTypeAccess = inferrableTypeAccessStack.getCurrent();
inferrableTypeAccessStack.push( () -> null );
try {
return sqmFunction.convertToSqlAst( this );
}
finally {
inferrableTypeAccessStack.pop();
functionImpliedResultTypeAccess = oldFunctionImpliedResultTypeAccess;
}
}
@ -5426,35 +5444,18 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
}
}
// private <X> X visitWithLenientInferredType(SqmExpression<?> expression, SqmExpression<?> inferred) {
// inferrableTypeAccessStack.push(
// () -> {
// MappingModelExpressible<?> definedType = creationContext
// .getDomainModel()
// .resolveMappingExpressible(
// expression.getNodeType(),
// getFromClauseIndex()::findTableGroup
// );
// if ( definedType != null ) {
// return definedType;
// }
// definedType = creationContext
// .getDomainModel()
// .lenientlyResolveMappingExpressible(
// inferred.getNodeType(),
// getFromClauseIndex()::findTableGroup
// );
// return definedType;
// }
// );
//
// try {
// return (X) expression.accept( this );
// }
// finally {
// inferrableTypeAccessStack.pop();
// }
// }
@Override
public Object visitWithInferredType(
SqmVisitableNode node,
Supplier<MappingModelExpressible<?>> inferredTypeAccess) {
inferrableTypeAccessStack.push( inferredTypeAccess );
try {
return node.accept( this );
}
finally {
inferrableTypeAccessStack.pop();
}
}
@Override
public Object visitAny(SqmAny<?> sqmAny) {

View File

@ -7,10 +7,14 @@
package org.hibernate.query.sqm.sql;
import java.util.List;
import java.util.function.Supplier;
import org.hibernate.LockMode;
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.metamodel.mapping.MappingModelExpressible;
import org.hibernate.query.sqm.spi.BaseSemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.sql.ast.Clause;
@ -80,6 +84,23 @@ public class FakeSqmToSqlAstConverter extends BaseSemanticQueryWalker implements
public void registerQueryTransformer(QueryTransformer transformer) {
}
@Override
public MappingModelExpressible<?> resolveFunctionImpliedReturnType() {
return null;
}
@Override
public MappingModelExpressible<?> determineValueMapping(SqmExpression<?> sqmExpression) {
return null;
}
@Override
public Object visitWithInferredType(
SqmVisitableNode node,
Supplier<MappingModelExpressible<?>> inferredTypeAccess) {
return node.accept( this );
}
@Override
public List<Expression> expandSelfRenderingFunctionMultiValueParameter(SqmParameter<?> sqmParameter) {
return null;

View File

@ -7,9 +7,13 @@
package org.hibernate.query.sqm.sql;
import java.util.List;
import java.util.function.Supplier;
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.metamodel.mapping.MappingModelExpressible;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
@ -28,6 +32,19 @@ public interface SqmToSqlAstConverter extends SemanticQueryWalker<Object>, SqlAs
void registerQueryTransformer(QueryTransformer transformer);
/**
* Returns the function return type implied from the context within which it is used.
* If there is no current function being processed or no context implied type, the return is <code>null</code>.
*/
MappingModelExpressible<?> resolveFunctionImpliedReturnType();
MappingModelExpressible<?> determineValueMapping(SqmExpression<?> sqmExpression);
/**
* Visits the given node with the given inferred type access.
*/
Object visitWithInferredType(SqmVisitableNode node, Supplier<MappingModelExpressible<?>> inferredTypeAccess);
List<Expression> expandSelfRenderingFunctionMultiValueParameter(SqmParameter<?> sqmParameter);
Predicate visitNestedTopLevelPredicate(SqmPredicate predicate);

View File

@ -52,6 +52,7 @@ public enum Clause {
FETCH,
FOR_UPDATE,
OVER,
WITHIN_GROUP,
PARTITION,
CALL,

View File

@ -8,6 +8,7 @@ package org.hibernate.sql.ast;
import java.util.Set;
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.select.QueryPart;
@ -34,6 +35,8 @@ public interface SqlAstTranslator<T extends JdbcOperation> extends SqlAstWalker
*/
QueryPart getCurrentQueryPart();
Stack<Clause> getCurrentClauseStack();
/**
* Not the best spot for this. Its the table names collected while walking the SQL AST.
* Its ok here because the translator is consider a one-time-use. It just needs to be called

View File

@ -587,11 +587,13 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
return ( (ComparisonPredicate) predicate ).getLeftHandExpression();
}
protected boolean inOverClause() {
protected boolean inOverOrWithinGroupClause() {
return clauseStack.findCurrentFirst(
clause -> {
if ( clause == Clause.OVER ) {
return true;
switch ( clause ) {
case OVER:
case WITHIN_GROUP:
return true;
}
return null;
}
@ -611,6 +613,11 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
return queryPartStack.getCurrent();
}
@Override
public Stack<Clause> getCurrentClauseStack() {
return clauseStack;
}
@Override
public T translate(JdbcParameterBindings jdbcParameterBindings, QueryOptions queryOptions) {
try {
@ -2208,7 +2215,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
emulateSortSpecificationNullPrecedence( sortExpression, nullPrecedence );
}
if ( inOverClause() ) {
if ( inOverOrWithinGroupClause() ) {
resolveAliasedExpression( sortExpression ).accept( this );
}
else {

View File

@ -62,7 +62,6 @@ public class CoalesceTest extends BaseCoreFunctionalTestCase {
}
@Test
@SkipForDialect(jiraKey = "HHH-10463", value = PostgreSQLDialect.class)
public void HHH_10463_NullInCoalesce() {
doInHibernate( this::sessionFactory, session -> {
TypedQuery<Person> query = session.createQuery( "from Person p where p.name = coalesce(:name, p.name) ", Person.class );

View File

@ -54,7 +54,7 @@ public class SubqueryTest extends BaseSessionFactoryFunctionalTest {
String name,
ArgumentsValidator argumentsValidator,
FunctionReturnTypeResolver returnTypeResolver) {
super( name, argumentsValidator, returnTypeResolver );
super( name, argumentsValidator, returnTypeResolver, null );
}
@Override

View File

@ -54,7 +54,8 @@ public class OrderByFragmentFunction extends AbstractSqmFunctionDescriptor {
super(
FUNCTION_NAME,
StandardArgumentsValidators.exactly( 2 ),
StandardFunctionReturnTypeResolvers.useArgType( 1 )
StandardFunctionReturnTypeResolvers.useArgType( 1 ),
null
);
}
@Override
@ -174,9 +175,6 @@ public class OrderByFragmentFunction extends AbstractSqmFunctionDescriptor {
@Override
public Expression convertToSqlAst(SqmToSqlAstConverter walker) {
final ReturnableType<?> resultType = resolveResultType(
walker.getCreationContext().getMappingMetamodel().getTypeConfiguration()
);
final String sqmAlias = ( (SqmLiteral<String>) getArguments().get( 0 ) ).getLiteralValue();
final String attributeRole = ( (SqmLiteral<String>) getArguments().get( 1 ) ).getLiteralValue();
final TableGroup tableGroup = ( (FromClauseIndex) walker.getFromClauseAccess() ).findTableGroup(