Repurpose DefaultSizeStrategy to SizeStrategy for resolving final size. Fix boolean encoding/decoding issues. Remove duplicate order bys. Fix set operation nesting. Fix lots of tests for SQLServer, MariaDB, Derby and Oracle
This commit is contained in:
parent
019f934344
commit
9f096e89ec
|
@ -2,12 +2,12 @@
|
|||
|
||||
mysql_5_7() {
|
||||
docker rm -f mysql || true
|
||||
docker run --name mysql -e MYSQL_USER=hibernate_orm_test -e MYSQL_PASSWORD=hibernate_orm_test -e MYSQL_DATABASE=hibernate_orm_test -p3306:3306 -d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||
docker run --name mysql -e MYSQL_USER=hibernate_orm_test -e MYSQL_PASSWORD=hibernate_orm_test -e MYSQL_DATABASE=hibernate_orm_test -e MYSQL_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||
}
|
||||
|
||||
mysql_8_0() {
|
||||
docker rm -f mysql || true
|
||||
docker run --name mysql -e MYSQL_USER=hibernate_orm_test -e MYSQL_PASSWORD=hibernate_orm_test -e MYSQL_DATABASE=hibernate_orm_test -p3306:3306 -d mysql:8.0.21 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||
docker run --name mysql -e MYSQL_USER=hibernate_orm_test -e MYSQL_PASSWORD=hibernate_orm_test -e MYSQL_DATABASE=hibernate_orm_test -e MYSQL_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d mysql:8.0.21 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||
}
|
||||
|
||||
mariadb() {
|
||||
|
|
|
@ -75,13 +75,13 @@ values
|
|||
// QUERY SPEC - general structure of root sqm or sub sqm
|
||||
|
||||
queryExpression
|
||||
: queryGroup queryOrder?
|
||||
: simpleQueryExpression # SimpleQueryGroup
|
||||
| queryExpression (setOperator simpleQueryExpression)+ # SetQueryGroup
|
||||
;
|
||||
|
||||
queryGroup
|
||||
: querySpec # QuerySpecQueryGroup
|
||||
| LEFT_PAREN queryGroup RIGHT_PAREN # NestedQueryGroup
|
||||
| queryGroup queryOrder? (setOperator (querySpec | LEFT_PAREN queryGroup RIGHT_PAREN))+ # SetQueryGroup
|
||||
simpleQueryExpression
|
||||
: querySpec queryOrder? # QuerySpecExpression
|
||||
| LEFT_PAREN queryExpression RIGHT_PAREN queryOrder? # NestedQueryExpression
|
||||
;
|
||||
|
||||
setOperator
|
||||
|
|
|
@ -225,6 +225,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
private final boolean procedureParameterNullPassingEnabled;
|
||||
private final boolean collectionJoinSubqueryRewriteEnabled;
|
||||
private final boolean omitJoinOfSuperclassTablesEnabled;
|
||||
private final int preferredSqlTypeCodeForBoolean;
|
||||
|
||||
// Caching
|
||||
private boolean secondLevelCacheEnabled;
|
||||
|
@ -415,6 +416,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
this.procedureParameterNullPassingEnabled = cfgService.getSetting( PROCEDURE_NULL_PARAM_PASSING, BOOLEAN, false );
|
||||
this.collectionJoinSubqueryRewriteEnabled = cfgService.getSetting( COLLECTION_JOIN_SUBQUERY, BOOLEAN, true );
|
||||
this.omitJoinOfSuperclassTablesEnabled = cfgService.getSetting( OMIT_JOIN_OF_SUPERCLASS_TABLES, BOOLEAN, true );
|
||||
this.preferredSqlTypeCodeForBoolean = ConfigurationHelper.getPreferredSqlTypeCodeForBoolean( serviceRegistry );
|
||||
|
||||
final RegionFactory regionFactory = serviceRegistry.getService( RegionFactory.class );
|
||||
if ( !NoCachingRegionFactory.class.isInstance( regionFactory ) ) {
|
||||
|
@ -1204,8 +1206,11 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
return omitJoinOfSuperclassTablesEnabled;
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@Override
|
||||
public int getPreferredSqlTypeCodeForBoolean() {
|
||||
return preferredSqlTypeCodeForBoolean;
|
||||
}
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// In-flight mutation access
|
||||
|
||||
public void applyBeanManager(Object beanManager) {
|
||||
|
|
|
@ -156,7 +156,7 @@ public class InferredBasicValueResolver {
|
|||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static BasicType<?> resolveSqlTypeIndicators(
|
||||
public static BasicType<?> resolveSqlTypeIndicators(
|
||||
SqlTypeDescriptorIndicators stdIndicators,
|
||||
BasicType<?> resolved) {
|
||||
if ( resolved instanceof SqlTypeDescriptorIndicatorCapable ) {
|
||||
|
|
|
@ -143,14 +143,12 @@ public class RelationalObjectBinder {
|
|||
if ( columnSource.getSizeSource().getLength() != null ) {
|
||||
column.setLength( columnSource.getSizeSource().getLength() );
|
||||
}
|
||||
final Integer precision = columnSource.getSizeSource().getPrecision();
|
||||
|
||||
if ( columnSource.getSizeSource().getScale() != null ) {
|
||||
if ( precision != null && precision > 0 ) {
|
||||
column.setPrecision( precision );
|
||||
column.setScale( columnSource.getSizeSource().getScale() );
|
||||
}
|
||||
|
||||
if ( columnSource.getSizeSource().getPrecision() != null ) {
|
||||
column.setPrecision( columnSource.getSizeSource().getPrecision() );
|
||||
}
|
||||
}
|
||||
|
||||
column.setNullable( interpretNullability( columnSource.isNullable(), areColumnsNullableByDefault ) );
|
||||
|
|
|
@ -484,4 +484,9 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
|
|||
public boolean isOmitJoinOfSuperclassTablesEnabled() {
|
||||
return delegate.isOmitJoinOfSuperclassTablesEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreferredSqlTypeCodeForBoolean() {
|
||||
return delegate.getPreferredSqlTypeCodeForBoolean();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -358,4 +358,6 @@ public interface SessionFactoryOptions extends QueryEngineOptions {
|
|||
}
|
||||
|
||||
boolean isOmitJoinOfSuperclassTablesEnabled();
|
||||
|
||||
int getPreferredSqlTypeCodeForBoolean();
|
||||
}
|
||||
|
|
|
@ -233,7 +233,7 @@ public class Ejb3Column {
|
|||
this.mappingColumn = new Column();
|
||||
redefineColumnName( columnName, propertyName, applyNamingStrategy );
|
||||
this.mappingColumn.setLength( length );
|
||||
if ( precision!=null ) { //relevant precision
|
||||
if ( precision != null && precision > 0 ) { //relevant precision
|
||||
this.mappingColumn.setPrecision( precision );
|
||||
this.mappingColumn.setScale( scale );
|
||||
}
|
||||
|
|
|
@ -1539,7 +1539,7 @@ public abstract class AbstractHANADialect extends Dialect {
|
|||
@Override
|
||||
public String translateDatetimeFormat(String format) {
|
||||
//I don't think HANA needs FM
|
||||
return OracleDialect.datetimeFormat( format, false ).result();
|
||||
return OracleDialect.datetimeFormat( format, false, false ).result();
|
||||
}
|
||||
|
||||
public boolean isUseUnicodeStringTypes() {
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.hibernate.NullOrdering;
|
|||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.IndividualLeastGreatestEmulation;
|
||||
import org.hibernate.dialect.identity.AbstractTransactSQLIdentityColumnSupport;
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
|
@ -100,6 +101,9 @@ abstract class AbstractTransactSQLDialect extends Dialect {
|
|||
CommonFunctionFactory.substring_substringLen( queryEngine );
|
||||
CommonFunctionFactory.datepartDatename( queryEngine );
|
||||
CommonFunctionFactory.lastDay_eomonth( queryEngine );
|
||||
|
||||
queryEngine.getSqmFunctionRegistry().register( "least", new IndividualLeastGreatestEmulation( true ) );
|
||||
queryEngine.getSqmFunctionRegistry().register( "greatest", new IndividualLeastGreatestEmulation( false ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import org.hibernate.query.CastType;
|
||||
|
||||
/**
|
||||
* Utility for decoding boolean representations.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public final class BooleanDecoder {
|
||||
|
||||
public static String toInteger(CastType from) {
|
||||
switch ( from ) {
|
||||
case BOOLEAN:
|
||||
return "decode(?1,false,0,true,1,null)";
|
||||
case YN_BOOLEAN:
|
||||
return "decode(?1,'Y',1,'N',0,null)";
|
||||
case TF_BOOLEAN:
|
||||
return "decode(?1,'T',1,'F',0,null)";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String toBoolean(CastType from) {
|
||||
switch ( from ) {
|
||||
case STRING:
|
||||
return "decode(?1,'T',true,'F',false,'Y',true,'N',false,null)";
|
||||
case YN_BOOLEAN:
|
||||
return "decode(?1,'Y',true,'N',false,null)";
|
||||
case TF_BOOLEAN:
|
||||
return "decode(?1,'T',true,'F',false,null)";
|
||||
case INTEGER:
|
||||
case LONG:
|
||||
case INTEGER_BOOLEAN:
|
||||
return "decode(?1,abs(sign(?1)),1,true,0,false,null)";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String toIntegerBoolean(CastType from) {
|
||||
switch ( from ) {
|
||||
case STRING:
|
||||
return "decode(?1,'T',1,'F',0,'Y',1,'N',0,null)";
|
||||
case YN_BOOLEAN:
|
||||
return "decode(?1,'Y',1,'N',0,null)";
|
||||
case TF_BOOLEAN:
|
||||
return "decode(?1,'T',1,'F',0,null)";
|
||||
case INTEGER:
|
||||
case LONG:
|
||||
return "abs(sign(?1))";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String toYesNoBoolean(CastType from) {
|
||||
switch ( from ) {
|
||||
case STRING:
|
||||
return "decode(?1,'T','Y','F','N','Y','Y','N','N',null)";
|
||||
case INTEGER_BOOLEAN:
|
||||
return "decode(?1,1,'Y',0,'N',null)";
|
||||
case TF_BOOLEAN:
|
||||
return "decode(?1,'T','Y','F','N',null)";
|
||||
case INTEGER:
|
||||
case LONG:
|
||||
return "decode(abs(sign(?1)),1,'Y',0,'N',null)";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String toTrueFalseBoolean(CastType from) {
|
||||
switch ( from ) {
|
||||
case STRING:
|
||||
return "decode(?1,'T','T','F','F','Y','T','N','F',null)";
|
||||
case INTEGER_BOOLEAN:
|
||||
return "decode(?1,1,'T',0,'F',null)";
|
||||
case YN_BOOLEAN:
|
||||
return "decode(?1,'Y','T','N','F',null)";
|
||||
case INTEGER:
|
||||
case LONG:
|
||||
return "decode(abs(sign(?1)),1,'T',0,'F',null)";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String toString(CastType from) {
|
||||
switch ( from ) {
|
||||
case INTEGER_BOOLEAN:
|
||||
return "decode(?1,0,'false',1,'true',null)";
|
||||
case TF_BOOLEAN:
|
||||
return "decode(?1,'T','true','F','false',null)";
|
||||
case YN_BOOLEAN:
|
||||
return "decode(?1,'Y','true','N','false',null)";
|
||||
case BOOLEAN:
|
||||
return "decode(?1,true,'true',false,'false',null)";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -304,7 +304,7 @@ public class CUBRIDDialect extends Dialect {
|
|||
public String translateDatetimeFormat(String format) {
|
||||
//I do not know if CUBRID supports FM, but it
|
||||
//seems that it does pad by default, so it needs it!
|
||||
return OracleDialect.datetimeFormat( format, true )
|
||||
return OracleDialect.datetimeFormat( format, true, false )
|
||||
.replace("SSSSSS", "FF")
|
||||
.replace("SSSSS", "FF")
|
||||
.replace("SSSS", "FF")
|
||||
|
|
|
@ -394,7 +394,7 @@ public class CacheDialect extends Dialect {
|
|||
@Override
|
||||
public String translateDatetimeFormat(String format) {
|
||||
//I don't think Cache needs FM
|
||||
return OracleDialect.datetimeFormat( format, false ).result();
|
||||
return OracleDialect.datetimeFormat( format, false, false ).result();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
|
|||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.CastType;
|
||||
import org.hibernate.query.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.mutation.internal.cte.CteStrategy;
|
||||
|
@ -661,11 +660,26 @@ public class DB2Dialect extends Dialect {
|
|||
return new DB2IdentityColumnSupport();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsValuesList() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsRowValueConstructorSyntaxInInList() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsPartitionBy() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsNonQueryWithCTE() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupBySummarizationRenderingStrategy getGroupBySummarizationRenderingStrategy() {
|
||||
return GroupBySummarizationRenderingStrategy.FUNCTION;
|
||||
|
@ -679,7 +693,7 @@ public class DB2Dialect extends Dialect {
|
|||
@Override
|
||||
public String translateDatetimeFormat(String format) {
|
||||
//DB2 does not need nor support FM
|
||||
return OracleDialect.datetimeFormat( format, false ).result();
|
||||
return OracleDialect.datetimeFormat( format, false, false ).result();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -703,16 +717,6 @@ public class DB2Dialect extends Dialect {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String castPattern(CastType from, CastType to) {
|
||||
if ( getVersion() < 1100 && from == CastType.BOOLEAN && to == CastType.STRING ) {
|
||||
return "case when ?1 = 1 then 'true' else 'false' end";
|
||||
}
|
||||
else {
|
||||
return super.castPattern( from, to );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String extractPattern(TemporalUnit unit) {
|
||||
if ( unit == TemporalUnit.WEEK ) {
|
||||
|
|
|
@ -12,6 +12,8 @@ import org.hibernate.boot.TempTableDdlTransactionHandling;
|
|||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.DerbyConcatEmulation;
|
||||
import org.hibernate.dialect.function.IndividualLeastGreatestEmulation;
|
||||
import org.hibernate.dialect.function.InsertSubstringOverlayEmulation;
|
||||
import org.hibernate.dialect.identity.DB2IdentityColumnSupport;
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
import org.hibernate.dialect.pagination.AbstractLimitHandler;
|
||||
|
@ -30,7 +32,6 @@ import org.hibernate.internal.util.JdbcExceptionHelper;
|
|||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.CastType;
|
||||
import org.hibernate.query.CastTypeKind;
|
||||
import org.hibernate.query.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
|
||||
|
@ -60,8 +61,6 @@ import java.sql.Types;
|
|||
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.query.CastType.BOOLEAN;
|
||||
|
||||
/**
|
||||
* Hibernate Dialect for Apache Derby / Cloudscape 10
|
||||
*
|
||||
|
@ -149,6 +148,13 @@ public class DerbyDialect extends Dialect {
|
|||
return 31;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreferredSqlTypeCodeForBoolean() {
|
||||
return getVersion() < 1070
|
||||
? Types.SMALLINT
|
||||
: Types.BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return version;
|
||||
|
@ -196,6 +202,7 @@ public class DerbyDialect extends Dialect {
|
|||
queryEngine.getSqmFunctionRegistry().register( "concat", new DerbyConcatEmulation() );
|
||||
|
||||
//no way I can see to pad with anything other than spaces
|
||||
// TODO: To support parameters, we have to inline the values
|
||||
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "lpad", "case when length(?1)<?2 then substr(char('',?2)||?1,length(?1)+1) else ?1 end" )
|
||||
.setInvariantType( StandardBasicTypes.STRING )
|
||||
.setExactArgumentCount( 2 )
|
||||
|
@ -206,6 +213,10 @@ public class DerbyDialect extends Dialect {
|
|||
.setExactArgumentCount( 2 )
|
||||
.setArgumentListSignature("(string, length)")
|
||||
.register();
|
||||
|
||||
queryEngine.getSqmFunctionRegistry().register( "least", new IndividualLeastGreatestEmulation( true ) );
|
||||
queryEngine.getSqmFunctionRegistry().register( "greatest", new IndividualLeastGreatestEmulation( false ) );
|
||||
queryEngine.getSqmFunctionRegistry().register( "overlay", new InsertSubstringOverlayEmulation( true ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -245,7 +256,14 @@ public class DerbyDialect extends Dialect {
|
|||
case DAY_OF_YEAR:
|
||||
return "({fn timestampdiff(sql_tsi_day, date(char(year(?2),4)||'-01-01'),?2)}+1)";
|
||||
case DAY_OF_WEEK:
|
||||
return "(mod({fn timestampdiff(sql_tsi_day, {d '2000-01-01'}, ?2)},7)+1)";
|
||||
// Use the approach as outlined here: https://stackoverflow.com/questions/36357013/day-of-week-from-seconds-since-epoch
|
||||
return "(mod(mod({fn timestampdiff(sql_tsi_day, {d '1970-01-01'}, ?2)}+4,7)+7,7)+1)";
|
||||
case WEEK:
|
||||
// Use the approach as outlined here: https://www.sqlservercentral.com/articles/a-simple-formula-to-calculate-the-iso-week-number
|
||||
// In SQL Server terms this is (DATEPART(dy,DATEADD(dd,DATEDIFF(dd,'17530101',@SomeDate)/7*7,'17530104'))+6)/7
|
||||
return "(({fn timestampdiff(sql_tsi_day, date(char(year(?2),4)||'-01-01'),{fn timestampadd(sql_tsi_day, {fn timestampdiff(sql_tsi_day, {d '1753-01-01'}, ?2)}/7*7, {d '1753-01-04'})})}+7)/7)";
|
||||
case QUARTER:
|
||||
return "((month(?2)+2)/3)";
|
||||
default:
|
||||
return "?1(?2)";
|
||||
}
|
||||
|
@ -273,36 +291,30 @@ public class DerbyDialect extends Dialect {
|
|||
*/
|
||||
@Override
|
||||
public String castPattern(CastType from, CastType to) {
|
||||
switch (to) {
|
||||
switch ( to ) {
|
||||
case FLOAT:
|
||||
return "cast(double(?1) as real)";
|
||||
case DOUBLE:
|
||||
return "double(?1)";
|
||||
case BOOLEAN:
|
||||
switch (from) {
|
||||
case STRING:
|
||||
// return "case when lower(?1)in('t','true') then true when lower(?1)in('f','false') then false end";
|
||||
return "case when ?1 in('t','true','T','TRUE') then true when ?1 in('f','false','F','FALSE') then false end";
|
||||
case LONG:
|
||||
case INTEGER:
|
||||
return "(?1<>0)";
|
||||
}
|
||||
break;
|
||||
case INTEGER:
|
||||
case LONG:
|
||||
if ( from == BOOLEAN && getVersion() >= 1070 ) {
|
||||
return "case ?1 when false then 0 when true then 1 end";
|
||||
}
|
||||
break;
|
||||
case STRING:
|
||||
// Derby madness http://db.apache.org/derby/docs/10.8/ref/rrefsqlj33562.html
|
||||
// With a nice rant: https://blog.jooq.org/2011/10/29/derby-casting-madness-the-sequel/
|
||||
// See https://issues.apache.org/jira/browse/DERBY-2072
|
||||
if ( from.getKind() == CastTypeKind.NUMERIC ) {
|
||||
// Use the maximum char capacity here as an intermediate type because Derby doesn't support direct conversion to varchar
|
||||
return "cast(cast(?1 as char(254)) as ?2)";
|
||||
|
||||
// Since numerics can't be cast to varchar directly, use char(254) i.e. with the maximum char capacity
|
||||
// as an intermediate type before converting to varchar
|
||||
switch ( from ) {
|
||||
case FLOAT:
|
||||
case DOUBLE:
|
||||
// Derby can't cast to char directly, but needs to be cast to decimal first...
|
||||
return "cast(trim(cast(cast(?1 as decimal) as char(254))) as ?2)";
|
||||
case INTEGER:
|
||||
case FIXED:
|
||||
return "cast(trim(cast(?1 as char(254))) as ?2)";
|
||||
}
|
||||
break;
|
||||
}
|
||||
return super.castPattern(from, to);
|
||||
return super.castPattern( from, to );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -357,8 +369,8 @@ public class DerbyDialect extends Dialect {
|
|||
@Override
|
||||
public String getQuerySequencesString() {
|
||||
return getVersion() < 1060
|
||||
? "select sys.sysschemas.schemaname as sequence_schema, sys.syssequences.* from sys.syssequences left join sys.sysschemas on sys.syssequences.schemaid = sys.sysschemas.schemaid"
|
||||
: null;
|
||||
? null
|
||||
: "select sys.sysschemas.schemaname as sequence_schema, sys.syssequences.* from sys.syssequences left join sys.sysschemas on sys.syssequences.schemaid = sys.sysschemas.schemaid";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -74,7 +74,6 @@ import org.hibernate.sql.*;
|
|||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.spi.ANSICaseExpressionWalker;
|
||||
import org.hibernate.sql.ast.spi.CaseExpressionWalker;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
||||
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl;
|
||||
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
|
||||
|
@ -152,7 +151,7 @@ public abstract class Dialect implements ConversionContext {
|
|||
|
||||
private final UniqueDelegate uniqueDelegate;
|
||||
|
||||
private DefaultSizeStrategy defaultSizeStrategy;
|
||||
private final SizeStrategy sizeStrategy;
|
||||
|
||||
// constructors and factory methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -242,7 +241,7 @@ public abstract class Dialect implements ConversionContext {
|
|||
}
|
||||
|
||||
uniqueDelegate = new DefaultUniqueDelegate( this );
|
||||
defaultSizeStrategy = new DefaultSizeStrategyImpl();
|
||||
sizeStrategy = new SizeStrategyImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -442,7 +441,7 @@ public abstract class Dialect implements ConversionContext {
|
|||
//very few databases support ANSI-style overlay() function, so emulate
|
||||
//it here in terms of either insert() or concat()/substring()
|
||||
|
||||
queryEngine.getSqmFunctionRegistry().register("overlay", new InsertSubstringOverlayEmulation());
|
||||
queryEngine.getSqmFunctionRegistry().register("overlay", new InsertSubstringOverlayEmulation( false ));
|
||||
|
||||
//ANSI SQL trim() function is supported on almost all of the databases
|
||||
//we care about, but on some it must be emulated using ltrim(), rtrim(),
|
||||
|
@ -634,6 +633,88 @@ public abstract class Dialect implements ConversionContext {
|
|||
* type the value argument is cast to
|
||||
*/
|
||||
public String castPattern(CastType from, CastType to) {
|
||||
switch ( to ) {
|
||||
case STRING:
|
||||
switch ( from ) {
|
||||
case INTEGER_BOOLEAN:
|
||||
return "case ?1 when 1 then 'true' when 0 then 'false' else null end";
|
||||
case YN_BOOLEAN:
|
||||
return "case ?1 when 'Y' then 'true' when 'N' then 'false' else null end";
|
||||
case TF_BOOLEAN:
|
||||
return "case ?1 when 'T' then 'true' when 'F' then 'false' else null end";
|
||||
}
|
||||
break;
|
||||
case INTEGER:
|
||||
case LONG:
|
||||
switch ( from ) {
|
||||
case YN_BOOLEAN:
|
||||
return "case ?1 when 'Y' then 1 when 'N' then 0 else null end";
|
||||
case TF_BOOLEAN:
|
||||
return "case ?1 when 'T' then 1 when 'F' then 0 else null end";
|
||||
case BOOLEAN:
|
||||
return "case ?1 when true then 1 when false then 0 else null end";
|
||||
}
|
||||
break;
|
||||
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";
|
||||
case INTEGER:
|
||||
case LONG:
|
||||
return "abs(sign(?1))";
|
||||
case YN_BOOLEAN:
|
||||
return "case ?1 when 'Y' then 1 when 'N' then 0 else null end";
|
||||
case TF_BOOLEAN:
|
||||
return "case ?1 when 'T' then 1 when 'F' then 0 else null end";
|
||||
case BOOLEAN:
|
||||
return "case ?1 when true then 1 when false then 0 else null end";
|
||||
}
|
||||
break;
|
||||
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";
|
||||
case INTEGER_BOOLEAN:
|
||||
return "case ?1 when 1 then 'Y' when 0 then 'N' else null end";
|
||||
case INTEGER:
|
||||
case LONG:
|
||||
return "case abs(sign(?1)) when 1 then 'Y' when 0 then 'N' else null end";
|
||||
case TF_BOOLEAN:
|
||||
return "case ?1 when 'T' then 'Y' when 'F' then 'N' else null end";
|
||||
case BOOLEAN:
|
||||
return "case ?1 when true then 'Y' when false then 'N' else null end";
|
||||
}
|
||||
break;
|
||||
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";
|
||||
case INTEGER_BOOLEAN:
|
||||
return "case ?1 when 1 then 'T' when 0 then 'F' else null end";
|
||||
case INTEGER:
|
||||
case LONG:
|
||||
return "case abs(sign(?1)) when 1 then 'T' when 0 then 'F' else null end";
|
||||
case YN_BOOLEAN:
|
||||
return "case ?1 when 'Y' then 'T' when 'N' then 'F' else null end";
|
||||
case BOOLEAN:
|
||||
return "case ?1 when true then 'T' when false then 'F' else null end";
|
||||
}
|
||||
break;
|
||||
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";
|
||||
case INTEGER_BOOLEAN:
|
||||
case INTEGER:
|
||||
case LONG:
|
||||
return "(?1<>0)";
|
||||
case YN_BOOLEAN:
|
||||
return "(?1<>'N')";
|
||||
case TF_BOOLEAN:
|
||||
return "(?1<>'F')";
|
||||
}
|
||||
break;
|
||||
}
|
||||
return "cast(?1 as ?2)";
|
||||
}
|
||||
|
||||
|
@ -913,9 +994,12 @@ public abstract class Dialect implements ConversionContext {
|
|||
Size size;
|
||||
if ( length == null && precision == null ) {
|
||||
//use defaults
|
||||
size = getDefaultSizeStrategy().resolveDefaultSize(
|
||||
size = getSizeStrategy().resolveSize(
|
||||
type.getJdbcMapping().getSqlTypeDescriptor(),
|
||||
type.getJdbcMapping().getJavaTypeDescriptor()
|
||||
type.getJdbcMapping().getJavaTypeDescriptor(),
|
||||
precision,
|
||||
scale,
|
||||
length
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
@ -3399,12 +3483,8 @@ public abstract class Dialect implements ConversionContext {
|
|||
return false;
|
||||
}
|
||||
|
||||
public DefaultSizeStrategy getDefaultSizeStrategy(){
|
||||
return defaultSizeStrategy;
|
||||
}
|
||||
|
||||
public void setDefaultSizeStrategy(DefaultSizeStrategy defaultSizeStrategy){
|
||||
this.defaultSizeStrategy = defaultSizeStrategy;
|
||||
public SizeStrategy getSizeStrategy() {
|
||||
return sizeStrategy;
|
||||
}
|
||||
|
||||
public long getDefaultLobLength() {
|
||||
|
@ -3519,38 +3599,63 @@ public abstract class Dialect implements ConversionContext {
|
|||
|
||||
/**
|
||||
* Pluggable strategy for determining the Size to use for columns of
|
||||
* a given SQL type when no explicit Size has been given.
|
||||
* a given SQL type.
|
||||
*
|
||||
* Allows Dialects, integrators and users a chance to apply default
|
||||
* column size limits in certain situations based on the mapped
|
||||
* Allows Dialects, integrators and users a chance to apply
|
||||
* column size defaults and limits in certain situations based on the mapped
|
||||
* SQL and Java types. E.g. when mapping a UUID to a VARCHAR column
|
||||
* we know the default Size should be `Size#length == 36`.
|
||||
*/
|
||||
public interface DefaultSizeStrategy {
|
||||
public interface SizeStrategy {
|
||||
/**
|
||||
* Resolve the default {@link Size} to use for columns of the given
|
||||
* Resolve the {@link Size} to use for columns of the given
|
||||
* {@link SqlTypeDescriptor SQL type} and {@link JavaTypeDescriptor Java type}.
|
||||
*
|
||||
* @return a non-null {@link Size}
|
||||
*/
|
||||
Size resolveDefaultSize(SqlTypeDescriptor sqlType, JavaTypeDescriptor javaType);
|
||||
Size resolveSize(
|
||||
SqlTypeDescriptor sqlType,
|
||||
JavaTypeDescriptor javaType,
|
||||
Integer precision,
|
||||
Integer scale, Long length);
|
||||
}
|
||||
|
||||
public class DefaultSizeStrategyImpl implements DefaultSizeStrategy {
|
||||
public class SizeStrategyImpl implements SizeStrategy {
|
||||
@Override
|
||||
public Size resolveDefaultSize(SqlTypeDescriptor sqlType, JavaTypeDescriptor javaType) {
|
||||
public Size resolveSize(
|
||||
SqlTypeDescriptor sqlType,
|
||||
JavaTypeDescriptor javaType,
|
||||
Integer precision,
|
||||
Integer scale,
|
||||
Long length) {
|
||||
final Size size = new Size();
|
||||
int jdbcTypeCode = sqlType.getJdbcTypeCode();
|
||||
|
||||
switch (jdbcTypeCode) {
|
||||
case Types.BIT:
|
||||
// Use the default length for Boolean if we encounter the JPA default 255 instead
|
||||
if ( javaType.getJavaType() == Boolean.class && length != null && length == 255 ) {
|
||||
length = null;
|
||||
}
|
||||
size.setLength( javaType.getDefaultSqlLength( Dialect.this ) );
|
||||
break;
|
||||
case Types.CHAR:
|
||||
// Use the default length for char if we encounter the JPA default 255 instead
|
||||
if ( javaType.getJavaType() == Character.class && length != null && length == 255 ) {
|
||||
length = null;
|
||||
}
|
||||
size.setLength( javaType.getDefaultSqlLength( Dialect.this ) );
|
||||
break;
|
||||
case Types.NCHAR:
|
||||
case Types.BINARY:
|
||||
case Types.VARCHAR:
|
||||
case Types.NVARCHAR:
|
||||
case Types.VARBINARY:
|
||||
size.setLength( javaType.getDefaultSqlLength(Dialect.this) );
|
||||
// Use the default length for UUID if we encounter the JPA default 255 instead
|
||||
if ( javaType.getJavaType() == UUID.class && length != null && length == 255 ) {
|
||||
length = null;
|
||||
}
|
||||
size.setLength( javaType.getDefaultSqlLength( Dialect.this ) );
|
||||
break;
|
||||
case Types.LONGVARCHAR:
|
||||
case Types.LONGNVARCHAR:
|
||||
|
@ -3562,11 +3667,11 @@ public abstract class Dialect implements ConversionContext {
|
|||
case Types.REAL:
|
||||
case Types.TIMESTAMP:
|
||||
case Types.TIMESTAMP_WITH_TIMEZONE:
|
||||
size.setPrecision( javaType.getDefaultSqlPrecision(Dialect.this) );
|
||||
size.setPrecision( javaType.getDefaultSqlPrecision( Dialect.this ) );
|
||||
break;
|
||||
case Types.NUMERIC:
|
||||
case Types.DECIMAL:
|
||||
size.setPrecision( javaType.getDefaultSqlPrecision(Dialect.this) );
|
||||
size.setPrecision( javaType.getDefaultSqlPrecision( Dialect.this ) );
|
||||
size.setScale( javaType.getDefaultSqlScale() );
|
||||
break;
|
||||
case Types.CLOB:
|
||||
|
@ -3575,6 +3680,16 @@ public abstract class Dialect implements ConversionContext {
|
|||
break;
|
||||
|
||||
}
|
||||
|
||||
if ( precision != null ) {
|
||||
size.setPrecision( precision );
|
||||
}
|
||||
if ( scale != null ) {
|
||||
size.setScale( scale );
|
||||
}
|
||||
if ( length != null ) {
|
||||
size.setLength( length );
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
@ -3620,7 +3735,7 @@ public abstract class Dialect implements ConversionContext {
|
|||
//most databases support a datetime format
|
||||
//copied from Oracle's to_char() function,
|
||||
//with some minor variation
|
||||
return OracleDialect.datetimeFormat( format, true ).result();
|
||||
return OracleDialect.datetimeFormat( format, true, false ).result();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -61,7 +61,6 @@ import java.util.regex.Pattern;
|
|||
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.query.CastType.*;
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.formatAsTimestampWithMillis;
|
||||
|
||||
/**
|
||||
|
@ -219,24 +218,49 @@ public class FirebirdDialect extends Dialect {
|
|||
*/
|
||||
@Override
|
||||
public String castPattern(CastType from, CastType to) {
|
||||
if ( to==BOOLEAN
|
||||
&& (from==LONG || from==INTEGER)) {
|
||||
return "(0<>?1)";
|
||||
String result;
|
||||
switch ( to ) {
|
||||
case FLOAT:
|
||||
return "cast(double(?1) as real)";
|
||||
case DOUBLE:
|
||||
return "double(?1)";
|
||||
case INTEGER:
|
||||
case LONG:
|
||||
result = BooleanDecoder.toInteger( from );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
||||
if ( getVersion() < 300 ) {
|
||||
if ( to==BOOLEAN && from==STRING ) {
|
||||
// return "iif(lower(?1) similar to 't|f|true|false', lower(?1) like 't%', null)";
|
||||
return "decode(lower(?1),'t',1,'f',0,'true',1,'false',0)";
|
||||
break;
|
||||
case BOOLEAN:
|
||||
result = BooleanDecoder.toBoolean( from );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
||||
if ( to==STRING && from==BOOLEAN ) {
|
||||
return "trim(decode(?1,0,'false','true'))";
|
||||
break;
|
||||
case INTEGER_BOOLEAN:
|
||||
result = BooleanDecoder.toIntegerBoolean( from );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case YN_BOOLEAN:
|
||||
result = BooleanDecoder.toYesNoBoolean( from );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
if ( from==BOOLEAN
|
||||
&& (to==LONG || to==INTEGER)) {
|
||||
return "decode(?1,false,0,true,1)";
|
||||
break;
|
||||
case TF_BOOLEAN:
|
||||
result = BooleanDecoder.toTrueFalseBoolean( from );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case STRING:
|
||||
result = BooleanDecoder.toString( from );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return super.castPattern( from, to );
|
||||
}
|
||||
|
|
|
@ -65,9 +65,6 @@ import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
|
|||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
|
||||
import static org.hibernate.query.CastType.BOOLEAN;
|
||||
import static org.hibernate.query.CastType.INTEGER;
|
||||
import static org.hibernate.query.CastType.LONG;
|
||||
|
||||
/**
|
||||
* An SQL dialect compatible with HyperSQL (HSQLDB) version 1.8 and above.
|
||||
|
@ -237,12 +234,47 @@ public class HSQLDialect extends Dialect {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String castPattern(CastType from, CastType to) {
|
||||
if ( from== BOOLEAN
|
||||
&& (to== INTEGER || to== LONG)) {
|
||||
return "casewhen(?1,1,0)";
|
||||
String result;
|
||||
switch ( to ) {
|
||||
case INTEGER:
|
||||
case LONG:
|
||||
result = BooleanDecoder.toInteger( from );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case BOOLEAN:
|
||||
result = BooleanDecoder.toBoolean( from );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case INTEGER_BOOLEAN:
|
||||
result = BooleanDecoder.toIntegerBoolean( from );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case YN_BOOLEAN:
|
||||
result = BooleanDecoder.toYesNoBoolean( from );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case TF_BOOLEAN:
|
||||
result = BooleanDecoder.toTrueFalseBoolean( from );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case STRING:
|
||||
result = BooleanDecoder.toString( from );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return super.castPattern( from, to );
|
||||
}
|
||||
|
@ -647,7 +679,7 @@ public class HSQLDialect extends Dialect {
|
|||
|
||||
@Override
|
||||
public String translateDatetimeFormat(String format) {
|
||||
return OracleDialect.datetimeFormat(format, false)
|
||||
return OracleDialect.datetimeFormat( format, false, false )
|
||||
.replace("SSSSSS", "FF")
|
||||
.replace("SSSSS", "FF")
|
||||
.replace("SSSS", "FF")
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.dialect;
|
|||
|
||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.IndividualLeastGreatestEmulation;
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
import org.hibernate.dialect.identity.InformixIdentityColumnSupport;
|
||||
import org.hibernate.dialect.pagination.FirstLimitHandler;
|
||||
|
@ -163,6 +164,9 @@ public class InformixDialect extends Dialect {
|
|||
).setArgumentListSignature("(pattern, string[, start])");
|
||||
|
||||
//coalesce() and nullif() both supported since Informix 12
|
||||
|
||||
queryEngine.getSqmFunctionRegistry().register( "least", new IndividualLeastGreatestEmulation( true ) );
|
||||
queryEngine.getSqmFunctionRegistry().register( "greatest", new IndividualLeastGreatestEmulation( false ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,7 +16,6 @@ import org.hibernate.dialect.sequence.MimerSequenceSupport;
|
|||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.engine.jdbc.Size;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.CastType;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
|
@ -32,8 +31,6 @@ import java.sql.Types;
|
|||
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.query.CastType.BOOLEAN;
|
||||
|
||||
/**
|
||||
* A dialect for Mimer SQL 11.
|
||||
*
|
||||
|
@ -124,34 +121,6 @@ public class MimerSQLDialect extends Dialect {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Mimer does have a real {@link java.sql.Types#BOOLEAN}
|
||||
* type, but it doesn't know how to cast to it.
|
||||
*/
|
||||
@Override
|
||||
public String castPattern(CastType from, CastType to) {
|
||||
switch (to) {
|
||||
case BOOLEAN:
|
||||
switch (from) {
|
||||
case STRING:
|
||||
// return "case when regexp_match(lower(?1), '^(t|f|true|false)$') then lower(?1) like 't%' end";
|
||||
// return "case when lower(?1)in('t','true') then true when lower(?1)in('f','false') then false end";
|
||||
return "case when ?1 in('t','true','T','TRUE') then true when ?1 in('f','false','F','FALSE') then false end";
|
||||
case LONG:
|
||||
case INTEGER:
|
||||
return "(?1<>0)";
|
||||
}
|
||||
break;
|
||||
case INTEGER:
|
||||
case LONG:
|
||||
if (from == BOOLEAN) {
|
||||
return "case ?1 when false then 0 when true then 1 end";
|
||||
}
|
||||
break;
|
||||
}
|
||||
return super.castPattern(from, to);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String currentTimestamp() {
|
||||
return "localtimestamp";
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.hibernate.dialect.sequence.NoSequenceSupport;
|
|||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.dialect.unique.MySQLUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
import org.hibernate.engine.jdbc.Size;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.exception.LockAcquisitionException;
|
||||
|
@ -33,7 +34,6 @@ import org.hibernate.internal.util.JdbcExceptionHelper;
|
|||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.SqlExpressable;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.CastType;
|
||||
import org.hibernate.query.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
|
||||
|
@ -47,6 +47,8 @@ import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
|||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperation;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.ResultSet;
|
||||
|
@ -56,7 +58,6 @@ import java.sql.Types;
|
|||
import javax.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
|
||||
import static org.hibernate.query.CastType.BOOLEAN;
|
||||
|
||||
/**
|
||||
* An SQL dialect for MySQL (prior to 5.x).
|
||||
|
@ -68,6 +69,7 @@ public class MySQLDialect extends Dialect {
|
|||
private final UniqueDelegate uniqueDelegate;
|
||||
private final MySQLStorageEngine storageEngine;
|
||||
private final int version;
|
||||
private final SizeStrategy sizeStrategy;
|
||||
|
||||
public MySQLDialect(DialectResolutionInfo info) {
|
||||
this( info.getDatabaseMajorVersion() * 100 + info.getDatabaseMinorVersion() * 10 );
|
||||
|
@ -88,10 +90,10 @@ public class MySQLDialect extends Dialect {
|
|||
if (storageEngine == null) {
|
||||
this.storageEngine = getDefaultMySQLStorageEngine();
|
||||
}
|
||||
else if( "innodb".equals( storageEngine.toLowerCase() ) ) {
|
||||
else if( "innodb".equalsIgnoreCase( storageEngine ) ) {
|
||||
this.storageEngine = InnoDBStorageEngine.INSTANCE;
|
||||
}
|
||||
else if( "myisam".equals( storageEngine.toLowerCase() ) ) {
|
||||
else if( "myisam".equalsIgnoreCase( storageEngine ) ) {
|
||||
this.storageEngine = MyISAMStorageEngine.INSTANCE;
|
||||
}
|
||||
else {
|
||||
|
@ -163,6 +165,25 @@ public class MySQLDialect extends Dialect {
|
|||
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
|
||||
|
||||
uniqueDelegate = new MySQLUniqueDelegate( this );
|
||||
sizeStrategy = new SizeStrategyImpl() {
|
||||
@Override
|
||||
public Size resolveSize(
|
||||
SqlTypeDescriptor sqlType,
|
||||
JavaTypeDescriptor javaType,
|
||||
Integer precision,
|
||||
Integer scale,
|
||||
Long length) {
|
||||
final int jdbcTypeCode = sqlType.getSqlType();
|
||||
switch ( jdbcTypeCode ) {
|
||||
case Types.BIT:
|
||||
// MySQL allows BIT with a length up to 64
|
||||
if ( length != null ) {
|
||||
return Size.length( Math.min( Math.max( length, 1 ), 64 ) );
|
||||
}
|
||||
}
|
||||
return super.resolveSize( sqlType, javaType, precision, scale, length );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -174,6 +195,11 @@ public class MySQLDialect extends Dialect {
|
|||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SizeStrategy getSizeStrategy() {
|
||||
return sizeStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDefaultLobLength() {
|
||||
//max length for mediumblob or mediumtext
|
||||
|
@ -334,31 +360,6 @@ public class MySQLDialect extends Dialect {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MySQL doesn't have a real {@link java.sql.Types#BOOLEAN}
|
||||
* type, so...
|
||||
*/
|
||||
@Override
|
||||
public String castPattern(CastType from, CastType to) {
|
||||
switch (to) {
|
||||
case BOOLEAN:
|
||||
switch (from) {
|
||||
case STRING:
|
||||
// return "if(?1 rlike '^(t|f|true|false)$', ?1 like 't%', null)";
|
||||
return "if(lower(?1) in('t','f','true','false'), ?1 like 't%', null)";
|
||||
case LONG:
|
||||
case INTEGER:
|
||||
return "(?1<>0)";
|
||||
}
|
||||
case STRING:
|
||||
if (from == BOOLEAN) {
|
||||
return "if(?1,'true','false')";
|
||||
}
|
||||
default:
|
||||
return super.castPattern(from, to);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) {
|
||||
switch (unit) {
|
||||
|
@ -717,11 +718,14 @@ public class MySQLDialect extends Dialect {
|
|||
return new LockAcquisitionException( message, sqlException, sql );
|
||||
}
|
||||
|
||||
switch ( JdbcExceptionHelper.extractSqlState( sqlException ) ) {
|
||||
final String sqlState = JdbcExceptionHelper.extractSqlState( sqlException );
|
||||
if ( sqlState != null ) {
|
||||
switch ( sqlState ) {
|
||||
case "41000":
|
||||
return new LockTimeoutException(message, sqlException, sql);
|
||||
return new LockTimeoutException( message, sqlException, sql );
|
||||
case "40001":
|
||||
return new LockAcquisitionException(message, sqlException, sql);
|
||||
return new LockAcquisitionException( message, sqlException, sql );
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -70,7 +70,6 @@ import java.util.regex.Pattern;
|
|||
import javax.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
|
||||
import static org.hibernate.query.CastType.STRING;
|
||||
import static org.hibernate.query.TemporalUnit.*;
|
||||
|
||||
/**
|
||||
|
@ -234,19 +233,40 @@ public class OracleDialect extends Dialect {
|
|||
*/
|
||||
@Override
|
||||
public String castPattern(CastType from, CastType to) {
|
||||
switch (to) {
|
||||
case BOOLEAN:
|
||||
switch (from) {
|
||||
case STRING:
|
||||
return "decode(lower(?1),'t',1,'f',0,'true',1,'false',0)";
|
||||
case LONG:
|
||||
String result;
|
||||
switch ( to ) {
|
||||
case INTEGER:
|
||||
return "abs(sign(?1))";
|
||||
case LONG:
|
||||
result = BooleanDecoder.toInteger( from );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
||||
case STRING:
|
||||
switch (from) {
|
||||
break;
|
||||
case INTEGER_BOOLEAN:
|
||||
result = BooleanDecoder.toIntegerBoolean( from );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case YN_BOOLEAN:
|
||||
result = BooleanDecoder.toYesNoBoolean( from );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case BOOLEAN:
|
||||
return "decode(?1,0,'false','true')";
|
||||
case TF_BOOLEAN:
|
||||
result = BooleanDecoder.toTrueFalseBoolean( from );
|
||||
if ( result != null ) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case STRING:
|
||||
switch ( from ) {
|
||||
case INTEGER_BOOLEAN:
|
||||
case TF_BOOLEAN:
|
||||
case YN_BOOLEAN:
|
||||
return BooleanDecoder.toString( from );
|
||||
case DATE:
|
||||
return "to_char(?1,'YYYY-MM-DD')";
|
||||
case TIME:
|
||||
|
@ -258,29 +278,34 @@ public class OracleDialect extends Dialect {
|
|||
case ZONE_TIMESTAMP:
|
||||
return "to_char(?1,'YYYY-MM-DD HH24:MI:SS.FF9 TZR')";
|
||||
}
|
||||
break;
|
||||
case DATE:
|
||||
if (from == STRING) {
|
||||
if ( from == CastType.STRING ) {
|
||||
return "to_date(?1,'YYYY-MM-DD')";
|
||||
}
|
||||
break;
|
||||
case TIME:
|
||||
if (from == STRING) {
|
||||
if ( from == CastType.STRING ) {
|
||||
return "to_date(?1,'HH24:MI:SS')";
|
||||
}
|
||||
break;
|
||||
case TIMESTAMP:
|
||||
if (from == STRING) {
|
||||
if ( from == CastType.STRING ) {
|
||||
return "to_timestamp(?1,'YYYY-MM-DD HH24:MI:SS.FF9')";
|
||||
}
|
||||
break;
|
||||
case OFFSET_TIMESTAMP:
|
||||
if (from == STRING) {
|
||||
if ( from == CastType.STRING ) {
|
||||
return "to_timestamp_tz(?1,'YYYY-MM-DD HH24:MI:SS.FF9TZH:TZM')";
|
||||
}
|
||||
break;
|
||||
case ZONE_TIMESTAMP:
|
||||
if (from == STRING) {
|
||||
if ( from == CastType.STRING ) {
|
||||
return "to_timestamp_tz(?1,'YYYY-MM-DD HH24:MI:SS.FF9 TZR')";
|
||||
}
|
||||
default:
|
||||
return super.castPattern(from, to);
|
||||
break;
|
||||
}
|
||||
return super.castPattern(from, to);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -315,6 +340,20 @@ public class OracleDialect extends Dialect {
|
|||
return "to_number(to_char(?2,'DDD'))";
|
||||
case WEEK:
|
||||
return "to_number(to_char(?2,'IW'))"; //the ISO week number
|
||||
case WEEK_OF_YEAR:
|
||||
return "to_number(to_char(?2,'WW'))";
|
||||
// Oracle doesn't support extracting the quarter
|
||||
case QUARTER:
|
||||
return "to_number(to_char(?2,'Q'))";
|
||||
// Oracle can't extract time parts from a date column, so we need to cast to timestamp
|
||||
// This is because Oracle treats date as ANSI SQL date which has no time part
|
||||
// Also see https://docs.oracle.com/cd/B28359_01/server.111/b28286/functions052.htm#SQLRF00639
|
||||
case HOUR:
|
||||
return "to_number(to_char(?2,'HH24'))";
|
||||
case MINUTE:
|
||||
return "to_number(to_char(?2,'MI'))";
|
||||
case SECOND:
|
||||
return "to_number(to_char(?2,'SS'))";
|
||||
default:
|
||||
return super.extractPattern(unit);
|
||||
}
|
||||
|
@ -855,7 +894,11 @@ public class OracleDialect extends Dialect {
|
|||
EntityMappingType rootEntityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new GlobalTemporaryTableStrategy(
|
||||
new IdTable( rootEntityDescriptor, name -> name.length() > 30 ? name.substring( 0, 30 ) : name, this ),
|
||||
new IdTable(
|
||||
rootEntityDescriptor,
|
||||
name -> "HT_" + ( name.length() > 27 ? name.substring( 0, 27 ) : name ),
|
||||
this
|
||||
),
|
||||
() -> new TempIdTableExporter( false, this::getTypeName ) {
|
||||
@Override
|
||||
protected String getCreateOptions() {
|
||||
|
@ -1050,8 +1093,16 @@ public class OracleDialect extends Dialect {
|
|||
return getWriteLockString( aliases, timeout );
|
||||
}
|
||||
|
||||
public static Replacer datetimeFormat(String format, boolean useFm) {
|
||||
@Override
|
||||
public String translateDatetimeFormat(String format) {
|
||||
// Unlike other databases, Oracle requires an explicit reset for the fm modifier,
|
||||
// otherwise all following pattern variables trim zeros
|
||||
return datetimeFormat( format, true, true ).result();
|
||||
}
|
||||
|
||||
public static Replacer datetimeFormat(String format, boolean useFm, boolean resetFm) {
|
||||
String fm = useFm ? "fm" : "";
|
||||
String fmReset = resetFm ? fm : "";
|
||||
return new Replacer( format, "'", "\"" )
|
||||
//era
|
||||
.replace("GG", "AD")
|
||||
|
@ -1059,42 +1110,42 @@ public class OracleDialect extends Dialect {
|
|||
|
||||
//year
|
||||
.replace("yyyy", "YYYY")
|
||||
.replace("yyy", fm + "YYYY")
|
||||
.replace("yyy", fm + "YYYY" + fmReset)
|
||||
.replace("yy", "YY")
|
||||
.replace("y", fm + "YYYY")
|
||||
.replace("y", fm + "YYYY" + fmReset)
|
||||
|
||||
//month of year
|
||||
.replace("MMMM", fm + "Month")
|
||||
.replace("MMMM", fm + "Month" + fmReset)
|
||||
.replace("MMM", "Mon")
|
||||
.replace("MM", "MM")
|
||||
.replace("M", fm + "MM")
|
||||
.replace("M", fm + "MM" + fmReset)
|
||||
|
||||
//week of year
|
||||
.replace("ww", "IW")
|
||||
.replace("w", fm + "IW")
|
||||
.replace("w", fm + "IW" + fmReset)
|
||||
//year for week
|
||||
.replace("YYYY", "IYYY")
|
||||
.replace("YYY", fm + "IYYY")
|
||||
.replace("YYY", fm + "IYYY" + fmReset)
|
||||
.replace("YY", "IY")
|
||||
.replace("Y", fm + "IYYY")
|
||||
.replace("Y", fm + "IYYY" + fmReset)
|
||||
|
||||
//week of month
|
||||
.replace("W", "W")
|
||||
|
||||
//day of week
|
||||
.replace("EEEE", fm + "Day")
|
||||
.replace("EEEE", fm + "Day" + fmReset)
|
||||
.replace("EEE", "Dy")
|
||||
.replace("ee", "D")
|
||||
.replace("e", fm + "D")
|
||||
.replace("e", fm + "D" + fmReset)
|
||||
|
||||
//day of month
|
||||
.replace("dd", "DD")
|
||||
.replace("d", fm + "DD")
|
||||
.replace("d", fm + "DD" + fmReset)
|
||||
|
||||
//day of year
|
||||
.replace("DDD", "DDD")
|
||||
.replace("DD", fm + "DDD")
|
||||
.replace("D", fm + "DDD")
|
||||
.replace("DD", fm + "DDD" + fmReset)
|
||||
.replace("D", fm + "DDD" + fmReset)
|
||||
|
||||
//am pm
|
||||
.replace("aa", "AM")
|
||||
|
@ -1103,16 +1154,16 @@ public class OracleDialect extends Dialect {
|
|||
//hour
|
||||
.replace("hh", "HH12")
|
||||
.replace("HH", "HH24")
|
||||
.replace("h", fm + "HH12")
|
||||
.replace("H", fm + "HH24")
|
||||
.replace("h", fm + "HH12" + fmReset)
|
||||
.replace("H", fm + "HH24" + fmReset)
|
||||
|
||||
//minute
|
||||
.replace("mm", "MI")
|
||||
.replace("m", fm + "MI")
|
||||
.replace("m", fm + "MI" + fmReset)
|
||||
|
||||
//second
|
||||
.replace("ss", "SS")
|
||||
.replace("s", fm + "SS")
|
||||
.replace("s", fm + "SS" + fmReset)
|
||||
|
||||
//fractional seconds
|
||||
.replace("SSSSSS", "FF6")
|
||||
|
|
|
@ -6,10 +6,14 @@
|
|||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import org.hibernate.FetchClauseType;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.collections.Stack;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.insert.Values;
|
||||
import org.hibernate.sql.ast.tree.select.QueryGroup;
|
||||
import org.hibernate.sql.ast.tree.select.QueryPart;
|
||||
import org.hibernate.sql.ast.tree.select.QuerySpec;
|
||||
|
@ -34,6 +38,30 @@ public class OracleSqlAstTranslator<T extends JdbcOperation> extends AbstractSql
|
|||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitValuesList(List<Values> valuesList) {
|
||||
if ( valuesList.size() < 2 ) {
|
||||
super.visitValuesList( valuesList );
|
||||
}
|
||||
else {
|
||||
// Oracle doesn't support a multi-values insert
|
||||
// So we render a select union emulation instead
|
||||
String separator = "";
|
||||
final Stack<Clause> clauseStack = getClauseStack();
|
||||
try {
|
||||
clauseStack.push( Clause.VALUES );
|
||||
for ( Values values : valuesList ) {
|
||||
appendSql( separator );
|
||||
renderExpressionsAsSubquery( values.getExpressions() );
|
||||
separator = " union all ";
|
||||
}
|
||||
}
|
||||
finally {
|
||||
clauseStack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitQueryGroup(QueryGroup queryGroup) {
|
||||
if ( shouldEmulateFetchClause( queryGroup ) ) {
|
||||
|
|
|
@ -669,7 +669,7 @@ public class PostgreSQLDialect extends Dialect {
|
|||
}
|
||||
|
||||
public Replacer datetimeFormat(String format) {
|
||||
return OracleDialect.datetimeFormat(format, true)
|
||||
return OracleDialect.datetimeFormat( format, true, false )
|
||||
.replace("SSSSSS", "US")
|
||||
.replace("SSSSS", "US")
|
||||
.replace("SSSS", "US")
|
||||
|
|
|
@ -343,7 +343,7 @@ public class RDMSOS2200Dialect extends Dialect {
|
|||
|
||||
@Override
|
||||
public String translateDatetimeFormat(String format) {
|
||||
return OracleDialect.datetimeFormat( format, true ) //Does it really support FM?
|
||||
return OracleDialect.datetimeFormat( format, true, false ) //Does it really support FM?
|
||||
.replace("SSSSSS", "MLS")
|
||||
.replace("SSSSS", "MLS")
|
||||
.replace("SSSS", "MLS")
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.dialect;
|
|||
|
||||
import org.hibernate.*;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.SQLServerFormatFunction;
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
import org.hibernate.dialect.identity.SQLServerIdentityColumnSupport;
|
||||
import org.hibernate.dialect.pagination.LimitHandler;
|
||||
|
@ -22,6 +23,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
import org.hibernate.exception.LockTimeoutException;
|
||||
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
|
||||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
import org.hibernate.query.CastType;
|
||||
import org.hibernate.query.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
|
@ -146,7 +148,7 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
|||
}
|
||||
|
||||
if ( getVersion() >= 11 ) {
|
||||
CommonFunctionFactory.format_format( queryEngine );
|
||||
queryEngine.getSqmFunctionRegistry().register( "format", new SQLServerFormatFunction( this ) );
|
||||
|
||||
//actually translate() was added in 2017 but
|
||||
//it's not worth adding a new dialect for that!
|
||||
|
@ -192,6 +194,22 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String castPattern(CastType from, CastType to) {
|
||||
if ( to == CastType.STRING ) {
|
||||
switch ( from ) {
|
||||
case TIMESTAMP:
|
||||
// SQL Server uses yyyy-MM-dd HH:mm:ss.nnnnnnn by default when doing a cast, but only need second precision
|
||||
return "format(?1,'yyyy-MM-dd HH:mm:ss')";
|
||||
case TIME:
|
||||
// SQL Server uses HH:mm:ss.nnnnnnn by default when doing a cast, but only need second precision
|
||||
// SQL Server requires quoting of ':' in time formats and the use of 'hh' instead of 'HH'
|
||||
return "format(?1,'hh\\:mm\\:ss')";
|
||||
}
|
||||
}
|
||||
return super.castPattern( from, to );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String currentTimestamp() {
|
||||
return "sysdatetime()";
|
||||
|
@ -199,7 +217,7 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
|||
|
||||
@Override
|
||||
public String currentTime() {
|
||||
return currentTimestamp();
|
||||
return "convert(time, getdate())";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -502,16 +520,25 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
|||
@Override
|
||||
public String extractPattern(TemporalUnit unit) {
|
||||
switch (unit) {
|
||||
case TIMEZONE_HOUR:
|
||||
return "(datepart(tz,?2)/60)";
|
||||
case TIMEZONE_MINUTE:
|
||||
return "(datepart(tz,?2)%60)";
|
||||
//currently Dialect.extract() doesn't need
|
||||
//to handle NANOSECOND (might change that?)
|
||||
// case NANOSECOND:
|
||||
// //this should evaluate to a bigint type
|
||||
// return "(datepart(second,?2,?3)*1000000000+datepart(nanosecond,?2,?3))";
|
||||
// return "(datepart(second,?2)*1000000000+datepart(nanosecond,?2))";
|
||||
case SECOND:
|
||||
//this should evaluate to a floating point type
|
||||
return "(datepart(second,?2,?3)+datepart(nanosecond,?2,?3)/1e9)";
|
||||
return "(datepart(second,?2)+datepart(nanosecond,?2)/1e9)";
|
||||
case WEEK:
|
||||
// Thanks https://www.sqlservercentral.com/articles/a-simple-formula-to-calculate-the-iso-week-number
|
||||
if ( getVersion() < 10 ) {
|
||||
return "(DATEPART(dy,DATEADD(dd,DATEDIFF(dd,'17530101',?2)/7*7,'17530104'))+6)/7)";
|
||||
}
|
||||
default:
|
||||
return "datepart(?1,?2,?3)";
|
||||
return "datepart(?1,?2)";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -565,6 +592,7 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
|||
switch ( unit ) {
|
||||
//the ISO week number (behavior of "week" depends on a system property)
|
||||
case WEEK: return "isowk";
|
||||
case OFFSET: return "tz";
|
||||
default: return super.translateExtractField(unit);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,20 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends Abstract
|
|||
hasLimit = queryPart.getFetchClauseExpression() != null;
|
||||
hasOffset = queryPart.getOffsetClauseExpression() != null;
|
||||
}
|
||||
if ( queryPart instanceof QueryGroup ) {
|
||||
// We can't use TOP for set operations
|
||||
if ( hasOffset || hasLimit ) {
|
||||
if ( version < 11 || !isRowsOnlyFetchClauseType( queryPart ) ) {
|
||||
return OffsetFetchClauseMode.EMULATED;
|
||||
}
|
||||
else {
|
||||
return OffsetFetchClauseMode.STANDARD;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
if ( version < 9 || !hasOffset ) {
|
||||
return hasLimit ? OffsetFetchClauseMode.TOP_ONLY : null;
|
||||
}
|
||||
|
@ -55,6 +69,15 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends Abstract
|
|||
return OffsetFetchClauseMode.STANDARD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsSimpleQueryGrouping() {
|
||||
// SQL Server is quite strict i.e. it requires `select .. union all select * from (select ...)`
|
||||
// rather than `select .. union all (select ...)` because parenthesis followed by select
|
||||
// is always treated as a subquery, which is not supported in a set operation
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean shouldEmulateFetchClause(QueryPart queryPart) {
|
||||
// Check if current query part is already row numbering to avoid infinite recursion
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.dialect;
|
||||
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.dialect.function.QuantifiedLeastGreatestEmulation;
|
||||
import org.hibernate.dialect.pagination.LimitHandler;
|
||||
import org.hibernate.dialect.pagination.TopLimitHandler;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
|
@ -16,6 +17,7 @@ import org.hibernate.exception.LockTimeoutException;
|
|||
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
|
||||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
import org.hibernate.query.TrimSpec;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.sql.ForUpdateFragment;
|
||||
import org.hibernate.sql.JoinFragment;
|
||||
import org.hibernate.sql.Sybase11JoinFragment;
|
||||
|
@ -340,7 +342,14 @@ public class SybaseASEDialect extends SybaseDialect {
|
|||
registerKeyword( "xmlvalidate" );
|
||||
}
|
||||
|
||||
// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@Override
|
||||
public void initializeFunctionRegistry(QueryEngine queryEngine) {
|
||||
super.initializeFunctionRegistry( queryEngine );
|
||||
|
||||
queryEngine.getSqmFunctionRegistry().register( "least", new QuantifiedLeastGreatestEmulation( true ) );
|
||||
queryEngine.getSqmFunctionRegistry().register( "greatest", new QuantifiedLeastGreatestEmulation( false ) );
|
||||
}
|
||||
// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@Override
|
||||
|
|
|
@ -42,11 +42,11 @@ public class CastFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
|||
public void render(SqlAppender sqlAppender, List<SqlAstNode> arguments, SqlAstWalker walker) {
|
||||
final Expression source = (Expression) arguments.get( 0 );
|
||||
final JdbcMapping sourceMapping = ( (SqlExpressable) source.getExpressionType() ).getJdbcMapping();
|
||||
final CastType sourceType = CastType.from( sourceMapping );
|
||||
final CastType sourceType = sourceMapping.getCastType();
|
||||
|
||||
final CastTarget castTarget = (CastTarget) arguments.get( 1 );
|
||||
final JdbcMapping targetJdbcMapping = castTarget.getExpressionType().getJdbcMapping();
|
||||
final CastType targetType = CastType.from( targetJdbcMapping );
|
||||
final CastType targetType = targetJdbcMapping.getCastType();
|
||||
|
||||
String cast = dialect.castPattern( sourceType, targetType );
|
||||
|
||||
|
|
|
@ -1254,7 +1254,7 @@ public class CommonFunctionFactory {
|
|||
.registerBinaryTernaryPattern(
|
||||
"substring",
|
||||
StandardBasicTypes.STRING,
|
||||
"substring(?1,?2,len(?1)-?2)",
|
||||
"substring(?1,?2,len(?1)-?2+1)",
|
||||
"substring(?1,?2,?3)"
|
||||
)
|
||||
.setArgumentListSignature("(string{ from|,} start[{ for|,} length])");
|
||||
|
|
|
@ -50,7 +50,7 @@ public class DB2FormatEmulation
|
|||
final Format format = (Format) arguments.get(1);
|
||||
|
||||
sqlAppender.appendSql("(");
|
||||
String[] bits = OracleDialect.datetimeFormat( format.getFormat(), false ).result().split("\"");
|
||||
String[] bits = OracleDialect.datetimeFormat( format.getFormat(), false, false ).result().split("\"");
|
||||
boolean first = true;
|
||||
for ( int i=0; i<bits.length; i++ ) {
|
||||
String bit = bits[i];
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.dialect.function;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class IndividualLeastGreatestEmulation
|
||||
extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||
|
||||
private final String operator;
|
||||
|
||||
public IndividualLeastGreatestEmulation(boolean least) {
|
||||
super(
|
||||
least ? "least" : "greatest",
|
||||
StandardArgumentsValidators.min( 2 ),
|
||||
StandardFunctionReturnTypeResolvers.useFirstNonNull()
|
||||
);
|
||||
this.operator = least ? "<=" : ">=";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> arguments,
|
||||
SqlAstWalker walker) {
|
||||
final int numberOfArguments = arguments.size();
|
||||
if ( numberOfArguments > 1 ) {
|
||||
final int lastArgument = numberOfArguments - 1;
|
||||
sqlAppender.appendSql( "case" );
|
||||
for ( int i = 0; i < lastArgument; i++ ) {
|
||||
sqlAppender.appendSql( " when " );
|
||||
String separator = "";
|
||||
for ( int j = i + 1; j < numberOfArguments; j++ ) {
|
||||
sqlAppender.appendSql( separator );
|
||||
arguments.get( i ).accept( walker );
|
||||
sqlAppender.appendSql( operator );
|
||||
arguments.get( j ).accept( walker );
|
||||
separator = " and ";
|
||||
}
|
||||
sqlAppender.appendSql( " then " );
|
||||
arguments.get( i ).accept( walker );
|
||||
}
|
||||
sqlAppender.appendSql( " else " );
|
||||
arguments.get( lastArgument ).accept( walker );
|
||||
sqlAppender.appendSql( " end" );
|
||||
}
|
||||
else {
|
||||
arguments.get( 0 ).accept( walker );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgumentListSignature() {
|
||||
return "(arg0[, arg1[, ...]])";
|
||||
}
|
||||
}
|
|
@ -8,7 +8,9 @@ package org.hibernate.dialect.function;
|
|||
|
||||
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;
|
||||
|
@ -16,14 +18,18 @@ import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
|||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.query.sqm.tree.SqmTypedNode;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.criteria.Expression;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
|
@ -32,12 +38,15 @@ import static java.util.Arrays.asList;
|
|||
public class InsertSubstringOverlayEmulation
|
||||
extends AbstractSqmFunctionDescriptor {
|
||||
|
||||
public InsertSubstringOverlayEmulation() {
|
||||
private final boolean strictSubstring;
|
||||
|
||||
public InsertSubstringOverlayEmulation(boolean strictSubstring) {
|
||||
super(
|
||||
"overlay",
|
||||
StandardArgumentsValidators.between( 3, 4 ),
|
||||
StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.STRING )
|
||||
);
|
||||
this.strictSubstring = strictSubstring;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -66,6 +75,7 @@ public class InsertSubstringOverlayEmulation
|
|||
);
|
||||
}
|
||||
else {
|
||||
SqmFunctionDescriptor lengthFunction = queryEngine.getSqmFunctionRegistry().findFunctionDescriptor("length");
|
||||
SqmFunctionDescriptor substring = queryEngine.getSqmFunctionRegistry().findFunctionDescriptor("substring");
|
||||
SqmFunctionDescriptor concat = queryEngine.getSqmFunctionRegistry().findFunctionDescriptor("concat");
|
||||
SqmLiteral<Integer> one = new SqmLiteral<>( 1, intType, queryEngine.getCriteriaBuilder() );
|
||||
|
@ -83,6 +93,30 @@ public class InsertSubstringOverlayEmulation
|
|||
intType,
|
||||
queryEngine.getCriteriaBuilder()
|
||||
);
|
||||
SqmExpressable<Object> stringType = (SqmExpressable<Object>) impliedResultType;
|
||||
SqmTypedNode<?> restString = substring.generateSqmExpression(
|
||||
asList( string, startPlusLength ),
|
||||
impliedResultType,
|
||||
queryEngine,
|
||||
typeConfiguration
|
||||
);
|
||||
if ( strictSubstring ) {
|
||||
restString = (SqmTypedNode<?>) new SqmCaseSearched<>( stringType, start.nodeBuilder() )
|
||||
.when(
|
||||
new SqmComparisonPredicate(
|
||||
startPlusLength,
|
||||
ComparisonOperator.GREATER_THAN,
|
||||
lengthFunction.generateSqmExpression(
|
||||
asList( string ),
|
||||
intType,
|
||||
queryEngine,
|
||||
typeConfiguration
|
||||
),
|
||||
string.nodeBuilder()
|
||||
),
|
||||
(Expression<?>) new SqmLiteral<>( "", stringType, string.nodeBuilder() )
|
||||
).otherwise( (Expression<?>) restString );
|
||||
}
|
||||
return concat.generateSqmExpression(
|
||||
asList(
|
||||
substring.generateSqmExpression(
|
||||
|
@ -92,12 +126,7 @@ public class InsertSubstringOverlayEmulation
|
|||
typeConfiguration
|
||||
),
|
||||
replacement,
|
||||
substring.generateSqmExpression(
|
||||
asList( string, startPlusLength ),
|
||||
impliedResultType,
|
||||
queryEngine,
|
||||
typeConfiguration
|
||||
)
|
||||
restString
|
||||
),
|
||||
impliedResultType,
|
||||
queryEngine,
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.dialect.function;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class QuantifiedLeastGreatestEmulation
|
||||
extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||
|
||||
private final String operator;
|
||||
|
||||
public QuantifiedLeastGreatestEmulation(boolean least) {
|
||||
super(
|
||||
least ? "least" : "greatest",
|
||||
StandardArgumentsValidators.min( 2 ),
|
||||
StandardFunctionReturnTypeResolvers.useFirstNonNull()
|
||||
);
|
||||
this.operator = least ? "<=" : ">=";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> arguments,
|
||||
SqlAstWalker walker) {
|
||||
final int numberOfArguments = arguments.size();
|
||||
if ( numberOfArguments > 1 ) {
|
||||
final int lastArgument = numberOfArguments - 1;
|
||||
sqlAppender.appendSql( "case" );
|
||||
for ( int i = 0; i < lastArgument; i++ ) {
|
||||
sqlAppender.appendSql( " when " );
|
||||
arguments.get( i ).accept( walker );
|
||||
sqlAppender.appendSql( operator );
|
||||
sqlAppender.appendSql( " all(" );
|
||||
String separator = "";
|
||||
for ( int j = i + 1; j < numberOfArguments; j++ ) {
|
||||
sqlAppender.appendSql( separator );
|
||||
arguments.get( j ).accept( walker );
|
||||
separator = ", ";
|
||||
}
|
||||
sqlAppender.appendSql( ") then " );
|
||||
arguments.get( i ).accept( walker );
|
||||
}
|
||||
sqlAppender.appendSql( " else " );
|
||||
arguments.get( lastArgument ).accept( walker );
|
||||
sqlAppender.appendSql( " end" );
|
||||
}
|
||||
else {
|
||||
arguments.get( 0 ).accept( walker );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgumentListSignature() {
|
||||
return "(arg0[, arg1[, ...]])";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.dialect.function;
|
||||
|
||||
import java.util.List;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.dialect.SQLServerDialect;
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.Format;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* SQL Server behaves strangely when the first argument to format is of the type time, so we cast to datetime.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class SQLServerFormatFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||
|
||||
private final SQLServerDialect dialect;
|
||||
|
||||
public SQLServerFormatFunction(SQLServerDialect dialect) {
|
||||
super(
|
||||
"format",
|
||||
StandardArgumentsValidators.exactly( 2 ),
|
||||
StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.STRING )
|
||||
);
|
||||
this.dialect = dialect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
List<SqlAstNode> arguments,
|
||||
SqlAstWalker walker) {
|
||||
final Expression datetime = (Expression) arguments.get(0);
|
||||
final boolean isTime = TypeConfiguration.getSqlTemporalType( datetime.getExpressionType() ) == TemporalType.TIME;
|
||||
final Format format = (Format) arguments.get(1);
|
||||
|
||||
sqlAppender.appendSql("format(");
|
||||
if ( isTime ) {
|
||||
sqlAppender.appendSql("cast(");
|
||||
datetime.accept( walker );
|
||||
sqlAppender.appendSql(" as datetime)");
|
||||
}
|
||||
else {
|
||||
datetime.accept( walker );
|
||||
}
|
||||
sqlAppender.appendSql(",'");
|
||||
sqlAppender.appendSql( dialect.translateDatetimeFormat( format.getFormat() ) );
|
||||
sqlAppender.appendSql("')");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgumentListSignature() {
|
||||
return "(datetime as pattern)";
|
||||
}
|
||||
}
|
|
@ -240,11 +240,8 @@ public class Column implements Selectable, Serializable, Cloneable {
|
|||
|
||||
public String getSqlType(Dialect dialect, Mapping mapping) throws HibernateException {
|
||||
if ( sqlType == null ) {
|
||||
final Size defaultSize = getColumnDefaultSize( dialect, mapping );
|
||||
|
||||
final Size size = getColumnSize( defaultSize );
|
||||
try {
|
||||
sqlType = dialect.getTypeName( getSqlTypeCode( mapping ), size );
|
||||
sqlType = dialect.getTypeName( getSqlTypeCode( mapping ), getColumnSize( dialect, mapping ) );
|
||||
}
|
||||
catch (HibernateException cause) {
|
||||
throw new HibernateException(
|
||||
|
@ -261,15 +258,7 @@ public class Column implements Selectable, Serializable, Cloneable {
|
|||
return sqlType;
|
||||
}
|
||||
|
||||
private Size getColumnSize(Size defaultSize) {
|
||||
final Integer columnPrecision = precision != null ? precision : defaultSize.getPrecision();
|
||||
final Integer columnScale = scale != null ? scale : defaultSize.getScale();
|
||||
final Long columnLength = length != null ? length : defaultSize.getLength();
|
||||
|
||||
return new Size( columnPrecision, columnScale, columnLength, null );
|
||||
}
|
||||
|
||||
private Size getColumnDefaultSize(Dialect dialect, Mapping mapping) {
|
||||
private Size getColumnSize(Dialect dialect, Mapping mapping) {
|
||||
Type type = getValue().getType();
|
||||
|
||||
if ( type instanceof EntityType ) {
|
||||
|
@ -278,9 +267,12 @@ public class Column implements Selectable, Serializable, Cloneable {
|
|||
if ( type instanceof ComponentType ) {
|
||||
type = getTypeForComponentValue( mapping, type, getTypeIndex() );
|
||||
}
|
||||
return dialect.getDefaultSizeStrategy().resolveDefaultSize(
|
||||
return dialect.getSizeStrategy().resolveSize(
|
||||
( (JdbcMapping) type ).getSqlTypeDescriptor(),
|
||||
( (JdbcMapping) type ).getJavaTypeDescriptor()
|
||||
( (JdbcMapping) type ).getJavaTypeDescriptor(),
|
||||
precision,
|
||||
scale,
|
||||
length
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.mapping;
|
||||
|
||||
import org.hibernate.query.CastType;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
@ -29,6 +30,9 @@ public interface JdbcMapping extends MappingType {
|
|||
*/
|
||||
SqlTypeDescriptor getSqlTypeDescriptor();
|
||||
|
||||
default CastType getCastType() {
|
||||
return getSqlTypeDescriptor().getCastType();
|
||||
}
|
||||
|
||||
/**
|
||||
* The strategy for extracting values of this expressable
|
||||
|
|
|
@ -8,16 +8,16 @@ package org.hibernate.metamodel.mapping.internal;
|
|||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.SortOrder;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.SelectionMapping;
|
||||
import org.hibernate.metamodel.mapping.ordering.ast.DomainPath;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.select.QuerySpec;
|
||||
|
@ -37,7 +37,6 @@ public abstract class AbstractDomainPath implements DomainPath {
|
|||
String modelPartName,
|
||||
SortOrder sortOrder,
|
||||
SqlAstCreationState creationState) {
|
||||
final SqlAstCreationContext creationContext = creationState.getCreationContext();
|
||||
apply(
|
||||
getReferenceModelPart(),
|
||||
ast,
|
||||
|
@ -45,9 +44,7 @@ public abstract class AbstractDomainPath implements DomainPath {
|
|||
collation,
|
||||
modelPartName,
|
||||
sortOrder,
|
||||
creationState,
|
||||
creationContext.getSessionFactory(),
|
||||
creationState.getSqlExpressionResolver()
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -58,9 +55,7 @@ public abstract class AbstractDomainPath implements DomainPath {
|
|||
String collation,
|
||||
String modelPartName,
|
||||
SortOrder sortOrder,
|
||||
SqlAstCreationState creationState,
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
SqlExpressionResolver sqlExprResolver) {
|
||||
SqlAstCreationState creationState) {
|
||||
if ( referenceModelPart instanceof BasicValuedModelPart ) {
|
||||
addSortSpecification(
|
||||
(BasicValuedModelPart) referenceModelPart,
|
||||
|
@ -86,9 +81,7 @@ public abstract class AbstractDomainPath implements DomainPath {
|
|||
collation,
|
||||
modelPartName,
|
||||
sortOrder,
|
||||
creationState,
|
||||
sessionFactory,
|
||||
sqlExprResolver
|
||||
creationState
|
||||
);
|
||||
}
|
||||
else if ( referenceModelPart instanceof EmbeddableValuedModelPart ) {
|
||||
|
@ -99,9 +92,7 @@ public abstract class AbstractDomainPath implements DomainPath {
|
|||
collation,
|
||||
modelPartName,
|
||||
sortOrder,
|
||||
creationState,
|
||||
sessionFactory,
|
||||
sqlExprResolver
|
||||
creationState
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
@ -117,30 +108,18 @@ public abstract class AbstractDomainPath implements DomainPath {
|
|||
String collation,
|
||||
String modelPartName,
|
||||
SortOrder sortOrder,
|
||||
SqlAstCreationState creationState,
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
SqlExpressionResolver sqlExprResolver) {
|
||||
SqlAstCreationState creationState) {
|
||||
if ( embeddableValuedModelPart.getFetchableName()
|
||||
.equals( modelPartName ) || ELEMENT_TOKEN.equals( modelPartName ) ) {
|
||||
embeddableValuedModelPart.forEachSelection(
|
||||
(columnIndex, selection) -> {
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( selection.getContainingTableExpression() );
|
||||
ast.addSortSpecification(
|
||||
new SortSpecification(
|
||||
sqlExprResolver.resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey(
|
||||
selection.getContainingTableExpression(),
|
||||
selection.getSelectionExpression()
|
||||
),
|
||||
sqlAstProcessingState -> new ColumnReference(
|
||||
tableReference,
|
||||
addSortSpecification(
|
||||
selection,
|
||||
sessionFactory
|
||||
)
|
||||
),
|
||||
ast,
|
||||
tableGroup,
|
||||
collation,
|
||||
sortOrder
|
||||
)
|
||||
sortOrder,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
);
|
||||
|
@ -160,24 +139,33 @@ public abstract class AbstractDomainPath implements DomainPath {
|
|||
}
|
||||
|
||||
private void addSortSpecification(
|
||||
BasicValuedModelPart basicValuedPart,
|
||||
SelectionMapping selection,
|
||||
QuerySpec ast,
|
||||
TableGroup tableGroup,
|
||||
String collation,
|
||||
SortOrder sortOrder,
|
||||
SqlAstCreationState creationState) {
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( basicValuedPart.getContainingTableExpression() );
|
||||
|
||||
ast.addSortSpecification(
|
||||
new SortSpecification(
|
||||
new ColumnReference(
|
||||
tableReference,
|
||||
basicValuedPart,
|
||||
creationState.getCreationContext().getSessionFactory()
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( selection.getContainingTableExpression() );
|
||||
final Expression expression = creationState.getSqlExpressionResolver().resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey(
|
||||
selection.getContainingTableExpression(),
|
||||
selection.getSelectionExpression()
|
||||
),
|
||||
collation,
|
||||
sortOrder
|
||||
sqlAstProcessingState -> new ColumnReference(
|
||||
tableReference,
|
||||
selection,
|
||||
creationState.getCreationContext().getSessionFactory()
|
||||
)
|
||||
);
|
||||
// It makes no sense to order by an expression multiple times
|
||||
// SQL Server even reports a query error in this case
|
||||
if ( ast.hasSortSpecifications() ) {
|
||||
for ( SortSpecification sortSpecification : ast.getSortSpecifications() ) {
|
||||
if ( sortSpecification.getSortExpression() == expression ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
ast.addSortSpecification( new SortSpecification( expression, collation, sortOrder ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.persister.entity.AbstractEntityPersister;
|
|||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
|
||||
|
@ -70,10 +71,7 @@ public class ColumnReference implements OrderingExpression, SequencePart {
|
|||
tableReference = getTableReference( tableGroup );
|
||||
|
||||
final SqlExpressionResolver sqlExpressionResolver = creationState.getSqlExpressionResolver();
|
||||
|
||||
ast.addSortSpecification(
|
||||
new SortSpecification(
|
||||
sqlExpressionResolver.resolveSqlExpression(
|
||||
final Expression expression = sqlExpressionResolver.resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey( tableReference, columnExpression ),
|
||||
sqlAstProcessingState -> new org.hibernate.sql.ast.tree.expression.ColumnReference(
|
||||
tableReference,
|
||||
|
@ -86,11 +84,18 @@ public class ColumnReference implements OrderingExpression, SequencePart {
|
|||
null,
|
||||
creationState.getCreationContext().getSessionFactory()
|
||||
)
|
||||
),
|
||||
collation,
|
||||
sortOrder
|
||||
)
|
||||
);
|
||||
// It makes no sense to order by an expression multiple times
|
||||
// SQL Server even reports a query error in this case
|
||||
if ( ast.hasSortSpecifications() ) {
|
||||
for ( SortSpecification sortSpecification : ast.getSortSpecifications() ) {
|
||||
if ( sortSpecification.getSortExpression() == expression ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ast.addSortSpecification( new SortSpecification( expression, collation, sortOrder ) );
|
||||
}
|
||||
|
||||
TableReference getTableReference(TableGroup tableGroup) {
|
||||
|
|
|
@ -6,13 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.query;
|
||||
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.query.sqm.SqmExpressable;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.time.*;
|
||||
|
||||
/**
|
||||
* Defines the set of basic types which should be
|
||||
* accepted by the {@code cast()} function on every
|
||||
|
@ -33,76 +26,25 @@ import java.time.*;
|
|||
* @author Gavin King
|
||||
*/
|
||||
public enum CastType {
|
||||
STRING(CastTypeKind.TEXT),
|
||||
BOOLEAN(CastTypeKind.BOOLEAN),
|
||||
INTEGER(CastTypeKind.NUMERIC), LONG(CastTypeKind.NUMERIC), FLOAT(CastTypeKind.NUMERIC), DOUBLE(CastTypeKind.NUMERIC), FIXED(CastTypeKind.NUMERIC),
|
||||
DATE(CastTypeKind.TEMPORAL), TIME(CastTypeKind.TEMPORAL), TIMESTAMP(CastTypeKind.TEMPORAL),
|
||||
OFFSET_TIMESTAMP(CastTypeKind.TEMPORAL), ZONE_TIMESTAMP(CastTypeKind.TEMPORAL),
|
||||
NULL(null),
|
||||
OTHER(null);
|
||||
STRING,
|
||||
BOOLEAN, INTEGER_BOOLEAN, YN_BOOLEAN, TF_BOOLEAN,
|
||||
INTEGER, LONG, FLOAT, DOUBLE, FIXED,
|
||||
DATE, TIME, TIMESTAMP,
|
||||
OFFSET_TIMESTAMP, ZONE_TIMESTAMP,
|
||||
NULL,
|
||||
OTHER;
|
||||
|
||||
private final CastTypeKind kind;
|
||||
|
||||
CastType(CastTypeKind kind) {
|
||||
this.kind = kind;
|
||||
public boolean isNumeric() {
|
||||
switch (this) {
|
||||
case INTEGER:
|
||||
case LONG:
|
||||
case INTEGER_BOOLEAN:
|
||||
case FLOAT:
|
||||
case DOUBLE:
|
||||
case FIXED:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
public CastTypeKind getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
public static CastType from(Class javaClass) {
|
||||
if (String.class.equals(javaClass)) {
|
||||
return STRING;
|
||||
}
|
||||
if (Boolean.class.equals(javaClass)
|
||||
|| boolean.class.equals(javaClass)) {
|
||||
return BOOLEAN;
|
||||
}
|
||||
if (Integer.class.equals(javaClass)
|
||||
|| int.class.equals(javaClass)) {
|
||||
return INTEGER;
|
||||
}
|
||||
if (Long.class.equals(javaClass)
|
||||
|| long.class.equals(javaClass)) {
|
||||
return LONG;
|
||||
}
|
||||
if (Float.class.equals(javaClass)
|
||||
|| float.class.equals(javaClass)) {
|
||||
return FLOAT;
|
||||
}
|
||||
if (Double.class.equals(javaClass)
|
||||
|| double.class.equals(javaClass)) {
|
||||
return DOUBLE;
|
||||
}
|
||||
if (BigInteger.class.equals(javaClass)) {
|
||||
return FIXED;
|
||||
}
|
||||
if (BigDecimal.class.equals(javaClass)) {
|
||||
return FIXED;
|
||||
}
|
||||
if (LocalDate.class.equals(javaClass)) {
|
||||
return DATE;
|
||||
}
|
||||
if (LocalTime.class.equals(javaClass)) {
|
||||
return TIME;
|
||||
}
|
||||
if (LocalDateTime.class.equals(javaClass)) {
|
||||
return TIMESTAMP;
|
||||
}
|
||||
if (OffsetDateTime.class.equals(javaClass)) {
|
||||
return OFFSET_TIMESTAMP;
|
||||
}
|
||||
if (ZonedDateTime.class.equals(javaClass)) {
|
||||
return ZONE_TIMESTAMP;
|
||||
}
|
||||
return OTHER;
|
||||
}
|
||||
|
||||
public static CastType from(JdbcMapping jdbcMapping) {
|
||||
//TODO: I really don't like using the Java type
|
||||
// here. Is there some way to base this
|
||||
// off of the mapped SQL type?
|
||||
return jdbcMapping == null ? NULL : from( jdbcMapping.getJavaTypeDescriptor().getJavaType() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query;
|
||||
|
||||
/**
|
||||
* The kind of type of a cast target.
|
||||
*
|
||||
* @see CastType
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public enum CastTypeKind {
|
||||
BOOLEAN,
|
||||
NUMERIC,
|
||||
TEMPORAL,
|
||||
TEXT
|
||||
}
|
|
@ -317,7 +317,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
);
|
||||
|
||||
try {
|
||||
visitQueryExpression( queryExpressionContext );
|
||||
queryExpressionContext.accept( this );
|
||||
}
|
||||
finally {
|
||||
processingStateStack.pop();
|
||||
|
@ -347,7 +347,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
processingStateStack.push( processingState );
|
||||
|
||||
try {
|
||||
visitQueryExpression( queryExpressionContext );
|
||||
queryExpressionContext.accept( this );
|
||||
|
||||
final SqmCreationProcessingState stateFieldsProcessingState = new SqmCreationProcessingStateImpl(
|
||||
insertStatement,
|
||||
|
@ -480,20 +480,28 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
// Query spec
|
||||
|
||||
@Override
|
||||
public SqmQueryPart visitQueryExpression(HqlParser.QueryExpressionContext ctx) {
|
||||
final SqmQueryPart queryPart = (SqmQueryPart) ctx.queryGroup().accept( this );
|
||||
visitQueryOrder( queryPart, ctx.queryOrder() );
|
||||
public SqmQueryPart visitSimpleQueryGroup(HqlParser.SimpleQueryGroupContext ctx) {
|
||||
return (SqmQueryPart) ctx.simpleQueryExpression().accept( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmQueryPart visitQuerySpecExpression(HqlParser.QuerySpecExpressionContext ctx) {
|
||||
final List<ParseTree> children = ctx.children;
|
||||
final SqmQueryPart queryPart = visitQuerySpec( (HqlParser.QuerySpecContext) children.get( 0 ) );
|
||||
if ( children.size() > 1 ) {
|
||||
visitQueryOrder( queryPart, (HqlParser.QueryOrderContext) children.get( 1 ) );
|
||||
}
|
||||
return queryPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmQueryPart visitQuerySpecQueryGroup(HqlParser.QuerySpecQueryGroupContext ctx) {
|
||||
return visitQuerySpec( ctx.querySpec() );
|
||||
public SqmQueryPart visitNestedQueryExpression(HqlParser.NestedQueryExpressionContext ctx) {
|
||||
final List<ParseTree> children = ctx.children;
|
||||
final SqmQueryPart queryPart = (SqmQueryPart) children.get( 1 ).accept( this );
|
||||
if ( children.size() > 3 ) {
|
||||
visitQueryOrder( queryPart, (HqlParser.QueryOrderContext) children.get( 3 ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmQueryPart visitNestedQueryGroup(HqlParser.NestedQueryGroupContext ctx) {
|
||||
return (SqmQueryPart) ctx.queryGroup().accept( this );
|
||||
return queryPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -515,20 +523,12 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
setCurrentQueryPart( queryGroup );
|
||||
final List<SqmSelection> firstSelections = firstQueryPart.getFirstQuerySpec().getSelectClause().getSelections();
|
||||
final int firstSelectionSize = firstSelections.size();
|
||||
final ParseTree maybeOrderContext = children.get( 1 );
|
||||
int i;
|
||||
if (maybeOrderContext instanceof HqlParser.QueryOrderContext ) {
|
||||
visitQueryOrder( firstQueryPart, (HqlParser.QueryOrderContext) maybeOrderContext );
|
||||
i = 2;
|
||||
}
|
||||
else {
|
||||
i = 1;
|
||||
}
|
||||
final int size = children.size();
|
||||
final SqmCreationProcessingState firstProcessingState = processingStateStack.pop();
|
||||
for ( ; i < size; i += 2 ) {
|
||||
for ( int i = 1; i < size; i += 2 ) {
|
||||
final SetOperator operator = visitSetOperator( (HqlParser.SetOperatorContext) children.get( i ) );
|
||||
final ParseTree parseTree = children.get( i + 1 );
|
||||
final HqlParser.SimpleQueryExpressionContext simpleQueryCtx =
|
||||
(HqlParser.SimpleQueryExpressionContext) children.get( i + 1 );
|
||||
final List<SqmQueryPart<?>> queryParts;
|
||||
if ( queryGroup.getSetOperator() == null || queryGroup.getSetOperator() == operator ) {
|
||||
queryGroup.setSetOperator( operator );
|
||||
|
@ -554,15 +554,28 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
this
|
||||
)
|
||||
);
|
||||
if ( parseTree instanceof HqlParser.QuerySpecContext ) {
|
||||
final List<ParseTree> subChildren = simpleQueryCtx.children;
|
||||
if ( subChildren.get( 0 ) instanceof HqlParser.QuerySpecContext ) {
|
||||
final SqmQuerySpec<?> querySpec = new SqmQuerySpec<>( creationContext.getNodeBuilder() );
|
||||
queryParts.add( querySpec );
|
||||
queryPart = visitQuerySpec( (HqlParser.QuerySpecContext) parseTree );
|
||||
queryPart = visitQuerySpecExpression( (HqlParser.QuerySpecExpressionContext) simpleQueryCtx );
|
||||
}
|
||||
else {
|
||||
queryPart = (SqmQueryPart<?>) children.get( i + 2 ).accept( this );
|
||||
try {
|
||||
final SqmSelectStatement selectStatement = new SqmSelectStatement( creationContext.getNodeBuilder() );
|
||||
processingStateStack.push(
|
||||
new SqmQuerySpecCreationProcessingStateStandardImpl(
|
||||
processingStateStack.getCurrent(),
|
||||
selectStatement,
|
||||
this
|
||||
)
|
||||
);
|
||||
queryPart = visitNestedQueryExpression( (HqlParser.NestedQueryExpressionContext) simpleQueryCtx );
|
||||
queryParts.add( queryPart );
|
||||
i += 2;
|
||||
}
|
||||
finally {
|
||||
processingStateStack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
|
@ -3867,7 +3880,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
);
|
||||
|
||||
try {
|
||||
visitQueryExpression( queryExpressionContext );
|
||||
queryExpressionContext.accept( this );
|
||||
return subQuery;
|
||||
}
|
||||
finally {
|
||||
|
|
|
@ -293,7 +293,7 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
|||
interpretation.getSqlAst()
|
||||
);
|
||||
|
||||
final Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamsXref = SqmUtil.generateJdbcParamsXref(
|
||||
final Map<QueryParameterImplementor<?>, Map<SqmParameter, List<List<JdbcParameter>>>> jdbcParamsXref = SqmUtil.generateJdbcParamsXref(
|
||||
domainParameterXref,
|
||||
interpretation::getJdbcParamsBySqmParam
|
||||
);
|
||||
|
@ -326,13 +326,13 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
|||
private static class CacheableSqmInterpretation {
|
||||
private final JdbcSelect jdbcSelect;
|
||||
private final FromClauseAccess tableGroupAccess;
|
||||
private final Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamsXref;
|
||||
private final Map<QueryParameterImplementor<?>, Map<SqmParameter, List<List<JdbcParameter>>>> jdbcParamsXref;
|
||||
private transient JdbcParameterBindings firstParameterBindings;
|
||||
|
||||
CacheableSqmInterpretation(
|
||||
JdbcSelect jdbcSelect,
|
||||
FromClauseAccess tableGroupAccess,
|
||||
Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamsXref,
|
||||
Map<QueryParameterImplementor<?>, Map<SqmParameter, List<List<JdbcParameter>>>> jdbcParamsXref,
|
||||
JdbcParameterBindings firstParameterBindings) {
|
||||
this.jdbcSelect = jdbcSelect;
|
||||
this.tableGroupAccess = tableGroupAccess;
|
||||
|
@ -348,7 +348,7 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
|||
return tableGroupAccess;
|
||||
}
|
||||
|
||||
Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> getJdbcParamsXref() {
|
||||
Map<QueryParameterImplementor<?>, Map<SqmParameter, List<List<JdbcParameter>>>> getJdbcParamsXref() {
|
||||
return jdbcParamsXref;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ public class SimpleDeleteQueryPlan implements NonSelectQueryPlan {
|
|||
|
||||
private JdbcDelete jdbcDelete;
|
||||
private SqmTranslation<DeleteStatement> sqmInterpretation;
|
||||
private Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamsXref;
|
||||
private Map<QueryParameterImplementor<?>, Map<SqmParameter, List<List<JdbcParameter>>>> jdbcParamsXref;
|
||||
|
||||
public SimpleDeleteQueryPlan(
|
||||
EntityMappingType entityDescriptor,
|
||||
|
|
|
@ -40,7 +40,7 @@ public class SimpleInsertQueryPlan implements NonSelectQueryPlan {
|
|||
|
||||
private JdbcInsert jdbcInsert;
|
||||
private FromClauseAccess tableGroupAccess;
|
||||
private Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamsXref;
|
||||
private Map<QueryParameterImplementor<?>, Map<SqmParameter, List<List<JdbcParameter>>>> jdbcParamsXref;
|
||||
|
||||
public SimpleInsertQueryPlan(
|
||||
SqmInsertStatement sqmInsert,
|
||||
|
|
|
@ -40,7 +40,7 @@ public class SimpleUpdateQueryPlan implements NonSelectQueryPlan {
|
|||
|
||||
private JdbcUpdate jdbcUpdate;
|
||||
private FromClauseAccess tableGroupAccess;
|
||||
private Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamsXref;
|
||||
private Map<QueryParameterImplementor<?>, Map<SqmParameter, List<List<JdbcParameter>>>> jdbcParamsXref;
|
||||
|
||||
public SimpleUpdateQueryPlan(
|
||||
SqmUpdateStatement sqmUpdate,
|
||||
|
|
|
@ -79,7 +79,7 @@ public class SqmUtil {
|
|||
}
|
||||
}
|
||||
|
||||
public static Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> generateJdbcParamsXref(
|
||||
public static Map<QueryParameterImplementor<?>, Map<SqmParameter, List<List<JdbcParameter>>>> generateJdbcParamsXref(
|
||||
DomainParameterXref domainParameterXref,
|
||||
JdbcParameterBySqmParameterAccess jdbcParameterBySqmParameterAccess) {
|
||||
if ( domainParameterXref == null || !domainParameterXref.hasParameters() ) {
|
||||
|
@ -87,13 +87,13 @@ public class SqmUtil {
|
|||
}
|
||||
|
||||
final int queryParameterCount = domainParameterXref.getQueryParameterCount();
|
||||
final Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> result = new IdentityHashMap<>( queryParameterCount );
|
||||
final Map<QueryParameterImplementor<?>, Map<SqmParameter, List<List<JdbcParameter>>>> result = new IdentityHashMap<>( queryParameterCount );
|
||||
|
||||
for ( Map.Entry<QueryParameterImplementor<?>, List<SqmParameter>> entry : domainParameterXref.getSqmParamByQueryParam().entrySet() ) {
|
||||
final QueryParameterImplementor<?> queryParam = entry.getKey();
|
||||
final List<SqmParameter> sqmParams = entry.getValue();
|
||||
|
||||
final Map<SqmParameter, List<JdbcParameter>> sqmParamMap = result.computeIfAbsent(
|
||||
final Map<SqmParameter, List<List<JdbcParameter>>> sqmParamMap = result.computeIfAbsent(
|
||||
queryParam,
|
||||
qp -> new IdentityHashMap<>( sqmParams.size() )
|
||||
);
|
||||
|
@ -157,7 +157,7 @@ public class SqmUtil {
|
|||
public static JdbcParameterBindings createJdbcParameterBindings(
|
||||
QueryParameterBindings domainParamBindings,
|
||||
DomainParameterXref domainParameterXref,
|
||||
Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamXref,
|
||||
Map<QueryParameterImplementor<?>, Map<SqmParameter, List<List<JdbcParameter>>>> jdbcParamXref,
|
||||
MappingMetamodel domainModel,
|
||||
Function<NavigablePath, TableGroup> tableGroupLocator,
|
||||
SharedSessionContractImplementor session) {
|
||||
|
@ -177,16 +177,17 @@ public class SqmUtil {
|
|||
session.getFactory()
|
||||
);
|
||||
|
||||
final Map<SqmParameter, List<JdbcParameter>> jdbcParamMap = jdbcParamXref.get( queryParam );
|
||||
final Map<SqmParameter, List<List<JdbcParameter>>> jdbcParamMap = jdbcParamXref.get( queryParam );
|
||||
for ( SqmParameter sqmParameter : sqmParameters ) {
|
||||
final List<JdbcParameter> jdbcParams = jdbcParamMap.get( sqmParameter );
|
||||
|
||||
if ( ! domainParamBinding.isBound() ) {
|
||||
final List<List<JdbcParameter>> jdbcParamsBinds = jdbcParamMap.get( sqmParameter );
|
||||
if ( !domainParamBinding.isBound() ) {
|
||||
final MappingModelExpressable mappingExpressable = SqmMappingModelHelper.resolveMappingModelExpressable(
|
||||
sqmParameter,
|
||||
domainModel,
|
||||
tableGroupLocator
|
||||
);
|
||||
for ( int i = 0; i < jdbcParamsBinds.size(); i++ ) {
|
||||
final List<JdbcParameter> jdbcParams = jdbcParamsBinds.get( i );
|
||||
mappingExpressable.forEachJdbcType(
|
||||
(position, jdbcType) -> {
|
||||
jdbcParameterBindings.addBinding(
|
||||
|
@ -196,12 +197,23 @@ public class SqmUtil {
|
|||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
else if ( domainParamBinding.isMultiValued() ) {
|
||||
final Collection<?> bindValues = domainParamBinding.getBindValues();
|
||||
final Iterator<?> valueItr = bindValues.iterator();
|
||||
|
||||
// the original SqmParameter is the one we are processing.. create a binding for it..
|
||||
createValueBindings( jdbcParameterBindings, domainParamBinding, parameterType, jdbcParams, valueItr.next(), session );
|
||||
for ( int i = 0; i < jdbcParamsBinds.size(); i++ ) {
|
||||
final List<JdbcParameter> jdbcParams = jdbcParamsBinds.get( i );
|
||||
createValueBindings(
|
||||
jdbcParameterBindings,
|
||||
domainParamBinding,
|
||||
parameterType,
|
||||
jdbcParams,
|
||||
valueItr.next(),
|
||||
session
|
||||
);
|
||||
}
|
||||
|
||||
// an then one for each of the expansions
|
||||
final List<SqmParameter> expansions = domainParameterXref.getExpansions( sqmParameter );
|
||||
|
@ -209,23 +221,45 @@ public class SqmUtil {
|
|||
int expansionPosition = 0;
|
||||
while ( valueItr.hasNext() ) {
|
||||
final SqmParameter expansionSqmParam = expansions.get( expansionPosition++ );
|
||||
final List<JdbcParameter> expansionJdbcParams = jdbcParamMap.get( expansionSqmParam );
|
||||
createValueBindings( jdbcParameterBindings, domainParamBinding, parameterType, expansionJdbcParams, valueItr.next(), session );
|
||||
final List<List<JdbcParameter>> jdbcParamBinds = jdbcParamMap.get( expansionSqmParam );
|
||||
for ( int i = 0; i < jdbcParamBinds.size(); i++ ) {
|
||||
List<JdbcParameter> expansionJdbcParams = jdbcParamBinds.get( i );
|
||||
createValueBindings(
|
||||
jdbcParameterBindings,
|
||||
domainParamBinding,
|
||||
parameterType,
|
||||
expansionJdbcParams,
|
||||
valueItr.next(),
|
||||
session
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( domainParamBinding.getBindValue() == null ) {
|
||||
assert jdbcParams != null;
|
||||
for ( int i = 0; i < jdbcParams.size(); i++ ) {
|
||||
final JdbcParameter jdbcParameter = jdbcParams.get( i );
|
||||
for ( int i = 0; i < jdbcParamsBinds.size(); i++ ) {
|
||||
final List<JdbcParameter> jdbcParams = jdbcParamsBinds.get( i );
|
||||
for ( int j = 0; j < jdbcParams.size(); j++ ) {
|
||||
final JdbcParameter jdbcParameter = jdbcParams.get( j );
|
||||
jdbcParameterBindings.addBinding(
|
||||
jdbcParameter,
|
||||
new JdbcParameterBindingImpl( null, null )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
final Object bindValue = domainParamBinding.getBindValue();
|
||||
createValueBindings( jdbcParameterBindings, domainParamBinding, parameterType, jdbcParams, bindValue, session );
|
||||
for ( int i = 0; i < jdbcParamsBinds.size(); i++ ) {
|
||||
final List<JdbcParameter> jdbcParams = jdbcParamsBinds.get( i );
|
||||
createValueBindings(
|
||||
jdbcParameterBindings,
|
||||
domainParamBinding,
|
||||
parameterType,
|
||||
jdbcParams,
|
||||
bindValue,
|
||||
session
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -198,8 +198,8 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter<Sta
|
|||
|
||||
final Expression expression = super.consumeSqmParameter( sqmParameter );
|
||||
|
||||
final List<JdbcParameter> jdbcParameters = getJdbcParamsBySqmParam().get( sqmParameter );
|
||||
parameterResolutionConsumer.accept( sqmParameter, jdbcParameters );
|
||||
final List<List<JdbcParameter>> jdbcParameters = getJdbcParamsBySqmParam().get( sqmParameter );
|
||||
parameterResolutionConsumer.accept( sqmParameter, jdbcParameters.get( jdbcParameters.size() - 1 ) );
|
||||
|
||||
return expression;
|
||||
}
|
||||
|
|
|
@ -90,13 +90,6 @@ public class CteStrategy implements SqmMultiTableMutationStrategy {
|
|||
);
|
||||
}
|
||||
|
||||
if ( !dialect.supportsRowValueConstructorSyntaxInInList() ) {
|
||||
throw new UnsupportedOperationException(
|
||||
getClass().getSimpleName() +
|
||||
" can only be used with Dialects that support IN clause row-value expressions (for composite identifiers)"
|
||||
);
|
||||
}
|
||||
|
||||
this.cteTable = new SqmCteTable( TABLE_NAME, rootDescriptor );
|
||||
}
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ public class IdTableHelper {
|
|||
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
|
||||
|
||||
try {
|
||||
final String dropCommand = exporter.getSqlCreateCommand( idTable );
|
||||
final String dropCommand = exporter.getSqlDropCommand( idTable );
|
||||
logStatement( dropCommand, jdbcServices );
|
||||
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
|
|
|
@ -125,7 +125,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
|||
final TableReference hierarchyRootTableReference = deletingTableGroup.resolveTableReference( hierarchyRootTableName );
|
||||
assert hierarchyRootTableReference != null;
|
||||
|
||||
final Map<SqmParameter, List<JdbcParameter>> parameterResolutions;
|
||||
final Map<SqmParameter, List<List<JdbcParameter>>> parameterResolutions;
|
||||
if ( domainParameterXref.getSqmParameterCount() == 0 ) {
|
||||
parameterResolutions = Collections.emptyMap();
|
||||
}
|
||||
|
@ -146,7 +146,10 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
|||
needsIdTableWrapper.set( true );
|
||||
}
|
||||
},
|
||||
parameterResolutions::put
|
||||
(sqmParameter, jdbcParameters) -> parameterResolutions.computeIfAbsent(
|
||||
sqmParameter,
|
||||
k -> new ArrayList<>( 1 )
|
||||
).add( jdbcParameters )
|
||||
);
|
||||
|
||||
final FilterPredicate filterPredicate = FilterHelper.createFilterPredicate(
|
||||
|
@ -183,7 +186,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
|||
private int executeWithoutIdTable(
|
||||
Predicate suppliedPredicate,
|
||||
TableGroup tableGroup,
|
||||
Map<SqmParameter, List<JdbcParameter>> restrictionSqmParameterResolutions,
|
||||
Map<SqmParameter, List<List<JdbcParameter>>> restrictionSqmParameterResolutions,
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
ExecutionContext executionContext) {
|
||||
final EntityPersister rootEntityPersister;
|
||||
|
@ -354,7 +357,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
|||
private int executeWithIdTable(
|
||||
Predicate predicate,
|
||||
TableGroup deletingTableGroup,
|
||||
Map<SqmParameter, List<JdbcParameter>> restrictionSqmParameterResolutions,
|
||||
Map<SqmParameter, List<List<JdbcParameter>>> restrictionSqmParameterResolutions,
|
||||
ExecutionContext executionContext) {
|
||||
final JdbcParameterBindings jdbcParameterBindings = SqmUtil.createJdbcParameterBindings(
|
||||
executionContext.getQueryParameterBindings(),
|
||||
|
|
|
@ -134,7 +134,7 @@ public class TableBasedUpdateHandler
|
|||
final TableReference hierarchyRootTableReference = updatingTableGroup.resolveTableReference( hierarchyRootTableName );
|
||||
assert hierarchyRootTableReference != null;
|
||||
|
||||
final Map<SqmParameter,List<JdbcParameter>> parameterResolutions;
|
||||
final Map<SqmParameter, List<List<JdbcParameter>>> parameterResolutions;
|
||||
if ( domainParameterXref.getSqmParameterCount() == 0 ) {
|
||||
parameterResolutions = Collections.emptyMap();
|
||||
}
|
||||
|
@ -151,7 +151,10 @@ public class TableBasedUpdateHandler
|
|||
converterDelegate.visitSetClause(
|
||||
getSqmDeleteOrUpdateStatement().getSetClause(),
|
||||
assignments::add,
|
||||
parameterResolutions::put
|
||||
(sqmParameter, jdbcParameters) -> parameterResolutions.computeIfAbsent(
|
||||
sqmParameter,
|
||||
k -> new ArrayList<>( 1 )
|
||||
).add( jdbcParameters )
|
||||
);
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -167,7 +170,10 @@ public class TableBasedUpdateHandler
|
|||
predicate = converterDelegate.visitWhereClause(
|
||||
whereClause,
|
||||
columnReference -> {},
|
||||
parameterResolutions::put
|
||||
(sqmParameter, jdbcParameters) -> parameterResolutions.computeIfAbsent(
|
||||
sqmParameter,
|
||||
k -> new ArrayList<>( 1 )
|
||||
).add( jdbcParameters )
|
||||
);
|
||||
assert predicate != null;
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ public class UpdateExecutionDelegate implements TableBasedUpdateHandler.Executio
|
|||
Map<String, TableReference> tableReferenceByAlias,
|
||||
List<Assignment> assignments,
|
||||
Predicate suppliedPredicate,
|
||||
Map<SqmParameter, List<JdbcParameter>> parameterResolutions,
|
||||
Map<SqmParameter, List<List<JdbcParameter>>> parameterResolutions,
|
||||
ExecutionContext executionContext) {
|
||||
this.sqmUpdate = sqmUpdate;
|
||||
this.sqmConverter = sqmConverter;
|
||||
|
|
|
@ -21,5 +21,5 @@ public interface JdbcParameterBySqmParameterAccess {
|
|||
/**
|
||||
* The mapping between an SqmParameter and all of its JDBC parameters
|
||||
*/
|
||||
Map<SqmParameter, List<JdbcParameter>> getJdbcParamsBySqmParam();
|
||||
Map<SqmParameter, List<List<JdbcParameter>>> getJdbcParamsBySqmParam();
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.boot.model.process.internal.InferredBasicValueResolver;
|
||||
import org.hibernate.dialect.function.TimestampaddFunction;
|
||||
import org.hibernate.dialect.function.TimestampdiffFunction;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
|
@ -41,9 +42,11 @@ import org.hibernate.loader.MultipleBagFetchException;
|
|||
import org.hibernate.metamodel.CollectionClassification;
|
||||
import org.hibernate.metamodel.MappingMetamodel;
|
||||
import org.hibernate.metamodel.mapping.Association;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
|
@ -265,8 +268,10 @@ import org.hibernate.sql.results.graph.entity.EntityResultGraphNode;
|
|||
import org.hibernate.sql.results.graph.instantiation.internal.DynamicInstantiation;
|
||||
import org.hibernate.sql.results.internal.SqlSelectionImpl;
|
||||
import org.hibernate.sql.results.internal.StandardEntityGraphTraversalStateImpl;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
@ -284,7 +289,7 @@ import static org.hibernate.type.spi.TypeConfiguration.isDuration;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends BaseSemanticQueryWalker
|
||||
implements SqmTranslator<T>, DomainResultCreationState {
|
||||
implements SqmTranslator<T>, DomainResultCreationState, SqlTypeDescriptorIndicators {
|
||||
|
||||
private static final Logger log = Logger.getLogger( BaseSqmToSqlAstConverter.class );
|
||||
|
||||
|
@ -403,6 +408,19 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
return statement;
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// SqlTypeDescriptorIndicators
|
||||
|
||||
@Override
|
||||
public TypeConfiguration getTypeConfiguration() {
|
||||
return creationContext.getSessionFactory().getTypeConfiguration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreferredSqlTypeCodeForBoolean() {
|
||||
return creationContext.getSessionFactory().getSessionFactoryOptions().getPreferredSqlTypeCodeForBoolean();
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// FromClauseAccess
|
||||
|
||||
|
@ -578,7 +596,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
|
||||
@Override
|
||||
public List<Assignment> visitSetClause(SqmSetClause setClause) {
|
||||
final List<Assignment> assignments = new ArrayList<>();
|
||||
final List<Assignment> assignments = new ArrayList<>( setClause.getAssignments().size() );
|
||||
|
||||
for ( SqmAssignment sqmAssignment : setClause.getAssignments() ) {
|
||||
final List<ColumnReference> targetColumnReferences = new ArrayList<>();
|
||||
|
@ -663,14 +681,15 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
}
|
||||
);
|
||||
|
||||
getJdbcParamsBySqmParam().put( sqmParameter, jdbcParametersForSqm );
|
||||
getJdbcParamsBySqmParam().computeIfAbsent( sqmParameter, k -> new ArrayList<>( 1 ) )
|
||||
.add( jdbcParametersForSqm );
|
||||
}
|
||||
else {
|
||||
final MappingMetamodel domainModel = getCreationContext().getDomainModel();
|
||||
final Expression valueExpression = (Expression) sqmAssignment.getValue().accept( this );
|
||||
|
||||
final int valueExprJdbcCount = valueExpression.getExpressionType().getJdbcTypeCount();
|
||||
final int assignedPathJdbcCount = assignedPathInterpretation.getExpressionType().getJdbcTypeCount();
|
||||
final int valueExprJdbcCount = getKeyExpressable( valueExpression.getExpressionType() ).getJdbcTypeCount();
|
||||
final int assignedPathJdbcCount = getKeyExpressable( assignedPathInterpretation.getExpressionType() )
|
||||
.getJdbcTypeCount();
|
||||
|
||||
if ( valueExprJdbcCount != assignedPathJdbcCount ) {
|
||||
SqlTreeCreationLogger.LOGGER.debugf(
|
||||
|
@ -2021,24 +2040,50 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
@Override
|
||||
public Expression visitLiteral(SqmLiteral<?> literal) {
|
||||
if ( literal instanceof SqmLiteralNull ) {
|
||||
return new NullnessLiteral( inferableTypeAccessStack.getCurrent().get() );
|
||||
final MappingModelExpressable mappingModelExpressable = inferableTypeAccessStack.getCurrent().get();
|
||||
if ( mappingModelExpressable instanceof BasicValuedMapping ) {
|
||||
return new NullnessLiteral( mappingModelExpressable );
|
||||
}
|
||||
|
||||
return new QueryLiteral<>(
|
||||
literal.getLiteralValue(),
|
||||
(BasicValuedMapping) SqmMappingModelHelper.resolveMappingModelExpressable(
|
||||
final MappingModelExpressable keyExpressable = getKeyExpressable( mappingModelExpressable );
|
||||
final List<Expression> expressions = new ArrayList<>( keyExpressable.getJdbcTypeCount() );
|
||||
keyExpressable.forEachJdbcType(
|
||||
(index, jdbcMapping) -> expressions.add(
|
||||
new QueryLiteral<>(
|
||||
null,
|
||||
(BasicValuedMapping) jdbcMapping
|
||||
)
|
||||
)
|
||||
);
|
||||
return new SqlTuple( expressions, mappingModelExpressable );
|
||||
}
|
||||
MappingModelExpressable expressable = SqmMappingModelHelper.resolveMappingModelExpressable(
|
||||
literal,
|
||||
getCreationContext().getDomainModel(),
|
||||
getFromClauseAccess()::findTableGroup
|
||||
)
|
||||
);
|
||||
if ( expressable instanceof BasicType<?> ) {
|
||||
expressable = InferredBasicValueResolver.resolveSqlTypeIndicators( this, (BasicType<?>) expressable );
|
||||
}
|
||||
return new QueryLiteral<>(
|
||||
literal.getLiteralValue(),
|
||||
(BasicValuedMapping) expressable
|
||||
);
|
||||
}
|
||||
|
||||
private final Map<SqmParameter, List<JdbcParameter>> jdbcParamsBySqmParam = new IdentityHashMap<>();
|
||||
private MappingModelExpressable<?> getKeyExpressable(MappingModelExpressable<?> mappingModelExpressable) {
|
||||
if ( mappingModelExpressable instanceof EntityAssociationMapping ) {
|
||||
return ( (EntityAssociationMapping) mappingModelExpressable ).getKeyTargetMatchPart();
|
||||
}
|
||||
else {
|
||||
return mappingModelExpressable;
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<SqmParameter, List<List<JdbcParameter>>> jdbcParamsBySqmParam = new IdentityHashMap<>();
|
||||
private final JdbcParameters jdbcParameters = new JdbcParametersImpl();
|
||||
|
||||
@Override
|
||||
public Map<SqmParameter, List<JdbcParameter>> getJdbcParamsBySqmParam() {
|
||||
public Map<SqmParameter, List<List<JdbcParameter>>> getJdbcParamsBySqmParam() {
|
||||
return jdbcParamsBySqmParam;
|
||||
}
|
||||
|
||||
|
@ -2059,7 +2104,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
);
|
||||
|
||||
this.jdbcParameters.addParameters( jdbcParametersForSqm );
|
||||
this.jdbcParamsBySqmParam.put( sqmParameter, jdbcParametersForSqm );
|
||||
this.jdbcParamsBySqmParam.computeIfAbsent( sqmParameter, k -> new ArrayList<>( 1 ) )
|
||||
.add( jdbcParametersForSqm );
|
||||
|
||||
final QueryParameterImplementor<?> queryParameter = domainParameterXref.getQueryParameter( sqmParameter );
|
||||
final QueryParameterBinding<?> binding = domainParameterBindings.getBinding( queryParameter );
|
||||
|
@ -2268,8 +2314,12 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
public Object visitCastTarget(SqmCastTarget target) {
|
||||
shallownessStack.push( Shallowness.FUNCTION );
|
||||
try {
|
||||
BasicValuedMapping targetType = (BasicValuedMapping) target.getType();
|
||||
if ( targetType instanceof BasicType<?> ) {
|
||||
targetType = InferredBasicValueResolver.resolveSqlTypeIndicators( this, (BasicType<?>) targetType );
|
||||
}
|
||||
return new CastTarget(
|
||||
(BasicValuedMapping) target.getType(),
|
||||
targetType,
|
||||
target.getLength(),
|
||||
target.getPrecision(),
|
||||
target.getScale()
|
||||
|
@ -2818,9 +2868,9 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
if ( type instanceof SqmExpressable ) {
|
||||
adjustedTimestampType = (SqmExpressable) type;
|
||||
}
|
||||
// else if (type instanceof BasicValuedMapping) {
|
||||
// adjustedTimestampType = ((BasicValuedMapping) type).getBasicType();
|
||||
// }
|
||||
else if (type instanceof AttributeMapping ) {
|
||||
adjustedTimestampType = (SqmExpressable) ( (AttributeMapping) type ).getMappedType();
|
||||
}
|
||||
else {
|
||||
// else we know it has not been transformed
|
||||
adjustedTimestampType = expression.getLeftHandOperand().getNodeType();
|
||||
|
|
|
@ -22,7 +22,7 @@ import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
|||
*/
|
||||
public interface SqmTranslation<T extends Statement> {
|
||||
T getSqlAst();
|
||||
Map<SqmParameter, List<JdbcParameter>> getJdbcParamsBySqmParam();
|
||||
Map<SqmParameter, List<List<JdbcParameter>>> getJdbcParamsBySqmParam();
|
||||
SqlExpressionResolver getSqlExpressionResolver();
|
||||
FromClauseAccess getFromClauseAccess();
|
||||
}
|
||||
|
|
|
@ -21,13 +21,13 @@ import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
|||
public class StandardSqmTranslation<T extends Statement> implements SqmTranslation<T> {
|
||||
|
||||
private final T sqlAst;
|
||||
private final Map<SqmParameter, List<JdbcParameter>> jdbcParamMap;
|
||||
private final Map<SqmParameter, List<List<JdbcParameter>>> jdbcParamMap;
|
||||
private final SqlExpressionResolver sqlExpressionResolver;
|
||||
private final FromClauseAccess fromClauseAccess;
|
||||
|
||||
public StandardSqmTranslation(
|
||||
T sqlAst,
|
||||
Map<SqmParameter, List<JdbcParameter>> jdbcParamMap,
|
||||
Map<SqmParameter, List<List<JdbcParameter>>> jdbcParamMap,
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
FromClauseAccess fromClauseAccess) {
|
||||
this.sqlAst = sqlAst;
|
||||
|
@ -42,7 +42,7 @@ public class StandardSqmTranslation<T extends Statement> implements SqmTranslati
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<SqmParameter, List<JdbcParameter>> getJdbcParamsBySqmParam() {
|
||||
public Map<SqmParameter, List<List<JdbcParameter>>> getJdbcParamsBySqmParam() {
|
||||
return jdbcParamMap;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,9 @@ public final class Template {
|
|||
KEYWORDS.add("all");
|
||||
KEYWORDS.add("union");
|
||||
KEYWORDS.add("minus");
|
||||
KEYWORDS.add("except");
|
||||
KEYWORDS.add("intersect");
|
||||
KEYWORDS.add("partition");
|
||||
|
||||
BEFORE_TABLE_KEYWORDS.add("from");
|
||||
BEFORE_TABLE_KEYWORDS.add("join");
|
||||
|
|
|
@ -11,12 +11,11 @@ import java.util.Set;
|
|||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperation;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SqlAstTranslator<T extends JdbcOperation> extends SqlAstWalker, SqlTypeDescriptorIndicators {
|
||||
public interface SqlAstTranslator<T extends JdbcOperation> extends SqlAstWalker {
|
||||
/**
|
||||
* Not the best spot for this. Its the table names collected while walking the SQL AST.
|
||||
* Its ok here because the translator is consider a one-time-use. It just needs to be called
|
||||
|
|
|
@ -121,16 +121,13 @@ import org.hibernate.type.IntegerType;
|
|||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.sql.JdbcLiteralFormatter;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import static org.hibernate.query.TemporalUnit.NANOSECOND;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractSqlAstWalker
|
||||
implements SqlAstWalker, SqlTypeDescriptorIndicators, SqlAppender {
|
||||
public abstract class AbstractSqlAstWalker implements SqlAstWalker, SqlAppender {
|
||||
|
||||
private static final QueryLiteral<Integer> ONE_LITERAL = new QueryLiteral<>( 1, IntegerType.INSTANCE );
|
||||
|
||||
|
@ -150,6 +147,7 @@ public abstract class AbstractSqlAstWalker
|
|||
|
||||
private final Dialect dialect;
|
||||
private String dmlTargetTableAlias;
|
||||
private boolean needsSelectAliases;
|
||||
private QueryPart queryPartForRowNumbering;
|
||||
private int queryPartForRowNumberingAliasCounter;
|
||||
private int queryGroupAliasCounter;
|
||||
|
@ -468,12 +466,21 @@ public abstract class AbstractSqlAstWalker
|
|||
statement.getSourceSelectStatement().accept( this );
|
||||
}
|
||||
else {
|
||||
visitValuesList( statement.getValuesList() );
|
||||
}
|
||||
visitReturningColumns( statement );
|
||||
}
|
||||
|
||||
private void renderImplicitTargetColumnSpec() {
|
||||
}
|
||||
|
||||
protected void visitValuesList(List<Values> valuesList) {
|
||||
appendSql("values");
|
||||
boolean firstTuple = true;
|
||||
final Stack<Clause> clauseStack = getClauseStack();
|
||||
try {
|
||||
clauseStack.push( Clause.VALUES );
|
||||
for ( Values values : statement.getValuesList() ) {
|
||||
for ( Values values : valuesList ) {
|
||||
if ( firstTuple ) {
|
||||
firstTuple = false;
|
||||
}
|
||||
|
@ -498,11 +505,6 @@ public abstract class AbstractSqlAstWalker
|
|||
clauseStack.pop();
|
||||
}
|
||||
}
|
||||
visitReturningColumns( statement );
|
||||
}
|
||||
|
||||
private void renderImplicitTargetColumnSpec() {
|
||||
}
|
||||
|
||||
protected void visitReturningColumns(MutationStatement mutationStatement) {
|
||||
final List<ColumnReference> returningColumns = mutationStatement.getReturningColumns();
|
||||
|
@ -623,13 +625,17 @@ public abstract class AbstractSqlAstWalker
|
|||
@Override
|
||||
public void visitQueryGroup(QueryGroup queryGroup) {
|
||||
final QueryPart queryPartForRowNumbering = this.queryPartForRowNumbering;
|
||||
final boolean needsSelectAliases = this.needsSelectAliases;
|
||||
try {
|
||||
String queryGroupAlias = null;
|
||||
if ( queryPartForRowNumbering != queryPartStack.getCurrent() ) {
|
||||
final QueryPart currentQueryPart = queryPartStack.getCurrent();
|
||||
if ( currentQueryPart != null && queryPartForRowNumbering != currentQueryPart ) {
|
||||
this.queryPartForRowNumbering = null;
|
||||
this.needsSelectAliases = false;
|
||||
}
|
||||
// If we do row counting for this query group, the wrapper select is added by the caller
|
||||
if ( queryPartForRowNumbering != queryGroup && !queryGroup.isRoot() ) {
|
||||
this.needsSelectAliases = true;
|
||||
queryGroupAlias = "grp_" + queryGroupAliasCounter + "_";
|
||||
queryGroupAliasCounter++;
|
||||
appendSql( "select " );
|
||||
|
@ -656,17 +662,39 @@ public abstract class AbstractSqlAstWalker
|
|||
finally {
|
||||
queryPartStack.pop();
|
||||
this.queryPartForRowNumbering = queryPartForRowNumbering;
|
||||
this.needsSelectAliases = needsSelectAliases;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitQuerySpec(QuerySpec querySpec) {
|
||||
final QueryPart queryPartForRowNumbering = this.queryPartForRowNumbering;
|
||||
final boolean needsSelectAliases = this.needsSelectAliases;
|
||||
try {
|
||||
if ( queryPartForRowNumbering != queryPartStack.getCurrent() ) {
|
||||
final QueryPart currentQueryPart = queryPartStack.getCurrent();
|
||||
if ( currentQueryPart != null && queryPartForRowNumbering != currentQueryPart ) {
|
||||
this.queryPartForRowNumbering = null;
|
||||
}
|
||||
final boolean needsParenthesis = !querySpec.isRoot() && !( queryPartStack.getCurrent() instanceof QueryGroup );
|
||||
String queryGroupAlias = "";
|
||||
final boolean needsParenthesis;
|
||||
if ( currentQueryPart instanceof QueryGroup ) {
|
||||
// We always need query wrapping if we are in a query group and the query part has a fetch clause
|
||||
if ( needsParenthesis = querySpec.hasOffsetOrFetchClause() ) {
|
||||
// If the parent is a query group with a fetch clause, we must use an alias
|
||||
// Some DBMS don't support grouping query expressions and need a select wrapper
|
||||
if ( !supportsSimpleQueryGrouping() || currentQueryPart.hasOffsetOrFetchClause() ) {
|
||||
this.needsSelectAliases = true;
|
||||
queryGroupAlias = " grp_" + queryGroupAliasCounter + "_";
|
||||
queryGroupAliasCounter++;
|
||||
appendSql( "select" );
|
||||
appendSql( queryGroupAlias );
|
||||
appendSql( ".* from " );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
needsParenthesis = !querySpec.isRoot();
|
||||
}
|
||||
queryPartStack.push( querySpec );
|
||||
if ( needsParenthesis ) {
|
||||
appendSql( "(" );
|
||||
|
@ -681,14 +709,20 @@ public abstract class AbstractSqlAstWalker
|
|||
|
||||
if ( needsParenthesis ) {
|
||||
appendSql( ")" );
|
||||
appendSql( queryGroupAlias );
|
||||
}
|
||||
}
|
||||
finally {
|
||||
queryPartStack.pop();
|
||||
this.queryPartForRowNumbering = queryPartForRowNumbering;
|
||||
this.needsSelectAliases = needsSelectAliases;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean supportsSimpleQueryGrouping() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected final void visitWhereClause(QuerySpec querySpec) {
|
||||
final Predicate whereClauseRestrictions = querySpec.getWhereClauseRestrictions();
|
||||
if ( whereClauseRestrictions != null && !whereClauseRestrictions.isEmpty() ) {
|
||||
|
@ -802,8 +836,12 @@ public abstract class AbstractSqlAstWalker
|
|||
appendSql( "()" );
|
||||
break;
|
||||
case SUBQUERY:
|
||||
appendSql( "(select 1 " );
|
||||
appendSql( dialect.getFromDual() );
|
||||
appendSql( "(select 1" );
|
||||
final String fromDual = dialect.getFromDual();
|
||||
if ( !fromDual.isEmpty() ) {
|
||||
appendSql( " " );
|
||||
appendSql( fromDual );
|
||||
}
|
||||
appendSql( ')' );
|
||||
break;
|
||||
case COLUMN_REFERENCE:
|
||||
|
@ -965,14 +1003,14 @@ public abstract class AbstractSqlAstWalker
|
|||
}
|
||||
}
|
||||
|
||||
private void renderExpressionsAsSubquery(final List<? extends Expression> expressions) {
|
||||
protected void renderExpressionsAsSubquery(final List<? extends Expression> expressions) {
|
||||
clauseStack.push( Clause.SELECT );
|
||||
|
||||
try {
|
||||
appendSql( "select " );
|
||||
|
||||
renderCommaSeparated( expressions );
|
||||
String fromDual = dialect.getFromDual();
|
||||
final String fromDual = dialect.getFromDual();
|
||||
if ( !fromDual.isEmpty() ) {
|
||||
appendSql( " " );
|
||||
appendSql( fromDual );
|
||||
|
@ -1634,8 +1672,10 @@ public abstract class AbstractSqlAstWalker
|
|||
FetchClauseType fetchClauseType,
|
||||
boolean emulateFetchClause) {
|
||||
final QueryPart queryPartForRowNumbering = this.queryPartForRowNumbering;
|
||||
final boolean needsSelectAliases = this.needsSelectAliases;
|
||||
try {
|
||||
this.queryPartForRowNumbering = queryPart;
|
||||
this.needsSelectAliases = true;
|
||||
final String alias = "r_" + queryPartForRowNumberingAliasCounter + "_";
|
||||
queryPartForRowNumberingAliasCounter++;
|
||||
appendSql( "select " );
|
||||
|
@ -1736,6 +1776,7 @@ public abstract class AbstractSqlAstWalker
|
|||
}
|
||||
finally {
|
||||
this.queryPartForRowNumbering = queryPartForRowNumbering;
|
||||
this.needsSelectAliases = needsSelectAliases;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1761,25 +1802,21 @@ public abstract class AbstractSqlAstWalker
|
|||
protected void visitSqlSelections(SelectClause selectClause) {
|
||||
final List<SqlSelection> sqlSelections = selectClause.getSqlSelections();
|
||||
final int size = sqlSelections.size();
|
||||
if ( queryPartForRowNumbering == null ) {
|
||||
if ( needsSelectAliases ) {
|
||||
String separator = NO_SEPARATOR;
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
final SqlSelection sqlSelection = sqlSelections.get( i );
|
||||
appendSql( separator );
|
||||
sqlSelection.accept( this );
|
||||
separator = COMA_SEPARATOR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
final SqlSelection sqlSelection = sqlSelections.get( i );
|
||||
sqlSelection.accept( this );
|
||||
appendSql( " c" );
|
||||
appendSql( Integer.toString( i ) );
|
||||
appendSql( COMA_SEPARATOR );
|
||||
separator = COMA_SEPARATOR;
|
||||
}
|
||||
|
||||
switch ( getFetchClauseTypeForRowNumbering( queryPartForRowNumbering ) ) {
|
||||
if ( queryPartForRowNumbering != null ) {
|
||||
final FetchClauseType fetchClauseType = getFetchClauseTypeForRowNumbering( queryPartForRowNumbering );
|
||||
if ( fetchClauseType != null ) {
|
||||
appendSql( separator );
|
||||
switch ( fetchClauseType ) {
|
||||
case PERCENT_ONLY:
|
||||
appendSql( "count(*) over () cnt," );
|
||||
case ROWS_ONLY:
|
||||
|
@ -1808,6 +1845,17 @@ public abstract class AbstractSqlAstWalker
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
String separator = NO_SEPARATOR;
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
final SqlSelection sqlSelection = sqlSelections.get( i );
|
||||
appendSql( separator );
|
||||
sqlSelection.accept( this );
|
||||
separator = COMA_SEPARATOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected FetchClauseType getFetchClauseTypeForRowNumbering(QueryPart queryPartForRowNumbering) {
|
||||
return queryPartForRowNumbering.getFetchClauseType();
|
||||
|
@ -2098,7 +2146,7 @@ public abstract class AbstractSqlAstWalker
|
|||
|
||||
@Override
|
||||
public void visitExtractUnit(ExtractUnit extractUnit) {
|
||||
appendSql( sessionFactory.getJdbcServices().getDialect().translateExtractField( extractUnit.getUnit() ) );
|
||||
appendSql( getDialect().translateExtractField( extractUnit.getUnit() ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2108,7 +2156,7 @@ public abstract class AbstractSqlAstWalker
|
|||
|
||||
@Override
|
||||
public void visitFormat(Format format) {
|
||||
final String dialectFormat = sessionFactory.getJdbcServices().getDialect().translateDatetimeFormat( format.getFormat() );
|
||||
final String dialectFormat = getDialect().translateDatetimeFormat( format.getFormat() );
|
||||
appendSql( "'" );
|
||||
appendSql( dialectFormat );
|
||||
appendSql( "'" );
|
||||
|
@ -2846,8 +2894,10 @@ public abstract class AbstractSqlAstWalker
|
|||
}
|
||||
|
||||
final QueryPart queryPartForRowNumbering = this.queryPartForRowNumbering;
|
||||
final boolean needsSelectAliases = this.needsSelectAliases;
|
||||
try {
|
||||
this.queryPartForRowNumbering = null;
|
||||
this.needsSelectAliases = false;
|
||||
queryPartStack.push( subQuery );
|
||||
appendSql( "exists (select 1" );
|
||||
visitFromClause( subQuery.getFromClause() );
|
||||
|
@ -2904,6 +2954,7 @@ public abstract class AbstractSqlAstWalker
|
|||
finally {
|
||||
queryPartStack.pop();
|
||||
this.queryPartForRowNumbering = queryPartForRowNumbering;
|
||||
this.needsSelectAliases = needsSelectAliases;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -2931,8 +2982,10 @@ public abstract class AbstractSqlAstWalker
|
|||
appendSql( " " );
|
||||
|
||||
final QueryPart queryPartForRowNumbering = this.queryPartForRowNumbering;
|
||||
final boolean needsSelectAliases = this.needsSelectAliases;
|
||||
try {
|
||||
this.queryPartForRowNumbering = null;
|
||||
this.needsSelectAliases = false;
|
||||
queryPartStack.push( subQuery );
|
||||
appendSql( "(" );
|
||||
visitSelectClause( subQuery.getSelectClause() );
|
||||
|
@ -2964,6 +3017,7 @@ public abstract class AbstractSqlAstWalker
|
|||
finally {
|
||||
queryPartStack.pop();
|
||||
this.queryPartForRowNumbering = queryPartForRowNumbering;
|
||||
this.needsSelectAliases = needsSelectAliases;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -3198,22 +3252,4 @@ public abstract class AbstractSqlAstWalker
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// JdbcRecommendedSqlTypeMappingContext
|
||||
|
||||
@Override
|
||||
public boolean isNationalized() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLob() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeConfiguration getTypeConfiguration() {
|
||||
return getSessionFactory().getTypeConfiguration();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.sql.ast.spi;
|
||||
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
public interface SqlSelectAstWalker extends SqlAstWalker {
|
||||
}
|
|
@ -100,7 +100,7 @@ public class JdbcSelectExecutorStandardImpl implements JdbcSelectExecutor {
|
|||
rowTransformer,
|
||||
(sql) -> executionContext.getSession().getJdbcCoordinator().getStatementPreparer().prepareQueryStatement(
|
||||
sql,
|
||||
true,
|
||||
false,
|
||||
scrollMode
|
||||
),
|
||||
ScrollableResultsConsumer.instance()
|
||||
|
|
|
@ -155,7 +155,7 @@ public class DeferredResultSetAccess extends AbstractResultSetAccess {
|
|||
|
||||
// For dialects that don't support an offset clause
|
||||
final int rowsToSkip;
|
||||
if ( !jdbcSelect.usesLimitParameters() && limit != null && limit.getFirstRow() != null && !limitHandler.supportsOffset() ) {
|
||||
if ( !jdbcSelect.usesLimitParameters() && limit != null && limit.getFirstRow() != null && !limitHandler.supportsLimitOffset() ) {
|
||||
rowsToSkip = limit.getFirstRow();
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.type;
|
|||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.query.CastType;
|
||||
import org.hibernate.type.descriptor.java.BooleanTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.IntegerTypeDescriptor;
|
||||
|
||||
|
@ -46,4 +47,8 @@ public class NumericBooleanType
|
|||
public String objectToSQLString(Boolean value, Dialect dialect) {
|
||||
return value ? "1" : "0";
|
||||
}
|
||||
@Override
|
||||
public CastType getCastType() {
|
||||
return CastType.INTEGER_BOOLEAN;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import javax.persistence.TemporalType;
|
|||
import org.hibernate.QueryException;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.metamodel.model.domain.AllowableTemporalParameterType;
|
||||
import org.hibernate.query.CastType;
|
||||
import org.hibernate.type.descriptor.java.OffsetDateTimeJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.TimestampWithTimeZoneDescriptor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
@ -79,4 +80,9 @@ public class OffsetDateTimeType
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CastType getCastType() {
|
||||
return CastType.OFFSET_TIMESTAMP;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,10 +9,9 @@ package org.hibernate.type;
|
|||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.query.CastType;
|
||||
import org.hibernate.type.descriptor.java.BooleanTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.CharTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators;
|
||||
|
||||
/**
|
||||
* A type that maps between {@link java.sql.Types#CHAR CHAR(1)} and {@link Boolean} (using 'T' and 'F')
|
||||
|
@ -22,7 +21,7 @@ import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators;
|
|||
*/
|
||||
public class TrueFalseType
|
||||
extends AbstractSingleColumnStandardBasicType<Boolean>
|
||||
implements PrimitiveType<Boolean>, DiscriminatorType<Boolean>, SqlTypeDescriptorIndicatorCapable<Boolean> {
|
||||
implements PrimitiveType<Boolean>, DiscriminatorType<Boolean> {
|
||||
|
||||
public static final TrueFalseType INSTANCE = new TrueFalseType();
|
||||
|
||||
|
@ -51,18 +50,7 @@ public class TrueFalseType
|
|||
}
|
||||
|
||||
@Override
|
||||
public <X> BasicType<X> resolveIndicatedType(SqlTypeDescriptorIndicators indicators) {
|
||||
if ( indicators.getPreferredSqlTypeCodeForBoolean() != getSqlTypeDescriptor().getJdbcTypeCode() ) {
|
||||
final SqlTypeDescriptor sqlTypeDescriptor = indicators.getTypeConfiguration()
|
||||
.getSqlTypeDescriptorRegistry()
|
||||
.getDescriptor( indicators.getPreferredSqlTypeCodeForBoolean() );
|
||||
//noinspection unchecked
|
||||
return (BasicType<X>) indicators.getTypeConfiguration()
|
||||
.getBasicTypeRegistry()
|
||||
.resolve( getJavaTypeDescriptor(), sqlTypeDescriptor );
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
return (BasicType<X>) this;
|
||||
public CastType getCastType() {
|
||||
return CastType.TF_BOOLEAN;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,10 +9,9 @@ package org.hibernate.type;
|
|||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.query.CastType;
|
||||
import org.hibernate.type.descriptor.java.BooleanTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.CharTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators;
|
||||
|
||||
/**
|
||||
* A type that maps between {@link java.sql.Types#CHAR CHAR(1)} and {@link Boolean} (using 'Y' and 'N')
|
||||
|
@ -22,7 +21,7 @@ import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators;
|
|||
*/
|
||||
public class YesNoType
|
||||
extends AbstractSingleColumnStandardBasicType<Boolean>
|
||||
implements PrimitiveType<Boolean>, DiscriminatorType<Boolean>, SqlTypeDescriptorIndicatorCapable<Boolean> {
|
||||
implements PrimitiveType<Boolean>, DiscriminatorType<Boolean> {
|
||||
|
||||
public static final YesNoType INSTANCE = new YesNoType();
|
||||
|
||||
|
@ -51,18 +50,7 @@ public class YesNoType
|
|||
}
|
||||
|
||||
@Override
|
||||
public <X> BasicType<X> resolveIndicatedType(SqlTypeDescriptorIndicators indicators) {
|
||||
if ( indicators.getPreferredSqlTypeCodeForBoolean() != getSqlTypeDescriptor().getJdbcTypeCode() ) {
|
||||
final SqlTypeDescriptor sqlTypeDescriptor = indicators.getTypeConfiguration()
|
||||
.getSqlTypeDescriptorRegistry()
|
||||
.getDescriptor( indicators.getPreferredSqlTypeCodeForBoolean() );
|
||||
//noinspection unchecked
|
||||
return (BasicType<X>) indicators.getTypeConfiguration()
|
||||
.getBasicTypeRegistry()
|
||||
.resolve( getJavaTypeDescriptor(), sqlTypeDescriptor );
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
return (BasicType<X>) this;
|
||||
public CastType getCastType() {
|
||||
return CastType.YN_BOOLEAN;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.hibernate.QueryException;
|
|||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.ZonedDateTimeComparator;
|
||||
import org.hibernate.metamodel.model.domain.AllowableTemporalParameterType;
|
||||
import org.hibernate.query.CastType;
|
||||
import org.hibernate.type.descriptor.java.ZonedDateTimeJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.TimestampWithTimeZoneDescriptor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
@ -73,4 +74,9 @@ public class ZonedDateTimeType
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CastType getCastType() {
|
||||
return CastType.ZONE_TIMESTAMP;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.query.CastType;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
|
@ -92,4 +94,44 @@ public interface SqlTypeDescriptor extends Serializable {
|
|||
* @return The appropriate extractor
|
||||
*/
|
||||
<X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor);
|
||||
|
||||
default CastType getCastType() {
|
||||
switch ( getSqlType() ) {
|
||||
case Types.INTEGER:
|
||||
case Types.TINYINT:
|
||||
case Types.SMALLINT:
|
||||
return CastType.INTEGER;
|
||||
case Types.BIGINT:
|
||||
return CastType.LONG;
|
||||
case Types.FLOAT:
|
||||
case Types.REAL:
|
||||
return CastType.FLOAT;
|
||||
case Types.DOUBLE:
|
||||
return CastType.DOUBLE;
|
||||
case Types.CHAR:
|
||||
case Types.NCHAR:
|
||||
case Types.VARCHAR:
|
||||
case Types.NVARCHAR:
|
||||
case Types.LONGVARCHAR:
|
||||
case Types.LONGNVARCHAR:
|
||||
return CastType.STRING;
|
||||
case Types.BOOLEAN:
|
||||
return CastType.BOOLEAN;
|
||||
case Types.DECIMAL:
|
||||
case Types.NUMERIC:
|
||||
return CastType.FIXED;
|
||||
case Types.DATE:
|
||||
return CastType.DATE;
|
||||
case Types.TIME:
|
||||
return CastType.TIME;
|
||||
case Types.TIMESTAMP:
|
||||
return CastType.TIMESTAMP;
|
||||
case Types.TIMESTAMP_WITH_TIMEZONE:
|
||||
return CastType.OFFSET_TIMESTAMP;
|
||||
case Types.NULL:
|
||||
return CastType.NULL;
|
||||
default:
|
||||
return CastType.OTHER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ public class VarbinaryTypeDescriptor implements SqlTypeDescriptor {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "VarbinaryTypeDescriptor)";
|
||||
return "VarbinaryTypeDescriptor";
|
||||
}
|
||||
|
||||
public int getSqlType() {
|
||||
|
|
|
@ -6,10 +6,14 @@
|
|||
*/
|
||||
package org.hibernate.type.internal;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.query.CastType;
|
||||
import org.hibernate.type.AbstractSingleColumnStandardBasicType;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.SqlTypeDescriptorIndicatorCapable;
|
||||
import org.hibernate.type.descriptor.java.BooleanTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators;
|
||||
|
@ -51,4 +55,20 @@ public class StandardBasicTypeImpl<J>
|
|||
.getBasicTypeRegistry()
|
||||
.resolve( getJavaTypeDescriptor(), recommendedSqlType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public CastType getCastType() {
|
||||
if ( getJavaTypeDescriptor() == BooleanTypeDescriptor.INSTANCE ) {
|
||||
switch ( sqlType() ) {
|
||||
case Types.BIT:
|
||||
case Types.SMALLINT:
|
||||
case Types.TINYINT:
|
||||
case Types.INTEGER:
|
||||
return CastType.INTEGER_BOOLEAN;
|
||||
case Types.CHAR:
|
||||
return CastType.YN_BOOLEAN;
|
||||
}
|
||||
}
|
||||
return super.getCastType();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -285,6 +285,9 @@ public class TypeConfiguration implements SessionFactoryObserver, Serializable {
|
|||
//this one is very fragile ... works well for BIT or BOOLEAN columns only
|
||||
//works OK, I suppose, for integer columns, but not at all for char columns
|
||||
case "boolean": return getBasicTypeForJavaType( Boolean.class );
|
||||
case "truefalse": return StandardBasicTypes.TRUE_FALSE;
|
||||
case "yesno": return StandardBasicTypes.YES_NO;
|
||||
case "numericboolean": return StandardBasicTypes.NUMERIC_BOOLEAN;
|
||||
default: throw new HibernateException( "unrecognized cast target type: " + name );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.hibernate.orm.test.annotations.collectionelement;
|
|||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
|
@ -100,6 +101,7 @@ public class EmbeddableElementCollectionMemberOfTest {
|
|||
this.street = street;
|
||||
}
|
||||
|
||||
@Column(name = "house_number")
|
||||
public int getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
|
|
@ -6,16 +6,11 @@
|
|||
*/
|
||||
package org.hibernate.orm.test.columntransformer;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.graph.GraphParser;
|
||||
import org.hibernate.graph.GraphSemantic;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
|
@ -122,7 +117,7 @@ public class ColumnTransformerTest {
|
|||
final String sqlString =
|
||||
// represents how each is mapped in the mappings - see their @ColumnTransformer#read
|
||||
"select size_in_cm / 2.54E0"
|
||||
+ ", radiusS / 2.54d"
|
||||
+ ", radiusS / 2.54E0"
|
||||
+ ", diamet / 2.54E0"
|
||||
+ " from t_staff"
|
||||
+ " where t_staff.id = 4";
|
||||
|
|
|
@ -18,9 +18,9 @@ import org.hibernate.dialect.DB2Dialect;
|
|||
import org.hibernate.dialect.DerbyDialect;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.HSQLDialect;
|
||||
import org.hibernate.dialect.MariaDB103Dialect;
|
||||
import org.hibernate.dialect.Oracle8iDialect;
|
||||
import org.hibernate.dialect.SQLServer2012Dialect;
|
||||
import org.hibernate.dialect.MariaDBDialect;
|
||||
import org.hibernate.dialect.OracleDialect;
|
||||
import org.hibernate.dialect.SQLServerDialect;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.exception.GenericJDBCException;
|
||||
import org.hibernate.jdbc.Work;
|
||||
|
@ -41,10 +41,10 @@ public class SequenceValueExtractor {
|
|||
else if ( dialect instanceof DB2Dialect ) {
|
||||
queryString = "values PREVIOUS value for " + sequenceName;
|
||||
}
|
||||
else if ( dialect instanceof Oracle8iDialect ) {
|
||||
else if ( dialect instanceof OracleDialect && dialect.getVersion() >= 8 ) {
|
||||
queryString = "select " + sequenceName + ".currval from dual";
|
||||
}
|
||||
else if ( dialect instanceof SQLServer2012Dialect ) {
|
||||
else if ( dialect instanceof SQLServerDialect && dialect.getVersion() >= 11 ) {
|
||||
queryString = "SELECT CONVERT(varchar(200), Current_value) FROM sys.sequences WHERE name = '" + sequenceName + "'";
|
||||
}
|
||||
else if ( dialect instanceof HSQLDialect ) {
|
||||
|
@ -55,7 +55,7 @@ public class SequenceValueExtractor {
|
|||
|
||||
queryString = "select " + sequenceName + ".currval from sys.dummy";
|
||||
}
|
||||
else if ( dialect instanceof MariaDB103Dialect ) {
|
||||
else if ( dialect instanceof MariaDBDialect && dialect.getVersion() >= 1030 ) {
|
||||
|
||||
queryString = "select LASTVAL(" + sequenceName + ")";
|
||||
}
|
||||
|
|
|
@ -75,9 +75,13 @@ public class SequenceMismatchStrategyFixWithSequenceGeneratorTest extends Entity
|
|||
|
||||
@AfterAll
|
||||
public void releaseResources() {
|
||||
if ( metadata != null ) {
|
||||
new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), metadata );
|
||||
}
|
||||
if ( serviceRegistry != null ) {
|
||||
StandardServiceRegistryBuilder.destroy( serviceRegistry );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
|
|
|
@ -73,9 +73,13 @@ public class SequenceMismatchStrategyLogTest extends EntityManagerFactoryBasedFu
|
|||
|
||||
@AfterAll
|
||||
public void releaseResources() {
|
||||
if ( metadata != null ) {
|
||||
new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), metadata );
|
||||
}
|
||||
if ( serviceRegistry != null ) {
|
||||
StandardServiceRegistryBuilder.destroy( serviceRegistry );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
|
|
|
@ -74,9 +74,13 @@ public class SequenceMismatchStrategyWithoutSequenceGeneratorTest extends Entity
|
|||
|
||||
@AfterAll
|
||||
public void releaseResources() {
|
||||
if ( metadata != null ) {
|
||||
new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), metadata );
|
||||
}
|
||||
if ( serviceRegistry != null ) {
|
||||
StandardServiceRegistryBuilder.destroy( serviceRegistry );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.orm.test.mapping.naturalid.inheritance;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
|
@ -24,6 +25,7 @@ public class User extends Principal {
|
|||
super( uid );
|
||||
}
|
||||
|
||||
@Column(name = "user_level")
|
||||
public String getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.util.Objects;
|
|||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
@ -135,6 +136,7 @@ public class SortNaturalByDefaultTests {
|
|||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@Column(name = "phone_number")
|
||||
private String number;
|
||||
|
||||
public Phone() {
|
||||
|
|
|
@ -65,8 +65,10 @@ public class OneToManySelfReferenceTest {
|
|||
@AfterEach
|
||||
public void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session ->
|
||||
session.createQuery( "delete from Event" ).executeUpdate()
|
||||
session -> {
|
||||
session.createQuery( "update Event e set e.parent = null" ).executeUpdate();
|
||||
session.createQuery( "delete from Event" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,24 +6,20 @@
|
|||
*/
|
||||
package org.hibernate.orm.test.query.hql;
|
||||
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.dialect.DerbyDialect;
|
||||
|
||||
import org.hibernate.testing.DialectChecks;
|
||||
import org.hibernate.testing.junit5.SessionFactoryBasedFunctionalTest;
|
||||
import org.hibernate.testing.orm.domain.StandardDomainModel;
|
||||
import org.hibernate.testing.orm.domain.gambit.EntityOfBasics;
|
||||
import org.hibernate.testing.orm.junit.DialectFeatureCheck;
|
||||
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.FailureExpected;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import java.sql.Date;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
|
@ -43,25 +39,24 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
@ServiceRegistry
|
||||
@DomainModel( standardModels = StandardDomainModel.GAMBIT )
|
||||
@SessionFactory
|
||||
public class FunctionTests extends SessionFactoryBasedFunctionalTest {
|
||||
public class FunctionTests {
|
||||
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources metadataSources) {
|
||||
StandardDomainModel.GAMBIT.getDescriptor().applyDomainModel(metadataSources);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sessionFactoryBuilt(SessionFactoryImplementor factory) {
|
||||
EntityManager em = factory.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
@BeforeAll
|
||||
public void prepareData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
em -> {
|
||||
EntityOfBasics entity = new EntityOfBasics();
|
||||
entity.setId(12);
|
||||
entity.setId(123);
|
||||
entity.setTheDate( new Date( 74, 2, 25 ) );
|
||||
entity.setTheTime( new Time( 23, 10, 8 ) );
|
||||
entity.setTheTimestamp( new Timestamp( System.currentTimeMillis() ) );
|
||||
em.persist(entity);
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsCharCodeConversion.class)
|
||||
public void testAsciiChrFunctions(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
|
@ -111,7 +106,7 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
|
|||
public void testCoalesceFunction(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery("select coalesce(null, e.gender, e.convertedGender) from EntityOfBasics e")
|
||||
session.createQuery("select coalesce(nullif('',''), e.gender, e.convertedGender) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select ifnull(e.gender, e.convertedGender) from EntityOfBasics e")
|
||||
.list();
|
||||
|
@ -159,7 +154,7 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
|
|||
.list();
|
||||
session.createQuery("select exp(e.theDouble), ln(e.theDouble + 1) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select power(e.theDouble, 2.5) from EntityOfBasics e")
|
||||
session.createQuery("select power(e.theDouble + 1, 2.5) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select ceiling(e.theDouble), floor(e.theDouble) from EntityOfBasics e")
|
||||
.list();
|
||||
|
@ -269,7 +264,7 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected(reason = "needs indirection in positional parameter bindings")
|
||||
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby doesn't support a parameter in the 'length' function or the 'char' function which we render as emulation")
|
||||
public void testOverlayFunctionParameters(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
|
@ -295,6 +290,7 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsReplace.class)
|
||||
public void testReplaceFunction(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
|
@ -342,6 +338,7 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby doesn't support a parameter in the 'length' function or the 'char' function which we render as emulation")
|
||||
public void testPadFunctionParameters(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
|
@ -361,6 +358,10 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
|
|||
public void testCastFunction(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
assertThat( ((String) session.createQuery("select cast(e.theBoolean as String) from EntityOfBasics e").getSingleResult()).toLowerCase(), is("false") );
|
||||
assertThat( ((String) session.createQuery("select cast(e.theNumericBoolean as String) from EntityOfBasics e").getSingleResult()).toLowerCase(), is("false") );
|
||||
assertThat( ((String) session.createQuery("select cast(e.theStringBoolean as String) from EntityOfBasics e").getSingleResult()).toLowerCase(), is("false") );
|
||||
|
||||
session.createQuery("select cast(e.theDate as String), cast(e.theTime as String), cast(e.theTimestamp as String) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select cast(e.id as String), cast(e.theInt as String), cast(e.theDouble as String) from EntityOfBasics e")
|
||||
|
@ -371,10 +372,6 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
|
|||
.list();
|
||||
session.createQuery("select cast(e.theString as String(15)), cast(e.theDouble as String(8)) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select cast(e.theString as Binary) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select cast(e.theString as Binary(10)) from EntityOfBasics e")
|
||||
.list();
|
||||
|
||||
session.createQuery("select cast('1002342345234523.452435245245243' as BigDecimal) from EntityOfBasics")
|
||||
.list();
|
||||
|
@ -427,6 +424,34 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
|
|||
assertThat( session.createQuery("select cast(date 1911-10-09 as String)").getSingleResult(), is("1911-10-09") );
|
||||
assertThat( session.createQuery("select cast(time 12:13:14 as String)").getSingleResult(), is("12:13:14") );
|
||||
assertThat( (String) session.createQuery("select cast(datetime 1911-10-09 12:13:14 as String)").getSingleResult(), startsWith("1911-10-09 12:13:14") );
|
||||
|
||||
assertThat( session.createQuery("select cast(1 as NumericBoolean)").getSingleResult(), is(true) );
|
||||
assertThat( session.createQuery("select cast(0 as NumericBoolean)").getSingleResult(), is(false) );
|
||||
assertThat( session.createQuery("select cast(true as YesNo)").getSingleResult(), is(true) );
|
||||
assertThat( session.createQuery("select cast(false as YesNo)").getSingleResult(), is(false) );
|
||||
assertThat( session.createQuery("select cast(1 as YesNo)").getSingleResult(), is(true) );
|
||||
assertThat( session.createQuery("select cast(0 as YesNo)").getSingleResult(), is(false) );
|
||||
assertThat( session.createQuery("select cast(true as TrueFalse)").getSingleResult(), is(true) );
|
||||
assertThat( session.createQuery("select cast(false as TrueFalse)").getSingleResult(), is(false) );
|
||||
assertThat( session.createQuery("select cast(1 as TrueFalse)").getSingleResult(), is(true) );
|
||||
assertThat( session.createQuery("select cast(0 as TrueFalse)").getSingleResult(), is(false) );
|
||||
assertThat( session.createQuery("select cast('Y' as YesNo)").getSingleResult(), is(true) );
|
||||
assertThat( session.createQuery("select cast('N' as YesNo)").getSingleResult(), is(false) );
|
||||
assertThat( session.createQuery("select cast('T' as TrueFalse)").getSingleResult(), is(true) );
|
||||
assertThat( session.createQuery("select cast('F' as TrueFalse)").getSingleResult(), is(false) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby doesn't support casting to the binary types")
|
||||
public void testCastFunctionBinary(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery("select cast(e.theString as Binary) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select cast(e.theString as Binary(10)) from EntityOfBasics e")
|
||||
.list();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -515,7 +540,9 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
|
|||
session -> {
|
||||
session.createQuery("select avg(e.theDouble), avg(abs(e.theDouble)), min(e.theDouble), max(e.theDouble), sum(e.theDouble), sum(e.theInt) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select avg(distinct e.theInt), sum(distinct e.theInt) from EntityOfBasics e")
|
||||
session.createQuery("select avg(distinct e.theInt) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select sum(distinct e.theInt) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select any(e.theInt > 0), every(e.theInt > 0) from EntityOfBasics e")
|
||||
.list();
|
||||
|
@ -763,11 +790,7 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
|
|||
.list();
|
||||
session.createQuery("select extract(day of month from e.theDate) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select extract(day of week from e.theDate) from EntityOfBasics e")
|
||||
.list();
|
||||
|
||||
session.createQuery("select extract(week from e.theDate) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select extract(quarter from e.theDate) from EntityOfBasics e")
|
||||
.list();
|
||||
|
||||
|
@ -813,6 +836,20 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractFunctionWeek(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery("select extract(day of week from e.theDate) from EntityOfBasics e")
|
||||
.list();
|
||||
|
||||
session.createQuery("select extract(week from e.theDate) from EntityOfBasics e")
|
||||
.list();
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsTimezoneTypes.class)
|
||||
public void testExtractFunctionTimeZone(SessionFactoryScope scope) {
|
||||
|
@ -833,10 +870,6 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
|
|||
public void testExtractFunctionWithAssertions(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
EntityOfBasics entity = new EntityOfBasics();
|
||||
entity.setId(1);
|
||||
session.save(entity);
|
||||
session.flush();
|
||||
assertThat(
|
||||
session.createQuery("select extract(week of year from date 2019-01-01) from EntityOfBasics").getResultList().get(0),
|
||||
is(1)
|
||||
|
@ -932,23 +965,15 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
|
|||
session.createQuery("select extract(time from local datetime) from EntityOfBasics").getResultList().get(0),
|
||||
instanceOf(LocalTime.class)
|
||||
);
|
||||
session.delete(entity);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby doesn't support formatting temporal types to strings")
|
||||
public void testFormat(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
EntityOfBasics entity = new EntityOfBasics();
|
||||
entity.setId(123);
|
||||
entity.setTheDate( new Date( 74, 2, 25 ) );
|
||||
entity.setTheTime( new Time( 23, 10, 8 ) );
|
||||
entity.setTheTimestamp( new Timestamp( System.currentTimeMillis() ) );
|
||||
session.persist(entity);
|
||||
session.flush();
|
||||
|
||||
session.createQuery("select format(e.theTime as 'hh:mm:ss aa') from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select format(e.theDate as 'dd/MM/yy'), format(e.theDate as 'EEEE, MMMM dd, yyyy') from EntityOfBasics e")
|
||||
|
@ -969,8 +994,8 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testGrouping() {
|
||||
inTransaction(
|
||||
public void testGrouping(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery("select max(e.theDouble), e.gender, e.theInt from EntityOfBasics e group by e.gender, e.theInt")
|
||||
.list();
|
||||
|
@ -980,12 +1005,21 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
|
|||
|
||||
@Test
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsGroupByRollup.class)
|
||||
public void testGroupingFunctions() {
|
||||
inTransaction(
|
||||
public void testGroupByRollup(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery("select avg(e.theDouble), e.gender, e.theInt from EntityOfBasics e group by rollup(e.gender, e.theInt)")
|
||||
.list();
|
||||
session.createQuery("select sum(e.theDouble), e.gender, e.theInt from EntityOfBasics e group by cube(e.gender, e.theInt)")
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsGroupByGroupingSets.class)
|
||||
public void testGroupByGroupingSets(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery("select avg(e.theDouble), e.gender, e.theInt from EntityOfBasics e group by cube(e.gender, e.theInt)")
|
||||
.list();
|
||||
}
|
||||
);
|
||||
|
|
|
@ -12,6 +12,8 @@ import java.sql.Timestamp;
|
|||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
|
||||
import org.hibernate.dialect.DerbyDialect;
|
||||
|
||||
import org.hibernate.testing.orm.domain.StandardDomainModel;
|
||||
import org.hibernate.testing.orm.domain.gambit.EntityOfBasics;
|
||||
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||
|
@ -20,6 +22,8 @@ import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
|||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
|
@ -34,6 +38,21 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
@DomainModel( standardModels = StandardDomainModel.GAMBIT )
|
||||
@SessionFactory
|
||||
public class StandardFunctionTests {
|
||||
|
||||
@BeforeAll
|
||||
public void prepareData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
em -> {
|
||||
EntityOfBasics entity = new EntityOfBasics();
|
||||
entity.setId(123);
|
||||
entity.setTheDate( new Date( 74, 2, 25 ) );
|
||||
entity.setTheTime( new Time( 23, 10, 8 ) );
|
||||
entity.setTheTimestamp( new Timestamp( System.currentTimeMillis() ) );
|
||||
em.persist(entity);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void currentTimestampTests(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
|
@ -105,11 +124,11 @@ public class StandardFunctionTests {
|
|||
session.createQuery( "select local_date from EntityOfBasics" ).list();
|
||||
session.createQuery( "select local_date() from EntityOfBasics" ).list();
|
||||
|
||||
session.createQuery( "select e from EntityOfBasics e where e.theTimestamp = local_date" ).list();
|
||||
session.createQuery( "select e from EntityOfBasics e where e.theTimestamp = local_date()" ).list();
|
||||
session.createQuery( "select e from EntityOfBasics e where e.theDate = local_date" ).list();
|
||||
session.createQuery( "select e from EntityOfBasics e where e.theDate = local_date()" ).list();
|
||||
|
||||
session.createQuery( "select e from EntityOfBasics e where local_date between e.theTimestamp and e.theTimestamp" ).list();
|
||||
session.createQuery( "select e from EntityOfBasics e where local_date() between e.theTimestamp and e.theTimestamp" ).list();
|
||||
session.createQuery( "select e from EntityOfBasics e where local_date between e.theDate and e.theDate" ).list();
|
||||
session.createQuery( "select e from EntityOfBasics e where local_date() between e.theDate and e.theDate" ).list();
|
||||
|
||||
assertThat(
|
||||
session.createQuery( "select local_date" ).getSingleResult(),
|
||||
|
@ -154,7 +173,7 @@ public class StandardFunctionTests {
|
|||
public void testCoalesceFunction(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery("select coalesce(null, e.gender, e.convertedGender) from EntityOfBasics e")
|
||||
session.createQuery("select coalesce(nullif('',''), e.gender, e.convertedGender) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select ifnull(e.gender, e.convertedGender) from EntityOfBasics e")
|
||||
.list();
|
||||
|
@ -191,9 +210,9 @@ public class StandardFunctionTests {
|
|||
.list();
|
||||
session.createQuery("select abs(e.theDouble), sign(e.theDouble), sqrt(e.theDouble) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select exp(e.theDouble), ln(e.theDouble) from EntityOfBasics e")
|
||||
session.createQuery("select exp(e.theDouble), ln(e.theDouble + 1) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select power(e.theDouble, 2.5) from EntityOfBasics e")
|
||||
session.createQuery("select power(e.theDouble + 1, 2.5) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select ceiling(e.theDouble), floor(e.theDouble) from EntityOfBasics e")
|
||||
.list();
|
||||
|
@ -232,6 +251,7 @@ public class StandardFunctionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsCharCodeConversion.class)
|
||||
public void testAsciiChrFunctions(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
|
@ -311,6 +331,7 @@ public class StandardFunctionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsReplace.class)
|
||||
public void testReplaceFunction(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
|
@ -612,14 +633,14 @@ public class StandardFunctionTests {
|
|||
public void testExtractFunctionTimeZone(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery("select extract(offset hour from e.theTime) from EntityOfBasics e")
|
||||
session.createQuery("select extract(offset hour from e.theZonedDateTime) from EntityOfBasics e")
|
||||
.list();
|
||||
|
||||
// the grammar rule is defined as `HOUR | MINUTE` so no idea how both ever worked.
|
||||
// session.createQuery("select extract(offset hour minute from e.theTime) from EntityOfBasics e")
|
||||
// session.createQuery("select extract(offset hour minute from e.theZonedDateTime) from EntityOfBasics e")
|
||||
// .list();
|
||||
|
||||
session.createQuery("select extract(offset from e.theTimestamp) from EntityOfBasics e")
|
||||
session.createQuery("select extract(offset from e.theZonedDateTime) from EntityOfBasics e")
|
||||
.list();
|
||||
}
|
||||
);
|
||||
|
@ -638,20 +659,11 @@ public class StandardFunctionTests {
|
|||
@Test
|
||||
// @FailureExpected
|
||||
public void testExtractFunctionWithAssertions(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
EntityOfBasics entity = new EntityOfBasics();
|
||||
entity.setId(1);
|
||||
session.save(entity);
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
assertThat(
|
||||
session.createQuery(
|
||||
"select extract(week of year from {2019-01-01}) from EntityOfBasics b where b.id = 1" )
|
||||
"select extract(week of year from {2019-01-01}) from EntityOfBasics b where b.id = 123" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 1 )
|
||||
|
@ -791,14 +803,6 @@ public class StandardFunctionTests {
|
|||
}
|
||||
);
|
||||
}
|
||||
finally {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete from EntityOfBasics" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractFunctions(SessionFactoryScope scope) {
|
||||
|
@ -874,26 +878,17 @@ public class StandardFunctionTests {
|
|||
session -> {
|
||||
session.createQuery("select avg(e.theDouble), avg(abs(e.theDouble)), min(e.theDouble), max(e.theDouble), sum(e.theDouble), sum(e.theInt) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select avg(distinct e.theInt), sum(distinct e.theInt) from EntityOfBasics e")
|
||||
session.createQuery("select sum(distinct e.theInt) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select sum(distinct e.theInt) from EntityOfBasics e")
|
||||
.list();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby doesn't support formatting temporal types to strings")
|
||||
public void testFormat(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
EntityOfBasics entity = new EntityOfBasics();
|
||||
entity.setId(123);
|
||||
entity.setTheDate( new Date( 74, 2, 25 ) );
|
||||
entity.setTheTime( new Time( 23, 10, 8 ) );
|
||||
entity.setTheTimestamp( new Timestamp( System.currentTimeMillis() ) );
|
||||
session.persist( entity );
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "select format(e.theTime as 'hh:mm:ss aa') from EntityOfBasics e" )
|
||||
|
@ -922,12 +917,4 @@ public class StandardFunctionTests {
|
|||
}
|
||||
);
|
||||
}
|
||||
finally {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete EntityOfBasics" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ public class NativeQueryParameterTests {
|
|||
public void testBasicParameterBinding(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createNativeQuery( "select t.id, t.ticket_key, t.subject from ticket t where t.ticket_key = ?" )
|
||||
session.createNativeQuery( "select t.id, t.ticket_key, t.subject from Ticket t where t.ticket_key = ?" )
|
||||
.setParameter( 1, "ABC-123" )
|
||||
.list();
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ public class NativeQueryParameterTests {
|
|||
@Test
|
||||
public void testJpaStylePositionalParametersInNativeSql(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
s -> s.createNativeQuery( "select t.subject from ticket t where t.ticket_key = ?1" ).setParameter( 1, "ABC-123" ).list()
|
||||
s -> s.createNativeQuery( "select t.subject from Ticket t where t.ticket_key = ?1" ).setParameter( 1, "ABC-123" ).list()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ public class NativeQueryParameterTests {
|
|||
public void testTypedParameterBinding(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createNativeQuery( "select t.id, t.ticket_key, t.subject from ticket t where t.ticket_key = ?" )
|
||||
session.createNativeQuery( "select t.id, t.ticket_key, t.subject from Ticket t where t.ticket_key = ?" )
|
||||
.setParameter( 1, "ABC-123", StandardBasicTypes.STRING )
|
||||
.list();
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ public class NativeQueryParameterTests {
|
|||
@Test
|
||||
public void testTemporalParameterBinding(SessionFactoryScope scope) {
|
||||
final String qryString = "select i.id, i.effectiveStart, i.effectiveEnd " +
|
||||
" from incident i" +
|
||||
" from Incident i" +
|
||||
" where i.reported BETWEEN ? AND ?";
|
||||
|
||||
scope.inTransaction(
|
||||
|
|
|
@ -14,6 +14,7 @@ import java.util.List;
|
|||
|
||||
import org.hibernate.dialect.DB2Dialect;
|
||||
import org.hibernate.dialect.DerbyDialect;
|
||||
import org.hibernate.dialect.SQLServerDialect;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.internal.BasicValuedSingularAttributeMapping;
|
||||
|
@ -80,10 +81,11 @@ public class NativeQueryResultBuilderTests {
|
|||
public void fullyImplicitTest2(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
// DB2 and Derby return an Integer for count by default
|
||||
// DB2, Derby and SQL Server return an Integer for count by default
|
||||
Assumptions.assumeThat( session.getJdbcServices().getDialect() )
|
||||
.isNotInstanceOf( DB2Dialect.class )
|
||||
.isNotInstanceOf( DerbyDialect.class );
|
||||
.isNotInstanceOf( DerbyDialect.class )
|
||||
.isNotInstanceOf( SQLServerDialect.class );
|
||||
final String sql = "select count(theString) from EntityOfBasics";
|
||||
final NativeQueryImplementor<?> query = session.createNativeQuery( sql );
|
||||
|
||||
|
|
|
@ -75,6 +75,23 @@ public class SetOperationTest {
|
|||
@Test
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsUnion.class)
|
||||
public void testUnionAllLimit(SessionFactoryScope scope) {
|
||||
scope.inSession(
|
||||
session -> {
|
||||
List<Tuple> list = session.createQuery(
|
||||
"(select e.id, e from EntityOfLists e where e.id = 1 " +
|
||||
"union all " +
|
||||
"select e.id, e from EntityOfLists e where e.id = 2) " +
|
||||
"order by 1 fetch first 1 row only",
|
||||
Tuple.class
|
||||
).list();
|
||||
assertThat( list.size(), is( 1 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsUnion.class)
|
||||
public void testUnionAllLimitSubquery(SessionFactoryScope scope) {
|
||||
scope.inSession(
|
||||
session -> {
|
||||
List<Tuple> list = session.createQuery(
|
||||
|
@ -84,6 +101,23 @@ public class SetOperationTest {
|
|||
"order by 1 fetch first 1 row only",
|
||||
Tuple.class
|
||||
).list();
|
||||
assertThat( list.size(), is( 2 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsUnion.class)
|
||||
public void testUnionAllLimitNested(SessionFactoryScope scope) {
|
||||
scope.inSession(
|
||||
session -> {
|
||||
List<Tuple> list = session.createQuery(
|
||||
"(select e.id, e from EntityOfLists e where e.id = 1 " +
|
||||
"union all " +
|
||||
"(select e.id, e from EntityOfLists e where e.id = 2 order by 1 fetch first 1 row only)) " +
|
||||
"order by 1 fetch first 1 row only",
|
||||
Tuple.class
|
||||
).list();
|
||||
assertThat( list.size(), is( 1 ) );
|
||||
}
|
||||
);
|
||||
|
|
|
@ -120,9 +120,13 @@ public class SmokeTests {
|
|||
sqlAst
|
||||
).translate( null, QueryOptions.NONE );
|
||||
|
||||
final String separator = session.getSessionFactory()
|
||||
.getJdbcServices()
|
||||
.getDialect()
|
||||
.getTableAliasSeparator();
|
||||
assertThat(
|
||||
jdbcSelectOperation.getSql(),
|
||||
is( "select s1_0.name from mapping_simple_entity as s1_0" )
|
||||
is( "select s1_0.name from mapping_simple_entity" + separator + "s1_0" )
|
||||
);
|
||||
}
|
||||
);
|
||||
|
@ -216,9 +220,13 @@ public class SmokeTests {
|
|||
sqlAst
|
||||
).translate( null, QueryOptions.NONE );
|
||||
|
||||
final String separator = session.getSessionFactory()
|
||||
.getJdbcServices()
|
||||
.getDialect()
|
||||
.getTableAliasSeparator();
|
||||
assertThat(
|
||||
jdbcSelectOperation.getSql(),
|
||||
is( "select s1_0.gender from mapping_simple_entity as s1_0" )
|
||||
is( "select s1_0.gender from mapping_simple_entity" + separator + "s1_0" )
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -67,6 +67,7 @@ public class EntityWithLazyManyToOneSelfReferenceTest {
|
|||
public void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "update EntityWithLazyManyToOneSelfReference e set e.other = null" ).executeUpdate();
|
||||
session.createQuery( "delete from EntityWithLazyManyToOneSelfReference" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
|
|
|
@ -66,6 +66,7 @@ public class EntityWithManyToOneSelfReferenceTest {
|
|||
public void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "update EntityWithManyToOneSelfReference e set e.other = null" ).executeUpdate();
|
||||
session.createQuery( "delete from EntityWithManyToOneSelfReference" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.testing.junit5;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Driver;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DatabaseMetaDataDialectResolutionInfoAdapter;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public final class DialectContext {
|
||||
|
||||
private static final Dialect dialect;
|
||||
|
||||
static {
|
||||
final Properties properties = Environment.getProperties();
|
||||
final String dialectName = properties.getProperty( Environment.DIALECT );
|
||||
if ( dialectName == null ) {
|
||||
throw new HibernateException( "The dialect was not set. Set the property hibernate.dialect." );
|
||||
}
|
||||
try {
|
||||
final Class<? extends Dialect> dialectClass = ReflectHelper.classForName( dialectName );
|
||||
final Constructor<? extends Dialect> constructor = dialectClass.getConstructor( DialectResolutionInfo.class );
|
||||
Driver driver = (Driver) Class.forName( properties.getProperty( Environment.DRIVER ) ).newInstance();
|
||||
Properties props = new Properties();
|
||||
props.setProperty( "user", properties.getProperty( Environment.USER ) );
|
||||
props.setProperty( "password", properties.getProperty( Environment.PASS ) );
|
||||
try (Connection connection = driver.connect( properties.getProperty( Environment.URL ), props )) {
|
||||
dialect = constructor.newInstance( new DatabaseMetaDataDialectResolutionInfoAdapter( connection.getMetaData() ) );
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException cnfe) {
|
||||
throw new HibernateException( "Dialect class not found: " + dialectName );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new HibernateException( "Could not instantiate given dialect class: " + dialectName, e );
|
||||
}
|
||||
}
|
||||
|
||||
private DialectContext() {
|
||||
}
|
||||
|
||||
public static Dialect getDialect() {
|
||||
return dialect;
|
||||
}
|
||||
}
|
|
@ -37,16 +37,6 @@ public class DialectFilterExtension implements ExecutionCondition {
|
|||
|
||||
@Override
|
||||
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
|
||||
if ( !context.getTestInstance().isPresent() ) {
|
||||
assert !context.getTestMethod().isPresent();
|
||||
|
||||
return ConditionEvaluationResult.enabled(
|
||||
"No test-instance was present - " +
|
||||
"likely that test was not defined with a per-class test lifecycle; " +
|
||||
"skipping Dialect checks for this context [" + context.getDisplayName() + "]"
|
||||
);
|
||||
}
|
||||
|
||||
final Dialect dialect = getDialect( context );
|
||||
if ( dialect == null ) {
|
||||
throw new RuntimeException( "#getDialect returned null" );
|
||||
|
@ -135,7 +125,7 @@ public class DialectFilterExtension implements ExecutionCondition {
|
|||
try {
|
||||
final DialectFeatureCheck dialectFeatureCheck = effectiveRequiresDialectFeature.feature()
|
||||
.newInstance();
|
||||
final boolean applicable = dialectFeatureCheck.apply( getDialect( context ) );
|
||||
final boolean applicable = dialectFeatureCheck.apply( dialect );
|
||||
final boolean reverse = effectiveRequiresDialectFeature.reverse();
|
||||
if ( !( applicable ^ reverse ) ) {
|
||||
return ConditionEvaluationResult.disabled(
|
||||
|
@ -156,22 +146,6 @@ public class DialectFilterExtension implements ExecutionCondition {
|
|||
}
|
||||
|
||||
private Dialect getDialect(ExtensionContext context) {
|
||||
final Optional<SessionFactoryScope> sfScope = SessionFactoryScopeExtension.findSessionFactoryScope( context );
|
||||
if ( !sfScope.isPresent() ) {
|
||||
final Optional<EntityManagerFactoryScope> emScope = EntityManagerFactoryScopeExtension.findEntityManagerFactoryScope( context );
|
||||
if ( !emScope.isPresent() ) {
|
||||
final Optional<DialectAccess> dialectAccess = Optional.ofNullable(
|
||||
(DialectAccess) context.getStore( DialectAccess.NAMESPACE )
|
||||
.get( context.getRequiredTestInstance() ) );
|
||||
if ( !dialectAccess.isPresent() ) {
|
||||
throw new RuntimeException(
|
||||
"Could not locate any DialectAccess implementation in JUnit ExtensionContext" );
|
||||
}
|
||||
return dialectAccess.get().getDialect();
|
||||
}
|
||||
return emScope.get().getDialect();
|
||||
}
|
||||
|
||||
return sfScope.get().getDialect();
|
||||
return DialectContext.getDialect();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ package org.hibernate.testing.junit5;
|
|||
import javax.persistence.EntityManagerFactory;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
||||
/**
|
||||
* Contract for things that expose an EntityManagerFactory
|
||||
|
@ -21,6 +20,6 @@ public interface EntityManagerFactoryAccess extends DialectAccess {
|
|||
|
||||
@Override
|
||||
default Dialect getDialect() {
|
||||
return Dialect.getDialect();
|
||||
return DialectContext.getDialect();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,6 @@ public interface SessionFactoryAccess extends DialectAccess {
|
|||
|
||||
@Override
|
||||
default Dialect getDialect() {
|
||||
return getSessionFactory().getJdbcServices().getDialect();
|
||||
return DialectContext.getDialect();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import javax.persistence.SqlResultSetMapping;
|
|||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.annotations.SqlType;
|
||||
import org.hibernate.annotations.SqlTypeCode;
|
||||
|
||||
/**
|
||||
|
@ -49,7 +50,9 @@ public class EntityOfBasics {
|
|||
}
|
||||
|
||||
private Integer id;
|
||||
private Boolean theBoolean;
|
||||
private Boolean theBoolean = false;
|
||||
private Boolean theNumericBoolean = false;
|
||||
private Boolean theStringBoolean = false;
|
||||
private String theString;
|
||||
private Integer theInteger;
|
||||
private int theInt;
|
||||
|
@ -258,6 +261,24 @@ public class EntityOfBasics {
|
|||
this.theBoolean = theBoolean;
|
||||
}
|
||||
|
||||
@SqlTypeCode( Types.INTEGER )
|
||||
public Boolean isTheNumericBoolean() {
|
||||
return theNumericBoolean;
|
||||
}
|
||||
|
||||
public void setTheNumericBoolean(Boolean theNumericBoolean) {
|
||||
this.theNumericBoolean = theNumericBoolean;
|
||||
}
|
||||
|
||||
@SqlTypeCode( Types.CHAR )
|
||||
public Boolean isTheStringBoolean() {
|
||||
return theStringBoolean;
|
||||
}
|
||||
|
||||
public void setTheStringBoolean(Boolean theStringBoolean) {
|
||||
this.theStringBoolean = theStringBoolean;
|
||||
}
|
||||
|
||||
@Convert( converter = MutableValueConverter.class )
|
||||
public MutableValue getMutableValue() {
|
||||
return mutableValue;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.testing.orm.domain.gambit;
|
||||
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Convert;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
|
@ -25,6 +26,7 @@ public class Shirt {
|
|||
private String data;
|
||||
|
||||
@Enumerated
|
||||
@Column(name = "shirt_size")
|
||||
private Size size;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.hibernate.dialect.FirebirdDialect;
|
|||
import org.hibernate.dialect.GroupBySummarizationRenderingStrategy;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.dialect.HSQLDialect;
|
||||
import org.hibernate.dialect.MariaDBDialect;
|
||||
import org.hibernate.dialect.MaxDBDialect;
|
||||
import org.hibernate.dialect.MimerSQLDialect;
|
||||
import org.hibernate.dialect.MySQLDialect;
|
||||
|
@ -104,7 +105,7 @@ abstract public class DialectFeatureChecks {
|
|||
}
|
||||
}
|
||||
|
||||
public static class SupportSubqueryAsLeftHandSideInPredicate implements DialectFeatureCheck {
|
||||
public static class SupportsSubqueryAsLeftHandSideInPredicate implements DialectFeatureCheck {
|
||||
public boolean apply(Dialect dialect) {
|
||||
return dialect.supportsSubselectAsInPredicateLHS();
|
||||
}
|
||||
|
@ -233,7 +234,7 @@ abstract public class DialectFeatureChecks {
|
|||
|
||||
public static class SupportsPadWithChar implements DialectFeatureCheck {
|
||||
public boolean apply(Dialect dialect) {
|
||||
return !(dialect instanceof DerbyDialect );
|
||||
return !( dialect instanceof DerbyDialect );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,6 +244,17 @@ abstract public class DialectFeatureChecks {
|
|||
}
|
||||
}
|
||||
|
||||
public static class SupportsGroupByGroupingSets implements DialectFeatureCheck {
|
||||
public boolean apply(Dialect dialect) {
|
||||
return dialect.getGroupBySummarizationRenderingStrategy() != GroupBySummarizationRenderingStrategy.NONE
|
||||
&& !( dialect instanceof DerbyDialect )
|
||||
// MariaDB only supports ROLLUP
|
||||
&& !( dialect instanceof MariaDBDialect )
|
||||
// MySQL only supports ROLLUP
|
||||
&& !( dialect instanceof MySQLDialect );
|
||||
}
|
||||
}
|
||||
|
||||
public static class SupportsTimezoneTypes implements DialectFeatureCheck {
|
||||
public boolean apply(Dialect dialect) {
|
||||
return dialect.supportsTimezoneTypes();
|
||||
|
@ -277,6 +289,7 @@ abstract public class DialectFeatureChecks {
|
|||
|| dialect instanceof DB2Dialect
|
||||
|| dialect instanceof FirebirdDialect && dialect.getVersion() >= 300
|
||||
|| dialect instanceof H2Dialect && dialect.getVersion() >= 104198
|
||||
|| dialect instanceof MariaDBDialect && dialect.getVersion() >= 1020
|
||||
|| dialect instanceof MySQLDialect && dialect.getVersion() >= 802
|
||||
|| dialect instanceof OracleDialect
|
||||
|| dialect instanceof PostgreSQLDialect
|
||||
|
@ -291,4 +304,18 @@ abstract public class DialectFeatureChecks {
|
|||
}
|
||||
}
|
||||
|
||||
public static class SupportsCharCodeConversion implements DialectFeatureCheck {
|
||||
public boolean apply(Dialect dialect) {
|
||||
// Derby doesn't support the `ASCII` or `CHR` functions
|
||||
return !( dialect instanceof DerbyDialect );
|
||||
}
|
||||
}
|
||||
|
||||
public static class SupportsReplace implements DialectFeatureCheck {
|
||||
public boolean apply(Dialect dialect) {
|
||||
// Derby doesn't support the `REPLACE` function
|
||||
return !( dialect instanceof DerbyDialect );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,10 +9,9 @@ package org.hibernate.testing.orm.junit;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
|
||||
import org.hibernate.testing.junit5.DialectContext;
|
||||
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
|
||||
import org.junit.jupiter.api.extension.ExecutionCondition;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
|
@ -30,16 +29,6 @@ public class DialectFilterExtension implements ExecutionCondition {
|
|||
|
||||
@Override
|
||||
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
|
||||
if ( !context.getTestInstance().isPresent() ) {
|
||||
assert !context.getTestMethod().isPresent();
|
||||
|
||||
return ConditionEvaluationResult.enabled(
|
||||
"No test-instance was present - " +
|
||||
"likely that test was not defined with a per-class test lifecycle; " +
|
||||
"skipping Dialect checks for this context [" + context.getDisplayName() + "]"
|
||||
);
|
||||
}
|
||||
|
||||
final Dialect dialect = getDialect( context );
|
||||
if ( dialect == null ) {
|
||||
throw new RuntimeException( "#getDialect returned null" );
|
||||
|
@ -109,7 +98,7 @@ public class DialectFilterExtension implements ExecutionCondition {
|
|||
try {
|
||||
final DialectFeatureCheck dialectFeatureCheck = effectiveRequiresDialectFeature.feature()
|
||||
.newInstance();
|
||||
if ( !dialectFeatureCheck.apply( getDialect( context ) ) ) {
|
||||
if ( !dialectFeatureCheck.apply( dialect ) ) {
|
||||
return ConditionEvaluationResult.disabled(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
|
@ -127,11 +116,6 @@ public class DialectFilterExtension implements ExecutionCondition {
|
|||
}
|
||||
|
||||
private Dialect getDialect(ExtensionContext context) {
|
||||
final StandardServiceRegistry serviceRegistry = ServiceRegistryExtension.findServiceRegistry(
|
||||
context.getRequiredTestInstance(),
|
||||
context
|
||||
);
|
||||
|
||||
return serviceRegistry.getService( JdbcServices.class ).getJdbcEnvironment().getDialect();
|
||||
return DialectContext.getDialect();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue