typecheck HQL function arguments

This commit is contained in:
Gavin King 2022-01-05 16:07:37 +01:00
parent a73068cc0f
commit cc91beb536
47 changed files with 888 additions and 232 deletions

View File

@ -49,6 +49,8 @@ import java.sql.Types;
import jakarta.persistence.TemporalType; import jakarta.persistence.TemporalType;
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate; import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.INTEGER;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.STRING;
/** /**
* Dialect for Intersystems Caché SQL 2007.1 and above. * Dialect for Intersystems Caché SQL 2007.1 and above.
@ -169,7 +171,8 @@ public class CacheDialect extends Dialect {
"locate", "locate",
queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ), queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ),
"$find(?2,?1)", "$find(?2,?1)",
"$find(?2,?1,?3)" "$find(?2,?1,?3)",
STRING, STRING, INTEGER
).setArgumentListSignature("(pattern, string[, start])"); ).setArgumentListSignature("(pattern, string[, start])");
CommonFunctionFactory.bitLength_pattern( queryEngine, "($length(?1)*8)" ); CommonFunctionFactory.bitLength_pattern( queryEngine, "($length(?1)*8)" );

View File

@ -74,6 +74,8 @@ import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import jakarta.persistence.TemporalType; import jakarta.persistence.TemporalType;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.INTEGER;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.STRING;
import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_END; import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_END;
import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_START_DATE; import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_START_DATE;
import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_START_TIME; import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_START_TIME;
@ -280,7 +282,8 @@ public class FirebirdDialect extends Dialect {
"locate", "locate",
integerType, integerType,
"position(?1 in ?2)", "position(?1 in ?2)",
"position(?1,?2,?3)" "position(?1,?2,?3)",
STRING, STRING, INTEGER
).setArgumentListSignature( "(pattern, string[, start])" ); ).setArgumentListSignature( "(pattern, string[, start])" );
functionRegistry.namedDescriptorBuilder( "ascii_val" ) functionRegistry.namedDescriptorBuilder( "ascii_val" )
.setExactArgumentCount( 1 ) .setExactArgumentCount( 1 )

View File

@ -60,6 +60,8 @@ import org.hibernate.type.StandardBasicTypes;
import java.sql.Types; import java.sql.Types;
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate; import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.INTEGER;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.STRING;
/** /**
* Dialect for Informix 7.31.UD3 with Informix * Dialect for Informix 7.31.UD3 with Informix
@ -184,7 +186,8 @@ public class InformixDialect extends Dialect {
"locate", "locate",
queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ), queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ),
"instr(?2,?1)", "instr(?2,?1)",
"instr(?2,?1,?3)" "instr(?2,?1,?3)",
STRING, STRING, INTEGER
).setArgumentListSignature("(pattern, string[, start])"); ).setArgumentListSignature("(pattern, string[, start])");
//coalesce() and nullif() both supported since Informix 12 //coalesce() and nullif() both supported since Informix 12

View File

@ -61,6 +61,9 @@ import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import jakarta.persistence.TemporalType; import jakarta.persistence.TemporalType;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.INTEGER;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.STRING;
/** /**
* An SQL dialect for Ingres 9.2. * An SQL dialect for Ingres 9.2.
* <p/> * <p/>
@ -283,7 +286,8 @@ public class IngresDialect extends Dialect {
"locate", "locate",
integerType, integerType,
"position(?1 in ?2)", "position(?1 in ?2)",
"(position(?1 in substring(?2 from ?3))+(?3)-1)" "(position(?1 in substring(?2 from ?3))+(?3)-1)",
STRING, STRING, INTEGER
).setArgumentListSignature("(pattern, string[, start])"); ).setArgumentListSignature("(pattern, string[, start])");
queryEngine.getSqmFunctionRegistry().registerPattern( "extract", "date_part('?1',?2)", integerType ); queryEngine.getSqmFunctionRegistry().registerPattern( "extract", "date_part('?1',?2)", integerType );

View File

@ -38,6 +38,8 @@ import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import static org.hibernate.dialect.SimpleDatabaseVersion.ZERO_VERSION; import static org.hibernate.dialect.SimpleDatabaseVersion.ZERO_VERSION;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.INTEGER;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.STRING;
/** /**
* A SQL dialect compatible with SAP MaxDB. * A SQL dialect compatible with SAP MaxDB.
@ -164,7 +166,8 @@ public class MaxDBDialect extends Dialect {
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate", "locate",
integerType, "index(?2,?1)", "index(?2,?1,?3)" integerType, "index(?2,?1)", "index(?2,?1,?3)",
STRING, STRING, INTEGER
).setArgumentListSignature("(pattern, string[, start])"); ).setArgumentListSignature("(pattern, string[, start])");
} }

View File

@ -66,6 +66,10 @@ import static org.hibernate.query.TemporalUnit.EPOCH;
import static org.hibernate.query.TemporalUnit.MONTH; import static org.hibernate.query.TemporalUnit.MONTH;
import static org.hibernate.query.TemporalUnit.QUARTER; import static org.hibernate.query.TemporalUnit.QUARTER;
import static org.hibernate.query.TemporalUnit.YEAR; import static org.hibernate.query.TemporalUnit.YEAR;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.INTEGER;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.NUMERIC;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.STRING;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.TEMPORAL;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate; import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime; import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros; import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
@ -271,24 +275,28 @@ public class SQLiteDialect extends Dialect {
"locate", "locate",
integerType, integerType,
"instr(?2,?1)", "instr(?2,?1)",
"instr(?2,?1,?3)" "instr(?2,?1,?3)",
STRING, STRING, INTEGER
).setArgumentListSignature("(pattern, string[, start])"); ).setArgumentListSignature("(pattern, string[, start])");
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"lpad", "lpad",
stringType, stringType,
"(substr(replace(hex(zeroblob(?2)),'00',' '),1,?2-length(?1))||?1)", "(substr(replace(hex(zeroblob(?2)),'00',' '),1,?2-length(?1))||?1)",
"(substr(replace(hex(zeroblob(?2)),'00',?3),1,?2-length(?1))||?1)" "(substr(replace(hex(zeroblob(?2)),'00',?3),1,?2-length(?1))||?1)",
STRING, INTEGER, STRING
).setArgumentListSignature("(string, length[, padding])"); ).setArgumentListSignature("(string, length[, padding])");
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"rpad", "rpad",
stringType, stringType,
"(?1||substr(replace(hex(zeroblob(?2)),'00',' '),1,?2-length(?1)))", "(?1||substr(replace(hex(zeroblob(?2)),'00',' '),1,?2-length(?1)))",
"(?1||substr(replace(hex(zeroblob(?2)),'00',?3),1,?2-length(?1)))" "(?1||substr(replace(hex(zeroblob(?2)),'00',?3),1,?2-length(?1)))",
STRING, INTEGER, STRING
).setArgumentListSignature("(string, length[, padding])"); ).setArgumentListSignature("(string, length[, padding])");
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("format", "strftime") queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("format", "strftime")
.setInvariantType( stringType ) .setInvariantType( stringType )
.setExactArgumentCount( 2 ) .setExactArgumentCount( 2 )
.setParameterTypes(TEMPORAL, STRING)
.setArgumentListSignature("(datetime as pattern)") .setArgumentListSignature("(datetime as pattern)")
.register(); .register();
@ -298,12 +306,14 @@ public class SQLiteDialect extends Dialect {
"(cast(?1 as int)-(?1<cast(?1 as int)))" "(cast(?1 as int)-(?1<cast(?1 as int)))"
).setReturnTypeResolver( StandardFunctionReturnTypeResolvers.useArgType( 1 ) ) ).setReturnTypeResolver( StandardFunctionReturnTypeResolvers.useArgType( 1 ) )
.setExactArgumentCount( 1 ) .setExactArgumentCount( 1 )
.setParameterTypes(NUMERIC)
.register(); .register();
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder(
"ceiling", "ceiling",
"(cast(?1 as int)+(?1>cast(?1 as int)))" "(cast(?1 as int)+(?1>cast(?1 as int)))"
).setReturnTypeResolver( StandardFunctionReturnTypeResolvers.useArgType( 1 ) ) ).setReturnTypeResolver( StandardFunctionReturnTypeResolvers.useArgType( 1 ) )
.setExactArgumentCount( 1 ) .setExactArgumentCount( 1 )
.setParameterTypes(NUMERIC)
.register(); .register();
} }
} }

View File

@ -46,6 +46,8 @@ import java.sql.Types;
import jakarta.persistence.TemporalType; import jakarta.persistence.TemporalType;
import static org.hibernate.dialect.SimpleDatabaseVersion.ZERO_VERSION; import static org.hibernate.dialect.SimpleDatabaseVersion.ZERO_VERSION;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.INTEGER;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.STRING;
/** /**
* A SQL dialect for TimesTen 5.1. * A SQL dialect for TimesTen 5.1.
@ -169,7 +171,8 @@ public class TimesTenDialect extends Dialect {
"locate", "locate",
queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ), queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ),
"instr(?2,?1)", "instr(?2,?1)",
"instr(?2,?1,?3)" "instr(?2,?1,?3)",
STRING, STRING, INTEGER
).setArgumentListSignature("(pattern, string[, start])"); ).setArgumentListSignature("(pattern, string[, start])");
} }

View File

@ -78,6 +78,8 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import jakarta.persistence.TemporalType; import jakarta.persistence.TemporalType;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType;
/** /**
* An abstract base class for SAP HANA dialects. * An abstract base class for SAP HANA dialects.
* <p> * <p>
@ -279,7 +281,8 @@ public abstract class AbstractHANADialect extends Dialect {
"locate", "locate",
queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ), queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ),
"locate(?2,?1)", "locate(?2,?1)",
"locate(?2,?1,?3)" "locate(?2,?1,?3)",
ParameterType.STRING, ParameterType.STRING, ParameterType.INTEGER
).setArgumentListSignature("(pattern, string[, start])"); ).setArgumentListSignature("(pattern, string[, start])");
CommonFunctionFactory.ceiling_ceil( queryEngine ); CommonFunctionFactory.ceiling_ceil( queryEngine );

View File

@ -8,7 +8,6 @@ package org.hibernate.dialect;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
import org.hibernate.boot.model.TypeContributions; import org.hibernate.boot.model.TypeContributions;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory; import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.function.DB2FormatEmulation; import org.hibernate.dialect.function.DB2FormatEmulation;
import org.hibernate.dialect.identity.DB2IdentityColumnSupport; import org.hibernate.dialect.identity.DB2IdentityColumnSupport;
@ -35,6 +34,8 @@ import org.hibernate.query.sqm.mutation.internal.cte.CteInsertStrategy;
import org.hibernate.query.sqm.mutation.internal.cte.CteMutationStrategy; import org.hibernate.query.sqm.mutation.internal.cte.CteMutationStrategy;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode; import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.SqlAstTranslator;
@ -196,6 +197,7 @@ public class DB2Dialect extends Dialect {
queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
) )
.setArgumentCountBetween( 2, 4 ) .setArgumentCountBetween( 2, 4 )
.setParameterTypes(ParameterType.STRING, ParameterType.INTEGER, ParameterType.INTEGER, ParameterType.ANY)
.setArgumentListSignature( "(string, start[, length[, units]])" ) .setArgumentListSignature( "(string, start[, length[, units]])" )
.register(); .register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "substring" ) queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "substring" )
@ -203,6 +205,7 @@ public class DB2Dialect extends Dialect {
queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
) )
.setArgumentCountBetween( 2, 4 ) .setArgumentCountBetween( 2, 4 )
.setParameterTypes(ParameterType.STRING, ParameterType.INTEGER, ParameterType.INTEGER, ParameterType.ANY)
.setArgumentListSignature( "(string{ from|,} start[{ for|,} length[, units]])" ) .setArgumentListSignature( "(string{ from|,} start[{ for|,} length[, units]])" )
.register(); .register();
CommonFunctionFactory.translate( queryEngine ); CommonFunctionFactory.translate( queryEngine );
@ -238,13 +241,15 @@ public class DB2Dialect extends Dialect {
CommonFunctionFactory.dateTrunc( queryEngine ); CommonFunctionFactory.dateTrunc( queryEngine );
CommonFunctionFactory.bitLength_pattern( queryEngine, "length(?1)*8" ); CommonFunctionFactory.bitLength_pattern( queryEngine, "length(?1)*8" );
queryEngine.getSqmFunctionRegistry().register( "format", new DB2FormatEmulation( queryEngine.getTypeConfiguration() ) ); queryEngine.getSqmFunctionRegistry().register( "format",
new DB2FormatEmulation( queryEngine.getTypeConfiguration() ) );
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "posstr" ) queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "posstr" )
.setInvariantType( .setInvariantType(
queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ) queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER )
) )
.setExactArgumentCount( 2 ) .setExactArgumentCount( 2 )
.setParameterTypes(ParameterType.STRING, ParameterType.STRING)
.setArgumentListSignature("(string, pattern)") .setArgumentListSignature("(string, pattern)")
.register(); .register();
} }

View File

@ -574,80 +574,6 @@ public abstract class Dialect implements ConversionContext {
: size; : size;
} }
/**
* Does the given JDBC type code represent some sort of
* numeric type?
* @param sqlType a JDBC type code from {@link Types}
*/
private static boolean isNumericType(int sqlType) {
switch (sqlType) {
case Types.BIT:
case Types.SMALLINT:
case Types.TINYINT:
case Types.INTEGER:
case Types.BIGINT:
case Types.DOUBLE:
case Types.REAL:
case Types.FLOAT:
case Types.NUMERIC:
case Types.DECIMAL:
return true;
default:
return false;
}
}
/**
* Does the given JDBC type code represent some sort of
* character string type?
* @param sqlType a JDBC type code from {@link Types}
*/
private static boolean isCharacterType(int sqlType) {
switch (sqlType) {
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR:
case Types.NCHAR:
case Types.NVARCHAR:
case Types.LONGNVARCHAR:
return true;
default:
return false;
}
}
/**
* Does the given JDBC type code represent some sort of
* variable-length character string type?
* @param sqlType a JDBC type code from {@link Types}
*/
private static boolean isVarcharType(int sqlType) {
switch (sqlType) {
case Types.VARCHAR:
case Types.LONGVARCHAR:
case Types.NVARCHAR:
case Types.LONGNVARCHAR:
return true;
default:
return false;
}
}
/**
* Does the given JDBC type code represent some sort of
* variable-length binary string type?
* @param sqlType a JDBC type code from {@link Types}
*/
private static boolean isVarbinaryType(int sqlType) {
switch (sqlType) {
case Types.VARBINARY:
case Types.LONGVARBINARY:
return true;
default:
return false;
}
}
/** /**
* Render a SQL check condition for a column that represents a boolean value. * Render a SQL check condition for a column that represents a boolean value.
*/ */
@ -1305,24 +1231,6 @@ public abstract class Dialect implements ConversionContext {
|| isVarbinaryType(typeCode1) && isVarbinaryType(typeCode2); || isVarbinaryType(typeCode1) && isVarbinaryType(typeCode2);
} }
private static boolean isNumericOrDecimal(int typeCode) {
return typeCode == Types.NUMERIC
|| typeCode == Types.DECIMAL;
}
private static boolean isFloatOrRealOrDouble(int typeCode) {
return typeCode == Types.FLOAT
|| typeCode == Types.REAL
|| typeCode == Types.DOUBLE;
}
private static boolean isIntegral(int typeCode) {
return typeCode == Types.INTEGER
|| typeCode == Types.BIGINT
|| typeCode == Types.SMALLINT
|| typeCode == Types.TINYINT;
}
/** /**
* Retrieve a set of default Hibernate properties for this database. * Retrieve a set of default Hibernate properties for this database.
* *

View File

@ -20,6 +20,8 @@ import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.ANY;
/** /**
* An SQL dialect for the SAP HANA column store. * An SQL dialect for the SAP HANA column store.
* <p> * <p>
@ -112,7 +114,8 @@ public class HANAColumnStoreDialect extends AbstractHANADialect {
"contains", "contains",
queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.BOOLEAN ), queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.BOOLEAN ),
"contains(?1,?2)", "contains(?1,?2)",
"contains(?1,?2,?3)" "contains(?1,?2,?3)",
ANY, ANY, ANY
); );
} }

View File

@ -87,6 +87,7 @@ import static org.hibernate.query.TemporalUnit.MINUTE;
import static org.hibernate.query.TemporalUnit.MONTH; import static org.hibernate.query.TemporalUnit.MONTH;
import static org.hibernate.query.TemporalUnit.SECOND; import static org.hibernate.query.TemporalUnit.SECOND;
import static org.hibernate.query.TemporalUnit.YEAR; import static org.hibernate.query.TemporalUnit.YEAR;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType;
import static org.hibernate.type.SqlTypes.*; import static org.hibernate.type.SqlTypes.*;
/** /**
@ -180,7 +181,8 @@ public class OracleDialect extends Dialect {
"locate", "locate",
queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ), queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ),
"instr(?2,?1)", "instr(?2,?1)",
"instr(?2,?1,?3)" "instr(?2,?1,?3)",
ParameterType.STRING, ParameterType.STRING, ParameterType.INTEGER
).setArgumentListSignature("(pattern, string[, start])"); ).setArgumentListSignature("(pattern, string[, start])");
} }

View File

@ -84,6 +84,7 @@ import static org.hibernate.query.TemporalUnit.EPOCH;
import static org.hibernate.query.TemporalUnit.MONTH; import static org.hibernate.query.TemporalUnit.MONTH;
import static org.hibernate.query.TemporalUnit.QUARTER; import static org.hibernate.query.TemporalUnit.QUARTER;
import static org.hibernate.query.TemporalUnit.YEAR; import static org.hibernate.query.TemporalUnit.YEAR;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType;
import static org.hibernate.type.SqlTypes.*; import static org.hibernate.type.SqlTypes.*;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate; import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime; import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
@ -451,7 +452,8 @@ public class PostgreSQLDialect extends Dialect {
"locate", "locate",
queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ), queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ),
"position(?1 in ?2)", "position(?1 in ?2)",
"(position(?1 in substring(?2 from ?3))+(?3)-1)" "(position(?1 in substring(?2 from ?3))+(?3)-1)",
ParameterType.STRING, ParameterType.STRING, ParameterType.INTEGER
).setArgumentListSignature("(pattern, string[, start])"); ).setArgumentListSignature("(pattern, string[, start])");
if ( getVersion().isSameOrAfter( 9, 4 ) ) { if ( getVersion().isSameOrAfter( 9, 4 ) ) {

View File

@ -68,6 +68,7 @@ import java.util.TimeZone;
import jakarta.persistence.TemporalType; import jakarta.persistence.TemporalType;
import static org.hibernate.query.TemporalUnit.NANOSECOND; import static org.hibernate.query.TemporalUnit.NANOSECOND;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.INTEGER;
import static org.hibernate.type.SqlTypes.*; import static org.hibernate.type.SqlTypes.*;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate; import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime; import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
@ -236,26 +237,32 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datefromparts" ) queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datefromparts" )
.setInvariantType( dateType ) .setInvariantType( dateType )
.setExactArgumentCount( 3 ) .setExactArgumentCount( 3 )
.setParameterTypes(INTEGER)
.register(); .register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "timefromparts" ) queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "timefromparts" )
.setInvariantType( timeType ) .setInvariantType( timeType )
.setExactArgumentCount( 5 ) .setExactArgumentCount( 5 )
.setParameterTypes(INTEGER)
.register(); .register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "smalldatetimefromparts" ) queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "smalldatetimefromparts" )
.setInvariantType( timestampType ) .setInvariantType( timestampType )
.setExactArgumentCount( 5 ) .setExactArgumentCount( 5 )
.setParameterTypes(INTEGER)
.register(); .register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datetimefromparts" ) queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datetimefromparts" )
.setInvariantType( timestampType ) .setInvariantType( timestampType )
.setExactArgumentCount( 7 ) .setExactArgumentCount( 7 )
.setParameterTypes(INTEGER)
.register(); .register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datetime2fromparts" ) queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datetime2fromparts" )
.setInvariantType( timestampType ) .setInvariantType( timestampType )
.setExactArgumentCount( 8 ) .setExactArgumentCount( 8 )
.setParameterTypes(INTEGER)
.register(); .register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datetimeoffsetfromparts" ) queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datetimeoffsetfromparts" )
.setInvariantType( timestampType ) .setInvariantType( timestampType )
.setExactArgumentCount( 10 ) .setExactArgumentCount( 10 )
.setParameterTypes(INTEGER)
.register(); .register();
} }
} }

View File

@ -14,6 +14,7 @@ import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.query.CastType; import org.hibernate.query.CastType;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.function.FunctionKind; 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.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer; import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
@ -27,6 +28,8 @@ import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.NUMERIC;
/** /**
* @author Christian Beikov * @author Christian Beikov
*/ */
@ -45,7 +48,7 @@ public class AvgFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
super( super(
FUNCTION_NAME, FUNCTION_NAME,
FunctionKind.AGGREGATE, FunctionKind.AGGREGATE,
StandardArgumentsValidators.exactly( 1 ), new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 1 ), NUMERIC ),
StandardFunctionReturnTypeResolvers.invariant( StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE )
) )

