From cc91beb5360db409408218dfcc4402593ee1523a Mon Sep 17 00:00:00 2001 From: Gavin King Date: Wed, 5 Jan 2022 16:07:37 +0100 Subject: [PATCH] typecheck HQL function arguments --- .../community/dialect/CacheDialect.java | 5 +- .../community/dialect/FirebirdDialect.java | 5 +- .../community/dialect/InformixDialect.java | 5 +- .../community/dialect/IngresDialect.java | 6 +- .../community/dialect/MaxDBDialect.java | 5 +- .../community/dialect/SQLiteDialect.java | 16 +- .../community/dialect/TimesTenDialect.java | 5 +- .../dialect/AbstractHANADialect.java | 5 +- .../org/hibernate/dialect/DB2Dialect.java | 9 +- .../java/org/hibernate/dialect/Dialect.java | 92 -------- .../dialect/HANAColumnStoreDialect.java | 5 +- .../org/hibernate/dialect/OracleDialect.java | 4 +- .../hibernate/dialect/PostgreSQLDialect.java | 4 +- .../hibernate/dialect/SQLServerDialect.java | 7 + .../dialect/function/AvgFunction.java | 5 +- .../function/CastingConcatFunction.java | 6 +- .../function/CommonFunctionFactory.java | 220 ++++++++++++++++-- .../dialect/function/CurrentFunction.java | 2 +- .../dialect/function/DB2FormatEmulation.java | 8 +- .../dialect/function/DerbyLpadEmulation.java | 7 +- .../dialect/function/DerbyRpadEmulation.java | 6 +- .../dialect/function/EveryAnyEmulation.java | 11 +- .../dialect/function/ExtractFunction.java | 9 +- .../InsertSubstringOverlayEmulation.java | 9 +- .../function/LpadRpadPadEmulation.java | 9 +- .../function/SQLServerEveryAnyEmulation.java | 5 +- .../function/TransactSQLStrFunction.java | 8 +- .../dialect/function/TrimFunction.java | 10 +- .../AbstractSqmFunctionDescriptor.java | 12 +- ...actSqmSelfRenderingFunctionDescriptor.java | 2 + .../JdbcEscapeFunctionDescriptor.java | 1 + .../MultipatternSqmFunctionDescriptor.java | 27 ++- ...SelfRenderingFunctionSqlAstExpression.java | 4 +- .../SelfRenderingSqmAggregateFunction.java | 4 +- .../function/SelfRenderingSqmFunction.java | 12 +- .../sqm/function/SqmFunctionDescriptor.java | 3 + .../sqm/function/SqmFunctionRegistry.java | 50 ++-- .../function/ArgumentTypesValidator.java | 134 +++++++++++ .../produce/function/ArgumentsValidator.java | 55 ++++- .../NamedFunctionDescriptorBuilder.java | 8 +- .../PatternFunctionDescriptorBuilder.java | 9 + .../function/StandardArgumentsValidators.java | 42 ++-- .../java/org/hibernate/type/SqlTypes.java | 135 +++++++++++ .../orm/test/hql/ASTParserLoadingTest.java | 29 +-- .../orm/test/query/hql/FunctionTests.java | 98 +++++++- .../function/OrderByFragmentFunction.java | 1 + .../dialect/oracle/SDOObjectProperty.java | 6 + 47 files changed, 888 insertions(+), 232 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentTypesValidator.java diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheDialect.java index b11fe480e9..01861a3927 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheDialect.java @@ -49,6 +49,8 @@ import java.sql.Types; import jakarta.persistence.TemporalType; 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. @@ -169,7 +171,8 @@ public class CacheDialect extends Dialect { "locate", queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ), "$find(?2,?1)", - "$find(?2,?1,?3)" + "$find(?2,?1,?3)", + STRING, STRING, INTEGER ).setArgumentListSignature("(pattern, string[, start])"); CommonFunctionFactory.bitLength_pattern( queryEngine, "($length(?1)*8)" ); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdDialect.java index 107406330f..e3851e60a7 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdDialect.java @@ -74,6 +74,8 @@ import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; 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_START_DATE; import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_START_TIME; @@ -280,7 +282,8 @@ public class FirebirdDialect extends Dialect { "locate", integerType, "position(?1 in ?2)", - "position(?1,?2,?3)" + "position(?1,?2,?3)", + STRING, STRING, INTEGER ).setArgumentListSignature( "(pattern, string[, start])" ); functionRegistry.namedDescriptorBuilder( "ascii_val" ) .setExactArgumentCount( 1 ) diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java index bce3c6abaf..35c8446184 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java @@ -60,6 +60,8 @@ import org.hibernate.type.StandardBasicTypes; import java.sql.Types; 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 @@ -184,7 +186,8 @@ public class InformixDialect extends Dialect { "locate", queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ), "instr(?2,?1)", - "instr(?2,?1,?3)" + "instr(?2,?1,?3)", + STRING, STRING, INTEGER ).setArgumentListSignature("(pattern, string[, start])"); //coalesce() and nullif() both supported since Informix 12 diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresDialect.java index 5e0848465e..f104441b4e 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresDialect.java @@ -61,6 +61,9 @@ import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; 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. *

