diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseDialect.java index 09d6ccbb2877..b4dc15316072 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseDialect.java @@ -395,20 +395,26 @@ public String castPattern(CastType from, CastType to) { } break; case INTEGER_BOOLEAN: - result = BooleanDecoder.toIntegerBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "1", "0" ) + : BooleanDecoder.toIntegerBoolean( from ); if ( result != null ) { return result; } break; case YN_BOOLEAN: - result = BooleanDecoder.toYesNoBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "'Y'", "'N'" ) + : BooleanDecoder.toYesNoBoolean( from ); if ( result != null ) { return result; } break; case BOOLEAN: case TF_BOOLEAN: - result = BooleanDecoder.toTrueFalseBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "'T'", "'F'" ) + : BooleanDecoder.toTrueFalseBoolean( from ); if ( result != null ) { return result; } @@ -704,4 +710,14 @@ public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() { }; } + @Override + public String getDual() { + return "dual"; + } + + @Override + public String getFromDualForSelectOnly() { + return " from " + getDual(); + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseSqlAstTranslator.java index 0ab86ef3ef16..a258f1d977d3 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseSqlAstTranslator.java @@ -221,16 +221,6 @@ public void visitQueryPartTableReference(QueryPartTableReference tableReference) emulateQueryPartTableReferenceColumnAliasing( tableReference ); } - @Override - protected String getDual() { - return "dual"; - } - - @Override - protected String getFromDualForSelectOnly() { - return " from " + getDual(); - } - @Override protected boolean needsRecursiveKeywordInWithClause() { return false; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDDialect.java index d73897a57aa6..1c4a5fbbca13 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDDialect.java @@ -517,4 +517,16 @@ private void timediff( sqlAppender.append( diffUnit.conversionFactor( toUnit, this ) ); } + @Override + public String getDual() { + //TODO: is this really needed? + //TODO: would "from table({0})" be better? + return "db_root"; + } + + @Override + public String getFromDualForSelectOnly() { + return " from " + getDual(); + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDSqlAstTranslator.java index e187406b3baa..5c59c6a29de3 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDSqlAstTranslator.java @@ -80,16 +80,4 @@ protected boolean supportsRowValueConstructorSyntaxInInList() { protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { return false; } - - @Override - protected String getDual() { - //TODO: is this really needed? - //TODO: would "from table({0})" be better? - return "db_root"; - } - - @Override - protected String getFromDualForSelectOnly() { - return " from " + getDual(); - } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java index c0cebad8c745..4aa408b64b93 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java @@ -70,6 +70,7 @@ import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.procedure.internal.DB2CallableStatementSupport; import org.hibernate.procedure.spi.CallableStatementSupport; +import org.hibernate.query.sqm.CastType; import org.hibernate.query.sqm.IntervalType; import org.hibernate.query.sqm.TemporalUnit; import org.hibernate.query.sqm.mutation.internal.cte.CteInsertStrategy; @@ -1141,6 +1142,16 @@ public String extractPattern(TemporalUnit unit) { return super.extractPattern( unit ); } + @Override + public String castPattern(CastType from, CastType to) { + if ( from == CastType.STRING && to == CastType.BOOLEAN ) { + return "cast(?1 as ?2)"; + } + else { + return super.castPattern( from, to ); + } + } + @Override public int getInExpressionCountLimit() { return BIND_PARAMETERS_NUMBER_LIMIT; @@ -1208,4 +1219,14 @@ public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() { public boolean supportsFromClauseInUpdate() { return getDB2Version().isSameOrAfter( 11 ); } + + @Override + public String getDual() { + return "sysibm.dual"; + } + + @Override + public String getFromDualForSelectOnly() { + return " from " + getDual(); + } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacySqlAstTranslator.java index 7f516f7e69db..5f75a3062dd3 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacySqlAstTranslator.java @@ -606,16 +606,6 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { return false; } - @Override - protected String getDual() { - return "sysibm.dual"; - } - - @Override - protected String getFromDualForSelectOnly() { - return " from " + getDual(); - } - @Override protected void visitReturningColumns(List returningColumns) { // For DB2 we use #renderReturningClause to render a wrapper around the DML statement diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacyDialect.java index 70e098ece421..df1b6bfa4df1 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacyDialect.java @@ -1055,6 +1055,11 @@ public boolean supportsWindowFunctions() { return getVersion().isSameOrAfter( 10, 4 ); } + @Override + public boolean supportsValuesList() { + return true; + } + @Override public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) throws SQLException { @@ -1066,4 +1071,14 @@ public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, D public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() { return DmlTargetColumnQualifierSupport.TABLE_ALIAS; } + + @Override + public String getDual() { + return "(values 0)"; + } + + @Override + public String getFromDualForSelectOnly() { + return " from " + getDual() + " dual"; + } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacySqlAstTranslator.java index 3aea1a5ebc1d..d3fee18516ff 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacySqlAstTranslator.java @@ -302,16 +302,6 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { return false; } - @Override - protected String getDual() { - return "(values 0)"; - } - - @Override - protected String getFromDualForSelectOnly() { - return " from " + getDual() + " dual"; - } - @Override protected boolean needsRowsToSkip() { return !supportsOffsetFetchClause(); 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 6f47f288fa0e..380fea18a3f8 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 @@ -403,25 +403,33 @@ public String castPattern(CastType from, CastType to) { } break; case BOOLEAN: - result = BooleanDecoder.toBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "true", "false" ) + : BooleanDecoder.toBoolean( from ); if ( result != null ) { return result; } break; case INTEGER_BOOLEAN: - result = BooleanDecoder.toIntegerBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "1", "0" ) + : BooleanDecoder.toIntegerBoolean( from ); if ( result != null ) { return result; } break; case YN_BOOLEAN: - result = BooleanDecoder.toYesNoBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "'Y'", "'N'" ) + : BooleanDecoder.toYesNoBoolean( from ); if ( result != null ) { return result; } break; case TF_BOOLEAN: - result = BooleanDecoder.toTrueFalseBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "'T'", "'F'" ) + : BooleanDecoder.toTrueFalseBoolean( from ); if ( result != null ) { return result; } @@ -1096,4 +1104,14 @@ else if ( supportsOffset && temporalAccessor instanceof Instant ) { } } + + @Override + public String getDual() { + return "rdb$database"; + } + + @Override + public String getFromDualForSelectOnly() { + return " from " + getDual(); + } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdSqlAstTranslator.java index 6f9c1215fda9..84ca5355bfa3 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdSqlAstTranslator.java @@ -262,16 +262,6 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { return false; } - @Override - protected String getDual() { - return "rdb$database"; - } - - @Override - protected String getFromDualForSelectOnly() { - return " from " + getDual(); - } - private boolean supportsOffsetFetchClause() { return getDialect().getVersion().isSameOrAfter( 3 ); } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java index 133e12225afc..17764e545966 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java @@ -48,6 +48,7 @@ import org.hibernate.internal.util.JdbcExceptionHelper; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.spi.RuntimeModelCreationContext; +import org.hibernate.query.sqm.CastType; import org.hibernate.query.sqm.FetchClauseType; import org.hibernate.query.sqm.IntervalType; import org.hibernate.dialect.NullOrdering; @@ -514,6 +515,16 @@ public String extractPattern(TemporalUnit unit) { : super.extractPattern(unit); } + @Override + public String castPattern(CastType from, CastType to) { + if ( from == CastType.STRING && to == CastType.BOOLEAN ) { + return "cast(?1 as ?2)"; + } + else { + return super.castPattern( from, to ); + } + } + @Override public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType, IntervalType intervalType) { if ( intervalType != null ) { @@ -992,4 +1003,14 @@ public String getCaseInsensitiveLike() { public boolean supportsCaseInsensitiveLike() { return getVersion().isSameOrAfter( 1, 4, 194 ); } + + @Override + public boolean supportsValuesList() { + return true; + } + + @Override + public String getDual() { + return "dual"; + } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacySqlAstTranslator.java index c95d269072d0..b081591b6452 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacySqlAstTranslator.java @@ -388,11 +388,6 @@ protected boolean supportsNullPrecedence() { return getClauseStack().getCurrent() != Clause.WITHIN_GROUP || getDialect().getVersion().isSameOrAfter( 2 ); } - @Override - protected String getDual() { - return "dual"; - } - private boolean supportsOffsetFetchClause() { return getDialect().getVersion().isSameOrAfter( 1, 4, 195 ); } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java index b491f19a8592..5460ff680c8f 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java @@ -315,25 +315,33 @@ public String castPattern(CastType from, CastType to) { } break; case BOOLEAN: - result = BooleanDecoder.toBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "true", "false" ) + : BooleanDecoder.toBoolean( from ); if ( result != null ) { return result; } break; case INTEGER_BOOLEAN: - result = BooleanDecoder.toIntegerBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "1", "0" ) + : BooleanDecoder.toIntegerBoolean( from ); if ( result != null ) { return result; } break; case YN_BOOLEAN: - result = BooleanDecoder.toYesNoBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "'Y'", "'N'" ) + : BooleanDecoder.toYesNoBoolean( from ); if ( result != null ) { return result; } break; case TF_BOOLEAN: - result = BooleanDecoder.toTrueFalseBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "'T'", "'F'" ) + : BooleanDecoder.toTrueFalseBoolean( from ); if ( result != null ) { return result; } @@ -825,6 +833,11 @@ public boolean requiresFloatCastingOfIntegerDivision() { return true; } + @Override + public boolean supportsValuesList() { + return true; + } + @Override public IdentityColumnSupport getIdentityColumnSupport() { return identityColumnSupport; @@ -900,4 +913,9 @@ public UniqueDelegate getUniqueDelegate() { public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() { return DmlTargetColumnQualifierSupport.TABLE_ALIAS; } + + @Override + public String getFromDualForSelectOnly() { + return " from " + getDual(); + } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacySqlAstTranslator.java index 0c4fb51be250..1ca3acd135b3 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacySqlAstTranslator.java @@ -341,11 +341,6 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { return false; } - @Override - protected String getFromDualForSelectOnly() { - return " from " + getDual(); - } - private boolean supportsOffsetFetchClause() { return getDialect().getVersion().isSameOrAfter( 2, 5 ); } 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 1c12fdc79933..5326d79fa71c 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 @@ -817,4 +817,14 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry jdbcTypeRegistry.addDescriptor( Types.NCLOB, ClobJdbcType.DEFAULT ); typeContributions.contributeJdbcType( VarcharUUIDJdbcType.INSTANCE ); } + + @Override + public String getDual() { + return "(select 0 from systables where tabid=1)"; + } + + @Override + public String getFromDualForSelectOnly() { + return " from " + getDual() + " dual"; + } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixSqlAstTranslator.java index 22528b21d065..eb451d4369e3 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixSqlAstTranslator.java @@ -153,16 +153,6 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { return false; } - @Override - protected String getDual() { - return "(select 0 from systables where tabid=1)"; - } - - @Override - protected String getFromDualForSelectOnly() { - return " from " + getDual() + " dual"; - } - @Override protected void renderNull(Literal literal) { if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.NO_UNTYPED ) { 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 5f62bfd28138..c2f5073404d0 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 @@ -559,4 +559,15 @@ public String translateExtractField(TemporalUnit unit) { public boolean supportsFetchClause(FetchClauseType type) { return getVersion().isSameOrAfter( 9, 3 ); } + + @Override + public String getDual() { + return "(select 0)"; + } + + @Override + public String getFromDualForSelectOnly() { + //this is only necessary if the query has a where clause + return " from " + getDual() + " dual"; + } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresSqlAstTranslator.java index 7a4af55cc9a6..be2c420c79e9 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresSqlAstTranslator.java @@ -138,17 +138,6 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { return false; } - @Override - protected String getDual() { - return "(select 0)"; - } - - @Override - protected String getFromDualForSelectOnly() { - //this is only necessary if the query has a where clause - return " from " + getDual() + " dual"; - } - @Override protected boolean needsRowsToSkip() { return !supportsOffsetFetchClause(); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MariaDBLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MariaDBLegacyDialect.java index d56e791050cb..402b34ee9a03 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MariaDBLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MariaDBLegacyDialect.java @@ -264,4 +264,14 @@ public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, D return super.buildIdentifierHelper( builder, dbMetaData ); } + + @Override + public String getDual() { + return "dual"; + } + + @Override + public String getFromDualForSelectOnly() { + return getVersion().isBefore( 10, 4 ) ? ( " from " + getDual() ) : ""; + } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MariaDBLegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MariaDBLegacySqlAstTranslator.java index 01cf6eb82e42..37b158444fb9 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MariaDBLegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MariaDBLegacySqlAstTranslator.java @@ -366,16 +366,6 @@ protected boolean supportsDistinctFromPredicate() { return true; } - @Override - protected String getDual() { - return "dual"; - } - - @Override - protected String getFromDualForSelectOnly() { - return getDialect().getVersion().isBefore( 10, 4 ) ? ( " from " + getDual() ) : ""; - } - @Override public MariaDBLegacyDialect getDialect() { return this.dialect; 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 e527bd5baafa..f179bed01780 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 @@ -331,5 +331,15 @@ public String getTemporaryTableCreateOptions() { public boolean supportsJdbcConnectionLobCreation(DatabaseMetaData databaseMetaData) { return false; } + + @Override + public String getDual() { + return "dual"; + } + + @Override + public String getFromDualForSelectOnly() { + return " from " + getDual(); + } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBSqlAstTranslator.java index 011098389488..3955edfddcf3 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBSqlAstTranslator.java @@ -92,14 +92,4 @@ protected boolean supportsRowValueConstructorSyntaxInInList() { protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { return false; } - - @Override - protected String getDual() { - return "dual"; - } - - @Override - protected String getFromDualForSelectOnly() { - return " from " + getDual(); - } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLDialect.java index 3da7ba4005a5..198ffa412d79 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLDialect.java @@ -344,4 +344,9 @@ public boolean useConnectionToCreateLob() { public IdentityColumnSupport getIdentityColumnSupport() { return MimerSQLIdentityColumnSupport.INSTANCE; } + + @Override + public String getFromDualForSelectOnly() { + return " from " + getDual(); + } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLSqlAstTranslator.java index 7510df6451ba..16d79ec7ffbb 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLSqlAstTranslator.java @@ -81,9 +81,4 @@ protected boolean supportsRowValueConstructorSyntaxInInList() { protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { return false; } - - @Override - protected String getFromDualForSelectOnly() { - return " from " + getDual(); - } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java index 4739b447acd2..88f292f62db6 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java @@ -1429,4 +1429,14 @@ public boolean supportsFromClauseInUpdate() { return true; } + @Override + public String getDual() { + return "dual"; + } + + @Override + public String getFromDualForSelectOnly() { + return getVersion().isSameOrAfter( 8 ) ? "" : ( " from " + getDual() ); + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacySqlAstTranslator.java index ec382f39b65d..78f63527c452 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacySqlAstTranslator.java @@ -389,16 +389,6 @@ protected boolean supportsWithClause() { return getDialect().getVersion().isSameOrAfter( 8 ); } - @Override - protected String getDual() { - return "dual"; - } - - @Override - protected String getFromDualForSelectOnly() { - return getDialect().getVersion().isSameOrAfter( 8 ) ? "" : ( " from " + getDual() ); - } - @Override public MySQLLegacyDialect getDialect() { return (MySQLLegacyDialect) DialectDelegateWrapper.extractRealDialect( super.getDialect() ); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java index 14d0037cb2ae..254758e2a4a5 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java @@ -398,20 +398,33 @@ public String castPattern(CastType from, CastType to) { } break; case INTEGER_BOOLEAN: - result = BooleanDecoder.toIntegerBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "1", "0" ) + : BooleanDecoder.toIntegerBoolean( from ); if ( result != null ) { return result; } break; case YN_BOOLEAN: - result = BooleanDecoder.toYesNoBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "'Y'", "'N'" ) + : BooleanDecoder.toYesNoBoolean( from ); if ( result != null ) { return result; } break; case BOOLEAN: + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "true", "false" ) + : BooleanDecoder.toBoolean( from ); + if ( result != null ) { + return result; + } + break; case TF_BOOLEAN: - result = BooleanDecoder.toTrueFalseBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "'T'", "'F'" ) + : BooleanDecoder.toTrueFalseBoolean( from ); if ( result != null ) { return result; } @@ -1564,4 +1577,14 @@ public boolean useInputStreamToInsertBlob() { return false; } + @Override + public String getDual() { + return "dual"; + } + + @Override + public String getFromDualForSelectOnly() { + return " from " + getDual(); + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacySqlAstTranslator.java index 1b8af5cc5d6c..15f5f489c427 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacySqlAstTranslator.java @@ -674,16 +674,6 @@ protected boolean supportsRowValueConstructorSyntaxInInSubQuery() { return getDialect().getVersion().isSameOrAfter( 9 ); } - @Override - protected String getDual() { - return "dual"; - } - - @Override - protected String getFromDualForSelectOnly() { - return " from " + getDual(); - } - private boolean supportsOffsetFetchClause() { return getDialect().supportsFetchClause( FetchClauseType.ROWS_ONLY ); } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java index 219079710bcf..4b5b73c012ce 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java @@ -60,6 +60,7 @@ import org.hibernate.procedure.spi.CallableStatementSupport; import org.hibernate.query.SemanticException; import org.hibernate.query.spi.QueryOptions; +import org.hibernate.query.sqm.CastType; import org.hibernate.query.sqm.FetchClauseType; import org.hibernate.query.sqm.IntervalType; import org.hibernate.query.sqm.TemporalUnit; @@ -418,6 +419,16 @@ public String extractPattern(TemporalUnit unit) { } } + @Override + public String castPattern(CastType from, CastType to) { + if ( from == CastType.STRING && to == CastType.BOOLEAN ) { + return "cast(?1 as ?2)"; + } + else { + return super.castPattern( from, to ); + } + } + /** * {@code microsecond} is the smallest unit for an {@code interval}, * and the highest precision for a {@code timestamp}, so we could diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200Dialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200Dialect.java index b4b111aa52a1..1e5f5db6cfcf 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200Dialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200Dialect.java @@ -434,4 +434,14 @@ public void appendDatetimeFormat(SqlAppender appender, String format) { public String trimPattern(TrimSpec specification, boolean isWhitespace) { return AbstractTransactSQLDialect.replaceLtrimRtrim( specification, isWhitespace ); } + + @Override + public String getDual() { + return "rdms.rdms_dummy"; + } + + @Override + public String getFromDualForSelectOnly() { + return " from " + getDual() + " where key_col=1"; + } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200SqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200SqlAstTranslator.java index 9a1f97109d78..24f726c877a1 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200SqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200SqlAstTranslator.java @@ -124,14 +124,4 @@ protected boolean supportsRowValueConstructorSyntaxInInList() { protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { return false; } - - @Override - protected String getDual() { - return "rdms.rdms_dummy"; - } - - @Override - protected String getFromDualForSelectOnly() { - return " from " + getDual() + " where key_col=1"; - } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SingleStoreDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SingleStoreDialect.java index 8af3ae96b905..7c0347fa07ce 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SingleStoreDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SingleStoreDialect.java @@ -1411,4 +1411,9 @@ public boolean isForUpdateLockingEnabled() { * @settingDefault {@code false} */ public static final String SINGLE_STORE_FOR_UPDATE_LOCK_ENABLED = "hibernate.dialect.singlestore.for_update_lock_enabled"; + + @Override + public String getDual() { + return "dual"; + } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SingleStoreSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SingleStoreSqlAstTranslator.java index c646a5500542..dac437dd4015 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SingleStoreSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SingleStoreSqlAstTranslator.java @@ -437,11 +437,6 @@ protected boolean supportsDistinctFromPredicate() { return false; } - @Override - protected String getDual() { - return "dual"; - } - @Override public SingleStoreDialect getDialect() { return this.dialect; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacyDialect.java index 230b6d4f1e6a..1799e3e5583e 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacyDialect.java @@ -696,4 +696,9 @@ public LimitHandler getLimitHandler() { } return new TopLimitHandler(false); } + + @Override + public String getDual() { + return "(select 1 c1)"; + } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacySqlAstTranslator.java index b5ace7590994..18197f136559 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacySqlAstTranslator.java @@ -530,11 +530,6 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { return false; } - @Override - protected String getDual() { - return "(select 1 c1)"; - } - private boolean supportsTopClause() { return getDialect().getVersion().isSameOrAfter( 12, 5 ); } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereDialect.java index e77527c4c9a6..0a5d8d137367 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereDialect.java @@ -215,4 +215,14 @@ public LimitHandler getLimitHandler() { return TopLimitHandler.INSTANCE; } + @Override + public String getDual() { + return "sys.dummy"; + } + + @Override + public String getFromDualForSelectOnly() { + return " from " + getDual(); + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereSqlAstTranslator.java index 841594f12e66..db347cfa8d1d 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereSqlAstTranslator.java @@ -239,14 +239,4 @@ protected boolean supportsRowValueConstructorSyntaxInInList() { protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { return false; } - - @Override - protected String getDual() { - return "sys.dummy"; - } - - @Override - protected String getFromDualForSelectOnly() { - return " from " + getDual(); - } } 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 be6f131f9e4c..23739954a25b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java @@ -1986,4 +1986,14 @@ public String getForUpdateSkipLockedString(String aliases) { public String getForUpdateString(LockMode lockMode) { return super.getForUpdateString(lockMode); } + + @Override + public String getDual() { + return "sys.dummy"; + } + + @Override + public String getFromDualForSelectOnly() { + return " from " + getDual(); + } } 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 070091a2661b..76a5ebce8973 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java @@ -61,6 +61,7 @@ import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.procedure.internal.DB2CallableStatementSupport; import org.hibernate.procedure.spi.CallableStatementSupport; +import org.hibernate.query.sqm.CastType; import org.hibernate.query.sqm.IntervalType; import org.hibernate.query.sqm.TemporalUnit; import org.hibernate.query.sqm.mutation.internal.cte.CteInsertStrategy; @@ -1249,6 +1250,16 @@ public String extractPattern(TemporalUnit unit) { return super.extractPattern( unit ); } + @Override + public String castPattern(CastType from, CastType to) { + if ( from == CastType.STRING && to == CastType.BOOLEAN ) { + return "cast(?1 as ?2)"; + } + else { + return super.castPattern( from, to ); + } + } + @Override public int getInExpressionCountLimit() { return BIND_PARAMETERS_NUMBER_LIMIT; @@ -1316,4 +1327,14 @@ public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() { public boolean supportsFromClauseInUpdate() { return getDB2Version().isSameOrAfter( 11 ); } + + @Override + public String getDual() { + return "sysibm.dual"; + } + + @Override + public String getFromDualForSelectOnly() { + return " from " + getDual(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2SqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2SqlAstTranslator.java index 7612266186d4..daf34f6c1deb 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2SqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2SqlAstTranslator.java @@ -587,16 +587,6 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { return false; } - @Override - protected String getDual() { - return "sysibm.dual"; - } - - @Override - protected String getFromDualForSelectOnly() { - return " from " + getDual(); - } - @Override protected void visitReturningColumns(List returningColumns) { // For DB2 we use #renderReturningClause to render a wrapper around the DML statement diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java index d4a5e9ff15ce..1b0ddc2fee2b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java @@ -1040,6 +1040,11 @@ public boolean supportsWindowFunctions() { return true; } + @Override + public boolean supportsValuesList() { + return true; + } + @Override public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) throws SQLException { @@ -1057,4 +1062,14 @@ public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() { return DmlTargetColumnQualifierSupport.TABLE_ALIAS; } + @Override + public String getDual() { + return "(values 0)"; + } + + @Override + public String getFromDualForSelectOnly() { + return " from " + getDual() + " dual"; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DerbySqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/DerbySqlAstTranslator.java index 2788fca3a688..a830f79ada6c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DerbySqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DerbySqlAstTranslator.java @@ -302,16 +302,6 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { return false; } - @Override - protected String getDual() { - return "(values 0)"; - } - - @Override - protected String getFromDualForSelectOnly() { - return " from " + getDual() + " dual"; - } - @Override protected boolean needsRowsToSkip() { return !supportsOffsetFetchClause(); 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 597c2d248677..1d686d28dacd 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java @@ -1441,7 +1441,7 @@ public String castPattern(CastType from, CastType to) { case INTEGER_BOOLEAN: switch ( from ) { case STRING: - return "case ?1 when 'T' then 1 when 'Y' then 1 when 'F' then 0 when 'N' then 0 else null end"; + return buildStringToBooleanCast( "1", "0" ); case INTEGER: case LONG: return "abs(sign(?1))"; @@ -1456,7 +1456,7 @@ public String castPattern(CastType from, CastType to) { case YN_BOOLEAN: switch ( from ) { case STRING: - return "case ?1 when 'T' then 'Y' when 'Y' then 'Y' when 'F' then 'N' when 'N' then 'N' else null end"; + return buildStringToBooleanCast( "'Y'", "'N'" ); case INTEGER_BOOLEAN: return "case ?1 when 1 then 'Y' when 0 then 'N' else null end"; case INTEGER: @@ -1471,7 +1471,7 @@ public String castPattern(CastType from, CastType to) { case TF_BOOLEAN: switch ( from ) { case STRING: - return "case ?1 when 'T' then 'T' when 'Y' then 'T' when 'F' then 'F' when 'N' then 'F' else null end"; + return buildStringToBooleanCast( "'T'", "'F'" ); case INTEGER_BOOLEAN: return "case ?1 when 1 then 'T' when 0 then 'F' else null end"; case INTEGER: @@ -1486,7 +1486,7 @@ public String castPattern(CastType from, CastType to) { case BOOLEAN: switch ( from ) { case STRING: - return "case ?1 when 'T' then true when 'Y' then true when 'F' then false when 'N' then false else null end"; + return buildStringToBooleanCast( "true", "false" ); case INTEGER_BOOLEAN: case INTEGER: case LONG: @@ -1501,6 +1501,153 @@ public String castPattern(CastType from, CastType to) { return "cast(?1 as ?2)"; } + protected static final String[] TRUE_STRING_VALUES = new String[] { "t", "true", "y", "1" }; + protected static final String[] FALSE_STRING_VALUES = new String[] { "f", "false", "n", "0" }; + + protected String buildStringToBooleanCast(String trueValue, String falseValue) { + final boolean supportsValuesList = supportsValuesList(); + final StringBuilder sb = new StringBuilder(); + sb.append( "(select v.x from (" ); + if ( supportsValuesList ) { + sb.append( "values (" ); + sb.append( trueValue ); + sb.append( "),(" ); + sb.append( falseValue ); + sb.append( ")) v(x)" ); + } + else { + sb.append( "select " ); + sb.append( trueValue ); + sb.append( " x"); + sb.append( getFromDualForSelectOnly() ); + sb.append(" union all select " ); + sb.append( falseValue ); + sb.append( getFromDualForSelectOnly() ); + sb.append( ") v" ); + } + sb.append( " left join (" ); + if ( supportsValuesList ) { + sb.append( "values" ); + char separator = ' '; + for ( String trueStringValue : Dialect.TRUE_STRING_VALUES ) { + sb.append( separator ); + sb.append( "('" ); + sb.append( trueStringValue ); + sb.append( "'," ); + sb.append( trueValue ); + sb.append( ')' ); + separator = ','; + } + for ( String falseStringValue : Dialect.FALSE_STRING_VALUES ) { + sb.append( ",('" ); + sb.append( falseStringValue ); + sb.append( "'," ); + sb.append( falseValue ); + sb.append( ')' ); + } + sb.append( ") t(k,v)" ); + } + else { + sb.append( "select '" ); + sb.append( Dialect.TRUE_STRING_VALUES[0] ); + sb.append( "' k," ); + sb.append( trueValue ); + sb.append( " v" ); + sb.append( getFromDualForSelectOnly() ); + for ( int i = 1; i < Dialect.TRUE_STRING_VALUES.length; i++ ) { + sb.append( " union all select '" ); + sb.append( Dialect.TRUE_STRING_VALUES[i] ); + sb.append( "'," ); + sb.append( trueValue ); + sb.append( getFromDualForSelectOnly() ); + } + for ( String falseStringValue : Dialect.FALSE_STRING_VALUES ) { + sb.append( " union all select '" ); + sb.append( falseStringValue ); + sb.append( "'," ); + sb.append( falseValue ); + sb.append( getFromDualForSelectOnly() ); + } + sb.append( ") t" ); + } + sb.append( " on " ); + sb.append( getLowercaseFunction() ); + sb.append( "(?1)=t.k where t.v is null or v.x=t.v)" ); + return sb.toString(); + } + + protected String buildStringToBooleanCastDecode(String trueValue, String falseValue) { + final boolean supportsValuesList = supportsValuesList(); + final StringBuilder sb = new StringBuilder(); + sb.append( "(select v.x from (" ); + if ( supportsValuesList ) { + sb.append( "values (" ); + sb.append( trueValue ); + sb.append( "),(" ); + sb.append( falseValue ); + sb.append( ")) v(x)" ); + } + else { + sb.append( "select " ); + sb.append( trueValue ); + sb.append( " x"); + sb.append( getFromDualForSelectOnly() ); + sb.append(" union all select " ); + sb.append( falseValue ); + sb.append( getFromDualForSelectOnly() ); + sb.append( ") v" ); + } + sb.append( ", (" ); + if ( supportsValuesList ) { + sb.append( "values (" ); + sb.append( buildStringToBooleanDecode( trueValue, falseValue ) ); + sb.append( ")) t(v)" ); + } + else { + sb.append( "select " ); + sb.append( buildStringToBooleanDecode( trueValue, falseValue ) ); + sb.append( " v"); + sb.append( getFromDualForSelectOnly() ); + sb.append(") t" ); + } + sb.append( " where t.v is null or v.x=t.v)" ); + return sb.toString(); + } + + protected String buildStringToBooleanDecode(String trueValue, String falseValue) { + final StringBuilder sb = new StringBuilder(); + sb.append( "decode(" ); + sb.append( getLowercaseFunction() ); + sb.append( "(?1)" ); + for ( String trueStringValue : TRUE_STRING_VALUES ) { + sb.append( ",'" ); + sb.append( trueStringValue ); + sb.append( "'," ); + sb.append( trueValue ); + } + for ( String falseStringValue : FALSE_STRING_VALUES ) { + sb.append( ",'" ); + sb.append( falseStringValue ); + sb.append( "'," ); + sb.append( falseValue ); + } + sb.append( ",null)" ); + return sb.toString(); + } + + /** + * Returns a table expression that has one row. + * + * @return the SQL equivalent to Oracle's {@code dual}. + */ + public String getDual() { + return "(values(0))"; + } + + public String getFromDualForSelectOnly() { + return ""; + } + /** * Obtain a pattern for the SQL equivalent to a * {@code trim()} function call. The resulting diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java index 622479b703e7..6aa5aba5726a 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java @@ -44,6 +44,7 @@ import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.persister.entity.mutation.EntityMutationTarget; +import org.hibernate.query.sqm.CastType; import org.hibernate.query.sqm.FetchClauseType; import org.hibernate.query.sqm.IntervalType; import org.hibernate.query.sqm.TemporalUnit; @@ -445,6 +446,16 @@ public String extractPattern(TemporalUnit unit) { : super.extractPattern(unit); } + @Override + public String castPattern(CastType from, CastType to) { + if ( from == CastType.STRING && to == CastType.BOOLEAN ) { + return "cast(?1 as ?2)"; + } + else { + return super.castPattern( from, to ); + } + } + @Override public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType, IntervalType intervalType) { if ( intervalType != null ) { @@ -1007,4 +1018,14 @@ public boolean supportsCaseInsensitiveLike(){ return true; } + @Override + public boolean supportsValuesList() { + return true; + } + + @Override + public String getDual() { + return "dual"; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2SqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2SqlAstTranslator.java index 093530fd5bf9..fe824b0dd052 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/H2SqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2SqlAstTranslator.java @@ -361,11 +361,6 @@ protected boolean supportsNullPrecedence() { return true; } - @Override - protected String getDual() { - return "dual"; - } - private boolean supportsOffsetFetchClause() { return true; } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/HANASqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/HANASqlAstTranslator.java index c77eac47d6ce..859e1fa38f26 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/HANASqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/HANASqlAstTranslator.java @@ -252,16 +252,6 @@ protected boolean supportsRowValueConstructorGtLtSyntax() { return false; } - @Override - protected String getDual() { - return "sys.dummy"; - } - - @Override - protected String getFromDualForSelectOnly() { - return " from " + getDual(); - } - @Override protected void renderInsertIntoNoColumns(TableInsertStandard tableInsert) { throw new MappingException( diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java index fa0ca8189f4a..91f831288e19 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java @@ -255,25 +255,33 @@ public String castPattern(CastType from, CastType to) { } break; case BOOLEAN: - result = BooleanDecoder.toBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "true", "false" ) + : BooleanDecoder.toBoolean( from ); if ( result != null ) { return result; } break; case INTEGER_BOOLEAN: - result = BooleanDecoder.toIntegerBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "1", "0" ) + : BooleanDecoder.toIntegerBoolean( from ); if ( result != null ) { return result; } break; case YN_BOOLEAN: - result = BooleanDecoder.toYesNoBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "'Y'", "'N'" ) + : BooleanDecoder.toYesNoBoolean( from ); if ( result != null ) { return result; } break; case TF_BOOLEAN: - result = BooleanDecoder.toTrueFalseBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "'T'", "'F'" ) + : BooleanDecoder.toTrueFalseBoolean( from ); if ( result != null ) { return result; } @@ -647,6 +655,11 @@ public boolean requiresFloatCastingOfIntegerDivision() { return true; } + @Override + public boolean supportsValuesList() { + return true; + } + @Override public IdentityColumnSupport getIdentityColumnSupport() { return identityColumnSupport; @@ -727,4 +740,9 @@ public String quoteCollation(String collation) { public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() { return DmlTargetColumnQualifierSupport.TABLE_ALIAS; } + + @Override + public String getFromDualForSelectOnly() { + return " from " + getDual(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLSqlAstTranslator.java index aac2ecdc232a..1357e12f522c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLSqlAstTranslator.java @@ -335,11 +335,6 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { return false; } - @Override - protected String getFromDualForSelectOnly() { - return " from " + getDual(); - } - private boolean supportsOffsetFetchClause() { return true; } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java index c77ee258a435..75b9335dafbc 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java @@ -276,4 +276,9 @@ public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, D return super.buildIdentifierHelper( builder, dbMetaData ); } + + @Override + public String getDual() { + return "dual"; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBSqlAstTranslator.java index 78272afe716e..a243e96979f7 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBSqlAstTranslator.java @@ -369,11 +369,6 @@ protected boolean supportsDistinctFromPredicate() { return true; } - @Override - protected String getDual() { - return "dual"; - } - @Override public MariaDBDialect getDialect() { return this.dialect; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java index 9e37920408cc..20ce0f69b5eb 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java @@ -1572,4 +1572,9 @@ public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() { public boolean supportsFromClauseInUpdate() { return true; } + + @Override + public String getDual() { + return "dual"; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLSqlAstTranslator.java index 6be62a55c40e..dd78fb8e0ea2 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLSqlAstTranslator.java @@ -443,11 +443,6 @@ protected boolean supportsWithClause() { return true; } - @Override - protected String getDual() { - return "dual"; - } - @Override public MySQLDialect getDialect() { return (MySQLDialect) DialectDelegateWrapper.extractRealDialect( super.getDialect() ); 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 24e33db59d31..1b9b313b71c7 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java @@ -462,25 +462,33 @@ public String castPattern(CastType from, CastType to) { } break; case INTEGER_BOOLEAN: - result = BooleanDecoder.toIntegerBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "1", "0" ) + : BooleanDecoder.toIntegerBoolean( from ); if ( result != null ) { return result; } break; case YN_BOOLEAN: - result = BooleanDecoder.toYesNoBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "'Y'", "'N'" ) + : BooleanDecoder.toYesNoBoolean( from ); if ( result != null ) { return result; } break; case BOOLEAN: - result = BooleanDecoder.toBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "true", "false" ) + : BooleanDecoder.toBoolean( from ); if ( result != null ) { return result; } break; case TF_BOOLEAN: - result = BooleanDecoder.toTrueFalseBoolean( from ); + result = from == CastType.STRING + ? buildStringToBooleanCastDecode( "'T'", "'F'" ) + : BooleanDecoder.toTrueFalseBoolean( from ); if ( result != null ) { return result; } @@ -1687,4 +1695,14 @@ public boolean useInputStreamToInsertBlob() { return false; } + @Override + public String getDual() { + return "dual"; + } + + @Override + public String getFromDualForSelectOnly() { + return getVersion().isSameOrAfter( 23 ) ? "" : ( " from " + getDual() ); + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java index 00558358553b..6f87c4f0cf65 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java @@ -617,16 +617,6 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { return false; } - @Override - protected String getDual() { - return "dual"; - } - - @Override - protected String getFromDualForSelectOnly() { - return getDialect().getVersion().isSameOrAfter( 23 ) ? "" : ( " from " + getDual() ); - } - private boolean supportsOffsetFetchClause() { return getDialect().supportsFetchClause( FetchClauseType.ROWS_ONLY ); } 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 67fa1ce56a10..404f10609cba 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java @@ -58,6 +58,7 @@ import org.hibernate.procedure.spi.CallableStatementSupport; import org.hibernate.query.SemanticException; import org.hibernate.query.spi.QueryOptions; +import org.hibernate.query.sqm.CastType; import org.hibernate.query.sqm.FetchClauseType; import org.hibernate.query.sqm.IntervalType; import org.hibernate.query.sqm.TemporalUnit; @@ -467,6 +468,16 @@ public String extractPattern(TemporalUnit unit) { } } + @Override + public String castPattern(CastType from, CastType to) { + if ( from == CastType.STRING && to == CastType.BOOLEAN ) { + return "cast(?1 as ?2)"; + } + else { + return super.castPattern( from, to ); + } + } + /** * {@code microsecond} is the smallest unit for an {@code interval}, * and the highest precision for a {@code timestamp}, so we could diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java index 52d320a52b4f..f42ac8b6a48d 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java @@ -712,4 +712,9 @@ public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() { public LimitHandler getLimitHandler() { return new TopLimitHandler(false); } + + @Override + public String getDual() { + return "(select 1 c1)"; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASESqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASESqlAstTranslator.java index eee92fa20b04..6fd185de98bc 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASESqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASESqlAstTranslator.java @@ -508,11 +508,6 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { return false; } - @Override - protected String getDual() { - return "(select 1 c1)"; - } - private boolean supportsParameterOffsetFetchExpression() { return false; } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/TiDBDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/TiDBDialect.java index 524128640903..4557bbfb53c8 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/TiDBDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/TiDBDialect.java @@ -190,4 +190,9 @@ public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType, } return super.timestampaddPattern( unit, temporalType, intervalType ); } + + @Override + public String getDual() { + return "dual"; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/TiDBSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/TiDBSqlAstTranslator.java index 1a4320239020..751e3ba6c810 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/TiDBSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/TiDBSqlAstTranslator.java @@ -332,11 +332,6 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { return false; } - @Override - protected String getDual() { - return "dual"; - } - @Override protected String getForShare(int timeoutMillis) { if ( timeoutMillis == LockOptions.NO_WAIT ) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java index 358cf5bac2ac..98960c77aa7c 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java @@ -8644,11 +8644,11 @@ protected String getFromDual() { * @return the SQL equivalent to Oracle's {@code dual}. */ protected String getDual() { - return "(values(0))"; + return dialect.getDual(); } protected String getFromDualForSelectOnly() { - return ""; + return dialect.getFromDualForSelectOnly(); } protected enum LockStrategy { 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 af1a148e83f2..1809da568c51 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 @@ -7,6 +7,9 @@ package org.hibernate.orm.test.query.hql; import org.hamcrest.Matchers; + +import org.hibernate.HibernateException; +import org.hibernate.JDBCException; import org.hibernate.QueryException; import org.hibernate.community.dialect.AltibaseDialect; import org.hibernate.dialect.CockroachDialect; @@ -23,6 +26,8 @@ import org.hibernate.dialect.SybaseDialect; import org.hibernate.dialect.TiDBDialect; import org.hibernate.query.sqm.produce.function.FunctionArgumentException; +import org.hibernate.sql.exec.ExecutionException; + import org.hibernate.testing.TestForIssue; import org.hibernate.testing.orm.domain.StandardDomainModel; import org.hibernate.testing.orm.domain.gambit.EntityOfBasics; @@ -31,6 +36,7 @@ import org.hibernate.testing.orm.domain.gambit.SimpleEntity; import org.hibernate.testing.orm.junit.DialectFeatureChecks; import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.Jira; import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.RequiresDialect; import org.hibernate.testing.orm.junit.RequiresDialectFeature; @@ -66,6 +72,7 @@ import static org.hibernate.testing.orm.domain.gambit.EntityOfBasics.Gender.FEMALE; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -1030,6 +1037,44 @@ public void testCastFunction(SessionFactoryScope scope) { ); } + @Test + @Jira("https://hibernate.atlassian.net/browse/HHH-18447") + public void testCastStringToBoolean(SessionFactoryScope scope) { + scope.inTransaction( session -> { + assertThat( session.createQuery("select cast('1' as Boolean)", Boolean.class).getSingleResult(), is(true) ); + assertThat( session.createQuery("select cast('0' as Boolean)", Boolean.class).getSingleResult(), is(false) ); + assertThat( session.createQuery("select cast('y' as Boolean)", Boolean.class).getSingleResult(), is(true) ); + assertThat( session.createQuery("select cast('n' as Boolean)", Boolean.class).getSingleResult(), is(false) ); + assertThat( session.createQuery("select cast('Y' as Boolean)", Boolean.class).getSingleResult(), is(true) ); + assertThat( session.createQuery("select cast('N' as Boolean)", Boolean.class).getSingleResult(), is(false) ); + assertThat( session.createQuery("select cast('t' as Boolean)", Boolean.class).getSingleResult(), is(true) ); + assertThat( session.createQuery("select cast('f' as Boolean)", Boolean.class).getSingleResult(), is(false) ); + assertThat( session.createQuery("select cast('T' as Boolean)", Boolean.class).getSingleResult(), is(true) ); + assertThat( session.createQuery("select cast('F' as Boolean)", Boolean.class).getSingleResult(), is(false) ); + assertThat( session.createQuery("select cast('true' as Boolean)", Boolean.class).getSingleResult(), is(true) ); + assertThat( session.createQuery("select cast('false' as Boolean)", Boolean.class).getSingleResult(), is(false) ); + assertThat( session.createQuery("select cast('TRUE' as Boolean)", Boolean.class).getSingleResult(), is(true) ); + assertThat( session.createQuery("select cast('FALSE' as Boolean)", Boolean.class).getSingleResult(), is(false) ); + }); + } + + @Test + @Jira("https://hibernate.atlassian.net/browse/HHH-18447") + public void testCastInvalidStringToBoolean(SessionFactoryScope scope) { + scope.inTransaction( session -> { + try { + session.createQuery( "select cast('bla' as Boolean)", Boolean.class ).getSingleResult(); + fail("Casting invalid boolean string should fail"); + } + catch ( HibernateException e ) { + // Expected + if ( !( e instanceof JDBCException || e instanceof ExecutionException ) ) { + throw e; + } + } + } ); + } + @Test @SkipForDialect(dialectClass = DB2Dialect.class, matchSubTypes = true) @SkipForDialect(dialectClass = DerbyDialect.class)