View File

@ -14,6 +14,8 @@ import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.query.CastType; import org.hibernate.query.CastType;
import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
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.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer; import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
@ -26,6 +28,8 @@ import org.hibernate.type.SqlTypes;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.STRING;
public class CastingConcatFunction extends AbstractSqmSelfRenderingFunctionDescriptor { public class CastingConcatFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
private final Dialect dialect; private final Dialect dialect;
@ -40,7 +44,7 @@ public class CastingConcatFunction extends AbstractSqmSelfRenderingFunctionDescr
TypeConfiguration typeConfiguration) { TypeConfiguration typeConfiguration) {
super( super(
"concat", "concat",
StandardArgumentsValidators.min( 1 ), new ArgumentTypesValidator( StandardArgumentsValidators.min( 1 ), STRING ),
StandardFunctionReturnTypeResolvers.invariant( StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
) )

View File

@ -24,7 +24,7 @@ public class CurrentFunction
private final String sql; private final String sql;
public CurrentFunction(String name, String sql, BasicType type) { public CurrentFunction(String name, String sql, BasicType<?> type) {
super( super(
name, name,
StandardArgumentsValidators.NO_ARGS, StandardArgumentsValidators.NO_ARGS,

View File

@ -7,8 +7,9 @@
package org.hibernate.dialect.function; package org.hibernate.dialect.function;
import org.hibernate.dialect.OracleDialect; import org.hibernate.dialect.OracleDialect;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
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.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.SqlAstTranslator;
@ -22,6 +23,9 @@ import org.hibernate.type.spi.TypeConfiguration;
import java.util.List; import java.util.List;
import jakarta.persistence.TemporalType; import jakarta.persistence.TemporalType;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.STRING;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.TEMPORAL;
/** /**
* DB2's varchar_format() can't handle quoted literal strings in * DB2's varchar_format() can't handle quoted literal strings in
* the format pattern. So just split the pattern into bits, call * the format pattern. So just split the pattern into bits, call
@ -36,7 +40,7 @@ public class DB2FormatEmulation
public DB2FormatEmulation(TypeConfiguration typeConfiguration) { public DB2FormatEmulation(TypeConfiguration typeConfiguration) {
super( super(
"format", "format",
StandardArgumentsValidators.exactly( 2 ), new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 2 ), TEMPORAL, STRING ),
StandardFunctionReturnTypeResolvers.invariant( StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
) )

View File

@ -10,6 +10,8 @@ import java.util.List;
import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
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.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode; import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
@ -19,6 +21,9 @@ import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.INTEGER;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.STRING;
/** /**
* A derby implementation for lpad. * A derby implementation for lpad.
* *
@ -30,7 +35,7 @@ public class DerbyLpadEmulation
public DerbyLpadEmulation(TypeConfiguration typeConfiguration) { public DerbyLpadEmulation(TypeConfiguration typeConfiguration) {
super( super(
"lpad", "lpad",
StandardArgumentsValidators.exactly( 2 ), new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 2 ), STRING, INTEGER ),
StandardFunctionReturnTypeResolvers.invariant( StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
) )

View File

@ -10,6 +10,7 @@ import java.util.List;
import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; 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.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode; import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
@ -19,6 +20,9 @@ import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.INTEGER;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.STRING;
/** /**
* A derby implementation for rpad. * A derby implementation for rpad.
* *
@ -30,7 +34,7 @@ public class DerbyRpadEmulation
public DerbyRpadEmulation(TypeConfiguration typeConfiguration) { public DerbyRpadEmulation(TypeConfiguration typeConfiguration) {
super( super(
"rpad", "rpad",
StandardArgumentsValidators.exactly( 2 ), new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 2 ), STRING, INTEGER ),
StandardFunctionReturnTypeResolvers.invariant( StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
) )

View File

@ -8,16 +8,11 @@ package org.hibernate.dialect.function;
import java.util.List; import java.util.List;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.function.FunctionKind; import org.hibernate.query.sqm.function.FunctionKind;
import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.SqlAstNode;
@ -25,6 +20,8 @@ import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.BOOLEAN;
/** /**
* @author Jan Schatteman * @author Jan Schatteman
*/ */
@ -36,7 +33,7 @@ public class EveryAnyEmulation extends AbstractSqmSelfRenderingFunctionDescripto
super( super(
every ? "every" : "any", every ? "every" : "any",
FunctionKind.AGGREGATE, FunctionKind.AGGREGATE,
StandardArgumentsValidators.exactly( 1 ), new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 1 ), BOOLEAN ),
StandardFunctionReturnTypeResolvers.invariant( StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.BOOLEAN ) typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.BOOLEAN )
) )

View File

@ -14,6 +14,8 @@ import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor; import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; import org.hibernate.query.sqm.function.SelfRenderingSqmFunction;
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.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode; import org.hibernate.query.sqm.tree.SqmTypedNode;
@ -27,6 +29,8 @@ import java.util.List;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static org.hibernate.query.BinaryArithmeticOperator.*; import static org.hibernate.query.BinaryArithmeticOperator.*;
import static org.hibernate.query.TemporalUnit.*; import static org.hibernate.query.TemporalUnit.*;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.ANY;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.TEMPORAL;
import static org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers.useArgType; import static org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers.useArgType;
/** /**
@ -40,7 +44,10 @@ public class ExtractFunction
public ExtractFunction(Dialect dialect) { public ExtractFunction(Dialect dialect) {
super( super(
"extract", "extract",
StandardArgumentsValidators.exactly( 2 ), new ArgumentTypesValidator(
StandardArgumentsValidators.exactly( 2 ),
ANY, TEMPORAL
),
StandardFunctionReturnTypeResolvers.useArgType( 1 ) StandardFunctionReturnTypeResolvers.useArgType( 1 )
); );
this.dialect = dialect; this.dialect = dialect;

View File

@ -10,10 +10,10 @@ import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.BinaryArithmeticOperator; import org.hibernate.query.BinaryArithmeticOperator;
import org.hibernate.query.ComparisonOperator; import org.hibernate.query.ComparisonOperator;
import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor; import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; import org.hibernate.query.sqm.function.SelfRenderingSqmFunction;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor; 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.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode; import org.hibernate.query.sqm.tree.SqmTypedNode;
@ -31,6 +31,8 @@ import java.util.List;
import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Expression;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.INTEGER;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.STRING;
/** /**
* @author Gavin King * @author Gavin King
@ -43,7 +45,10 @@ public class InsertSubstringOverlayEmulation
public InsertSubstringOverlayEmulation(TypeConfiguration typeConfiguration, boolean strictSubstring) { public InsertSubstringOverlayEmulation(TypeConfiguration typeConfiguration, boolean strictSubstring) {
super( super(
"overlay", "overlay",
StandardArgumentsValidators.between( 3, 4 ), new ArgumentTypesValidator(
StandardArgumentsValidators.between( 3, 4 ),
STRING, INTEGER, INTEGER, STRING
),
StandardFunctionReturnTypeResolvers.invariant( StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
) )

View File

@ -11,6 +11,7 @@ import org.hibernate.query.TrimSpec;
import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor; import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; 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.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode; import org.hibernate.query.sqm.tree.SqmTypedNode;
@ -21,6 +22,9 @@ import org.hibernate.type.spi.TypeConfiguration;
import java.util.List; import java.util.List;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.ANY;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.INTEGER;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.STRING;
/** /**
* @author Gavin King * @author Gavin King
@ -31,7 +35,10 @@ public class LpadRpadPadEmulation
public LpadRpadPadEmulation(TypeConfiguration typeConfiguration) { public LpadRpadPadEmulation(TypeConfiguration typeConfiguration) {
super( super(
"pad", "pad",
StandardArgumentsValidators.between( 3, 4 ), new ArgumentTypesValidator(
StandardArgumentsValidators.between( 3, 4 ),
STRING, INTEGER, ANY, STRING
),
StandardFunctionReturnTypeResolvers.invariant( StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
) )

View File

@ -10,6 +10,7 @@ import java.util.List;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.function.FunctionKind; 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.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.SqlAstTranslator;
@ -19,6 +20,8 @@ import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.BOOLEAN;
/** /**
* @author Jan Schatteman * @author Jan Schatteman
*/ */
@ -30,7 +33,7 @@ public class SQLServerEveryAnyEmulation extends AbstractSqmSelfRenderingFunction
super( super(
every ? "every" : "any", every ? "every" : "any",
FunctionKind.AGGREGATE, FunctionKind.AGGREGATE,
StandardArgumentsValidators.exactly( 1 ), new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 1 ), BOOLEAN ),
StandardFunctionReturnTypeResolvers.invariant( StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.BOOLEAN ) typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.BOOLEAN )
) )