@@ -283,7 +286,8 @@ public class IngresDialect extends Dialect { "locate", integerType, "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])"); queryEngine.getSqmFunctionRegistry().registerPattern( "extract", "date_part('?1',?2)", integerType ); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBDialect.java index 4d21521eee..cbd8de48f4 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBDialect.java @@ -38,6 +38,8 @@ import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; 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. @@ -164,7 +166,8 @@ public class MaxDBDialect extends Dialect { queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "locate", - integerType, "index(?2,?1)", "index(?2,?1,?3)" + integerType, "index(?2,?1)", "index(?2,?1,?3)", + STRING, STRING, INTEGER ).setArgumentListSignature("(pattern, string[, start])"); } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteDialect.java index 3a96eee92d..322d4aed39 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteDialect.java @@ -66,6 +66,10 @@ import static org.hibernate.query.TemporalUnit.EPOCH; import static org.hibernate.query.TemporalUnit.MONTH; import static org.hibernate.query.TemporalUnit.QUARTER; 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.appendAsTime; import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros; @@ -271,24 +275,28 @@ public class SQLiteDialect extends Dialect { "locate", integerType, "instr(?2,?1)", - "instr(?2,?1,?3)" + "instr(?2,?1,?3)", + STRING, STRING, INTEGER ).setArgumentListSignature("(pattern, string[, start])"); queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "lpad", stringType, "(substr(replace(hex(zeroblob(?2)),'00',' '),1,?2-length(?1))||?1)", - "(substr(replace(hex(zeroblob(?2)),'00',?3),1,?2-length(?1))||?1)" + "(substr(replace(hex(zeroblob(?2)),'00',?3),1,?2-length(?1))||?1)", + STRING, INTEGER, STRING ).setArgumentListSignature("(string, length[, padding])"); queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "rpad", stringType, "(?1||substr(replace(hex(zeroblob(?2)),'00',' '),1,?2-length(?1)))", - "(?1||substr(replace(hex(zeroblob(?2)),'00',?3),1,?2-length(?1)))" + "(?1||substr(replace(hex(zeroblob(?2)),'00',?3),1,?2-length(?1)))", + STRING, INTEGER, STRING ).setArgumentListSignature("(string, length[, padding])"); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("format", "strftime") .setInvariantType( stringType ) .setExactArgumentCount( 2 ) + .setParameterTypes(TEMPORAL, STRING) .setArgumentListSignature("(datetime as pattern)") .register(); @@ -298,12 +306,14 @@ public class SQLiteDialect extends Dialect { "(cast(?1 as int)-(?1cast(?1 as int)))" ).setReturnTypeResolver( StandardFunctionReturnTypeResolvers.useArgType( 1 ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TimesTenDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TimesTenDialect.java index 369a182090..493414bda3 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TimesTenDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TimesTenDialect.java @@ -46,6 +46,8 @@ import java.sql.Types; import jakarta.persistence.TemporalType; 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. @@ -169,7 +171,8 @@ public class TimesTenDialect extends Dialect { "locate", queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ), "instr(?2,?1)", - "instr(?2,?1,?3)" + "instr(?2,?1,?3)", + STRING, STRING, INTEGER ).setArgumentListSignature("(pattern, string[, start])"); } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java index 82a41b3f74..3b20bd81ad 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java @@ -78,6 +78,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import jakarta.persistence.TemporalType; +import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType; + /** * An abstract base class for SAP HANA dialects. *

@@ -279,7 +281,8 @@ public abstract class AbstractHANADialect extends Dialect { "locate", queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ), "locate(?2,?1)", - "locate(?2,?1,?3)" + "locate(?2,?1,?3)", + ParameterType.STRING, ParameterType.STRING, ParameterType.INTEGER ).setArgumentListSignature("(pattern, string[, start])"); CommonFunctionFactory.ceiling_ceil( queryEngine ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java index d4d5651ed6..62c1af4ba6 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java @@ -8,7 +8,6 @@ package org.hibernate.dialect; import org.hibernate.LockOptions; import org.hibernate.boot.model.TypeContributions; -import org.hibernate.cfg.Environment; import org.hibernate.dialect.function.CommonFunctionFactory; import org.hibernate.dialect.function.DB2FormatEmulation; 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.spi.SqmMultiTableInsertStrategy; 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.sql.ast.SqlAstNodeRenderingMode; import org.hibernate.sql.ast.SqlAstTranslator; @@ -196,6 +197,7 @@ public class DB2Dialect extends Dialect { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setArgumentCountBetween( 2, 4 ) + .setParameterTypes(ParameterType.STRING, ParameterType.INTEGER, ParameterType.INTEGER, ParameterType.ANY) .setArgumentListSignature( "(string, start[, length[, units]])" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "substring" ) @@ -203,6 +205,7 @@ public class DB2Dialect extends Dialect { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setArgumentCountBetween( 2, 4 ) + .setParameterTypes(ParameterType.STRING, ParameterType.INTEGER, ParameterType.INTEGER, ParameterType.ANY) .setArgumentListSignature( "(string{ from|,} start[{ for|,} length[, units]])" ) .register(); CommonFunctionFactory.translate( queryEngine ); @@ -238,13 +241,15 @@ public class DB2Dialect extends Dialect { CommonFunctionFactory.dateTrunc( queryEngine ); 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" ) .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(ParameterType.STRING, ParameterType.STRING) .setArgumentListSignature("(string, pattern)") .register(); } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java index 8b33e678b8..12826d093b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java @@ -574,80 +574,6 @@ public abstract class Dialect implements ConversionContext { : 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. */ @@ -1305,24 +1231,6 @@ public abstract class Dialect implements ConversionContext { || 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. * diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/HANAColumnStoreDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/HANAColumnStoreDialect.java index e540723141..a358c4ea33 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/HANAColumnStoreDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/HANAColumnStoreDialect.java @@ -20,6 +20,8 @@ import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy; 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. *

@@ -112,7 +114,8 @@ public class HANAColumnStoreDialect extends AbstractHANADialect { "contains", queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.BOOLEAN ), "contains(?1,?2)", - "contains(?1,?2,?3)" + "contains(?1,?2,?3)", + ANY, ANY, ANY ); } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java index 59a7862b4a..5c600398b5 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java @@ -87,6 +87,7 @@ import static org.hibernate.query.TemporalUnit.MINUTE; import static org.hibernate.query.TemporalUnit.MONTH; import static org.hibernate.query.TemporalUnit.SECOND; import static org.hibernate.query.TemporalUnit.YEAR; +import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType; import static org.hibernate.type.SqlTypes.*; /** @@ -180,7 +181,8 @@ public class OracleDialect extends Dialect { "locate", queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ), "instr(?2,?1)", - "instr(?2,?1,?3)" + "instr(?2,?1,?3)", + ParameterType.STRING, ParameterType.STRING, ParameterType.INTEGER ).setArgumentListSignature("(pattern, string[, start])"); } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java index 3092594534..8dafafaab0 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java @@ -84,6 +84,7 @@ import static org.hibernate.query.TemporalUnit.EPOCH; import static org.hibernate.query.TemporalUnit.MONTH; import static org.hibernate.query.TemporalUnit.QUARTER; 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.descriptor.DateTimeUtils.appendAsDate; import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime; @@ -451,7 +452,8 @@ public class PostgreSQLDialect extends Dialect { "locate", queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ), "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])"); if ( getVersion().isSameOrAfter( 9, 4 ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java index d0b39abd2a..81faaef495 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java @@ -68,6 +68,7 @@ import java.util.TimeZone; import jakarta.persistence.TemporalType; 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.descriptor.DateTimeUtils.appendAsDate; import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime; @@ -236,26 +237,32 @@ public class SQLServerDialect extends AbstractTransactSQLDialect { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datefromparts" ) .setInvariantType( dateType ) .setExactArgumentCount( 3 ) + .setParameterTypes(INTEGER) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "timefromparts" ) .setInvariantType( timeType ) .setExactArgumentCount( 5 ) + .setParameterTypes(INTEGER) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "smalldatetimefromparts" ) .setInvariantType( timestampType ) .setExactArgumentCount( 5 ) + .setParameterTypes(INTEGER) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datetimefromparts" ) .setInvariantType( timestampType ) .setExactArgumentCount( 7 ) + .setParameterTypes(INTEGER) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datetime2fromparts" ) .setInvariantType( timestampType ) .setExactArgumentCount( 8 ) + .setParameterTypes(INTEGER) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datetimeoffsetfromparts" ) .setInvariantType( timestampType ) .setExactArgumentCount( 10 ) + .setParameterTypes(INTEGER) .register(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/AvgFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/AvgFunction.java index c4de5e3d2c..6e3f30d18d 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/AvgFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/AvgFunction.java @@ -14,6 +14,7 @@ import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.query.CastType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.FunctionKind; +import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; 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.spi.TypeConfiguration; +import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.NUMERIC; + /** * @author Christian Beikov */ @@ -45,7 +48,7 @@ public class AvgFunction extends AbstractSqmSelfRenderingFunctionDescriptor { super( FUNCTION_NAME, FunctionKind.AGGREGATE, - StandardArgumentsValidators.exactly( 1 ), + new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 1 ), NUMERIC ), StandardFunctionReturnTypeResolvers.invariant( typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/CastingConcatFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/CastingConcatFunction.java index f7e25c960f..21b01a920b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/CastingConcatFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/CastingConcatFunction.java @@ -14,6 +14,8 @@ import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.query.CastType; import org.hibernate.query.spi.QueryEngine; 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.StandardFunctionReturnTypeResolvers; 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.spi.TypeConfiguration; +import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.STRING; + public class CastingConcatFunction extends AbstractSqmSelfRenderingFunctionDescriptor { private final Dialect dialect; @@ -40,7 +44,7 @@ public class CastingConcatFunction extends AbstractSqmSelfRenderingFunctionDescr TypeConfiguration typeConfiguration) { super( "concat", - StandardArgumentsValidators.min( 1 ), + new ArgumentTypesValidator( StandardArgumentsValidators.min( 1 ), STRING ), StandardFunctionReturnTypeResolvers.invariant( typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java index 54678ce644..70cabb9c12 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java @@ -31,6 +31,7 @@ import org.hibernate.type.SqlTypes; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.spi.TypeConfiguration; +import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.*; import static org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers.useArgType; /** @@ -50,12 +51,14 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); } public static void cot(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "cot" ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) @@ -65,6 +68,7 @@ public class CommonFunctionFactory { public static void degrees(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "degrees" ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) @@ -74,6 +78,7 @@ public class CommonFunctionFactory { public static void log(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "log" ) .setArgumentCountBetween( 1, 2 ) + .setParameterTypes(NUMERIC, NUMERIC) .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) @@ -86,12 +91,14 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); } public static void log10(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "log10" ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) @@ -104,6 +111,7 @@ public class CommonFunctionFactory { public static void log10_log(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "log10", "log(10,?1)" ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) @@ -116,12 +124,14 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); } public static void radians(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "radians" ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) @@ -131,6 +141,7 @@ public class CommonFunctionFactory { public static void sinh(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "sinh" ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) @@ -140,6 +151,7 @@ public class CommonFunctionFactory { public static void tanh(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "tanh" ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) @@ -152,14 +164,17 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "acosh" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "asinh" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "atanh" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); } @@ -169,6 +184,7 @@ public class CommonFunctionFactory { public static void trunc(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "trunc" ) .setArgumentCountBetween( 1, 2 ) + .setParameterTypes(NUMERIC, INTEGER) .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) @@ -179,6 +195,7 @@ public class CommonFunctionFactory { public static void truncate(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "truncate" ) .setExactArgumentCount( 2 ) //some databases allow 1 arg but in these it's a synonym for trunc() + .setParameterTypes(NUMERIC, INTEGER) .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) @@ -192,6 +209,7 @@ public class CommonFunctionFactory { public static void truncate_round(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "truncate", "round(?1,?2,1)" ) .setExactArgumentCount( 2 ) + .setParameterTypes(NUMERIC, INTEGER) .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) @@ -205,6 +223,7 @@ public class CommonFunctionFactory { public static void rand(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "rand" ) .setArgumentCountBetween( 0, 1 ) + .setParameterTypes(INTEGER) .setUseParenthesesWhenNoArgs( true ) .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) @@ -219,6 +238,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); } @@ -232,6 +252,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); } @@ -247,6 +268,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); } @@ -262,6 +284,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); } @@ -271,10 +294,12 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "stddev_pop" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "stddev_samp" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); } @@ -284,10 +309,12 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "var_pop" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "var_samp" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); } @@ -297,10 +324,12 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "covar_pop" ) .setInvariantType( doubleType ) .setExactArgumentCount( 2 ) + .setParameterTypes(NUMERIC, NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "covar_samp" ) .setInvariantType( doubleType ) .setExactArgumentCount( 2 ) + .setParameterTypes(NUMERIC, NUMERIC) .register(); } @@ -310,6 +339,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(NUMERIC, NUMERIC) .register(); } @@ -326,6 +356,7 @@ public class CommonFunctionFactory { fnName -> queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( fnName ) .setInvariantType( doubleType ) .setExactArgumentCount( 2 ) + .setParameterTypes(NUMERIC, NUMERIC) .register() ); } @@ -339,10 +370,12 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "stddev_samp" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "variance_samp" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); } @@ -357,10 +390,12 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "stdev" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "stdevp" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "stddev_samp", "stdev" ); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "stddev_pop", "stdevp" ); @@ -376,10 +411,12 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "var" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "varp" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "var_samp", "var" ); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "var_pop", "varp" ); @@ -412,11 +449,13 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "ltrim" ) .setInvariantType( stringType ) .setArgumentCountBetween( 1, 2 ) + .setParameterTypes(STRING, STRING) .setArgumentListSignature( "(string[, characters])" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "rtrim" ) .setInvariantType( stringType ) .setArgumentCountBetween( 1, 2 ) + .setParameterTypes(STRING, STRING) .setArgumentListSignature( "(string[, characters])" ) .register(); } @@ -427,11 +466,13 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "ltrim" ) .setInvariantType( stringType ) .setExactArgumentCount( 1 ) + .setParameterTypes(STRING) .setArgumentListSignature( "(string)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "rtrim" ) .setInvariantType( stringType ) .setExactArgumentCount( 1 ) + .setParameterTypes(STRING) .setArgumentListSignature( "(string)" ) .register(); } @@ -442,11 +483,13 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "lpad" ) .setInvariantType( stringType ) .setArgumentCountBetween( 2, 3 ) + .setParameterTypes(STRING, INTEGER, STRING) .setArgumentListSignature( "(string, length[, padding])" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "rpad" ) .setInvariantType( stringType ) .setArgumentCountBetween( 2, 3 ) + .setParameterTypes(STRING, INTEGER, STRING) .setArgumentListSignature( "(string, length[, padding])" ) .register(); } @@ -461,13 +504,15 @@ public class CommonFunctionFactory { "lpad", stringType, "lpad(?1,?2,' ')", - "lpad(?1,?2,?3)" + "lpad(?1,?2,?3)", + STRING, INTEGER, STRING ).setArgumentListSignature( "(string, length[, padding])" ); queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "rpad", stringType, "rpad(?1,?2,' ')", - "rpad(?1,?2,?3)" + "rpad(?1,?2,?3)", + STRING, INTEGER, STRING ).setArgumentListSignature( "(string, length[, padding])" ); } @@ -481,13 +526,15 @@ public class CommonFunctionFactory { "lpad", stringType, "(space(?2-len(?1))+?1)", - "(replicate(?3,?2-len(?1))+?1)" + "(replicate(?3,?2-len(?1))+?1)", + STRING, INTEGER, STRING ).setArgumentListSignature( "(string, length[, padding])" ); queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "rpad", stringType, "(?1+space(?2-len(?1)))", - "(?1+replicate(?3,?2-len(?1)))" + "(?1+replicate(?3,?2-len(?1)))", + STRING, INTEGER, STRING ).setArgumentListSignature( "(string, length[, padding])" ); } @@ -498,13 +545,15 @@ public class CommonFunctionFactory { "lpad", stringType, "(repeat(' ',?2-character_length(?1))||?1)", - "(repeat(?3,?2-character_length(?1))||?1)" + "(repeat(?3,?2-character_length(?1))||?1)", + STRING, INTEGER, STRING ).setArgumentListSignature( "(string, length[, padding])" ); queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "rpad", stringType, "(?1||repeat(' ',?2-character_length(?1)))", - "(?1||repeat(?3,?2-character_length(?1)))" + "(?1||repeat(?3,?2-character_length(?1)))", + STRING, INTEGER, STRING ).setArgumentListSignature( "(string, length[, padding])" ); } @@ -518,13 +567,15 @@ public class CommonFunctionFactory { "lpad", stringType, "lfill(?1,' ',?2)", - "lfill(?1,?3,?2)" + "lfill(?1,?3,?2)", + STRING, INTEGER, STRING ).setArgumentListSignature( "(string, length[, padding])" ); queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "rpad", stringType, "rfill(?1,' ',?2)", - "rfill(?1,?3,?2)" + "rfill(?1,?3,?2)", + STRING, INTEGER, STRING ).setArgumentListSignature( "(string, length[, padding])" ); } @@ -534,6 +585,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(STRING) .register(); } @@ -543,6 +595,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(INTEGER) .register(); } @@ -552,6 +605,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(STRING, INTEGER) .setArgumentListSignature( "(string, times)" ) .register(); } @@ -562,11 +616,13 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "left" ) .setInvariantType( stringType ) .setExactArgumentCount( 2 ) + .setParameterTypes(STRING, INTEGER) .setArgumentListSignature( "(string, length)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "right" ) .setInvariantType( stringType ) .setExactArgumentCount( 2 ) + .setParameterTypes(STRING, INTEGER) .setArgumentListSignature( "(string, length)" ) .register(); } @@ -577,11 +633,13 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "left", "substr(?1,1,?2)" ) .setInvariantType( stringType ) .setExactArgumentCount( 2 ) + .setParameterTypes(STRING, INTEGER) .setArgumentListSignature( "(string, length)" ) .register(); queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "right", "substr(?1,-?2)" ) .setInvariantType( stringType ) .setExactArgumentCount( 2 ) + .setParameterTypes(STRING, INTEGER) .setArgumentListSignature( "(string, length)" ) .register(); } @@ -592,11 +650,13 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "left", "substr(?1,1,?2)" ) .setInvariantType( stringType ) .setExactArgumentCount( 2 ) + .setParameterTypes(STRING, INTEGER) .setArgumentListSignature( "(string, length)" ) .register(); queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "right", "substr(?1,length(?1)-?2+1)" ) .setInvariantType( stringType ) .setExactArgumentCount( 2 ) + .setParameterTypes(STRING, INTEGER) .setArgumentListSignature( "(string, length)" ) .register(); } @@ -607,6 +667,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(STRING, INTEGER) .setArgumentListSignature( "(string, times)" ) .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "repeat", "replicate" ); @@ -636,6 +697,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ) ) .setArgumentCountBetween( 2, 4 ) + .setParameterTypes(STRING, STRING, INTEGER, INTEGER) .setArgumentListSignature( "(string, pattern[, start[, occurrence]])" ) .register(); } @@ -646,6 +708,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setArgumentCountBetween( 2, 3 ) + .setParameterTypes(STRING, STRING, INTEGER) .setArgumentListSignature( "(string, start[, length])" ) .register(); } @@ -783,12 +846,14 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "every" ) .setExactArgumentCount( 1 ) .setInvariantType( booleanType ) + .setParameterTypes(BOOLEAN) .setArgumentListSignature( "(predicate)" ) .register(); queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "any" ) .setExactArgumentCount( 1 ) .setInvariantType( booleanType ) + .setParameterTypes(BOOLEAN) .setArgumentListSignature( "(predicate)" ) .register(); } @@ -805,6 +870,7 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "bool_and" ) .setExactArgumentCount( 1 ) + .setParameterTypes(BOOLEAN) .setInvariantType( booleanType ) .setArgumentListSignature( "(predicate)" ) .register(); @@ -812,6 +878,7 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "bool_or" ) .setExactArgumentCount( 1 ) + .setParameterTypes(BOOLEAN) .setInvariantType( booleanType ) .setArgumentListSignature( "(predicate)" ) .register(); @@ -824,8 +891,10 @@ public class CommonFunctionFactory { * aggregation functions using sum() and case. */ public static void everyAny_sumCase(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().register( "every", new EveryAnyEmulation( queryEngine.getTypeConfiguration(), true ) ); - queryEngine.getSqmFunctionRegistry().register( "any", new EveryAnyEmulation( queryEngine.getTypeConfiguration(), false ) ); + queryEngine.getSqmFunctionRegistry().register( "every", + new EveryAnyEmulation( queryEngine.getTypeConfiguration(), true ) ); + queryEngine.getSqmFunctionRegistry().register( "any", + new EveryAnyEmulation( queryEngine.getTypeConfiguration(), false ) ); } /** @@ -833,8 +902,10 @@ public class CommonFunctionFactory { * for SQL Server. */ public static void everyAny_sumIif(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().register( "every", new SQLServerEveryAnyEmulation( queryEngine.getTypeConfiguration(), true ) ); - queryEngine.getSqmFunctionRegistry().register( "any", new SQLServerEveryAnyEmulation( queryEngine.getTypeConfiguration(), false ) ); + queryEngine.getSqmFunctionRegistry().register( "every", + new SQLServerEveryAnyEmulation( queryEngine.getTypeConfiguration(), true ) ); + queryEngine.getSqmFunctionRegistry().register( "any", + new SQLServerEveryAnyEmulation( queryEngine.getTypeConfiguration(), false ) ); } @@ -853,14 +924,17 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "day" ) .setInvariantType( integerType ) .setExactArgumentCount( 1 ) + .setParameterTypes(DATE) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "month" ) .setInvariantType( integerType ) .setExactArgumentCount( 1 ) + .setParameterTypes(DATE) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "year" ) .setInvariantType( integerType ) .setExactArgumentCount( 1 ) + .setParameterTypes(DATE) .register(); } @@ -870,18 +944,22 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "hour" ) .setInvariantType( integerType ) .setExactArgumentCount( 1 ) + .setParameterTypes(TIME) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "minute" ) .setInvariantType( integerType ) .setExactArgumentCount( 1 ) + .setParameterTypes(TIME) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "second" ) .setInvariantType( integerType ) .setExactArgumentCount( 1 ) + .setParameterTypes(TIME) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "microsecond" ) .setInvariantType( integerType ) .setExactArgumentCount( 1 ) + .setParameterTypes(TIME) .register(); } @@ -891,15 +969,18 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "dayofweek" ) .setInvariantType( integerType ) .setExactArgumentCount( 1 ) + .setParameterTypes(DATE) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "dayofmonth" ) .setInvariantType( integerType ) .setExactArgumentCount( 1 ) + .setParameterTypes(DATE) .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "day", "dayofmonth" ); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "dayofyear" ) .setInvariantType( integerType ) .setExactArgumentCount( 1 ) + .setParameterTypes(DATE) .register(); } @@ -909,15 +990,18 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "day_of_week" ) .setInvariantType( integerType ) .setExactArgumentCount( 1 ) + .setParameterTypes(DATE) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "day_of_month" ) .setInvariantType( integerType ) .setExactArgumentCount( 1 ) + .setParameterTypes(DATE) .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "day", "day_of_month" ); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "day_of_year" ) .setInvariantType( integerType ) .setExactArgumentCount( 1 ) + .setParameterTypes(DATE) .register(); } @@ -927,10 +1011,12 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "monthname" ) .setInvariantType( stringType ) .setExactArgumentCount( 1 ) + .setParameterTypes(DATE) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "dayname" ) .setInvariantType( stringType ) .setExactArgumentCount( 1 ) + .setParameterTypes(DATE) .register(); } @@ -940,9 +1026,11 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "week" ) .setInvariantType( integerType ) .setExactArgumentCount( 1 ) + .setParameterTypes(DATE) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "quarter" ) .setExactArgumentCount( 1 ) + .setParameterTypes(DATE) .setInvariantType( integerType ) .register(); } @@ -953,6 +1041,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DATE ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(DATE) .register(); } @@ -962,6 +1051,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DATE ) ) .setArgumentCountBetween( 1, 2 ) + .setParameterTypes(DATE, INTEGER) .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "last_date", "eomonth" ); } @@ -969,6 +1059,7 @@ public class CommonFunctionFactory { public static void ceiling_ceil(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "ceil" ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) // To avoid truncating to a specific data type, we default to using the argument type .setReturnTypeResolver( useArgType( 1 ) ) .register(); @@ -1009,6 +1100,7 @@ public class CommonFunctionFactory { public static void timestamp(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "timestamp" ) .setArgumentCountBetween( 1, 2 ) + //accepts (DATE,TIME) (DATE,INTEGER) or DATE or STRING .setInvariantType( queryEngine.getTypeConfiguration() .getBasicTypeRegistry() @@ -1020,6 +1112,7 @@ public class CommonFunctionFactory { public static void time(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "time" ) .setExactArgumentCount( 1 ) + //accepts TIME or STRING .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.TIME ) ) @@ -1029,6 +1122,7 @@ public class CommonFunctionFactory { public static void date(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "date" ) .setExactArgumentCount( 1 ) + //accepts DATE or STRING .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DATE ) ) @@ -1073,6 +1167,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(DATE) .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "week", "weekofyear" ); } @@ -1085,7 +1180,8 @@ public class CommonFunctionFactory { .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) -// .setMinArgumentCount( 1 ) + .setMinArgumentCount( 1 ) + .setParameterTypes(STRING) .setArgumentListSignature( "(string0[, string1[, ...]])" ) .register(); } @@ -1098,7 +1194,8 @@ public class CommonFunctionFactory { .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) -// .setMinArgumentCount( 1 ) + .setMinArgumentCount( 1 ) + .setParameterTypes(STRING) .setArgumentListSignature( "(string0[, string1[, ...]])" ) .register(); } @@ -1165,11 +1262,13 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "makedate" ) .setInvariantType( basicTypeRegistry.resolve( StandardBasicTypes.DATE ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(INTEGER, INTEGER) .setArgumentListSignature( "(year, dayofyear)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "maketime" ) .setInvariantType( basicTypeRegistry.resolve( StandardBasicTypes.TIME )) .setExactArgumentCount( 3 ) + .setParameterTypes(INTEGER, INTEGER, INTEGER) .setArgumentListSignature( "(hour, min, sec)" ) .register(); } @@ -1183,18 +1282,22 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "make_date" ) .setInvariantType( basicTypeRegistry.resolve( StandardBasicTypes.DATE ) ) .setExactArgumentCount( 3 ) + .setParameterTypes(INTEGER, INTEGER, INTEGER) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "make_time" ) .setInvariantType( basicTypeRegistry.resolve( StandardBasicTypes.TIME ) ) .setExactArgumentCount( 3 ) + .setParameterTypes(INTEGER, INTEGER, INTEGER) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "make_timestamp" ) .setInvariantType( timestampType ) .setExactArgumentCount( 6 ) + .setParameterTypes(INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "make_timestamptz" ) .setInvariantType( timestampType ) .setArgumentCountBetween( 6, 7 ) + .setParameterTypes(INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER, INTEGER) .register(); } @@ -1279,36 +1382,43 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "sin" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "cos" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "tan" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "asin" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "acos" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "atan" ) .setInvariantType( doubleType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "atan2" ) .setInvariantType( doubleType ) .setExactArgumentCount( 2 ) + .setParameterTypes(NUMERIC, NUMERIC) .register(); } @@ -1321,6 +1431,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(NUMERIC, NUMERIC) .register(); } @@ -1355,6 +1466,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(STRING) .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "length", "character_length" ); } @@ -1368,6 +1480,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(STRING) .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "character_length", "len" ); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "length", "len" ); @@ -1382,6 +1495,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(STRING) .setArgumentRenderingMode( argumentRenderingMode ) .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "character_length", "length" ); @@ -1393,6 +1507,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(STRING) .register(); } @@ -1402,6 +1517,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(STRING) .register(); } @@ -1411,6 +1527,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(STRING) .register(); } @@ -1423,6 +1540,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(STRING, STRING) .setArgumentListSignature( "(pattern in string)" ) .register(); } @@ -1433,6 +1551,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ) ) .setArgumentCountBetween( 2, 3 ) + .setParameterTypes(STRING, STRING, INTEGER) .setArgumentListSignature( "(pattern, string[, start])" ) .register(); } @@ -1446,6 +1565,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ) ) .setArgumentCountBetween( 2, 3 ) + .setParameterTypes(STRING, STRING, INTEGER) .setArgumentListSignature( "(pattern, string[, start])" ) .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "locate", "charindex" ); @@ -1458,7 +1578,8 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "locate", queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ), - "position(?1 in ?2)", "(position(?1 in substring(?2 from ?3))+?3)" + "position(?1 in ?2)", "(position(?1 in substring(?2 from ?3))+?3)", + STRING, STRING, INTEGER ) .setArgumentListSignature( "(pattern, string[, start])" ); } @@ -1469,7 +1590,8 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "substring", queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ), - "substring(?1 from ?2)", "substring(?1 from ?2 for ?3)" + "substring(?1 from ?2)", "substring(?1 from ?2 for ?3)", + STRING, INTEGER, INTEGER ) .setArgumentListSignature( "(string{ from|,} start[{ for|,} length])" ); } @@ -1483,6 +1605,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setArgumentCountBetween( 2, 3 ) + .setParameterTypes(STRING, INTEGER, INTEGER) .setArgumentListSignature( "(string{ from|,} start[{ for|,} length])" ) .register(); } @@ -1496,7 +1619,8 @@ public class CommonFunctionFactory { "substring", queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ), "substring(?1,?2,len(?1)-?2+1)", - "substring(?1,?2,?3)" + "substring(?1,?2,?3)", + STRING, INTEGER, INTEGER ) .setArgumentListSignature( "(string{ from|,} start[{ for|,} length])" ); } @@ -1511,6 +1635,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setArgumentCountBetween( 2, 3 ) + .setParameterTypes(STRING, INTEGER, INTEGER) .register(); } @@ -1519,7 +1644,7 @@ public class CommonFunctionFactory { .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) - .setExactArgumentCount( 4 ) + .setParameterTypes(STRING, INTEGER, INTEGER, STRING) .setArgumentListSignature( "(string, start, length, replacement)" ) .register(); } @@ -1536,6 +1661,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setExactArgumentCount( 4 ) + .setParameterTypes(STRING, INTEGER, INTEGER, STRING) .setArgumentListSignature( "(string, start, length, replacement)" ) .register(); } @@ -1548,7 +1674,8 @@ public class CommonFunctionFactory { "overlay", queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ), "overlay(?1 placing ?2 from ?3)", - "overlay(?1 placing ?2 from ?3 for ?4)" + "overlay(?1 placing ?2 from ?3 for ?4)", + STRING, STRING, INTEGER, INTEGER ) .setArgumentListSignature( "(string placing replacement from start[ for length])" ); } @@ -1563,7 +1690,8 @@ public class CommonFunctionFactory { //use character_length() here instead of length() //because DB2 doesn't like "length(?)" "overlay(?1 placing ?2 from ?3 for character_length(?2))", - "overlay(?1 placing ?2 from ?3 for ?4)" + "overlay(?1 placing ?2 from ?3 for ?4)", + STRING, STRING, INTEGER, INTEGER ) .setArgumentListSignature( "(string placing replacement from start[ for length])" ); } @@ -1574,6 +1702,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setExactArgumentCount( 3 ) + .setParameterTypes(STRING, STRING, STRING) .setArgumentListSignature( "(string, pattern, replacement)" ) .register(); } @@ -1587,6 +1716,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setExactArgumentCount( 3 ) + .setParameterTypes(STRING, STRING, STRING) .setArgumentListSignature( "(string, pattern, replacement)" ) .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "replace", "str_replace" ); @@ -1598,6 +1728,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setMinArgumentCount( 1 ) + .setParameterTypes(STRING) .setArgumentListSignature( "(string0[, string1[, ...]])" ) .register(); } @@ -1608,12 +1739,14 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "lower" ) .setInvariantType( stringType ) .setExactArgumentCount( 1 ) + .setParameterTypes(STRING) .setArgumentListSignature( "(string)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "upper" ) .setInvariantType( stringType ) .setExactArgumentCount( 1 ) + .setParameterTypes(STRING) .setArgumentListSignature( "(string)" ) .register(); } @@ -1621,6 +1754,7 @@ public class CommonFunctionFactory { public static void ascii(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "ascii" ) .setExactArgumentCount( 1 ) + .setParameterTypes(STRING) .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ) )//should it be BYTE?? @@ -1630,6 +1764,7 @@ public class CommonFunctionFactory { public static void char_chr(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "chr" ) .setExactArgumentCount( 1 ) + .setParameterTypes(INTEGER) .setInvariantType( queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.CHARACTER ) ) @@ -1655,6 +1790,7 @@ public class CommonFunctionFactory { // .setInvariantType( StandardBasicTypes.INTEGER ) .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(ANY, TEMPORAL) .setArgumentListSignature( "(field, arg)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datename" ) @@ -1662,6 +1798,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(ANY, TEMPORAL) .setArgumentListSignature( "(field, arg)" ) .register(); } @@ -1839,6 +1976,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().register( @@ -1875,33 +2013,39 @@ public class CommonFunctionFactory { // To avoid truncating to a specific data type, we default to using the argument type .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(NUMERIC, INTEGER) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "floor" ) // To avoid truncating to a specific data type, we default to using the argument type .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "ceiling" ) // To avoid truncating to a specific data type, we default to using the argument type .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "mod" ) // According to JPA spec 4.6.17.2.2. .setInvariantType( integerType ) .setExactArgumentCount( 2 ) + .setParameterTypes(INTEGER, INTEGER) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "abs" ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "sign" ) .setInvariantType( integerType ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "sqrt" ) @@ -1910,18 +2054,22 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "ln" ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "exp" ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "power" ) .setExactArgumentCount( 2 ) + .setParameterTypes(NUMERIC, NUMERIC) .setReturnTypeResolver( new PowerReturnTypeResolver( queryEngine.getTypeConfiguration() ) ) .register(); } @@ -1932,12 +2080,14 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(INTEGER, INTEGER) .register(); } public static void power_expLn(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "power", "exp(ln(?1)*?2)" ) .setExactArgumentCount( 2 ) + .setParameterTypes(NUMERIC, NUMERIC) .setReturnTypeResolver( new PowerReturnTypeResolver( queryEngine.getTypeConfiguration() ) ) .register(); } @@ -1945,6 +2095,7 @@ public class CommonFunctionFactory { public static void square(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "square" ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); } @@ -1954,6 +2105,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) ) .setExactArgumentCount( 1 ) + .setParameterTypes(NUMERIC) .register(); } @@ -2002,6 +2154,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(DATE, DATE) .setArgumentListSignature( "(end, start)" ) .register(); } @@ -2013,21 +2166,25 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "adddate" ) .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(DATE, INTEGER) .setArgumentListSignature( "(datetime, days)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "subdate" ) .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(DATE, INTEGER) .setArgumentListSignature( "(datetime, days)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "addtime" ) .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(TIME, INTEGER) .setArgumentListSignature( "(datetime, time)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "subtime" ) .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(TIME, INTEGER) .setArgumentListSignature( "(datetime, time)" ) .register(); } @@ -2037,6 +2194,7 @@ public class CommonFunctionFactory { .setReturnTypeResolver( useArgType( 1 ) ) .setArgumentListSignature( "(datetime, months)" ) .setExactArgumentCount( 2 ) + .setParameterTypes(DATE, INTEGER) .register(); } @@ -2047,6 +2205,7 @@ public class CommonFunctionFactory { ) .setExactArgumentCount( 2 ) .setArgumentListSignature( "(end, start)" ) + .setParameterTypes(DATE, DATE) .register(); } @@ -2056,6 +2215,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(DATE, DATE) .setArgumentListSignature( "(end, start)" ) .register(); } @@ -2066,6 +2226,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.LONG ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(TIME, TIME) .setArgumentListSignature( "(end, start)" ) .register(); } @@ -2077,31 +2238,37 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "years_between" ) .setInvariantType( integerType ) .setExactArgumentCount( 2 ) + .setParameterTypes(DATE, DATE) .setArgumentListSignature( "(end, start)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "months_between" ) .setInvariantType( integerType ) .setExactArgumentCount( 2 ) + .setParameterTypes(DATE, DATE) .setArgumentListSignature( "(end, start)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "days_between" ) .setInvariantType( integerType ) .setExactArgumentCount( 2 ) + .setParameterTypes(DATE, DATE) .setArgumentListSignature( "(end, start)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "hours_between" ) .setInvariantType( longType ) .setExactArgumentCount( 2 ) + .setParameterTypes(TIME, TIME) .setArgumentListSignature( "(end, start)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "minutes_between" ) .setInvariantType( longType ) .setExactArgumentCount( 2 ) + .setParameterTypes(TIME, TIME) .setArgumentListSignature( "(end, start)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "seconds_between" ) .setInvariantType( longType ) .setExactArgumentCount( 2 ) + .setParameterTypes(TIME, TIME) .setArgumentListSignature( "(end, start)" ) .register(); } @@ -2110,31 +2277,37 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "add_years" ) .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(DATE, INTEGER) .setArgumentListSignature( "(datetime, years)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "add_months" ) .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(DATE, INTEGER) .setArgumentListSignature( "(datetime, months)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "add_days" ) .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(DATE, INTEGER) .setArgumentListSignature( "(datetime, days)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "add_hours" ) .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(TIME, INTEGER) .setArgumentListSignature( "(datetime, hours)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "add_minutes" ) .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(TIME, INTEGER) .setArgumentListSignature( "(datetime, minutes)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "add_seconds" ) .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(TIME, INTEGER) .setArgumentListSignature( "(datetime, seconds)" ) .register(); } @@ -2148,6 +2321,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(TEMPORAL, STRING) .setArgumentListSignature( "(datetime as pattern)" ) .register(); } @@ -2163,6 +2337,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(TEMPORAL, STRING) .setArgumentListSignature( "(datetime as pattern)" ) .register(); } @@ -2178,6 +2353,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(TEMPORAL, STRING) .setArgumentListSignature( "(datetime as pattern)" ) .register(); } @@ -2193,6 +2369,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(TEMPORAL, STRING) .setArgumentListSignature( "(datetime as pattern)" ) .register(); } @@ -2206,6 +2383,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(STRING, ANY) .setArgumentListSignature("(string as collation)") .register(); } @@ -2219,6 +2397,7 @@ public class CommonFunctionFactory { queryEngine.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(STRING, ANY) .setArgumentListSignature("(string as collation)") .register(); } @@ -2231,6 +2410,7 @@ public class CommonFunctionFactory { .resolve( StandardBasicTypes.TIMESTAMP ) ) .setExactArgumentCount( 2 ) + .setParameterTypes(ANY, TEMPORAL) .setArgumentListSignature( "(field, datetime)" ) .register(); } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/CurrentFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/CurrentFunction.java index d8d375041e..d16ebc9164 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/CurrentFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/CurrentFunction.java @@ -24,7 +24,7 @@ public class CurrentFunction private final String sql; - public CurrentFunction(String name, String sql, BasicType type) { + public CurrentFunction(String name, String sql, BasicType type) { super( name, StandardArgumentsValidators.NO_ARGS, diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2FormatEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2FormatEmulation.java index ee1b95a7a6..02f5a8791e 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2FormatEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2FormatEmulation.java @@ -7,8 +7,9 @@ package org.hibernate.dialect.function; import org.hibernate.dialect.OracleDialect; -import org.hibernate.query.spi.QueryEngine; 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.StandardFunctionReturnTypeResolvers; import org.hibernate.sql.ast.SqlAstTranslator; @@ -22,6 +23,9 @@ import org.hibernate.type.spi.TypeConfiguration; import java.util.List; 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 * the format pattern. So just split the pattern into bits, call @@ -36,7 +40,7 @@ public class DB2FormatEmulation public DB2FormatEmulation(TypeConfiguration typeConfiguration) { super( "format", - StandardArgumentsValidators.exactly( 2 ), + new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 2 ), TEMPORAL, STRING ), StandardFunctionReturnTypeResolvers.invariant( typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyLpadEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyLpadEmulation.java index 41143ddfef..6697e5c750 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyLpadEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyLpadEmulation.java @@ -10,6 +10,8 @@ import java.util.List; import org.hibernate.query.spi.QueryEngine; 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.StandardFunctionReturnTypeResolvers; 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.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. * @@ -30,7 +35,7 @@ public class DerbyLpadEmulation public DerbyLpadEmulation(TypeConfiguration typeConfiguration) { super( "lpad", - StandardArgumentsValidators.exactly( 2 ), + new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 2 ), STRING, INTEGER ), StandardFunctionReturnTypeResolvers.invariant( typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyRpadEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyRpadEmulation.java index b1254e2ebc..0a4e96d1ee 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyRpadEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyRpadEmulation.java @@ -10,6 +10,7 @@ import java.util.List; import org.hibernate.query.spi.QueryEngine; 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.StandardFunctionReturnTypeResolvers; 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.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. * @@ -30,7 +34,7 @@ public class DerbyRpadEmulation public DerbyRpadEmulation(TypeConfiguration typeConfiguration) { super( "rpad", - StandardArgumentsValidators.exactly( 2 ), + new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 2 ), STRING, INTEGER ), StandardFunctionReturnTypeResolvers.invariant( typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/EveryAnyEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/EveryAnyEmulation.java index 68a3f3342f..60918c71d7 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/EveryAnyEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/EveryAnyEmulation.java @@ -8,16 +8,11 @@ package org.hibernate.dialect.function; 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.FunctionKind; -import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; -import org.hibernate.query.sqm.produce.function.ArgumentsValidator; -import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; +import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; 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.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; 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.spi.TypeConfiguration; +import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.BOOLEAN; + /** * @author Jan Schatteman */ @@ -36,7 +33,7 @@ public class EveryAnyEmulation extends AbstractSqmSelfRenderingFunctionDescripto super( every ? "every" : "any", FunctionKind.AGGREGATE, - StandardArgumentsValidators.exactly( 1 ), + new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 1 ), BOOLEAN ), StandardFunctionReturnTypeResolvers.invariant( typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.BOOLEAN ) ) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/ExtractFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/ExtractFunction.java index 7845c9ff13..2e56a3c5ef 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/ExtractFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/ExtractFunction.java @@ -14,6 +14,8 @@ import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor; import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; +import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; +import org.hibernate.query.sqm.produce.function.ArgumentsValidator; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.query.sqm.tree.SqmTypedNode; @@ -27,6 +29,8 @@ import java.util.List; import static java.util.Arrays.asList; import static org.hibernate.query.BinaryArithmeticOperator.*; 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; /** @@ -40,7 +44,10 @@ public class ExtractFunction public ExtractFunction(Dialect dialect) { super( "extract", - StandardArgumentsValidators.exactly( 2 ), + new ArgumentTypesValidator( + StandardArgumentsValidators.exactly( 2 ), + ANY, TEMPORAL + ), StandardFunctionReturnTypeResolvers.useArgType( 1 ) ); this.dialect = dialect; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/InsertSubstringOverlayEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/InsertSubstringOverlayEmulation.java index 5475a5b2a0..44b8ec1617 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/InsertSubstringOverlayEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/InsertSubstringOverlayEmulation.java @@ -10,10 +10,10 @@ import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; import org.hibernate.query.BinaryArithmeticOperator; import org.hibernate.query.ComparisonOperator; 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.SelfRenderingSqmFunction; import org.hibernate.query.sqm.function.SqmFunctionDescriptor; +import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.query.sqm.tree.SqmTypedNode; @@ -31,6 +31,8 @@ import java.util.List; import jakarta.persistence.criteria.Expression; 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 @@ -43,7 +45,10 @@ public class InsertSubstringOverlayEmulation public InsertSubstringOverlayEmulation(TypeConfiguration typeConfiguration, boolean strictSubstring) { super( "overlay", - StandardArgumentsValidators.between( 3, 4 ), + new ArgumentTypesValidator( + StandardArgumentsValidators.between( 3, 4 ), + STRING, INTEGER, INTEGER, STRING + ), StandardFunctionReturnTypeResolvers.invariant( typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/LpadRpadPadEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/LpadRpadPadEmulation.java index 68e9d6996f..f47ca1f1fa 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/LpadRpadPadEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/LpadRpadPadEmulation.java @@ -11,6 +11,7 @@ import org.hibernate.query.TrimSpec; import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor; import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; +import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.query.sqm.tree.SqmTypedNode; @@ -21,6 +22,9 @@ import org.hibernate.type.spi.TypeConfiguration; import java.util.List; 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 @@ -31,7 +35,10 @@ public class LpadRpadPadEmulation public LpadRpadPadEmulation(TypeConfiguration typeConfiguration) { super( "pad", - StandardArgumentsValidators.between( 3, 4 ), + new ArgumentTypesValidator( + StandardArgumentsValidators.between( 3, 4 ), + STRING, INTEGER, ANY, STRING + ), StandardFunctionReturnTypeResolvers.invariant( typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/SQLServerEveryAnyEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/SQLServerEveryAnyEmulation.java index e24b91f6e3..d2bf908886 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/SQLServerEveryAnyEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/SQLServerEveryAnyEmulation.java @@ -10,6 +10,7 @@ import java.util.List; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.FunctionKind; +import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; 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.spi.TypeConfiguration; +import static org.hibernate.query.sqm.produce.function.ArgumentsValidator.ParameterType.BOOLEAN; + /** * @author Jan Schatteman */ @@ -30,7 +33,7 @@ public class SQLServerEveryAnyEmulation extends AbstractSqmSelfRenderingFunction super( every ? "every" : "any", FunctionKind.AGGREGATE, - StandardArgumentsValidators.exactly( 1 ), + new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 1 ), BOOLEAN ), StandardFunctionReturnTypeResolvers.invariant( typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.BOOLEAN ) ) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/TransactSQLStrFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/TransactSQLStrFunction.java index 08d623d215..9b78da29de 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/TransactSQLStrFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/TransactSQLStrFunction.java @@ -46,7 +46,12 @@ public class TransactSQLStrFunction extends CastStrEmulation implements Function QueryEngine queryEngine, TypeConfiguration typeConfiguration) { if ( arguments.size() == 1 ) { - return super.generateSqmFunctionExpression( arguments, impliedResultType, queryEngine, typeConfiguration ); + return super.generateSqmFunctionExpression( + arguments, + impliedResultType, + queryEngine, + typeConfiguration + ); } return new SelfRenderingSqmFunction<>( @@ -54,6 +59,7 @@ public class TransactSQLStrFunction extends CastStrEmulation implements Function this, arguments, impliedResultType, + getArgumentsValidator(), getReturnTypeResolver(), queryEngine.getCriteriaBuilder(), getName() diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/TrimFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/TrimFunction.java index fa454e0ba5..e9aeaba1bb 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/TrimFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/TrimFunction.java @@ -8,8 +8,8 @@ package org.hibernate.dialect.function; import org.hibernate.dialect.Dialect; import org.hibernate.query.TrimSpec; -import org.hibernate.query.spi.QueryEngine; 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.StandardFunctionReturnTypeResolvers; 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.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 */ @@ -35,7 +38,10 @@ public class TrimFunction extends AbstractSqmSelfRenderingFunctionDescriptor { public TrimFunction(Dialect dialect, TypeConfiguration typeConfiguration) { super( "trim", - StandardArgumentsValidators.exactly( 3 ), + new ArgumentTypesValidator( + StandardArgumentsValidators.exactly( 3 ), + ANY, STRING, STRING + ), StandardFunctionReturnTypeResolvers.invariant( typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ) ) diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmFunctionDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmFunctionDescriptor.java index 967a948767..62946704e2 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmFunctionDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmFunctionDescriptor.java @@ -65,6 +65,11 @@ public abstract class AbstractSqmFunctionDescriptor implements SqmFunctionDescri return getReturnSignature() + name + getArgumentListSignature(); } + @Override + public ArgumentsValidator getArgumentsValidator() { + return argumentsValidator; + } + public String getReturnSignature() { String result = returnTypeResolver.getReturnType(); return result.isEmpty() ? "" : result + " "; @@ -98,7 +103,7 @@ public abstract class AbstractSqmFunctionDescriptor implements SqmFunctionDescri AllowableFunctionReturnType impliedResultType, QueryEngine queryEngine, TypeConfiguration typeConfiguration) { - argumentsValidator.validate( arguments ); + argumentsValidator.validate( arguments, getName() ); return generateSqmFunctionExpression( arguments, @@ -115,7 +120,7 @@ public abstract class AbstractSqmFunctionDescriptor implements SqmFunctionDescri AllowableFunctionReturnType impliedResultType, QueryEngine queryEngine, TypeConfiguration typeConfiguration) { - argumentsValidator.validate( arguments ); + argumentsValidator.validate( arguments, getName() ); return generateSqmAggregateFunctionExpression( arguments, @@ -130,8 +135,7 @@ public abstract class AbstractSqmFunctionDescriptor implements SqmFunctionDescri * 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 * 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 */ protected abstract SelfRenderingSqmFunction generateSqmFunctionExpression( diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmSelfRenderingFunctionDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmSelfRenderingFunctionDescriptor.java index 10d6cf35b3..0ffa9f3f0b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmSelfRenderingFunctionDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmSelfRenderingFunctionDescriptor.java @@ -64,6 +64,7 @@ public abstract class AbstractSqmSelfRenderingFunctionDescriptor this::render, arguments, impliedResultType, + getArgumentsValidator(), getReturnTypeResolver(), queryEngine.getCriteriaBuilder(), getName() @@ -86,6 +87,7 @@ public abstract class AbstractSqmSelfRenderingFunctionDescriptor arguments, filter, impliedResultType, + getArgumentsValidator(), getReturnTypeResolver(), queryEngine.getCriteriaBuilder(), getName() diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/JdbcEscapeFunctionDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/JdbcEscapeFunctionDescriptor.java index 0bca4085df..c496ed69e2 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/JdbcEscapeFunctionDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/JdbcEscapeFunctionDescriptor.java @@ -55,6 +55,7 @@ public class JdbcEscapeFunctionDescriptor }, arguments, impliedResultType, + getArgumentsValidator(), getReturnTypeResolver(), queryEngine.getCriteriaBuilder(), getName()); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/MultipatternSqmFunctionDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/MultipatternSqmFunctionDescriptor.java index 4f65303b1f..fcf6a78b1f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/MultipatternSqmFunctionDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/MultipatternSqmFunctionDescriptor.java @@ -8,9 +8,12 @@ package org.hibernate.query.sqm.function; import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; 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.StandardFunctionReturnTypeResolvers; import org.hibernate.query.sqm.tree.SqmTypedNode; +import org.hibernate.type.BasicType; import org.hibernate.type.spi.TypeConfiguration; import java.util.List; @@ -48,21 +51,25 @@ public class MultipatternSqmFunctionDescriptor extends AbstractSqmFunctionDescri * template. The array must be padded with leading nulls * where there is no overloaded form corresponding to * lower arities. - * - * @param name + * @param name * @param functions the function templates to delegate to, - * where array position corresponds to + * @param type */ public MultipatternSqmFunctionDescriptor( - String name, SqmFunctionDescriptor[] functions, - FunctionReturnTypeResolver type) { + String name, + SqmFunctionDescriptor[] functions, + BasicType type, + ParameterType... parameterTypes) { super( name, - StandardArgumentsValidators.between( - first(functions), - last(functions) + new ArgumentTypesValidator( + StandardArgumentsValidators.between( + first(functions), + last(functions) + ), + parameterTypes ), - type + StandardFunctionReturnTypeResolvers.invariant( type ) ); this.functions = functions; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingFunctionSqlAstExpression.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingFunctionSqlAstExpression.java index 7a75da7ba4..369dc81fbd 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingFunctionSqlAstExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingFunctionSqlAstExpression.java @@ -21,6 +21,7 @@ import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; import org.hibernate.query.SemanticException; import org.hibernate.query.sqm.sql.internal.DomainResultProducer; 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.SqlAstCreationState; import org.hibernate.sql.ast.spi.SqlExpressionResolver; @@ -188,8 +189,7 @@ public class SelfRenderingFunctionSqlAstExpression } @Override - public int forEachJdbcType( - int offset, IndexedConsumer action) { + public int forEachJdbcType(int offset, IndexedConsumer action) { throw new NotYetImplementedFor6Exception( getClass() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmAggregateFunction.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmAggregateFunction.java index 0431dbab42..2a8bca970d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmAggregateFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmAggregateFunction.java @@ -10,6 +10,7 @@ import java.util.List; import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; 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.sql.BaseSqmToSqlAstConverter; import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; @@ -34,10 +35,11 @@ public class SelfRenderingSqmAggregateFunction extends SelfRenderingSqmFuncti List> arguments, SqmPredicate filter, AllowableFunctionReturnType impliedResultType, + ArgumentsValidator argumentsValidator, FunctionReturnTypeResolver returnTypeResolver, NodeBuilder nodeBuilder, String name) { - super( descriptor, renderingSupport, arguments, impliedResultType, returnTypeResolver, nodeBuilder, name ); + super( descriptor, renderingSupport, arguments, impliedResultType, argumentsValidator, returnTypeResolver, nodeBuilder, name ); this.filter = filter; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmFunction.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmFunction.java index dae6a33354..88b5deec40 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmFunction.java @@ -11,16 +11,19 @@ import java.util.List; import org.hibernate.metamodel.MappingMetamodel; import org.hibernate.metamodel.mapping.BasicValuedMapping; +import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; import org.hibernate.query.sqm.NodeBuilder; 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.sql.SqmToSqlAstConverter; import org.hibernate.query.sqm.tree.SqmTypedNode; import org.hibernate.query.sqm.tree.SqmVisitableNode; import org.hibernate.query.sqm.tree.expression.SqmFunction; import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.type.spi.TypeConfiguration; import static java.util.Collections.emptyList; @@ -30,6 +33,7 @@ import static java.util.Collections.emptyList; */ public class SelfRenderingSqmFunction extends SqmFunction { private final AllowableFunctionReturnType impliedResultType; + private final ArgumentsValidator argumentsValidator; private final FunctionReturnTypeResolver returnTypeResolver; private final FunctionRenderingSupport renderingSupport; private AllowableFunctionReturnType resultType; @@ -39,12 +43,14 @@ public class SelfRenderingSqmFunction extends SqmFunction { FunctionRenderingSupport renderingSupport, List> arguments, AllowableFunctionReturnType impliedResultType, + ArgumentsValidator argumentsValidator, FunctionReturnTypeResolver returnTypeResolver, NodeBuilder nodeBuilder, String name) { super( name, descriptor, impliedResultType, arguments, nodeBuilder ); this.renderingSupport = renderingSupport; this.impliedResultType = impliedResultType; + this.argumentsValidator = argumentsValidator; this.returnTypeResolver = returnTypeResolver; } @@ -70,10 +76,14 @@ public class SelfRenderingSqmFunction extends SqmFunction { walker.getCreationContext().getDomainModel().getTypeConfiguration() ); + List arguments = resolveSqlAstArguments( getArguments(), walker ); + if ( argumentsValidator != null ) { + argumentsValidator.validateSqlTypes( arguments, getFunctionName() ); + } return new SelfRenderingFunctionSqlAstExpression( getFunctionName(), getRenderingSupport(), - resolveSqlAstArguments( getArguments(), walker ), + arguments, resultType, resultType == null ? null : getMappingModelExpressable( walker, resultType ) ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SqmFunctionDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SqmFunctionDescriptor.java index ea433fef38..a4489c8795 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SqmFunctionDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SqmFunctionDescriptor.java @@ -8,6 +8,7 @@ package org.hibernate.query.sqm.function; import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; 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.predicate.SqmPredicate; import org.hibernate.type.spi.TypeConfiguration; @@ -122,4 +123,6 @@ public interface SqmFunctionDescriptor { default FunctionKind getFunctionKind() { return FunctionKind.NORMAL; } + + ArgumentsValidator getArgumentsValidator(); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SqmFunctionRegistry.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SqmFunctionRegistry.java index f83a822206..8b7f7cb51b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SqmFunctionRegistry.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SqmFunctionRegistry.java @@ -11,9 +11,9 @@ import java.util.Map; import java.util.TreeMap; 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.PatternFunctionDescriptorBuilder; -import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.type.BasicType; import org.jboss.logging.Logger; @@ -254,8 +254,9 @@ public class SqmFunctionRegistry { String name, BasicType type, String pattern0, - String pattern1) { - return registerPatterns( name, type, pattern0, pattern1 ); + String pattern1, + ParameterType parameterType) { + return registerPatterns( name, type, new ParameterType[]{parameterType}, pattern0, pattern1 ); } /** @@ -265,10 +266,14 @@ public class SqmFunctionRegistry { */ public MultipatternSqmFunctionDescriptor registerUnaryBinaryPattern( String name, - BasicType type, + BasicType type, String pattern1, - String pattern2) { - return registerPatterns( name, type, null, pattern1, pattern2 ); + String 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( String name, - BasicType type, + BasicType type, String pattern2, - String pattern3) { - return registerPatterns( name, type, null, null, pattern2, pattern3 ); + String 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( String name, - BasicType type, + BasicType type, String pattern3, - String pattern4) { - return registerPatterns( name, type, null, null, null, pattern3, pattern4 ); + String 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( String name, - BasicType type, + BasicType type, + ParameterType[] parameterTypes, String... patterns) { SqmFunctionDescriptor[] descriptors = new SqmFunctionDescriptor[patterns.length]; @@ -309,15 +326,14 @@ public class SqmFunctionRegistry { descriptors[i] = patternDescriptorBuilder( name, pattern ) .setExactArgumentCount( i ) + .setParameterTypes( parameterTypes ) .setInvariantType( type ) .descriptor(); } } - MultipatternSqmFunctionDescriptor function = new MultipatternSqmFunctionDescriptor( - name, descriptors, - StandardFunctionReturnTypeResolvers.invariant( type ) - ); + MultipatternSqmFunctionDescriptor function = + new MultipatternSqmFunctionDescriptor( name, descriptors, type, parameterTypes ); register( name, function ); return function; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentTypesValidator.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentTypesValidator.java new file mode 100644 index 0000000000..cfe68c64b3 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentTypesValidator.java @@ -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 . + */ +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> arguments, String functionName) { + delegate.validate(arguments, functionName); + } + + @Override + public void validateSqlTypes(List 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 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; + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentsValidator.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentsValidator.java index f13285328a..12d2be0bbc 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentsValidator.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentsValidator.java @@ -7,6 +7,7 @@ package org.hibernate.query.sqm.produce.function; import org.hibernate.query.sqm.tree.SqmTypedNode; +import org.hibernate.sql.ast.tree.SqlAstNode; import java.util.List; @@ -15,12 +16,62 @@ import java.util.List; */ 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> arguments); + void validate(List> arguments, String functionName); default String getSignature() { return "( ... )"; } + /** + * Perform validation that requires the {@link SqlAstNode} tree and + * assigned JDBC types. + */ + default void validateSqlTypes(List arguments, String functionName) {} + + /** + * A mini-"type system" for HQL function parameters. + *

+ * 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 + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/NamedFunctionDescriptorBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/NamedFunctionDescriptorBuilder.java index 46d2656de8..b3725cebd0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/NamedFunctionDescriptorBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/NamedFunctionDescriptorBuilder.java @@ -64,11 +64,16 @@ public class NamedFunctionDescriptorBuilder { return this; } - public NamedFunctionDescriptorBuilder setInvariantType(BasicType invariantType) { + public NamedFunctionDescriptorBuilder setInvariantType(BasicType invariantType) { setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant( invariantType ) ); return this; } + public NamedFunctionDescriptorBuilder setParameterTypes(ArgumentsValidator.ParameterType... types) { + setArgumentsValidator( new ArgumentTypesValidator(argumentsValidator, types) ); + return this; + } + public NamedFunctionDescriptorBuilder setUseParenthesesWhenNoArgs(boolean useParenthesesWhenNoArgs) { this.useParenthesesWhenNoArgs = useParenthesesWhenNoArgs; return this; @@ -100,4 +105,5 @@ public class NamedFunctionDescriptorBuilder { argumentRenderingMode ); } + } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/PatternFunctionDescriptorBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/PatternFunctionDescriptorBuilder.java index dc0ae220e8..0133b251e8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/PatternFunctionDescriptorBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/PatternFunctionDescriptorBuilder.java @@ -44,6 +44,15 @@ public class PatternFunctionDescriptorBuilder { 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) { return setArgumentsValidator( StandardArgumentsValidators.exactly( exactArgumentCount ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/StandardArgumentsValidators.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/StandardArgumentsValidators.java index a2029dfc7a..9a3e89cf24 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/StandardArgumentsValidators.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/StandardArgumentsValidators.java @@ -28,7 +28,7 @@ public final class StandardArgumentsValidators { */ public static final ArgumentsValidator NONE = new ArgumentsValidator() { @Override - public void validate(List> arguments) {} + public void validate(List> arguments, String functionName) {} @Override public String getSignature() { @@ -41,9 +41,16 @@ public final class StandardArgumentsValidators { */ public static final ArgumentsValidator NO_ARGS = new ArgumentsValidator() { @Override - public void validate(List> arguments) { + public void validate(List> arguments, String functionName) { 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() { @Override - public void validate(List> arguments) { + public void validate(List> arguments, String functionName) { if (arguments.size() < minNumOfArgs) { throw new QueryException( String.format( 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, arguments.size() ) @@ -92,12 +100,13 @@ public final class StandardArgumentsValidators { public static ArgumentsValidator exactly(int number) { return new ArgumentsValidator() { @Override - public void validate(List> arguments) { + public void validate(List> arguments, String functionName) { if (arguments.size() != number) { throw new QueryException( String.format( Locale.ROOT, - "Function requires %d arguments, but %d found", + "Function %s() has %d parameters, but %d arguments given", + functionName, number, arguments.size() ) @@ -127,12 +136,13 @@ public final class StandardArgumentsValidators { public static ArgumentsValidator max(int maxNumOfArgs) { return new ArgumentsValidator() { @Override - public void validate(List> arguments) { + public void validate(List> arguments, String functionName) { if (arguments.size() > maxNumOfArgs) { throw new QueryException( String.format( Locale.ROOT, - "Function requires %d or fewer arguments, but %d found", + "Function %s() allows at most %d arguments, but %d arguments given", + functionName, maxNumOfArgs, arguments.size() ) @@ -158,12 +168,13 @@ public final class StandardArgumentsValidators { public static ArgumentsValidator between(int minNumOfArgs, int maxNumOfArgs) { return new ArgumentsValidator() { @Override - public void validate(List> arguments) { + public void validate(List> arguments, String functionName) { if (arguments.size() < minNumOfArgs || arguments.size() > maxNumOfArgs) { throw new QueryException( String.format( 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, maxNumOfArgs, arguments.size() @@ -191,14 +202,15 @@ public final class StandardArgumentsValidators { } public static ArgumentsValidator of(Class javaType) { - return arguments -> arguments.forEach( + return (arguments, functionName) -> arguments.forEach( arg -> { Class argType = arg.getNodeJavaTypeDescriptor().getJavaTypeClass(); if ( !javaType.isAssignableFrom( argType ) ) { throw new QueryException( String.format( 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(), argType.getName() ) @@ -213,8 +225,8 @@ public final class StandardArgumentsValidators { } public static ArgumentsValidator composite(List validators) { - return arguments -> validators.forEach( - individualValidator -> individualValidator.validate( arguments ) + return (arguments, functionName) -> validators.forEach( + individualValidator -> individualValidator.validate( arguments, functionName) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/SqlTypes.java b/hibernate-core/src/main/java/org/hibernate/type/SqlTypes.java index 1df8982ae9..7631f471ef 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/SqlTypes.java +++ b/hibernate-core/src/main/java/org/hibernate/type/SqlTypes.java @@ -452,4 +452,139 @@ public class 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; + } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ASTParserLoadingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ASTParserLoadingTest.java index 77ef413bee..83b7793497 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ASTParserLoadingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ASTParserLoadingTest.java @@ -35,10 +35,7 @@ import org.hibernate.dialect.DerbyDialect; import org.hibernate.dialect.H2Dialect; import org.hibernate.dialect.HSQLDialect; import org.hibernate.dialect.MySQLDialect; -import org.hibernate.dialect.Oracle8iDialect; import org.hibernate.dialect.PostgreSQLDialect; -import org.hibernate.dialect.SQLServerDialect; -import org.hibernate.dialect.SybaseDialect; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.internal.util.StringHelper; import org.hibernate.loader.MultipleBagFetchException; @@ -300,8 +297,8 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase { inTransaction( (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 Constructor result = (Constructor) session.createQuery(qry ).setParameter( "id", created.getId() ).uniqueResult(); + 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 = session.createQuery(qry, Constructor.class).setParameter( "id", created.getId() ).uniqueResult(); assertEquals( 1, Constructor.getConstructorExecutionCount() ); Constructor expected = new Constructor( created.getId(), @@ -3697,29 +3694,11 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase { hql = "from Animal a where mod(16, 4) = 4"; session.createQuery(hql).list(); - /** - * PostgreSQL >= 8.3.7 typecasts are no longer automatically allowed - * http://www.postgresql.org/docs/current/static/release-8-3.html - */ - 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(); - 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(); /*hql = "select object(a) from Animal a where CURRENT_DATE = :p1 or CURRENT_TIME = :p2 or CURRENT_TIMESTAMP = :p3"; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java index 67643667e1..8f71c0da5e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java @@ -6,6 +6,7 @@ */ package org.hibernate.orm.test.query.hql; +import org.hibernate.QueryException; import org.hibernate.dialect.DerbyDialect; import org.hibernate.testing.orm.domain.StandardDomainModel; @@ -29,12 +30,9 @@ import java.time.LocalTime; import org.hamcrest.Matchers; -import static org.hamcrest.CoreMatchers.anyOf; -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.CoreMatchers.*; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.fail; /** * @author Gavin King @@ -206,6 +204,19 @@ public class FunctionTests { 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 @@ -217,6 +228,19 @@ public class FunctionTests { 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 @@ -234,6 +258,19 @@ public class FunctionTests { 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 @@ -324,6 +361,19 @@ public class FunctionTests { 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 @@ -342,6 +392,19 @@ public class FunctionTests { 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 @@ -359,6 +422,31 @@ public class FunctionTests { 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 diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/function/OrderByFragmentFunction.java b/hibernate-envers/src/main/java/org/hibernate/envers/function/OrderByFragmentFunction.java index b80ff7cb1d..c7979537af 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/function/OrderByFragmentFunction.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/function/OrderByFragmentFunction.java @@ -61,6 +61,7 @@ public class OrderByFragmentFunction extends AbstractSqmFunctionDescriptor { null, arguments, impliedResultType, + getArgumentsValidator(), getReturnTypeResolver(), queryEngine.getCriteriaBuilder(), getName() diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOObjectProperty.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOObjectProperty.java index 71f734397e..33d7a6a99f 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOObjectProperty.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOObjectProperty.java @@ -16,6 +16,7 @@ import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; 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.predicate.SqmPredicate; import org.hibernate.type.BasicTypeReference; @@ -53,6 +54,11 @@ class SDOObjectProperty implements SqmFunctionDescriptor { return true; } + @Override + public ArgumentsValidator getArgumentsValidator() { + return null; + } + /* * (non-Javadoc) *