View File

@ -46,7 +46,12 @@ public class TransactSQLStrFunction extends CastStrEmulation implements Function
QueryEngine queryEngine, QueryEngine queryEngine,
TypeConfiguration typeConfiguration) { TypeConfiguration typeConfiguration) {
if ( arguments.size() == 1 ) { if ( arguments.size() == 1 ) {
return super.generateSqmFunctionExpression( arguments, impliedResultType, queryEngine, typeConfiguration ); return super.generateSqmFunctionExpression(
arguments,
impliedResultType,
queryEngine,
typeConfiguration
);
} }
return new SelfRenderingSqmFunction<>( return new SelfRenderingSqmFunction<>(
@ -54,6 +59,7 @@ public class TransactSQLStrFunction extends CastStrEmulation implements Function
this, this,
arguments, arguments,
impliedResultType, impliedResultType,
getArgumentsValidator(),
getReturnTypeResolver(), getReturnTypeResolver(),
queryEngine.getCriteriaBuilder(), queryEngine.getCriteriaBuilder(),
getName() getName()

View File

@ -8,8 +8,8 @@ package org.hibernate.dialect.function;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.query.TrimSpec; import org.hibernate.query.TrimSpec;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; 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.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer; import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
@ -25,6 +25,9 @@ import org.hibernate.type.spi.TypeConfiguration;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.ANY;
import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.STRING;
/** /**
* @author Gavin King * @author Gavin King
*/ */
@ -35,7 +38,10 @@ public class TrimFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
public TrimFunction(Dialect dialect, TypeConfiguration typeConfiguration) { public TrimFunction(Dialect dialect, TypeConfiguration typeConfiguration) {
super( super(
"trim", "trim",
StandardArgumentsValidators.exactly( 3 ), new ArgumentTypesValidator(
StandardArgumentsValidators.exactly( 3 ),
ANY, STRING, STRING
),
StandardFunctionReturnTypeResolvers.invariant( StandardFunctionReturnTypeResolvers.invariant(
typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING )
) )

View File

@ -65,6 +65,11 @@ public abstract class AbstractSqmFunctionDescriptor implements SqmFunctionDescri
return getReturnSignature() + name + getArgumentListSignature(); return getReturnSignature() + name + getArgumentListSignature();
} }
@Override
public ArgumentsValidator getArgumentsValidator() {
return argumentsValidator;
}
public String getReturnSignature() { public String getReturnSignature() {
String result = returnTypeResolver.getReturnType(); String result = returnTypeResolver.getReturnType();
return result.isEmpty() ? "" : result + " "; return result.isEmpty() ? "" : result + " ";
@ -98,7 +103,7 @@ public abstract class AbstractSqmFunctionDescriptor implements SqmFunctionDescri
AllowableFunctionReturnType<T> impliedResultType, AllowableFunctionReturnType<T> impliedResultType,
QueryEngine queryEngine, QueryEngine queryEngine,
TypeConfiguration typeConfiguration) { TypeConfiguration typeConfiguration) {
argumentsValidator.validate( arguments ); argumentsValidator.validate( arguments, getName() );
return generateSqmFunctionExpression( return generateSqmFunctionExpression(
arguments, arguments,
@ -115,7 +120,7 @@ public abstract class AbstractSqmFunctionDescriptor implements SqmFunctionDescri
AllowableFunctionReturnType<T> impliedResultType, AllowableFunctionReturnType<T> impliedResultType,
QueryEngine queryEngine, QueryEngine queryEngine,
TypeConfiguration typeConfiguration) { TypeConfiguration typeConfiguration) {
argumentsValidator.validate( arguments ); argumentsValidator.validate( arguments, getName() );
return generateSqmAggregateFunctionExpression( return generateSqmAggregateFunctionExpression(
arguments, arguments,
@ -130,8 +135,7 @@ public abstract class AbstractSqmFunctionDescriptor implements SqmFunctionDescri
* Return an SQM node or subtree representing an invocation of this function * Return an SQM node or subtree representing an invocation of this function
* with the given arguments. This method may be overridden in the case of * with the given arguments. This method may be overridden in the case of
* function descriptors that wish to customize creation of the node. * function descriptors that wish to customize creation of the node.
* * @param arguments the arguments of the function invocation
* @param arguments the arguments of the function invocation
* @param impliedResultType the function return type as inferred from its usage * @param impliedResultType the function return type as inferred from its usage
*/ */
protected abstract <T> SelfRenderingSqmFunction<T> generateSqmFunctionExpression( protected abstract <T> SelfRenderingSqmFunction<T> generateSqmFunctionExpression(

View File

@ -64,6 +64,7 @@ public abstract class AbstractSqmSelfRenderingFunctionDescriptor
this::render, this::render,
arguments, arguments,
impliedResultType, impliedResultType,
getArgumentsValidator(),
getReturnTypeResolver(), getReturnTypeResolver(),
queryEngine.getCriteriaBuilder(), queryEngine.getCriteriaBuilder(),
getName() getName()
@ -86,6 +87,7 @@ public abstract class AbstractSqmSelfRenderingFunctionDescriptor
arguments, arguments,
filter, filter,
impliedResultType, impliedResultType,
getArgumentsValidator(),
getReturnTypeResolver(), getReturnTypeResolver(),
queryEngine.getCriteriaBuilder(), queryEngine.getCriteriaBuilder(),
getName() getName()

View File

@ -55,6 +55,7 @@ public class JdbcEscapeFunctionDescriptor
}, },
arguments, arguments,
impliedResultType, impliedResultType,
getArgumentsValidator(),
getReturnTypeResolver(), getReturnTypeResolver(),
queryEngine.getCriteriaBuilder(), queryEngine.getCriteriaBuilder(),
getName()); getName());

View File

@ -8,9 +8,12 @@ package org.hibernate.query.sqm.function;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode; import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.type.BasicType;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import java.util.List; import java.util.List;
@ -48,21 +51,25 @@ public class MultipatternSqmFunctionDescriptor extends AbstractSqmFunctionDescri
* template. The array must be padded with leading nulls * template. The array must be padded with leading nulls
* where there is no overloaded form corresponding to * where there is no overloaded form corresponding to
* lower arities. * lower arities.
* * @param name
* @param name
* @param functions the function templates to delegate to, * @param functions the function templates to delegate to,
* where array position corresponds to * @param type
*/ */
public MultipatternSqmFunctionDescriptor( public MultipatternSqmFunctionDescriptor(
String name, SqmFunctionDescriptor[] functions, String name,
FunctionReturnTypeResolver type) { SqmFunctionDescriptor[] functions,
BasicType<?> type,
ParameterType... parameterTypes) {
super( super(
name, name,
StandardArgumentsValidators.between( new ArgumentTypesValidator(
first(functions), StandardArgumentsValidators.between(
last(functions) first(functions),
last(functions)
),
parameterTypes
), ),
type StandardFunctionReturnTypeResolvers.invariant( type )
); );
this.functions = functions; this.functions = functions;
} }

View File

@ -21,6 +21,7 @@ import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.SemanticException; import org.hibernate.query.SemanticException;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer; import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver; import org.hibernate.sql.ast.spi.SqlExpressionResolver;
@ -188,8 +189,7 @@ public class SelfRenderingFunctionSqlAstExpression
} }
@Override @Override
public int forEachJdbcType( public int forEachJdbcType(int offset, IndexedConsumer<JdbcMapping> action) {
int offset, IndexedConsumer<JdbcMapping> action) {
throw new NotYetImplementedFor6Exception( getClass() ); throw new NotYetImplementedFor6Exception( getClass() );
} }
} }

View File

@ -10,6 +10,7 @@ import java.util.List;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter; import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
@ -34,10 +35,11 @@ public class SelfRenderingSqmAggregateFunction<T> extends SelfRenderingSqmFuncti
List<? extends SqmTypedNode<?>> arguments, List<? extends SqmTypedNode<?>> arguments,
SqmPredicate filter, SqmPredicate filter,
AllowableFunctionReturnType<T> impliedResultType, AllowableFunctionReturnType<T> impliedResultType,
ArgumentsValidator argumentsValidator,
FunctionReturnTypeResolver returnTypeResolver, FunctionReturnTypeResolver returnTypeResolver,
NodeBuilder nodeBuilder, NodeBuilder nodeBuilder,
String name) { String name) {
super( descriptor, renderingSupport, arguments, impliedResultType, returnTypeResolver, nodeBuilder, name ); super( descriptor, renderingSupport, arguments, impliedResultType, argumentsValidator, returnTypeResolver, nodeBuilder, name );
this.filter = filter; this.filter = filter;
} }

View File

@ -11,16 +11,19 @@ import java.util.List;
import org.hibernate.metamodel.MappingMetamodel; import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.BasicValuedMapping; import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmExpressable; import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmTypedNode; import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode; import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.query.sqm.tree.expression.SqmFunction; import org.hibernate.query.sqm.tree.expression.SqmFunction;
import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
@ -30,6 +33,7 @@ import static java.util.Collections.emptyList;
*/ */
public class SelfRenderingSqmFunction<T> extends SqmFunction<T> { public class SelfRenderingSqmFunction<T> extends SqmFunction<T> {
private final AllowableFunctionReturnType<T> impliedResultType; private final AllowableFunctionReturnType<T> impliedResultType;
private final ArgumentsValidator argumentsValidator;
private final FunctionReturnTypeResolver returnTypeResolver; private final FunctionReturnTypeResolver returnTypeResolver;
private final FunctionRenderingSupport renderingSupport; private final FunctionRenderingSupport renderingSupport;
private AllowableFunctionReturnType<?> resultType; private AllowableFunctionReturnType<?> resultType;
@ -39,12 +43,14 @@ public class SelfRenderingSqmFunction<T> extends SqmFunction<T> {
FunctionRenderingSupport renderingSupport, FunctionRenderingSupport renderingSupport,
List<? extends SqmTypedNode<?>> arguments, List<? extends SqmTypedNode<?>> arguments,
AllowableFunctionReturnType<T> impliedResultType, AllowableFunctionReturnType<T> impliedResultType,
ArgumentsValidator argumentsValidator,
FunctionReturnTypeResolver returnTypeResolver, FunctionReturnTypeResolver returnTypeResolver,
NodeBuilder nodeBuilder, NodeBuilder nodeBuilder,
String name) { String name) {
super( name, descriptor, impliedResultType, arguments, nodeBuilder ); super( name, descriptor, impliedResultType, arguments, nodeBuilder );
this.renderingSupport = renderingSupport; this.renderingSupport = renderingSupport;
this.impliedResultType = impliedResultType; this.impliedResultType = impliedResultType;
this.argumentsValidator = argumentsValidator;
this.returnTypeResolver = returnTypeResolver; this.returnTypeResolver = returnTypeResolver;
} }
@ -70,10 +76,14 @@ public class SelfRenderingSqmFunction<T> extends SqmFunction<T> {
walker.getCreationContext().getDomainModel().getTypeConfiguration() walker.getCreationContext().getDomainModel().getTypeConfiguration()
); );
List<SqlAstNode> arguments = resolveSqlAstArguments( getArguments(), walker );
if ( argumentsValidator != null ) {
argumentsValidator.validateSqlTypes( arguments, getFunctionName() );
}
return new SelfRenderingFunctionSqlAstExpression( return new SelfRenderingFunctionSqlAstExpression(
getFunctionName(), getFunctionName(),
getRenderingSupport(), getRenderingSupport(),
resolveSqlAstArguments( getArguments(), walker ), arguments,
resultType, resultType,
resultType == null ? null : getMappingModelExpressable( walker, resultType ) resultType == null ? null : getMappingModelExpressable( walker, resultType )
); );

View File

@ -8,6 +8,7 @@ package org.hibernate.query.sqm.function;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.tree.SqmTypedNode; import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
@ -122,4 +123,6 @@ public interface SqmFunctionDescriptor {
default FunctionKind getFunctionKind() { default FunctionKind getFunctionKind() {
return FunctionKind.NORMAL; return FunctionKind.NORMAL;
} }
ArgumentsValidator getArgumentsValidator();
} }

View File

@ -11,9 +11,9 @@ import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType;
import org.hibernate.query.sqm.produce.function.NamedFunctionDescriptorBuilder; import org.hibernate.query.sqm.produce.function.NamedFunctionDescriptorBuilder;
import org.hibernate.query.sqm.produce.function.PatternFunctionDescriptorBuilder; import org.hibernate.query.sqm.produce.function.PatternFunctionDescriptorBuilder;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
@ -254,8 +254,9 @@ public class SqmFunctionRegistry {
String name, String name,
BasicType type, BasicType type,
String pattern0, String pattern0,
String pattern1) { String pattern1,
return registerPatterns( name, type, pattern0, pattern1 ); ParameterType parameterType) {
return registerPatterns( name, type, new ParameterType[]{parameterType}, pattern0, pattern1 );
} }
/** /**
@ -265,10 +266,14 @@ public class SqmFunctionRegistry {
*/ */
public MultipatternSqmFunctionDescriptor registerUnaryBinaryPattern( public MultipatternSqmFunctionDescriptor registerUnaryBinaryPattern(
String name, String name,
BasicType type, BasicType<?> type,
String pattern1, String pattern1,
String pattern2) { String pattern2,
return registerPatterns( name, type, null, pattern1, pattern2 ); ParameterType parameterType1,
ParameterType parameterType2) {
return registerPatterns( name, type,
new ParameterType[]{parameterType1,parameterType2},
null, pattern1, pattern2 );
} }
/** /**
@ -278,10 +283,15 @@ public class SqmFunctionRegistry {
*/ */
public MultipatternSqmFunctionDescriptor registerBinaryTernaryPattern( public MultipatternSqmFunctionDescriptor registerBinaryTernaryPattern(
String name, String name,
BasicType type, BasicType<?> type,
String pattern2, String pattern2,
String pattern3) { String pattern3,
return registerPatterns( name, type, null, null, pattern2, pattern3 ); ParameterType parameterType1,
ParameterType parameterType2,
ParameterType parameterType3) {
return registerPatterns( name, type,
new ParameterType[]{parameterType1,parameterType2,parameterType3},
null, null, pattern2, pattern3 );
} }
/** /**
@ -291,15 +301,22 @@ public class SqmFunctionRegistry {
*/ */
public MultipatternSqmFunctionDescriptor registerTernaryQuaternaryPattern( public MultipatternSqmFunctionDescriptor registerTernaryQuaternaryPattern(
String name, String name,
BasicType type, BasicType<?> type,
String pattern3, String pattern3,
String pattern4) { String pattern4,
return registerPatterns( name, type, null, null, null, pattern3, pattern4 ); ParameterType parameterType1,
ParameterType parameterType2,
ParameterType parameterType3,
ParameterType parameterType4) {
return registerPatterns( name, type,
new ParameterType[]{parameterType1,parameterType2,parameterType3, parameterType4},
null, null, null, pattern3, pattern4 );
} }
private MultipatternSqmFunctionDescriptor registerPatterns( private MultipatternSqmFunctionDescriptor registerPatterns(
String name, String name,
BasicType type, BasicType<?> type,
ParameterType[] parameterTypes,
String... patterns) { String... patterns) {
SqmFunctionDescriptor[] descriptors = SqmFunctionDescriptor[] descriptors =
new SqmFunctionDescriptor[patterns.length]; new SqmFunctionDescriptor[patterns.length];
@ -309,15 +326,14 @@ public class SqmFunctionRegistry {
descriptors[i] = descriptors[i] =
patternDescriptorBuilder( name, pattern ) patternDescriptorBuilder( name, pattern )
.setExactArgumentCount( i ) .setExactArgumentCount( i )
.setParameterTypes( parameterTypes )
.setInvariantType( type ) .setInvariantType( type )
.descriptor(); .descriptor();
} }
} }
MultipatternSqmFunctionDescriptor function = new MultipatternSqmFunctionDescriptor( MultipatternSqmFunctionDescriptor function =
name, descriptors, new MultipatternSqmFunctionDescriptor( name, descriptors, type, parameterTypes );
StandardFunctionReturnTypeResolvers.invariant( type )
);
register( name, function ); register( name, function );
return function; return function;
} }

View File

@ -0,0 +1,134 @@
/*
* 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.QueryException;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.sql.ast.spi.AbstractSqlAstWalker;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import java.lang.reflect.Type;
import java.util.List;
import static org.hibernate.type.SqlTypes.*;
/**
* Typechecks the arguments of HQL functions based on the assigned JDBC types.
*/
public class ArgumentTypesValidator implements ArgumentsValidator {
final ArgumentsValidator delegate;
private final ParameterType[] types;
public ArgumentTypesValidator(ArgumentsValidator delegate, ParameterType... types) {
this.types = types;
if (types.length==0) {
System.out.println();
}
if (delegate == null ) {
delegate = StandardArgumentsValidators.exactly(types.length);
}
this.delegate = delegate;
}
@Override
public void validate(List<? extends SqmTypedNode<?>> arguments, String functionName) {
delegate.validate(arguments, functionName);
}
@Override
public void validateSqlTypes(List<? extends SqlAstNode> arguments, String functionName) {
int count = 0;
for (int i = 0; i < arguments.size(); i++ ) {
SqlAstNode argument = arguments.get(i);
if (argument instanceof Expression) {
JdbcMappingContainer expressionType = ((Expression) argument).getExpressionType();
if ( expressionType != null ) {
ParameterDetector detector = new ParameterDetector();
argument.accept(detector);
if ( detector.detected ) {
count += expressionType.getJdbcTypeCount();
}
else {
count = validateArgument(count, expressionType, functionName);
}
}
}
}
}
private int validateArgument(int count, JdbcMappingContainer expressionType, String functionName) {
List<JdbcMapping> mappings = expressionType.getJdbcMappings();
for (JdbcMapping mapping : mappings) {
ParameterType type = count < types.length ? types[count++] : types[types.length - 1];
if (type != null) {
int code = mapping.getJdbcTypeDescriptor().getJdbcTypeCode();
Type javaType = mapping.getJavaTypeDescriptor().getJavaType();
switch (type) {
case STRING:
if (!isCharacterType(code)) {
throwError(type, javaType, functionName, count);
}
break;
case NUMERIC:
if (!isNumericType(code)) {
throwError(type, javaType, functionName, count);
}
break;
case INTEGER:
if (!isIntegral(code)) {
throwError(type, javaType, functionName, count);
}
break;
case BOOLEAN:
if (code != BOOLEAN && code != BIT) {
throwError(type, javaType, functionName, count);
}
case TEMPORAL:
if (!isTemporalType(code)) {
throwError(type, javaType, functionName, count);
}
break;
case DATE:
if (!hasDatePart(code)) {
throwError(type, javaType, functionName, count);
}
break;
case TIME:
if (!hasTimePart(code)) {
throwError(type, javaType, functionName, count);
}
break;
}
}
}
return count;
}
private void throwError(ParameterType type, Type javaType, String functionName, int count) {
throw new QueryException(
String.format(
"Parameter %d of function %s() has type %s, but argument is of type %s",
count,
functionName,
type,
javaType.getTypeName()
)
);
}
private static class ParameterDetector extends AbstractSqlAstWalker {
private boolean detected;
@Override
public void visitParameter(JdbcParameter jdbcParameter) {
detected = true;
}
}
}

View File

@ -7,6 +7,7 @@
package org.hibernate.query.sqm.produce.function; package org.hibernate.query.sqm.produce.function;
import org.hibernate.query.sqm.tree.SqmTypedNode; import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.sql.ast.tree.SqlAstNode;
import java.util.List; import java.util.List;
@ -15,12 +16,62 @@ import java.util.List;
*/ */
public interface ArgumentsValidator { public interface ArgumentsValidator {
/** /**
* The main (functional) operation defining validation * Perform validation that may be done using the {@link SqmTypedNode}
* tree and assigned Java types.
*/ */
void validate(List<? extends SqmTypedNode<?>> arguments); void validate(List<? extends SqmTypedNode<?>> arguments, String functionName);
default String getSignature() { default String getSignature() {
return "( ... )"; return "( ... )";
} }
/**
* Perform validation that requires the {@link SqlAstNode} tree and
* assigned JDBC types.
*/
default void validateSqlTypes(List<? extends SqlAstNode> arguments, String functionName) {}
/**
* A mini-"type system" for HQL function parameters.
* <p>
* Note that typical database type systems have relatively few types,
* and lots of implicit type conversion between them. So we can be
* pretty forgiving here.
*/
enum ParameterType {
/**
* @see org.hibernate.type.SqlTypes#isCharacterType(int)
*/
STRING,
/**
* @see org.hibernate.type.SqlTypes#isNumericType(int)
*/
NUMERIC,
/**
* @see org.hibernate.type.SqlTypes#isIntegral(int)
*/
INTEGER,
/**
* @see org.hibernate.type.SqlTypes#isTemporalType(int)
*/
TEMPORAL,
/**
* @see org.hibernate.type.SqlTypes#hasDatePart(int)
*/
DATE,
/**
* @see org.hibernate.type.SqlTypes#hasTimePart(int)
*/
TIME,
/**
* Indicates that the argument should be of type
* {@link org.hibernate.type.SqlTypes#BOOLEAN} or
* a logical expression (predicate)
*/
BOOLEAN,
/**
* Indicates a parameter that accepts any type
*/
ANY
}
} }

View File

@ -64,11 +64,16 @@ public class NamedFunctionDescriptorBuilder {
return this; return this;
} }
public NamedFunctionDescriptorBuilder setInvariantType(BasicType invariantType) { public NamedFunctionDescriptorBuilder setInvariantType(BasicType<?> invariantType) {
setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant( invariantType ) ); setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant( invariantType ) );
return this; return this;
} }
public NamedFunctionDescriptorBuilder setParameterTypes(ArgumentsValidator.ParameterType... types) {
setArgumentsValidator( new ArgumentTypesValidator(argumentsValidator, types) );
return this;
}
public NamedFunctionDescriptorBuilder setUseParenthesesWhenNoArgs(boolean useParenthesesWhenNoArgs) { public NamedFunctionDescriptorBuilder setUseParenthesesWhenNoArgs(boolean useParenthesesWhenNoArgs) {
this.useParenthesesWhenNoArgs = useParenthesesWhenNoArgs; this.useParenthesesWhenNoArgs = useParenthesesWhenNoArgs;
return this; return this;
@ -100,4 +105,5 @@ public class NamedFunctionDescriptorBuilder {
argumentRenderingMode argumentRenderingMode
); );
} }
} }

View File

@ -44,6 +44,15 @@ public class PatternFunctionDescriptorBuilder {
return this; return this;
} }
public PatternFunctionDescriptorBuilder setParameterTypes(ArgumentsValidator.ParameterType... types) {
setArgumentsValidator( new ArgumentTypesValidator(argumentsValidator, types) );
return this;
}
public PatternFunctionDescriptorBuilder setMinArgumentCount(int min) {
return setArgumentsValidator( StandardArgumentsValidators.min( min ) );
}
public PatternFunctionDescriptorBuilder setExactArgumentCount(int exactArgumentCount) { public PatternFunctionDescriptorBuilder setExactArgumentCount(int exactArgumentCount) {
return setArgumentsValidator( StandardArgumentsValidators.exactly( exactArgumentCount ) ); return setArgumentsValidator( StandardArgumentsValidators.exactly( exactArgumentCount ) );
} }

View File

@ -28,7 +28,7 @@ public final class StandardArgumentsValidators {
*/ */
public static final ArgumentsValidator NONE = new ArgumentsValidator() { public static final ArgumentsValidator NONE = new ArgumentsValidator() {
@Override @Override
public void validate(List<? extends SqmTypedNode<?>> arguments) {} public void validate(List<? extends SqmTypedNode<?>> arguments, String functionName) {}
@Override @Override
public String getSignature() { public String getSignature() {
@ -41,9 +41,16 @@ public final class StandardArgumentsValidators {
*/ */
public static final ArgumentsValidator NO_ARGS = new ArgumentsValidator() { public static final ArgumentsValidator NO_ARGS = new ArgumentsValidator() {
@Override @Override
public void validate(List<? extends SqmTypedNode<?>> arguments) { public void validate(List<? extends SqmTypedNode<?>> arguments, String functionName) {
if (!arguments.isEmpty()) { if (!arguments.isEmpty()) {
throw new QueryException("Expecting no arguments, but found " + arguments.size()); throw new QueryException(
String.format(
Locale.ROOT,
"Function %s has no parameters, but %d arguments given",
functionName,
arguments.size()
)
);
} }
} }
@ -59,12 +66,13 @@ public final class StandardArgumentsValidators {
} }
return new ArgumentsValidator() { return new ArgumentsValidator() {
@Override @Override
public void validate(List<? extends SqmTypedNode<?>> arguments) { public void validate(List<? extends SqmTypedNode<?>> arguments, String functionName) {
if (arguments.size() < minNumOfArgs) { if (arguments.size() < minNumOfArgs) {
throw new QueryException( throw new QueryException(
String.format( String.format(
Locale.ROOT, Locale.ROOT,
"Function requires %d or more arguments, but only %d found", "Function %s() requires at least %d arguments, but only %d arguments given",
functionName,
minNumOfArgs, minNumOfArgs,
arguments.size() arguments.size()
) )
@ -92,12 +100,13 @@ public final class StandardArgumentsValidators {
public static ArgumentsValidator exactly(int number) { public static ArgumentsValidator exactly(int number) {
return new ArgumentsValidator() { return new ArgumentsValidator() {
@Override @Override
public void validate(List<? extends SqmTypedNode<?>> arguments) { public void validate(List<? extends SqmTypedNode<?>> arguments, String functionName) {
if (arguments.size() != number) { if (arguments.size() != number) {
throw new QueryException( throw new QueryException(
String.format( String.format(
Locale.ROOT, Locale.ROOT,
"Function requires %d arguments, but %d found", "Function %s() has %d parameters, but %d arguments given",
functionName,
number, number,
arguments.size() arguments.size()
) )
@ -127,12 +136,13 @@ public final class StandardArgumentsValidators {
public static ArgumentsValidator max(int maxNumOfArgs) { public static ArgumentsValidator max(int maxNumOfArgs) {
return new ArgumentsValidator() { return new ArgumentsValidator() {
@Override @Override
public void validate(List<? extends SqmTypedNode<?>> arguments) { public void validate(List<? extends SqmTypedNode<?>> arguments, String functionName) {
if (arguments.size() > maxNumOfArgs) { if (arguments.size() > maxNumOfArgs) {
throw new QueryException( throw new QueryException(
String.format( String.format(
Locale.ROOT, Locale.ROOT,
"Function requires %d or fewer arguments, but %d found", "Function %s() allows at most %d arguments, but %d arguments given",
functionName,
maxNumOfArgs, maxNumOfArgs,
arguments.size() arguments.size()
) )
@ -158,12 +168,13 @@ public final class StandardArgumentsValidators {
public static ArgumentsValidator between(int minNumOfArgs, int maxNumOfArgs) { public static ArgumentsValidator between(int minNumOfArgs, int maxNumOfArgs) {
return new ArgumentsValidator() { return new ArgumentsValidator() {
@Override @Override
public void validate(List<? extends SqmTypedNode<?>> arguments) { public void validate(List<? extends SqmTypedNode<?>> arguments, String functionName) {
if (arguments.size() < minNumOfArgs || arguments.size() > maxNumOfArgs) { if (arguments.size() < minNumOfArgs || arguments.size() > maxNumOfArgs) {
throw new QueryException( throw new QueryException(
String.format( String.format(
Locale.ROOT, Locale.ROOT,
"Function requires between %d and %d arguments, but %d found", "Function %s() requires between %d and %d arguments, but %d arguments given",
functionName,
minNumOfArgs, minNumOfArgs,
maxNumOfArgs, maxNumOfArgs,
arguments.size() arguments.size()
@ -191,14 +202,15 @@ public final class StandardArgumentsValidators {
} }
public static ArgumentsValidator of(Class<?> javaType) { public static ArgumentsValidator of(Class<?> javaType) {
return arguments -> arguments.forEach( return (arguments, functionName) -> arguments.forEach(
arg -> { arg -> {
Class<?> argType = arg.getNodeJavaTypeDescriptor().getJavaTypeClass(); Class<?> argType = arg.getNodeJavaTypeDescriptor().getJavaTypeClass();
if ( !javaType.isAssignableFrom( argType ) ) { if ( !javaType.isAssignableFrom( argType ) ) {
throw new QueryException( throw new QueryException(
String.format( String.format(
Locale.ROOT, Locale.ROOT,
"Function expects arguments to be of type %s, but %s found", "Function %s() has parameters of type %s, but argument of type %s given",
functionName,
javaType.getName(), javaType.getName(),
argType.getName() argType.getName()
) )
@ -213,8 +225,8 @@ public final class StandardArgumentsValidators {
} }
public static ArgumentsValidator composite(List<ArgumentsValidator> validators) { public static ArgumentsValidator composite(List<ArgumentsValidator> validators) {
return arguments -> validators.forEach( return (arguments, functionName) -> validators.forEach(
individualValidator -> individualValidator.validate( arguments ) individualValidator -> individualValidator.validate( arguments, functionName)
); );
} }
} }

View File

@ -452,4 +452,139 @@ public class SqlTypes {
private SqlTypes() { private SqlTypes() {
} }
/**
* Does the given JDBC type code represent some sort of
* numeric type?
* @param sqlType a JDBC type code from {@link Types}
*/
public static boolean isNumericType(int sqlType) {
switch (sqlType) {
case Types.BIT:
case Types.SMALLINT:
case Types.TINYINT:
case Types.INTEGER:
case Types.BIGINT:
case Types.DOUBLE:
case Types.REAL:
case Types.FLOAT:
case Types.NUMERIC:
case Types.DECIMAL:
return true;
default:
return false;
}
}
/**
* Does the given JDBC type code represent some sort of
* character string type?
* @param sqlType a JDBC type code from {@link Types}
*/
public static boolean isCharacterType(int sqlType) {
switch (sqlType) {
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR:
case Types.NCHAR:
case Types.NVARCHAR:
case Types.LONGNVARCHAR:
return true;
default:
return false;
}
}
/**
* Does the given JDBC type code represent some sort of
* variable-length character string type?
* @param sqlType a JDBC type code from {@link Types}
*/
public static boolean isVarcharType(int sqlType) {
switch (sqlType) {
case Types.VARCHAR:
case Types.LONGVARCHAR:
case Types.NVARCHAR:
case Types.LONGNVARCHAR:
return true;
default:
return false;
}
}
/**
* Does the given JDBC type code represent some sort of
* variable-length binary string type?
* @param sqlType a JDBC type code from {@link Types}
*/
public static boolean isVarbinaryType(int sqlType) {
switch (sqlType) {
case Types.VARBINARY:
case Types.LONGVARBINARY:
return true;
default:
return false;
}
}
/**
* Does the given typecode represent one of the two SQL decimal types?
* @param typeCode a JDBC type code from {@link Types}
*/
public static boolean isNumericOrDecimal(int typeCode) {
return typeCode == NUMERIC
|| typeCode == DECIMAL;
}
/**
* Does the given typecode represent a SQL floating point type?
* @param typeCode a JDBC type code from {@link Types}
*/
public static boolean isFloatOrRealOrDouble(int typeCode) {
return typeCode == FLOAT
|| typeCode == REAL
|| typeCode == DOUBLE;
}
/**
* Does the given typecode represent a SQL integer type?
* @param typeCode a JDBC type code from {@link Types}
*/
public static boolean isIntegral(int typeCode) {
return typeCode == INTEGER
|| typeCode == BIGINT
|| typeCode == SMALLINT
|| typeCode == TINYINT;
}
/**
* Does the given typecode represent a SQL date, time, or timestamp type?
* @param typeCode a JDBC type code from {@link Types}
*/
public static boolean isTemporalType(int typeCode) {
return typeCode == DATE
|| typeCode == TIME
|| typeCode == TIMESTAMP
|| typeCode == TIMESTAMP_WITH_TIMEZONE;
}
/**
* Does the given typecode represent a SQL date or timestamp type?
* @param typeCode a JDBC type code from {@link Types}
*/
public static boolean hasDatePart(int typeCode) {
return typeCode == DATE
|| typeCode == TIMESTAMP
|| typeCode == TIMESTAMP_WITH_TIMEZONE;
}
/**
* Does the given typecode represent a SQL time or timestamp type?
* @param typeCode a JDBC type code from {@link Types}
*/
public static boolean hasTimePart(int typeCode) {
return typeCode == TIME
|| typeCode == TIMESTAMP
|| typeCode == TIMESTAMP_WITH_TIMEZONE;
}
} }

View File

@ -35,10 +35,7 @@ import org.hibernate.dialect.DerbyDialect;
import org.hibernate.dialect.H2Dialect; import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.HSQLDialect; import org.hibernate.dialect.HSQLDialect;
import org.hibernate.dialect.MySQLDialect; import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.dialect.SybaseDialect;
import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.loader.MultipleBagFetchException; import org.hibernate.loader.MultipleBagFetchException;
@ -300,8 +297,8 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
inTransaction( inTransaction(
(session) -> { (session) -> {
final String qry = "select new Constructor( c.id, c.id is not null, c.id = c.id, c.id + 1, concat( c.id, 'foo' ) ) from Constructor c where c.id = :id"; final String qry = "select new Constructor( c.id, c.id is not null, c.id = c.id, c.id + 1, concat( str(c.id), 'foo' ) ) from Constructor c where c.id = :id";
final Constructor result = (Constructor) session.createQuery(qry ).setParameter( "id", created.getId() ).uniqueResult(); final Constructor result = session.createQuery(qry, Constructor.class).setParameter( "id", created.getId() ).uniqueResult();
assertEquals( 1, Constructor.getConstructorExecutionCount() ); assertEquals( 1, Constructor.getConstructorExecutionCount() );
Constructor expected = new Constructor( Constructor expected = new Constructor(
created.getId(), created.getId(),
@ -3697,29 +3694,11 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
hql = "from Animal a where mod(16, 4) = 4"; hql = "from Animal a where mod(16, 4) = 4";
session.createQuery(hql).list(); session.createQuery(hql).list();
/**
* PostgreSQL >= 8.3.7 typecasts are no longer automatically allowed
* <link>http://www.postgresql.org/docs/current/static/release-8-3.html</link>
*/
if ( getDialect() instanceof PostgreSQLDialect
|| getDialect() instanceof HSQLDialect
|| getDialect() instanceof CockroachDialect ) {
hql = "from Animal a where bit_length(str(a.bodyWeight)) = 24";
}
else {
hql = "from Animal a where bit_length(a.bodyWeight) = 24";
}
hql = "from Animal a where bit_length(str(a.bodyWeight)) = 24";
session.createQuery(hql).list(); session.createQuery(hql).list();
if ( getDialect() instanceof PostgreSQLDialect
|| getDialect() instanceof HSQLDialect
|| getDialect() instanceof CockroachDialect ) {
hql = "select bit_length(str(a.bodyWeight)) from Animal a";
}
else {
hql = "select bit_length(a.bodyWeight) from Animal a";
}
hql = "select bit_length(str(a.bodyWeight)) from Animal a";
session.createQuery(hql).list(); session.createQuery(hql).list();
/*hql = "select object(a) from Animal a where CURRENT_DATE = :p1 or CURRENT_TIME = :p2 or CURRENT_TIMESTAMP = :p3"; /*hql = "select object(a) from Animal a where CURRENT_DATE = :p1 or CURRENT_TIME = :p2 or CURRENT_TIMESTAMP = :p3";

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.orm.test.query.hql; package org.hibernate.orm.test.query.hql;
import org.hibernate.QueryException;
import org.hibernate.dialect.DerbyDialect; import org.hibernate.dialect.DerbyDialect;
import org.hibernate.testing.orm.domain.StandardDomainModel; import org.hibernate.testing.orm.domain.StandardDomainModel;
@ -29,12 +30,9 @@ import java.time.LocalTime;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import static org.hamcrest.CoreMatchers.anyOf; import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.fail;
/** /**
* @author Gavin King * @author Gavin King
@ -206,6 +204,19 @@ public class FunctionTests {
assertThat( session.createQuery("select upper('hello')").getSingleResult(), is("HELLO") ); assertThat( session.createQuery("select upper('hello')").getSingleResult(), is("HELLO") );
} }
); );
try {
scope.inTransaction(
session -> {
session.createQuery("select upper(3)")
.list();
}
);
fail();
}
catch (IllegalArgumentException e) {
assertThat( e.getCause(), is(instanceOf(QueryException.class)) );
}
} }
@Test @Test
@ -217,6 +228,19 @@ public class FunctionTests {
assertThat( session.createQuery("select length('hello')").getSingleResult(), is(5) ); assertThat( session.createQuery("select length('hello')").getSingleResult(), is(5) );
} }
); );
try {
scope.inTransaction(
session -> {
session.createQuery("select length(3)")
.list();
}
);
fail();
}
catch (IllegalArgumentException e) {
assertThat( e.getCause(), is(instanceOf(QueryException.class)) );
}
} }
@Test @Test
@ -234,6 +258,19 @@ public class FunctionTests {
assertThat( session.createQuery("select substring('hello world',4, 5)").getSingleResult(), is("lo wo") ); assertThat( session.createQuery("select substring('hello world',4, 5)").getSingleResult(), is("lo wo") );
} }
); );
try {
scope.inTransaction(
session -> {
session.createQuery("select substring('hello world', 'world', 5)")
.list();
}
);
fail();
}
catch (IllegalArgumentException e) {
assertThat( e.getCause(), is(instanceOf(QueryException.class)) );
}
} }
@Test @Test
@ -324,6 +361,19 @@ public class FunctionTests {
assertThat( session.createQuery("select replace('hello world', 'o', 'ooo')").getSingleResult(), is("hellooo wooorld") ); assertThat( session.createQuery("select replace('hello world', 'o', 'ooo')").getSingleResult(), is("hellooo wooorld") );
} }
); );
try {
scope.inTransaction(
session -> {
session.createQuery("select replace(e.theString, 1, 'goodbye') from EntityOfBasics e")
.list();
}
);
fail();
}
catch (IllegalArgumentException e) {
assertThat( e.getCause(), is(instanceOf(QueryException.class)) );
}
} }
@Test @Test
@ -342,6 +392,19 @@ public class FunctionTests {
assertThat( session.createQuery("select trim(both '-' from '---hello---')").getSingleResult(), is("hello") ); assertThat( session.createQuery("select trim(both '-' from '---hello---')").getSingleResult(), is("hello") );
} }
); );
try {
scope.inTransaction(
session -> {
session.createQuery("select trim(leading ' ' from 3)")
.list();
}
);
fail();
}
catch (IllegalArgumentException e) {
assertThat( e.getCause(), is(instanceOf(QueryException.class)) );
}
} }
@Test @Test
@ -359,6 +422,31 @@ public class FunctionTests {
is("hello.....")); is("hello....."));
} }
); );
try {
scope.inTransaction(
session -> {
session.createQuery("select pad('hello' with ' ' leading)")
.list();
}
);
fail();
}
catch (IllegalArgumentException e) {
assertThat( e.getCause(), is(instanceOf(QueryException.class)) );
}
try {
scope.inTransaction(
session -> {
session.createQuery("select pad(3 with 4 leading)")
.list();
}
);
fail();
}
catch (IllegalArgumentException e) {
assertThat( e.getCause(), is(instanceOf(QueryException.class)) );
}
} }
@Test @Test

View File

@ -61,6 +61,7 @@ public class OrderByFragmentFunction extends AbstractSqmFunctionDescriptor {
null, null,
arguments, arguments,
impliedResultType, impliedResultType,
getArgumentsValidator(),
getReturnTypeResolver(), getReturnTypeResolver(),
queryEngine.getCriteriaBuilder(), queryEngine.getCriteriaBuilder(),
getName() getName()

View File

@ -16,6 +16,7 @@ import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; import org.hibernate.query.sqm.function.SelfRenderingSqmFunction;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor; import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
import org.hibernate.query.sqm.tree.SqmTypedNode; import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.type.BasicTypeReference; import org.hibernate.type.BasicTypeReference;
@ -53,6 +54,11 @@ class SDOObjectProperty implements SqmFunctionDescriptor {
return true; return true;
} }
@Override
public ArgumentsValidator getArgumentsValidator() {
return null;
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* *