Fix a few test issues, implement tuple emulation, group by support and support configuring criteria value handling mode

This commit is contained in:
Christian Beikov 2020-11-19 15:50:16 +01:00
parent b9e7cc3c93
commit d9446e7c77
87 changed files with 3121 additions and 1112 deletions

View File

@ -277,15 +277,7 @@ mapKeyNavigablePath
// GROUP BY clause // GROUP BY clause
groupByClause groupByClause
: GROUP BY groupingSpecification : GROUP BY expression ( COMMA expression )*
;
groupingSpecification
: groupingValue ( COMMA groupingValue )*
;
groupingValue
: expression collationSpecification?
; ;
@ -312,7 +304,7 @@ orderByFragment
; ;
sortSpecification sortSpecification
: sortExpression collationSpecification? orderingSpecification? nullsPrecedence? : sortExpression orderingSpecification? nullsPrecedence?
; ;
nullsPrecedence nullsPrecedence
@ -320,8 +312,8 @@ nullsPrecedence
; ;
sortExpression sortExpression
: identifier : identifier collationSpecification?
| INTEGER_LITERAL | INTEGER_LITERAL collationSpecification?
| expression | expression
; ;
@ -406,15 +398,15 @@ expression
//highest to lowest precedence //highest to lowest precedence
: LEFT_PAREN expression RIGHT_PAREN # GroupedExpression : LEFT_PAREN expression RIGHT_PAREN # GroupedExpression
| LEFT_PAREN subQuery RIGHT_PAREN # SubQueryExpression | LEFT_PAREN subQuery RIGHT_PAREN # SubQueryExpression
| caseList # CaseExpression | caseList collationSpecification? # CaseExpression
| literal # LiteralExpression | literal collationSpecification? # LiteralExpression
| parameter # ParameterExpression | parameter collationSpecification? # ParameterExpression
| entityTypeReference # EntityTypeExpression | entityTypeReference # EntityTypeExpression
| entityIdReference # EntityIdExpression | entityIdReference collationSpecification? # EntityIdExpression
| entityVersionReference # EntityVersionExpression | entityVersionReference collationSpecification? # EntityVersionExpression
| entityNaturalIdReference # EntityNaturalIdExpression | entityNaturalIdReference collationSpecification? # EntityNaturalIdExpression
| path # PathExpression | path collationSpecification? # PathExpression
| function # FunctionExpression | function collationSpecification? # FunctionExpression
| signOperator expression # UnaryExpression | signOperator expression # UnaryExpression
| expression datetimeField # ToDurationExpression | expression datetimeField # ToDurationExpression
| expression BY datetimeField # FromDurationExpression | expression BY datetimeField # FromDurationExpression
@ -568,7 +560,9 @@ day: INTEGER_LITERAL;
hour: INTEGER_LITERAL; hour: INTEGER_LITERAL;
minute: INTEGER_LITERAL; minute: INTEGER_LITERAL;
second: INTEGER_LITERAL | FLOAT_LITERAL; second: INTEGER_LITERAL | FLOAT_LITERAL;
zoneId: STRING_LITERAL; zoneId
: IDENTIFIER (SLASH IDENTIFIER)?
| STRING_LITERAL;
jdbcTimestampLiteral jdbcTimestampLiteral
: TIMESTAMP_ESCAPE_START (dateTime | genericTemporalLiteralText) RIGHT_BRACE : TIMESTAMP_ESCAPE_START (dateTime | genericTemporalLiteralText) RIGHT_BRACE

View File

@ -572,6 +572,8 @@ public class DB2Dialect extends Dialect {
// Therefore here we overwrite the sql type descriptors to // Therefore here we overwrite the sql type descriptors to
// use the non-N variants which are supported. // use the non-N variants which are supported.
switch ( sqlCode ) { switch ( sqlCode ) {
case Types.BOOLEAN:
return SmallIntTypeDescriptor.INSTANCE;
case Types.NCHAR: case Types.NCHAR:
return CharTypeDescriptor.INSTANCE; return CharTypeDescriptor.INSTANCE;
case Types.NCLOB: case Types.NCLOB:
@ -678,6 +680,11 @@ public class DB2Dialect extends Dialect {
return true; return true;
} }
@Override
public boolean supportsGroupByRollup() {
return true;
}
@Override @Override
public String translateDatetimeFormat(String format) { public String translateDatetimeFormat(String format) {
//DB2 does not need nor support FM //DB2 does not need nor support FM

View File

@ -9,6 +9,7 @@ package org.hibernate.dialect;
import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.boot.TempTableDdlTransactionHandling; import org.hibernate.boot.TempTableDdlTransactionHandling;
import org.hibernate.cfg.Environment; import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CastStrEmulation;
import org.hibernate.dialect.function.CommonFunctionFactory; import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.function.DerbyConcatEmulation; import org.hibernate.dialect.function.DerbyConcatEmulation;
import org.hibernate.dialect.identity.DB2IdentityColumnSupport; import org.hibernate.dialect.identity.DB2IdentityColumnSupport;
@ -27,6 +28,7 @@ import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.query.CastType; import org.hibernate.query.CastType;
import org.hibernate.query.CastTypeKind;
import org.hibernate.query.TemporalUnit; import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction; import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
@ -41,7 +43,9 @@ import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNo
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.sql.DecimalTypeDescriptor; import org.hibernate.type.descriptor.sql.DecimalTypeDescriptor;
import org.hibernate.type.descriptor.sql.SmallIntTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.descriptor.sql.TimestampTypeDescriptor;
import java.sql.DatabaseMetaData; import java.sql.DatabaseMetaData;
import java.sql.SQLException; import java.sql.SQLException;
@ -87,11 +91,14 @@ public class DerbyDialect extends Dialect {
registerColumnType( Types.BIT, 1, "boolean" ); //no bit registerColumnType( Types.BIT, 1, "boolean" ); //no bit
registerColumnType( Types.BIT, "smallint" ); //no bit registerColumnType( Types.BIT, "smallint" ); //no bit
registerColumnType( Types.TINYINT, "smallint" ); //no tinyint registerColumnType( Types.TINYINT, "smallint" ); //no tinyint
registerColumnType( Types.CHAR, "char(1)" );
//HHH-12827: map them both to the same type to //HHH-12827: map them both to the same type to
// avoid problems with schema update // avoid problems with schema update
// registerColumnType( Types.DECIMAL, "decimal($p,$s)" ); // registerColumnType( Types.DECIMAL, "decimal($p,$s)" );
registerColumnType( Types.NUMERIC, "decimal($p,$s)" ); registerColumnType( Types.NUMERIC, "decimal($p,$s)" );
registerColumnType( Types.FLOAT, "float" );
registerColumnType( Types.DOUBLE, "double" );
registerColumnType( Types.BINARY, "varchar($l) for bit data" ); registerColumnType( Types.BINARY, "varchar($l) for bit data" );
registerColumnType( Types.BINARY, 254, "char($l) for bit data" ); registerColumnType( Types.BINARY, 254, "char($l) for bit data" );
@ -165,7 +172,7 @@ public class DerbyDialect extends Dialect {
queryEngine.getSqmFunctionRegistry().register( "concat", new DerbyConcatEmulation() ); queryEngine.getSqmFunctionRegistry().register( "concat", new DerbyConcatEmulation() );
//no way I can see to pad with anything other than spaces //no way I can see to pad with anything other than spaces
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "lpad", "case when length(?1)<?2 then substr(char('',?2)||?1,length(?1)) else ?1 end" ) queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "lpad", "case when length(?1)<?2 then substr(char('',?2)||?1,length(?1)+1) else ?1 end" )
.setInvariantType( StandardBasicTypes.STRING ) .setInvariantType( StandardBasicTypes.STRING )
.setExactArgumentCount( 2 ) .setExactArgumentCount( 2 )
.setArgumentListSignature("(string, length)") .setArgumentListSignature("(string, length)")
@ -252,6 +259,12 @@ public class DerbyDialect extends Dialect {
return "case ?1 when false then 0 when true then 1 end"; return "case ?1 when false then 0 when true then 1 end";
} }
break; break;
case STRING:
// See https://issues.apache.org/jira/browse/DERBY-2072
if ( from.getKind() == CastTypeKind.NUMERIC ) {
return "cast(cast(?1 as char(38)) as ?2)";
}
break;
} }
return super.castPattern(from, to); return super.castPattern(from, to);
} }
@ -440,9 +453,16 @@ public class DerbyDialect extends Dialect {
} }
protected SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) { protected SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) {
return sqlCode == Types.NUMERIC switch ( sqlCode ) {
? DecimalTypeDescriptor.INSTANCE case Types.BOOLEAN:
: super.getSqlTypeDescriptorOverride(sqlCode); return SmallIntTypeDescriptor.INSTANCE;
case Types.NUMERIC:
return DecimalTypeDescriptor.INSTANCE;
case Types.TIMESTAMP_WITH_TIMEZONE:
return TimestampTypeDescriptor.INSTANCE;
default:
return super.getSqlTypeDescriptorOverride(sqlCode);
}
} }
@Override @Override
@ -738,4 +758,9 @@ public class DerbyDialect extends Dialect {
runtimeModelCreationContext.getSessionFactory() runtimeModelCreationContext.getSessionFactory()
); );
} }
@Override
public boolean supportsGroupByRollup() {
return true;
}
} }

View File

@ -73,6 +73,7 @@ import org.hibernate.sql.*;
import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.ANSICaseExpressionWalker; import org.hibernate.sql.ast.spi.ANSICaseExpressionWalker;
import org.hibernate.sql.ast.spi.CaseExpressionWalker; import org.hibernate.sql.ast.spi.CaseExpressionWalker;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory; import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl; import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl; import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
@ -2590,6 +2591,22 @@ public abstract class Dialect implements ConversionContext {
return supportsRowValueConstructorSyntax(); return supportsRowValueConstructorSyntax();
} }
/**
* Is this dialect known to support what ANSI-SQL terms "row value
* constructor" syntax; sometimes called tuple syntax with quantified predicates.
* <p/>
* Basically, does it support syntax like
* "... where (FIRST_NAME, LAST_NAME) = ALL (select ...) ...".
*
* @return True if this SQL dialect is known to support "row value
* constructor" syntax with quantified predicates; false otherwise.
* @since 6.0
*/
public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
// return false here, as most databases do not properly support this construct...
return false;
}
/** /**
* If the dialect supports {@link #supportsRowValueConstructorSyntax() row values}, * If the dialect supports {@link #supportsRowValueConstructorSyntax() row values},
* does it offer such support in IN lists as well? * does it offer such support in IN lists as well?
@ -2604,6 +2621,17 @@ public abstract class Dialect implements ConversionContext {
return false; return false;
} }
/**
* Is this dialect known to support ROLLUP functions in the GROUP BY clause.
*
* @return True if this SQL dialect supports ROLLUP functions; false otherwise.
* @since 6.0
*/
public boolean supportsGroupByRollup() {
// return false here, as most databases do not properly support this construct...
return false;
}
/** /**
* Should LOBs (both BLOB and CLOB) be bound using stream operations (i.e. * Should LOBs (both BLOB and CLOB) be bound using stream operations (i.e.
* {@link java.sql.PreparedStatement#setBinaryStream}). * {@link java.sql.PreparedStatement#setBinaryStream}).
@ -3164,6 +3192,14 @@ public abstract class Dialect implements ConversionContext {
return String.format( "\'%s\'", escapeLiteral( literal ) ); return String.format( "\'%s\'", escapeLiteral( literal ) );
} }
/**
* Appends the collate clause for the given collation name to the SQL appender.
*/
public void appendCollate(SqlAppender sqlAppender, String collationName) {
sqlAppender.appendSql( " collate " );
sqlAppender.appendSql( collationName );
}
/** /**
* Check whether the JDBC {@link java.sql.Connection} supports creating LOBs via {@link Connection#createBlob()}, * Check whether the JDBC {@link java.sql.Connection} supports creating LOBs via {@link Connection#createBlob()},
* {@link Connection#createNClob()} or {@link Connection#createClob()}. * {@link Connection#createNClob()} or {@link Connection#createClob()}.
@ -3575,55 +3611,62 @@ public abstract class Dialect implements ConversionContext {
return wrapAsJdbcTimeLiteral( time ); return wrapAsJdbcTimeLiteral( time );
} }
public String formatDateTimeLiteral(TemporalAccessor temporalAccessor, TemporalType precision) { public String formatDateTimeLiteral(
TemporalAccessor temporalAccessor,
TemporalType precision,
TimeZone jdbcTimeZone) {
switch ( precision ) { switch ( precision ) {
case DATE: case DATE:
return wrapDateLiteral( formatAsDate( temporalAccessor ) ); return wrapDateLiteral( formatAsDate( temporalAccessor ) );
case TIME: case TIME:
return wrapTimeLiteral( formatAsTime(temporalAccessor) ); return wrapTimeLiteral( formatAsTime( temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone ) );
case TIMESTAMP: case TIMESTAMP:
return wrapTimestampLiteral( formatAsTimestamp(temporalAccessor) ); return wrapTimestampLiteral( formatAsTimestamp( temporalAccessor, jdbcTimeZone ) );
default: default:
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
} }
protected String formatAsTimestamp(TemporalAccessor temporalAccessor) { protected String formatAsTimestamp(TemporalAccessor temporalAccessor, TimeZone jdbcTimeZone) {
return formatAsTimestampWithMicros(temporalAccessor); return formatAsTimestampWithMicros( temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
} }
public String formatDateTimeLiteral(Date date, TemporalType precision) { public String formatDateTimeLiteral(Date date, TemporalType precision, TimeZone jdbcTimeZone) {
switch ( precision ) { switch ( precision ) {
case DATE: case DATE:
return wrapDateLiteral( formatAsDate( date ) ); return wrapDateLiteral( formatAsDate( date ) );
case TIME: case TIME:
return wrapTimeLiteral( formatAsTime( date ) ); return wrapTimeLiteral( formatAsTime( date ) );
case TIMESTAMP: case TIMESTAMP:
return wrapTimestampLiteral( formatAsTimestamp(date) ); return wrapTimestampLiteral( formatAsTimestamp( date, jdbcTimeZone) );
default: default:
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
} }
protected String formatAsTimestamp(Date date) { protected String formatAsTimestamp(Date date, TimeZone jdbcTimeZone) {
return formatAsTimestampWithMicros(date); return formatAsTimestampWithMicros( date, jdbcTimeZone );
} }
public String formatDateTimeLiteral(Calendar calendar, TemporalType precision) { public String formatDateTimeLiteral(Calendar calendar, TemporalType precision, TimeZone jdbcTimeZone) {
switch ( precision ) { switch ( precision ) {
case DATE: case DATE:
return wrapDateLiteral( formatAsDate( calendar ) ); return wrapDateLiteral( formatAsDate( calendar ) );
case TIME: case TIME:
return wrapTimeLiteral( formatAsTime( calendar ) ); return wrapTimeLiteral( formatAsTime( calendar ) );
case TIMESTAMP: case TIMESTAMP:
return wrapTimestampLiteral( formatAsTimestamp(calendar) ); return wrapTimestampLiteral( formatAsTimestamp( calendar, jdbcTimeZone ) );
default: default:
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
} }
protected String formatAsTimestamp(Calendar calendar) { protected String formatAsTimestamp(Calendar calendar, TimeZone jdbcTimeZone) {
return formatAsTimestampWithMicros(calendar); return formatAsTimestampWithMicros( calendar, jdbcTimeZone );
}
public boolean supportsTemporalLiteralOffset() {
return false;
} }
// deprecated limit/offset support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // deprecated limit/offset support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -22,6 +22,7 @@ import org.hibernate.engine.jdbc.Size;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo; import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.LockAcquisitionException;
import org.hibernate.exception.LockTimeoutException; import org.hibernate.exception.LockTimeoutException;
@ -49,6 +50,7 @@ import java.sql.Types;
import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAccessor;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.TimeZone;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -491,18 +493,18 @@ public class FirebirdDialect extends Dialect {
} }
@Override @Override
protected String formatAsTimestamp(Date date) { protected String formatAsTimestamp(Date date, TimeZone jdbcTimeZone) {
return formatAsTimestampWithMillis(date); return formatAsTimestampWithMillis( date, jdbcTimeZone );
} }
@Override @Override
protected String formatAsTimestamp(Calendar calendar) { protected String formatAsTimestamp(Calendar calendar, TimeZone jdbcTimeZone) {
return formatAsTimestampWithMillis(calendar); return formatAsTimestampWithMillis( calendar, jdbcTimeZone );
} }
@Override @Override
protected String formatAsTimestamp(TemporalAccessor temporalAccessor) { protected String formatAsTimestamp(TemporalAccessor temporalAccessor, TimeZone jdbcTimeZone) {
return formatAsTimestampWithMillis(temporalAccessor); return formatAsTimestampWithMillis( temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
} }
@Override @Override

View File

@ -196,6 +196,11 @@ public class H2Dialect extends Dialect {
return "datediff(?1, ?2, ?3)"; return "datediff(?1, ?2, ?3)";
} }
@Override
public boolean supportsTemporalLiteralOffset() {
return true;
}
@Override @Override
public String toBooleanValueString(boolean bool) { public String toBooleanValueString(boolean bool) {
return String.valueOf( bool ); return String.valueOf( bool );

View File

@ -918,4 +918,9 @@ public class MySQLDialect extends Dialect {
boolean supportsAliasLocks() { boolean supportsAliasLocks() {
return getVersion() >= 800; return getVersion() >= 800;
} }
@Override
public boolean supportsGroupByRollup() {
return true;
}
} }

View File

@ -794,6 +794,11 @@ public class OracleDialect extends Dialect {
return false; return false;
} }
@Override
public boolean supportsGroupByRollup() {
return true;
}
@Override @Override
public int getInExpressionCountLimit() { public int getInExpressionCountLimit() {
return PARAM_LIST_SIZE_LIMIT; return PARAM_LIST_SIZE_LIMIT;

View File

@ -605,6 +605,11 @@ public class PostgreSQLDialect extends Dialect {
return true; return true;
} }
@Override
public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return true;
}
@Override @Override
public CallableStatementSupport getCallableStatementSupport() { public CallableStatementSupport getCallableStatementSupport() {
return PostgresCallableStatementSupport.INSTANCE; return PostgresCallableStatementSupport.INSTANCE;
@ -765,6 +770,11 @@ public class PostgreSQLDialect extends Dialect {
return getVersion() >= 950; return getVersion() >= 950;
} }
@Override
public boolean supportsGroupByRollup() {
return getVersion() >= 950;
}
@Override @Override
public void augmentRecognizedTableTypes(List<String> tableTypesList) { public void augmentRecognizedTableTypes(List<String> tableTypesList) {
super.augmentRecognizedTableTypes( tableTypesList ); super.augmentRecognizedTableTypes( tableTypesList );
@ -832,7 +842,7 @@ public class PostgreSQLDialect extends Dialect {
X value, X value,
int index, int index,
WrapperOptions wrapperOptions) throws SQLException { WrapperOptions wrapperOptions) throws SQLException {
st.setObject( index, javaTypeDescriptor.unwrap( value, UUID.class, wrapperOptions.getSession() ), Types.OTHER ); st.setObject( index, javaTypeDescriptor.unwrap( value, UUID.class, wrapperOptions ), Types.OTHER );
} }
@Override @Override
@ -841,7 +851,7 @@ public class PostgreSQLDialect extends Dialect {
X value, X value,
String name, String name,
WrapperOptions wrapperOptions) throws SQLException { WrapperOptions wrapperOptions) throws SQLException {
st.setObject( name, javaTypeDescriptor.unwrap( value, UUID.class, wrapperOptions.getSession() ), Types.OTHER ); st.setObject( name, javaTypeDescriptor.unwrap( value, UUID.class, wrapperOptions ), Types.OTHER );
} }
}; };
} }
@ -851,17 +861,17 @@ public class PostgreSQLDialect extends Dialect {
return new BasicExtractor<X>( javaTypeDescriptor, this ) { return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override @Override
protected X doExtract(ResultSet rs, int position, WrapperOptions wrapperOptions) throws SQLException { protected X doExtract(ResultSet rs, int position, WrapperOptions wrapperOptions) throws SQLException {
return javaTypeDescriptor.wrap( rs.getObject( position ), wrapperOptions.getSession() ); return javaTypeDescriptor.wrap( rs.getObject( position ), wrapperOptions );
} }
@Override @Override
protected X doExtract(CallableStatement statement, int position, WrapperOptions wrapperOptions) throws SQLException { protected X doExtract(CallableStatement statement, int position, WrapperOptions wrapperOptions) throws SQLException {
return javaTypeDescriptor.wrap( statement.getObject( position ), wrapperOptions.getSession() ); return javaTypeDescriptor.wrap( statement.getObject( position ), wrapperOptions );
} }
@Override @Override
protected X doExtract(CallableStatement statement, String name, WrapperOptions wrapperOptions) throws SQLException { protected X doExtract(CallableStatement statement, String name, WrapperOptions wrapperOptions) throws SQLException {
return javaTypeDescriptor.wrap( statement.getObject( name ), wrapperOptions.getSession() ); return javaTypeDescriptor.wrap( statement.getObject( name ), wrapperOptions );
} }
}; };
} }

View File

@ -353,6 +353,11 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
return getVersion() >= 9; return getVersion() >= 9;
} }
@Override
public boolean supportsGroupByRollup() {
return true;
}
@Override @Override
public SequenceSupport getSequenceSupport() { public SequenceSupport getSequenceSupport() {
return getVersion() < 11 return getVersion() < 11

View File

@ -200,7 +200,7 @@ public final class FastSessionServices {
return elr.getEventListenerGroup( type ); return elr.getEventListenerGroup( type );
} }
SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) { public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
if ( !sqlTypeDescriptor.canBeRemapped() ) { if ( !sqlTypeDescriptor.canBeRemapped() ) {
return sqlTypeDescriptor; return sqlTypeDescriptor;
} }
@ -288,6 +288,10 @@ public final class FastSessionServices {
return defaultJdbcObservers; return defaultJdbcObservers;
} }
public boolean useStreamForLobBinding() {
return useStreamForLobBinding;
}
public void firePostLoadEvent(final PostLoadEvent postLoadEvent) { public void firePostLoadEvent(final PostLoadEvent postLoadEvent) {
eventListenerGroup_POST_LOAD.fireEventOnEachListener( postLoadEvent, PostLoadEventListener::onPostLoad ); eventListenerGroup_POST_LOAD.fireEventOnEachListener( postLoadEvent, PostLoadEventListener::onPostLoad );
} }

View File

@ -221,7 +221,7 @@ public class SessionImpl
//There might be custom properties for this session that affect the LockOptions state //There might be custom properties for this session that affect the LockOptions state
LockOptionsHelper.applyPropertiesToLockOptions( this.properties, this::getLockOptionsForWrite ); LockOptionsHelper.applyPropertiesToLockOptions( this.properties, this::getLockOptionsForWrite );
} }
getSession().setCacheMode( fastSessionServices.initialSessionCacheMode ); setCacheMode( fastSessionServices.initialSessionCacheMode );
// NOTE : pulse() already handles auto-join-ability correctly // NOTE : pulse() already handles auto-join-ability correctly
getTransactionCoordinator().pulse(); getTransactionCoordinator().pulse();
@ -235,7 +235,7 @@ public class SessionImpl
else { else {
initialMode = ConfigurationHelper.getFlushMode( getSessionProperty( AvailableSettings.FLUSH_MODE ), FlushMode.AUTO ); initialMode = ConfigurationHelper.getFlushMode( getSessionProperty( AvailableSettings.FLUSH_MODE ), FlushMode.AUTO );
} }
getSession().setHibernateFlushMode( initialMode ); setHibernateFlushMode( initialMode );
} }
if ( log.isTraceEnabled() ) { if ( log.isTraceEnabled() ) {
@ -2872,7 +2872,7 @@ public class SessionImpl
LockOptionsHelper.applyPropertiesToLockOptions( properties, this::getLockOptionsForWrite ); LockOptionsHelper.applyPropertiesToLockOptions( properties, this::getLockOptionsForWrite );
} }
else if ( JPA_SHARED_CACHE_RETRIEVE_MODE.equals( propertyName ) || JPA_SHARED_CACHE_STORE_MODE.equals( propertyName ) ) { else if ( JPA_SHARED_CACHE_RETRIEVE_MODE.equals( propertyName ) || JPA_SHARED_CACHE_STORE_MODE.equals( propertyName ) ) {
getSession().setCacheMode( setCacheMode(
CacheModeHelper.interpretCacheMode( CacheModeHelper.interpretCacheMode(
determineCacheStoreMode( properties ), determineCacheStoreMode( properties ),
determineCacheRetrieveMode( properties ) determineCacheRetrieveMode( properties )

View File

@ -37,7 +37,6 @@ import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcSelect; import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry; import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl; import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
import org.hibernate.type.SerializableType;
/** /**
* Batch support for natural-id multi loading * Batch support for natural-id multi loading
@ -139,10 +138,17 @@ public class MultiNaturalIdLoadingBatcher {
if ( needsExecution ) { if ( needsExecution ) {
while ( jdbcParamItr.hasNext() ) { while ( jdbcParamItr.hasNext() ) {
final JdbcParameterBindings jdbcParamBindingsRef = jdbcParamBindings;
final Iterator<JdbcParameter> jdbcParamItrRef = jdbcParamItr;
// pad the remaining parameters with null // pad the remaining parameters with null
jdbcParamBindings.addBinding( entityDescriptor.getNaturalIdMapping().visitJdbcValues(
jdbcParamItr.next(), null,
new JdbcParameterBindingImpl( SerializableType.INSTANCE, null ) Clause.IRRELEVANT,
(jdbcValue, jdbcMapping) -> jdbcParamBindingsRef.addBinding(
jdbcParamItrRef.next(),
new JdbcParameterBindingImpl( jdbcMapping, jdbcValue )
),
session
); );
} }
final List<E> batchResults = performLoad( jdbcParamBindings, session ); final List<E> batchResults = performLoad( jdbcParamBindings, session );

View File

@ -241,7 +241,7 @@ public abstract class AbstractCompositeIdentifierMapping
} }
@Override @Override
public Expression toSqlExpression( public SqlTuple toSqlExpression(
TableGroup tableGroup, TableGroup tableGroup,
Clause clause, Clause clause,
SqmToSqlAstConverter walker, SqmToSqlAstConverter walker,

View File

@ -13,6 +13,7 @@ import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.sql.ast.Clause; import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer; import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.Fetchable;
@ -54,7 +55,7 @@ public interface EmbeddableValuedModelPart extends ModelPart, Fetchable, Fetchab
return null; return null;
} }
Expression toSqlExpression( SqlTuple toSqlExpression(
TableGroup tableGroup, TableGroup tableGroup,
Clause clause, Clause clause,
SqmToSqlAstConverter walker, SqmToSqlAstConverter walker,

View File

@ -27,36 +27,7 @@ public class MappingModelHelper {
SessionFactoryImplementor sessionFactory) { SessionFactoryImplementor sessionFactory) {
final int jdbcTypeCount = modelPart.getJdbcTypeCount( sessionFactory.getTypeConfiguration() ); final int jdbcTypeCount = modelPart.getJdbcTypeCount( sessionFactory.getTypeConfiguration() );
if ( jdbcTypeCount == 1 ) { if ( modelPart instanceof EmbeddableValuedModelPart ) {
assert modelPart instanceof BasicValuedModelPart;
final BasicValuedModelPart basicPart = (BasicValuedModelPart) modelPart;
if ( sqlExpressionResolver == null ) {
return new ColumnReference(
basicPart.getContainingTableExpression(),
basicPart.getMappedColumnExpression(),
basicPart.isMappedColumnExpressionFormula(),
basicPart.getCustomReadExpression(),
basicPart.getCustomWriteExpression(),
basicPart.getJdbcMapping(),
sessionFactory
);
}
else {
return sqlExpressionResolver.resolveSqlExpression(
createColumnReferenceKey( basicPart.getContainingTableExpression(), basicPart.getMappedColumnExpression() ),
sqlAstProcessingState -> new ColumnReference(
basicPart.getContainingTableExpression(),
basicPart.getMappedColumnExpression(),
basicPart.isMappedColumnExpressionFormula(),
basicPart.getCustomReadExpression(),
basicPart.getCustomWriteExpression(),
basicPart.getJdbcMapping(),
sessionFactory
)
);
}
}
else {
final List<ColumnReference> columnReferences = new ArrayList<>( jdbcTypeCount ); final List<ColumnReference> columnReferences = new ArrayList<>( jdbcTypeCount );
modelPart.visitColumns( modelPart.visitColumns(
(table, column, isFormula, readFragment, writeFragment, jdbcMapping) -> { (table, column, isFormula, readFragment, writeFragment, jdbcMapping) -> {
@ -91,6 +62,35 @@ public class MappingModelHelper {
); );
return new SqlTuple( columnReferences, modelPart ); return new SqlTuple( columnReferences, modelPart );
} }
else {
assert modelPart instanceof BasicValuedModelPart;
final BasicValuedModelPart basicPart = (BasicValuedModelPart) modelPart;
if ( sqlExpressionResolver == null ) {
return new ColumnReference(
basicPart.getContainingTableExpression(),
basicPart.getMappedColumnExpression(),
basicPart.isMappedColumnExpressionFormula(),
basicPart.getCustomReadExpression(),
basicPart.getCustomWriteExpression(),
basicPart.getJdbcMapping(),
sessionFactory
);
}
else {
return sqlExpressionResolver.resolveSqlExpression(
createColumnReferenceKey( basicPart.getContainingTableExpression(), basicPart.getMappedColumnExpression() ),
sqlAstProcessingState -> new ColumnReference(
basicPart.getContainingTableExpression(),
basicPart.getMappedColumnExpression(),
basicPart.isMappedColumnExpressionFormula(),
basicPart.getCustomReadExpression(),
basicPart.getCustomWriteExpression(),
basicPart.getJdbcMapping(),
sessionFactory
)
);
}
}
} }
private MappingModelHelper() { private MappingModelHelper() {

View File

@ -223,7 +223,7 @@ public class EmbeddedAttributeMapping
} }
@Override @Override
public Expression toSqlExpression( public SqlTuple toSqlExpression(
TableGroup tableGroup, TableGroup tableGroup,
Clause clause, Clause clause,
SqmToSqlAstConverter walker, SqmToSqlAstConverter walker,

View File

@ -210,7 +210,7 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
} }
@Override @Override
public Expression toSqlExpression( public SqlTuple toSqlExpression(
TableGroup tableGroup, TableGroup tableGroup,
Clause clause, Clause clause,
SqmToSqlAstConverter walker, SqmToSqlAstConverter walker,

View File

@ -33,13 +33,23 @@ import java.time.*;
* @author Gavin King * @author Gavin King
*/ */
public enum CastType { public enum CastType {
STRING, STRING(CastTypeKind.TEXT),
BOOLEAN, BOOLEAN(CastTypeKind.BOOLEAN),
INTEGER, LONG, FLOAT, DOUBLE, FIXED, INTEGER(CastTypeKind.NUMERIC), LONG(CastTypeKind.NUMERIC), FLOAT(CastTypeKind.NUMERIC), DOUBLE(CastTypeKind.NUMERIC), FIXED(CastTypeKind.NUMERIC),
DATE, TIME, TIMESTAMP, DATE(CastTypeKind.TEMPORAL), TIME(CastTypeKind.TEMPORAL), TIMESTAMP(CastTypeKind.TEMPORAL),
OFFSET_TIMESTAMP, ZONE_TIMESTAMP, OFFSET_TIMESTAMP(CastTypeKind.TEMPORAL), ZONE_TIMESTAMP(CastTypeKind.TEMPORAL),
NULL, NULL(null),
OTHER; OTHER(null);
private final CastTypeKind kind;
CastType(CastTypeKind kind) {
this.kind = kind;
}
public CastTypeKind getKind() {
return kind;
}
public static CastType from(Class javaClass) { public static CastType from(Class javaClass) {
if (String.class.equals(javaClass)) { if (String.class.equals(javaClass)) {

View File

@ -0,0 +1,21 @@
/*
* 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
}

View File

@ -12,10 +12,16 @@ package org.hibernate.query;
*/ */
public enum ComparisonOperator { public enum ComparisonOperator {
EQUAL { EQUAL {
@Override
public ComparisonOperator negated() { public ComparisonOperator negated() {
return NOT_EQUAL; return NOT_EQUAL;
} }
@Override
public ComparisonOperator invert() {
return EQUAL;
}
@Override @Override
public String sqlText() { public String sqlText() {
return "="; return "=";
@ -23,10 +29,16 @@ public enum ComparisonOperator {
}, },
NOT_EQUAL { NOT_EQUAL {
@Override
public ComparisonOperator negated() { public ComparisonOperator negated() {
return EQUAL; return EQUAL;
} }
@Override
public ComparisonOperator invert() {
return NOT_EQUAL;
}
@Override @Override
public String sqlText() { public String sqlText() {
return "!="; return "!=";
@ -34,10 +46,16 @@ public enum ComparisonOperator {
}, },
LESS_THAN { LESS_THAN {
@Override
public ComparisonOperator negated() { public ComparisonOperator negated() {
return GREATER_THAN_OR_EQUAL; return GREATER_THAN_OR_EQUAL;
} }
@Override
public ComparisonOperator invert() {
return GREATER_THAN;
}
@Override @Override
public String sqlText() { public String sqlText() {
return "<"; return "<";
@ -45,10 +63,16 @@ public enum ComparisonOperator {
}, },
LESS_THAN_OR_EQUAL { LESS_THAN_OR_EQUAL {
@Override
public ComparisonOperator negated() { public ComparisonOperator negated() {
return GREATER_THAN; return GREATER_THAN;
} }
@Override
public ComparisonOperator invert() {
return GREATER_THAN_OR_EQUAL;
}
@Override @Override
public String sqlText() { public String sqlText() {
return "<="; return "<=";
@ -56,10 +80,16 @@ public enum ComparisonOperator {
}, },
GREATER_THAN { GREATER_THAN {
@Override
public ComparisonOperator negated() { public ComparisonOperator negated() {
return LESS_THAN_OR_EQUAL; return LESS_THAN_OR_EQUAL;
} }
@Override
public ComparisonOperator invert() {
return LESS_THAN;
}
@Override @Override
public String sqlText() { public String sqlText() {
return ">"; return ">";
@ -67,10 +97,16 @@ public enum ComparisonOperator {
}, },
GREATER_THAN_OR_EQUAL { GREATER_THAN_OR_EQUAL {
@Override
public ComparisonOperator negated() { public ComparisonOperator negated() {
return LESS_THAN; return LESS_THAN;
} }
@Override
public ComparisonOperator invert() {
return LESS_THAN_OR_EQUAL;
}
@Override @Override
public String sqlText() { public String sqlText() {
return ">="; return ">=";
@ -78,5 +114,6 @@ public enum ComparisonOperator {
}; };
public abstract ComparisonOperator negated(); public abstract ComparisonOperator negated();
public abstract ComparisonOperator invert();
public abstract String sqlText(); public abstract String sqlText();
} }

View File

@ -32,6 +32,7 @@ import javax.persistence.criteria.Subquery;
import org.hibernate.NullPrecedence; import org.hibernate.NullPrecedence;
import org.hibernate.SortOrder; import org.hibernate.SortOrder;
import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
/** /**
* Hibernate extensions to the JPA CriteriaBuilder. * Hibernate extensions to the JPA CriteriaBuilder.
@ -330,6 +331,8 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
<K, L extends List<?>> JpaExpression<Set<K>> indexes(L list); <K, L extends List<?>> JpaExpression<Set<K>> indexes(L list);
<T> SqmExpression<T> value(T value);
<V, C extends Collection<V>> JpaExpression<Collection<V>> values(C collection); <V, C extends Collection<V>> JpaExpression<Collection<V>> values(C collection);
@Override @Override

View File

@ -94,5 +94,5 @@ public interface JpaQueryStructure<T> extends JpaCriteriaNode {
<X> JpaExpression<X> getOffset(); <X> JpaExpression<X> getOffset();
JpaQueryStructure<T> setOffset(JpaExpression offset); JpaQueryStructure<T> setOffset(JpaExpression<?> offset);
} }

View File

@ -6,7 +6,9 @@
*/ */
package org.hibernate.query.hql.internal; package org.hibernate.query.hql.internal;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.NotYetImplementedFor6Exception;
@ -58,8 +60,6 @@ import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation; import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiationArgument; import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiationArgument;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiationTarget; import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiationTarget;
import org.hibernate.query.sqm.tree.select.SqmGroupByClause;
import org.hibernate.query.sqm.tree.select.SqmHavingClause;
import org.hibernate.query.sqm.tree.select.SqmOrderByClause; import org.hibernate.query.sqm.tree.select.SqmOrderByClause;
import org.hibernate.query.sqm.tree.select.SqmQuerySpec; import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
import org.hibernate.query.sqm.tree.select.SqmSelectClause; import org.hibernate.query.sqm.tree.select.SqmSelectClause;
@ -188,7 +188,8 @@ public class QuerySplitter {
sqmQuerySpec.setFromClause( visitFromClause( querySpec.getFromClause() ) ); sqmQuerySpec.setFromClause( visitFromClause( querySpec.getFromClause() ) );
sqmQuerySpec.setSelectClause( visitSelectClause( querySpec.getSelectClause() ) ); sqmQuerySpec.setSelectClause( visitSelectClause( querySpec.getSelectClause() ) );
sqmQuerySpec.setWhereClause( visitWhereClause( querySpec.getWhereClause() ) ); sqmQuerySpec.setWhereClause( visitWhereClause( querySpec.getWhereClause() ) );
sqmQuerySpec.setGroupByClause( visitGroupByClause( querySpec.getGroupByClause() ) ); sqmQuerySpec.setGroupByClauseExpressions( visitGroupByClause( querySpec.getGroupByClauseExpressions() ) );
sqmQuerySpec.setHavingClausePredicate( visitHavingClause( querySpec.getHavingClausePredicate() ) );
sqmQuerySpec.setOrderByClause( visitOrderByClause( querySpec.getOrderByClause() ) ); sqmQuerySpec.setOrderByClause( visitOrderByClause( querySpec.getOrderByClause() ) );
if ( querySpec.getLimitExpression() != null ) { if ( querySpec.getLimitExpression() != null ) {
sqmQuerySpec.setLimitExpression( (SqmExpression) querySpec.getLimitExpression().accept( this ) ); sqmQuerySpec.setLimitExpression( (SqmExpression) querySpec.getLimitExpression().accept( this ) );
@ -218,33 +219,23 @@ public class QuerySplitter {
} }
@Override @Override
public SqmGroupByClause visitGroupByClause(SqmGroupByClause clause) { public List<SqmExpression<?>> visitGroupByClause(List<SqmExpression<?>> groupByClauseExpressions) {
if ( clause == null ) { if ( groupByClauseExpressions.isEmpty() ) {
return null; return groupByClauseExpressions;
} }
final SqmGroupByClause result = new SqmGroupByClause(); List<SqmExpression<?>> expressions = new ArrayList<>( groupByClauseExpressions.size() );
clause.visitGroupings( for ( SqmExpression<?> groupByClauseExpression : groupByClauseExpressions ) {
grouping -> result.addGrouping( expressions.add( (SqmExpression<?>) groupByClauseExpression.accept( this ) );
(SqmExpression) grouping.getExpression().accept( this ), }
grouping.getCollation() return expressions;
)
);
return result;
} }
@Override @Override
public SqmGroupByClause.SqmGrouping visitGrouping(SqmGroupByClause.SqmGrouping grouping) { public SqmPredicate visitHavingClause(SqmPredicate sqmPredicate) {
throw new UnsupportedOperationException(); if ( sqmPredicate == null ) {
}
@Override
public SqmHavingClause visitHavingClause(SqmHavingClause clause) {
if ( clause == null || clause.getPredicate() == null ) {
return null; return null;
} }
return new SqmHavingClause( return (SqmPredicate) sqmPredicate.accept( this );
(SqmPredicate) clause.getPredicate().accept( this )
);
} }
@Override @Override
@ -598,7 +589,6 @@ public class QuerySplitter {
public SqmSortSpecification visitSortSpecification(SqmSortSpecification sortSpecification) { public SqmSortSpecification visitSortSpecification(SqmSortSpecification sortSpecification) {
return new SqmSortSpecification( return new SqmSortSpecification(
(SqmExpression) sortSpecification.getSortExpression().accept( this ), (SqmExpression) sortSpecification.getSortExpression().accept( this ),
sortSpecification.getCollation(),
sortSpecification.getSortOrder(), sortSpecification.getSortOrder(),
sortSpecification.getNullPrecedence() sortSpecification.getNullPrecedence()
); );
@ -638,7 +628,7 @@ public class QuerySplitter {
} }
@Override @Override
public SqmLiteral visitLiteral(SqmLiteral literal) { public SqmLiteral visitLiteral(SqmLiteral<?> literal) {
return new SqmLiteral( return new SqmLiteral(
literal.getLiteralValue(), literal.getLiteralValue(),
literal.getNodeType(), literal.getNodeType(),

View File

@ -6,23 +6,23 @@
*/ */
package org.hibernate.query.internal; package org.hibernate.query.internal;
import java.util.Arrays;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import org.hibernate.Incubating; import org.hibernate.Incubating;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.QueryException; import org.hibernate.QueryException;
import org.hibernate.QueryParameterException; import org.hibernate.QueryParameterException;
import org.hibernate.cache.spi.QueryKey; import org.hibernate.cache.spi.QueryKey;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.query.QueryParameter; import org.hibernate.query.QueryParameter;
import org.hibernate.query.spi.ParameterMetadataImplementor; import org.hibernate.query.spi.ParameterMetadataImplementor;
import org.hibernate.query.spi.QueryParameterBinding; import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.QueryParameterBindings; import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.spi.QueryParameterImplementor; import org.hibernate.query.spi.QueryParameterImplementor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/** /**
* Manages the group of QueryParameterBinding for a particular query. * Manages the group of QueryParameterBinding for a particular query.
@ -179,21 +179,50 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
@Override @Override
public QueryKey.ParameterBindingsMemento generateQueryKeyMemento() { public QueryKey.ParameterBindingsMemento generateQueryKeyMemento() {
// todo (6.0) : need to decide how to handle final int size = parameterBindingMap.size();
if ( parameterMetadata.getParameterCount() == 0 && CollectionHelper.isEmpty( parameterBindingMap ) ) { final Object[] values = new Object[size];
return new QueryKey.ParameterBindingsMemento() { int i = 0;
int hashCode = 0;
for ( QueryParameterBinding binding : parameterBindingMap.values() ) {
JavaTypeDescriptor javaTypeDescriptor = binding.getBindType().getExpressableJavaTypeDescriptor();
final Object value = javaTypeDescriptor.getMutabilityPlan().deepCopy( binding.getBindValue() );
hashCode = 31 * hashCode + javaTypeDescriptor.extractHashCode( value );
values[i] = value;
}
return new ParameterBindingsMementoImpl( values, hashCode);
}
private static class ParameterBindingsMementoImpl implements QueryKey.ParameterBindingsMemento {
private final Object[] values;
private final int hashCode;
private ParameterBindingsMementoImpl(Object[] values, int hashCode) {
this.values = values;
this.hashCode = hashCode;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
ParameterBindingsMementoImpl queryKey = (ParameterBindingsMementoImpl) o;
if ( hashCode != queryKey.hashCode ) {
return false;
}
// Probably incorrect - comparing Object[] arrays with Arrays.equals
return Arrays.equals( values, queryKey.values );
}
@Override @Override
public int hashCode() { public int hashCode() {
return QueryParameterBindingsImpl.class.hashCode(); return hashCode;
} }
@Override
public boolean equals(Object obj) {
return obj instanceof QueryKey.ParameterBindingsMemento;
}
};
}
throw new NotYetImplementedFor6Exception( getClass() );
} }
} }

View File

@ -60,6 +60,11 @@ public class SqlSelectionImpl implements SqlSelection, Expression, SqlExpression
return valuesArrayPosition; return valuesArrayPosition;
} }
@Override
public Expression getExpression() {
return this;
}
@Override @Override
public MappingModelExpressable getExpressionType() { public MappingModelExpressable getExpressionType() {
return valueMapping; return valueMapping;

View File

@ -10,6 +10,7 @@ import org.hibernate.HibernateException;
import org.hibernate.Incubating; import org.hibernate.Incubating;
import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.BootstrapContext;
import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.config.spi.ConfigurationService;
@ -19,6 +20,7 @@ import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.metamodel.model.domain.JpaMetamodel; import org.hibernate.metamodel.model.domain.JpaMetamodel;
import org.hibernate.query.QueryLogging; import org.hibernate.query.QueryLogging;
import org.hibernate.query.criteria.LiteralHandlingMode;
import org.hibernate.query.hql.HqlTranslator; import org.hibernate.query.hql.HqlTranslator;
import org.hibernate.query.hql.internal.StandardHqlTranslator; import org.hibernate.query.hql.internal.StandardHqlTranslator;
import org.hibernate.query.hql.spi.SqmCreationOptions; import org.hibernate.query.hql.spi.SqmCreationOptions;
@ -68,6 +70,7 @@ public class QueryEngine {
return new QueryEngine( return new QueryEngine(
() -> sessionFactory.getRuntimeMetamodels().getJpaMetamodel(), () -> sessionFactory.getRuntimeMetamodels().getJpaMetamodel(),
sessionFactory.getSessionFactoryOptions().getCriteriaLiteralHandlingMode(),
metadata.buildNamedQueryRepository( sessionFactory ), metadata.buildNamedQueryRepository( sessionFactory ),
hqlTranslator, hqlTranslator,
sqmTranslatorFactory, sqmTranslatorFactory,
@ -89,6 +92,7 @@ public class QueryEngine {
public QueryEngine( public QueryEngine(
Supplier<JpaMetamodel> jpaMetamodelAccess, Supplier<JpaMetamodel> jpaMetamodelAccess,
LiteralHandlingMode criteriaLiteralHandlingMode,
NamedObjectRepository namedObjectRepository, NamedObjectRepository namedObjectRepository,
HqlTranslator hqlTranslator, HqlTranslator hqlTranslator,
SqmTranslatorFactory sqmTranslatorFactory, SqmTranslatorFactory sqmTranslatorFactory,
@ -106,7 +110,8 @@ public class QueryEngine {
this.criteriaBuilder = new SqmCriteriaNodeBuilder( this.criteriaBuilder = new SqmCriteriaNodeBuilder(
this, this,
jpaMetamodelAccess, jpaMetamodelAccess,
serviceRegistry serviceRegistry,
criteriaLiteralHandlingMode
); );
this.sqmFunctionRegistry = new SqmFunctionRegistry(); this.sqmFunctionRegistry = new SqmFunctionRegistry();
@ -132,6 +137,7 @@ public class QueryEngine {
*/ */
public QueryEngine( public QueryEngine(
JpaMetamodel jpaMetamodel, JpaMetamodel jpaMetamodel,
LiteralHandlingMode criteriaLiteralHandlingMode,
boolean useStrictJpaCompliance, boolean useStrictJpaCompliance,
NamedObjectRepository namedObjectRepository, NamedObjectRepository namedObjectRepository,
NativeQueryInterpreter nativeQueryInterpreter, NativeQueryInterpreter nativeQueryInterpreter,
@ -147,7 +153,8 @@ public class QueryEngine {
this.criteriaBuilder = new SqmCriteriaNodeBuilder( this.criteriaBuilder = new SqmCriteriaNodeBuilder(
this, this,
() -> jpaMetamodel, () -> jpaMetamodel,
serviceRegistry serviceRegistry,
criteriaLiteralHandlingMode
); );
final SqmCreationContext sqmCreationContext = new SqmCreationContext() { final SqmCreationContext sqmCreationContext = new SqmCreationContext() {

View File

@ -6,6 +6,8 @@
*/ */
package org.hibernate.query.sqm; package org.hibernate.query.sqm;
import java.util.List;
import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.query.sqm.tree.cte.SqmCteConsumer; import org.hibernate.query.sqm.tree.cte.SqmCteConsumer;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement; import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
@ -30,6 +32,7 @@ import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple; import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
import org.hibernate.query.sqm.tree.expression.SqmCastTarget; import org.hibernate.query.sqm.tree.expression.SqmCastTarget;
import org.hibernate.query.sqm.tree.expression.SqmCoalesce; import org.hibernate.query.sqm.tree.expression.SqmCoalesce;
import org.hibernate.query.sqm.tree.expression.SqmCollate;
import org.hibernate.query.sqm.tree.expression.SqmCollectionSize; import org.hibernate.query.sqm.tree.expression.SqmCollectionSize;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter; import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmDurationUnit; import org.hibernate.query.sqm.tree.expression.SqmDurationUnit;
@ -75,10 +78,9 @@ import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmOrPredicate; import org.hibernate.query.sqm.tree.predicate.SqmOrPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause; import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation; import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation;
import org.hibernate.query.sqm.tree.select.SqmGroupByClause;
import org.hibernate.query.sqm.tree.select.SqmHavingClause;
import org.hibernate.query.sqm.tree.select.SqmJpaCompoundSelection; import org.hibernate.query.sqm.tree.select.SqmJpaCompoundSelection;
import org.hibernate.query.sqm.tree.select.SqmOrderByClause; import org.hibernate.query.sqm.tree.select.SqmOrderByClause;
import org.hibernate.query.sqm.tree.select.SqmQuerySpec; import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
@ -165,11 +167,9 @@ public interface SemanticQueryWalker<T> {
T visitValues(SqmValues values); T visitValues(SqmValues values);
T visitGroupByClause(SqmGroupByClause clause); T visitGroupByClause(List<SqmExpression<?>> groupByClauseExpressions);
T visitGrouping(SqmGroupByClause.SqmGrouping grouping); T visitHavingClause(SqmPredicate clause);
T visitHavingClause(SqmHavingClause clause);
T visitDynamicInstantiation(SqmDynamicInstantiation<?> sqmDynamicInstantiation); T visitDynamicInstantiation(SqmDynamicInstantiation<?> sqmDynamicInstantiation);
@ -189,6 +189,8 @@ public interface SemanticQueryWalker<T> {
T visitTuple(SqmTuple<?> sqmTuple); T visitTuple(SqmTuple<?> sqmTuple);
T visitCollate(SqmCollate<?> sqmCollate);
T visitBinaryArithmeticExpression(SqmBinaryArithmetic<?> expression); T visitBinaryArithmeticExpression(SqmBinaryArithmetic<?> expression);
T visitSubQueryExpression(SqmSubQuery<?> expression); T visitSubQueryExpression(SqmSubQuery<?> expression);
@ -200,6 +202,7 @@ public interface SemanticQueryWalker<T> {
T visitSearchedCaseExpression(SqmCaseSearched<?> expression); T visitSearchedCaseExpression(SqmCaseSearched<?> expression);
T visitAny(SqmAny<?> sqmAny); T visitAny(SqmAny<?> sqmAny);
T visitEvery(SqmEvery<?> sqmEvery); T visitEvery(SqmEvery<?> sqmEvery);
T visitPositionalParameterExpression(SqmPositionalParameter<?> expression); T visitPositionalParameterExpression(SqmPositionalParameter<?> expression);

View File

@ -52,6 +52,8 @@ import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.query.sqm.tree.SqmDmlStatement; import org.hibernate.query.sqm.tree.SqmDmlStatement;
import org.hibernate.query.sqm.tree.SqmStatement; import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement; import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
import org.hibernate.query.sqm.tree.expression.SqmParameter; import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.from.SqmRoot; import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.insert.SqmInsertStatement; import org.hibernate.query.sqm.tree.insert.SqmInsertStatement;
@ -230,6 +232,17 @@ public class QuerySqmImpl<R>
} }
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, producer.getFactory() ); this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, producer.getFactory() );
// Parameters might be created through HibernateCriteriaBuilder.value which we need to bind here
for ( SqmParameter<?> sqmParameter : this.domainParameterXref.getParameterResolutions().getSqmParameters() ) {
if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper<?> ) {
final JpaCriteriaParameter<Object> jpaCriteriaParameter = ( (SqmJpaCriteriaParameterWrapper<Object>) sqmParameter ).getJpaCriteriaParameter();
final Object value = jpaCriteriaParameter.getValue();
// We don't set a null value, unless the type is also null which is the case when using HibernateCriteriaBuilder.value
if ( value != null || jpaCriteriaParameter.getNodeType() == null ) {
setParameter( jpaCriteriaParameter, value );
}
}
}
} }
private static <T> void checkQueryReturnType(SqmSelectStatement<T> sqm, Class<T> resultClass, SessionFactoryImplementor sessionFactory) { private static <T> void checkQueryReturnType(SqmSelectStatement<T> sqm, Class<T> resultClass, SessionFactoryImplementor sessionFactory) {

View File

@ -36,6 +36,7 @@ import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.NullPrecedence; import org.hibernate.NullPrecedence;
import org.hibernate.QueryException; import org.hibernate.QueryException;
import org.hibernate.SortOrder; import org.hibernate.SortOrder;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
@ -52,6 +53,7 @@ import org.hibernate.query.criteria.JpaCoalesce;
import org.hibernate.query.criteria.JpaCompoundSelection; import org.hibernate.query.criteria.JpaCompoundSelection;
import org.hibernate.query.criteria.JpaExpression; import org.hibernate.query.criteria.JpaExpression;
import org.hibernate.query.criteria.JpaSelection; import org.hibernate.query.criteria.JpaSelection;
import org.hibernate.query.criteria.LiteralHandlingMode;
import org.hibernate.query.internal.QueryHelper; import org.hibernate.query.internal.QueryHelper;
import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.NodeBuilder;
@ -104,6 +106,7 @@ import org.hibernate.query.sqm.tree.select.SqmSortSpecification;
import org.hibernate.query.sqm.tree.select.SqmSubQuery; import org.hibernate.query.sqm.tree.select.SqmSubQuery;
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement; import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.BasicType;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
@ -124,21 +127,25 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
return new SqmCriteriaNodeBuilder( return new SqmCriteriaNodeBuilder(
sf.getQueryEngine(), sf.getQueryEngine(),
() -> sf.getRuntimeMetamodels().getJpaMetamodel(), () -> sf.getRuntimeMetamodels().getJpaMetamodel(),
sf.getServiceRegistry() sf.getServiceRegistry(),
sf.getSessionFactoryOptions().getCriteriaLiteralHandlingMode()
); );
} }
private final QueryEngine queryEngine; private final QueryEngine queryEngine;
private final Supplier<JpaMetamodel> domainModelAccess; private final Supplier<JpaMetamodel> domainModelAccess;
private final ServiceRegistry serviceRegistry; private final ServiceRegistry serviceRegistry;
private final LiteralHandlingMode criteriaLiteralHandlingMode;
public SqmCriteriaNodeBuilder( public SqmCriteriaNodeBuilder(
QueryEngine queryEngine, QueryEngine queryEngine,
Supplier<JpaMetamodel> domainModelAccess, Supplier<JpaMetamodel> domainModelAccess,
ServiceRegistry serviceRegistry) { ServiceRegistry serviceRegistry,
LiteralHandlingMode criteriaLiteralHandlingMode) {
this.queryEngine = queryEngine; this.queryEngine = queryEngine;
this.domainModelAccess = domainModelAccess; this.domainModelAccess = domainModelAccess;
this.serviceRegistry = serviceRegistry; this.serviceRegistry = serviceRegistry;
this.criteriaLiteralHandlingMode = criteriaLiteralHandlingMode;
} }
@Override @Override
@ -573,17 +580,17 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
@Override @Override
public <N extends Number> SqmExpression<N> sum(Expression<? extends N> x, N y) { public <N extends Number> SqmExpression<N> sum(Expression<? extends N> x, N y) {
return createSqmArithmeticNode( BinaryArithmeticOperator.ADD, (SqmExpression) x, literal( y ) ); return createSqmArithmeticNode( BinaryArithmeticOperator.ADD, (SqmExpression) x, value( y ) );
} }
@Override @Override
public <N extends Number> SqmExpression<N> sum(N x, Expression<? extends N> y) { public <N extends Number> SqmExpression<N> sum(N x, Expression<? extends N> y) {
return createSqmArithmeticNode( BinaryArithmeticOperator.ADD, literal( x ), (SqmExpression) y ); return createSqmArithmeticNode( BinaryArithmeticOperator.ADD, value( x ), (SqmExpression) y );
} }
@Override @Override
public <N extends Number> SqmExpression<N> prod(Expression<? extends N> x, Expression<? extends N> y) { public <N extends Number> SqmExpression<N> prod(Expression<? extends N> x, Expression<? extends N> y) {
return createSqmArithmeticNode( BinaryArithmeticOperator.ADD, literal( x ), (SqmExpression) y ); return createSqmArithmeticNode( BinaryArithmeticOperator.ADD, value( x ), (SqmExpression) y );
} }
@Override @Override
@ -610,7 +617,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
return createSqmArithmeticNode( return createSqmArithmeticNode(
BinaryArithmeticOperator.SUBTRACT, BinaryArithmeticOperator.SUBTRACT,
(SqmExpression) x, (SqmExpression) x,
literal( y ) value( y )
); );
} }
@ -618,7 +625,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
public <N extends Number> SqmExpression<N> diff(N x, Expression<? extends N> y) { public <N extends Number> SqmExpression<N> diff(N x, Expression<? extends N> y) {
return createSqmArithmeticNode( return createSqmArithmeticNode(
BinaryArithmeticOperator.SUBTRACT, BinaryArithmeticOperator.SUBTRACT,
literal( x ), value( x ),
(SqmExpression) y (SqmExpression) y
); );
} }
@ -637,7 +644,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
return createSqmArithmeticNode( return createSqmArithmeticNode(
BinaryArithmeticOperator.QUOT, BinaryArithmeticOperator.QUOT,
(SqmExpression) x, (SqmExpression) x,
literal( y ) value( y )
); );
} }
@ -645,7 +652,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
public SqmExpression<Number> quot(Number x, Expression<? extends Number> y) { public SqmExpression<Number> quot(Number x, Expression<? extends Number> y) {
return createSqmArithmeticNode( return createSqmArithmeticNode(
BinaryArithmeticOperator.QUOT, BinaryArithmeticOperator.QUOT,
literal( x ), value( x ),
(SqmExpression) y (SqmExpression) y
); );
} }
@ -664,7 +671,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
return createSqmArithmeticNode( return createSqmArithmeticNode(
BinaryArithmeticOperator.MODULO, BinaryArithmeticOperator.MODULO,
(SqmExpression) x, (SqmExpression) x,
literal( y ) value( y )
); );
} }
@ -672,7 +679,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
public SqmExpression<Integer> mod(Integer x, Expression<Integer> y) { public SqmExpression<Integer> mod(Integer x, Expression<Integer> y) {
return createSqmArithmeticNode( return createSqmArithmeticNode(
BinaryArithmeticOperator.MODULO, BinaryArithmeticOperator.MODULO,
literal( x ), value( x ),
(SqmExpression) y (SqmExpression) y
); );
} }
@ -882,7 +889,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
@Override @Override
public SqmExpression<String> concat(Expression<String> x, String y) { public SqmExpression<String> concat(Expression<String> x, String y) {
final SqmExpression xSqmExpression = (SqmExpression) x; final SqmExpression xSqmExpression = (SqmExpression) x;
final SqmExpression ySqmExpression = literal( y ); final SqmExpression ySqmExpression = value( y );
//noinspection unchecked //noinspection unchecked
return getFunctionDescriptor( "concat" ).generateSqmExpression( return getFunctionDescriptor( "concat" ).generateSqmExpression(
asList( xSqmExpression, ySqmExpression ), asList( xSqmExpression, ySqmExpression ),
@ -898,7 +905,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
@Override @Override
public SqmExpression<String> concat(String x, Expression<String> y) { public SqmExpression<String> concat(String x, Expression<String> y) {
final SqmExpression xSqmExpression = literal( x ); final SqmExpression xSqmExpression = value( x );
final SqmExpression ySqmExpression = (SqmExpression) y; final SqmExpression ySqmExpression = (SqmExpression) y;
//noinspection unchecked //noinspection unchecked
return getFunctionDescriptor( "concat" ).generateSqmExpression( return getFunctionDescriptor( "concat" ).generateSqmExpression(
@ -915,8 +922,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
@Override @Override
public SqmExpression<String> concat(String x, String y) { public SqmExpression<String> concat(String x, String y) {
final SqmExpression xSqmExpression = literal( x ); final SqmExpression xSqmExpression = value( x );
final SqmExpression ySqmExpression = literal( y ); final SqmExpression ySqmExpression = value( y );
//noinspection unchecked //noinspection unchecked
return getFunctionDescriptor( "concat" ).generateSqmExpression( return getFunctionDescriptor( "concat" ).generateSqmExpression(
asList( xSqmExpression, ySqmExpression ), asList( xSqmExpression, ySqmExpression ),
@ -958,7 +965,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
public SqmFunction<String> substring(Expression<String> source, int from) { public SqmFunction<String> substring(Expression<String> source, int from) {
return createSubstringNode( return createSubstringNode(
(SqmExpression) source, (SqmExpression) source,
literal( from ), value( from ),
null null
); );
} }
@ -976,8 +983,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
public SqmFunction<String> substring(Expression<String> source, int from, int len) { public SqmFunction<String> substring(Expression<String> source, int from, int len) {
return createSubstringNode( return createSubstringNode(
(SqmExpression) source, (SqmExpression) source,
literal( from ), value( from ),
literal( len ) value( len )
); );
} }
@ -1148,7 +1155,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
public SqmFunction<Integer> locate(Expression<String> source, String pattern) { public SqmFunction<Integer> locate(Expression<String> source, String pattern) {
return createLocateFunctionNode( return createLocateFunctionNode(
(SqmExpression<String>) source, (SqmExpression<String>) source,
literal( pattern ), value( pattern ),
null null
); );
} }
@ -1166,8 +1173,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
public SqmFunction<Integer> locate(Expression<String> source, String pattern, int startPosition) { public SqmFunction<Integer> locate(Expression<String> source, String pattern, int startPosition) {
return createLocateFunctionNode( return createLocateFunctionNode(
(SqmExpression<String>) source, (SqmExpression<String>) source,
literal( pattern ), value( pattern ),
literal( startPosition ) value( startPosition )
); );
} }
@ -1280,6 +1287,27 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
throw new NotYetImplementedFor6Exception(); throw new NotYetImplementedFor6Exception();
} }
@Override
public <T> SqmExpression<T> value(T value) {
if ( criteriaLiteralHandlingMode == LiteralHandlingMode.INLINE ) {
return literal( value );
}
else {
final BasicType basicType;
if ( value == null ) {
basicType = null;
}
else {
basicType = getTypeConfiguration().getBasicTypeForJavaType( value.getClass() );
}
return new JpaCriteriaParameter<>(
basicType,
value,
this
);
}
}
@Override @Override
public <V, C extends Collection<V>> SqmExpression<Collection<V>> values(C collection) { public <V, C extends Collection<V>> SqmExpression<Collection<V>> values(C collection) {
throw new NotYetImplementedFor6Exception(); throw new NotYetImplementedFor6Exception();
@ -1326,7 +1354,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
@Override @Override
public <Y> JpaCoalesce<Y> coalesce(Expression<? extends Y> x, Y y) { public <Y> JpaCoalesce<Y> coalesce(Expression<? extends Y> x, Y y) {
return coalesce( x, literal( y ) ); return coalesce( x, value( y ) );
} }
@Override @Override
@ -1338,7 +1366,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
@Override @Override
public <Y> SqmExpression<Y> nullif(Expression<Y> x, Y y) { public <Y> SqmExpression<Y> nullif(Expression<Y> x, Y y) {
//noinspection unchecked //noinspection unchecked
return createNullifFunctionNode( (SqmExpression) x, literal( y ) ); return createNullifFunctionNode( (SqmExpression) x, value( y ) );
} }
private <Y> SqmExpression<Y> createNullifFunctionNode(SqmExpression<Y> first, SqmExpression<Y> second) { private <Y> SqmExpression<Y> createNullifFunctionNode(SqmExpression<Y> first, SqmExpression<Y> second) {
@ -1498,8 +1526,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
public <Y extends Comparable<? super Y>> SqmPredicate between(Expression<? extends Y> value, Y lower, Y upper) { public <Y extends Comparable<? super Y>> SqmPredicate between(Expression<? extends Y> value, Y lower, Y upper) {
return new SqmBetweenPredicate( return new SqmBetweenPredicate(
(SqmExpression) value, (SqmExpression) value,
literal( lower ), value( lower ),
literal( upper ), value( upper ),
false, false,
this this
); );
@ -1520,7 +1548,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.EQUAL, ComparisonOperator.EQUAL,
literal( y ), value( y ),
this this
); );
} }
@ -1540,7 +1568,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.NOT_EQUAL, ComparisonOperator.NOT_EQUAL,
literal( y ), value( y ),
this this
); );
} }
@ -1560,7 +1588,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN, ComparisonOperator.GREATER_THAN,
literal( y ), value( y ),
this this
); );
} }
@ -1580,7 +1608,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN_OR_EQUAL, ComparisonOperator.GREATER_THAN_OR_EQUAL,
literal( y ), value( y ),
this this
); );
} }
@ -1600,7 +1628,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.LESS_THAN, ComparisonOperator.LESS_THAN,
literal( y ), value( y ),
this this
); );
} }
@ -1620,7 +1648,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.LESS_THAN_OR_EQUAL, ComparisonOperator.LESS_THAN_OR_EQUAL,
literal( y ), value( y ),
this this
); );
} }
@ -1640,7 +1668,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN, ComparisonOperator.GREATER_THAN,
literal( y ), value( y ),
this this
); );
} }
@ -1660,7 +1688,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.GREATER_THAN_OR_EQUAL, ComparisonOperator.GREATER_THAN_OR_EQUAL,
literal( y ), value( y ),
this this
); );
} }
@ -1680,7 +1708,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.LESS_THAN, ComparisonOperator.LESS_THAN,
literal( y ), value( y ),
this this
); );
} }
@ -1700,7 +1728,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
return new SqmComparisonPredicate( return new SqmComparisonPredicate(
(SqmExpression<?>) x, (SqmExpression<?>) x,
ComparisonOperator.LESS_THAN_OR_EQUAL, ComparisonOperator.LESS_THAN_OR_EQUAL,
literal( y ), value( y ),
this this
); );
} }
@ -1748,7 +1776,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
public SqmPredicate like(Expression<String> searchString, String pattern) { public SqmPredicate like(Expression<String> searchString, String pattern) {
return new SqmLikePredicate( return new SqmLikePredicate(
(SqmExpression) searchString, (SqmExpression) searchString,
literal( pattern ), value( pattern ),
this this
); );
} }
@ -1777,7 +1805,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
public SqmPredicate like(Expression<String> searchString, String pattern, Expression<Character> escapeChar) { public SqmPredicate like(Expression<String> searchString, String pattern, Expression<Character> escapeChar) {
return new SqmLikePredicate( return new SqmLikePredicate(
(SqmExpression) searchString, (SqmExpression) searchString,
literal( pattern ), value( pattern ),
(SqmExpression) escapeChar, (SqmExpression) escapeChar,
this this
); );
@ -1787,7 +1815,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
public SqmPredicate like(Expression<String> searchString, String pattern, char escapeChar) { public SqmPredicate like(Expression<String> searchString, String pattern, char escapeChar) {
return new SqmLikePredicate( return new SqmLikePredicate(
(SqmExpression) searchString, (SqmExpression) searchString,
literal( pattern ), value( pattern ),
literal( escapeChar ), literal( escapeChar ),
this this
); );

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.query.sqm.internal; package org.hibernate.query.sqm.internal;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.NotYetImplementedFor6Exception;
@ -36,6 +37,7 @@ import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple; import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
import org.hibernate.query.sqm.tree.expression.SqmCastTarget; import org.hibernate.query.sqm.tree.expression.SqmCastTarget;
import org.hibernate.query.sqm.tree.expression.SqmCoalesce; import org.hibernate.query.sqm.tree.expression.SqmCoalesce;
import org.hibernate.query.sqm.tree.expression.SqmCollate;
import org.hibernate.query.sqm.tree.expression.SqmCollectionSize; import org.hibernate.query.sqm.tree.expression.SqmCollectionSize;
import org.hibernate.query.sqm.tree.expression.SqmDistinct; import org.hibernate.query.sqm.tree.expression.SqmDistinct;
import org.hibernate.query.sqm.tree.expression.SqmDurationUnit; import org.hibernate.query.sqm.tree.expression.SqmDurationUnit;
@ -81,10 +83,9 @@ import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmOrPredicate; import org.hibernate.query.sqm.tree.predicate.SqmOrPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause; import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation; import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation;
import org.hibernate.query.sqm.tree.select.SqmGroupByClause;
import org.hibernate.query.sqm.tree.select.SqmHavingClause;
import org.hibernate.query.sqm.tree.select.SqmOrderByClause; import org.hibernate.query.sqm.tree.select.SqmOrderByClause;
import org.hibernate.query.sqm.tree.select.SqmQuerySpec; import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
import org.hibernate.query.sqm.tree.select.SqmSelectClause; import org.hibernate.query.sqm.tree.select.SqmSelectClause;
@ -394,21 +395,18 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
// query-spec // query-spec
@Override @Override
public Object visitQuerySpec(SqmQuerySpec querySpec) { public Object visitQuerySpec(SqmQuerySpec<?> querySpec) {
processStanza( processStanza(
"query-spec", "query-spec",
() -> { () -> {
visitSelectClause( querySpec.getSelectClause() ); visitSelectClause( querySpec.getSelectClause() );
visitFromClause( querySpec.getFromClause() ); visitFromClause( querySpec.getFromClause() );
visitGroupByClause( querySpec.getGroupByClause() );
visitHavingClause( querySpec.getHavingClause() );
visitWhereClause( querySpec.getWhereClause() ); visitWhereClause( querySpec.getWhereClause() );
visitOrderByClause( querySpec.getOrderByClause() ); visitGroupByClause( querySpec.getGroupByClauseExpressions() );
visitHavingClause( querySpec.getHavingClausePredicate() );
visitOrderByClause( querySpec.getOrderByClause() );
visitLimitExpression( querySpec.getLimitExpression() ); visitLimitExpression( querySpec.getLimitExpression() );
visitOffsetExpression( querySpec.getOffsetExpression() ); visitOffsetExpression( querySpec.getOffsetExpression() );
} }
@ -418,11 +416,11 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
} }
@Override @Override
public Object visitGroupByClause(SqmGroupByClause clause) { public Object visitGroupByClause(List<SqmExpression<?>> groupByClauseExpressions) {
if ( clause != null ) { if ( groupByClauseExpressions != null && !groupByClauseExpressions.isEmpty() ) {
processStanza( processStanza(
"group-by", "group-by",
() -> clause.visitGroupings( this::visitGrouping ) () -> groupByClauseExpressions.forEach( e -> e.accept( this ) )
); );
} }
@ -430,21 +428,11 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
} }
@Override @Override
public Object visitGrouping(SqmGroupByClause.SqmGrouping grouping) { public Object visitHavingClause(SqmPredicate predicate) {
processStanza( if ( predicate != null ) {
"grouping",
() -> grouping.getExpression().accept( this )
);
return null;
}
@Override
public Object visitHavingClause(SqmHavingClause clause) {
if ( clause != null ) {
processStanza( processStanza(
"having", "having",
() -> clause.getPredicate().accept( this ) () -> predicate.accept( this )
); );
} }
@ -912,6 +900,11 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
return null; return null;
} }
@Override
public Object visitCollate(SqmCollate<?> sqmCollate) {
return null;
}
@Override @Override
public Object visitBinaryArithmeticExpression(SqmBinaryArithmetic expression) { public Object visitBinaryArithmeticExpression(SqmBinaryArithmetic expression) {
return null; return null;

View File

@ -231,7 +231,7 @@ public class SqmUtil {
final JdbcParameter jdbcParameter = jdbcParams.get( i ); final JdbcParameter jdbcParameter = jdbcParams.get( i );
jdbcParameterBindings.addBinding( jdbcParameterBindings.addBinding(
jdbcParameter, jdbcParameter,
new JdbcParameterBindingImpl( StandardBasicTypes.SERIALIZABLE, null ) new JdbcParameterBindingImpl( null, null )
); );
} }
} }

View File

@ -6,6 +6,8 @@
*/ */
package org.hibernate.query.sqm.spi; package org.hibernate.query.sqm.spi;
import java.util.List;
import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.cte.SqmCteConsumer; import org.hibernate.query.sqm.tree.cte.SqmCteConsumer;
@ -33,6 +35,7 @@ import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple; import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
import org.hibernate.query.sqm.tree.expression.SqmCastTarget; import org.hibernate.query.sqm.tree.expression.SqmCastTarget;
import org.hibernate.query.sqm.tree.expression.SqmCoalesce; import org.hibernate.query.sqm.tree.expression.SqmCoalesce;
import org.hibernate.query.sqm.tree.expression.SqmCollate;
import org.hibernate.query.sqm.tree.expression.SqmCollectionSize; import org.hibernate.query.sqm.tree.expression.SqmCollectionSize;
import org.hibernate.query.sqm.tree.expression.SqmDurationUnit; import org.hibernate.query.sqm.tree.expression.SqmDurationUnit;
import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral; import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral;
@ -77,10 +80,9 @@ import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmOrPredicate; import org.hibernate.query.sqm.tree.predicate.SqmOrPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause; import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation; import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation;
import org.hibernate.query.sqm.tree.select.SqmGroupByClause;
import org.hibernate.query.sqm.tree.select.SqmHavingClause;
import org.hibernate.query.sqm.tree.select.SqmOrderByClause; import org.hibernate.query.sqm.tree.select.SqmOrderByClause;
import org.hibernate.query.sqm.tree.select.SqmQuerySpec; import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
import org.hibernate.query.sqm.tree.select.SqmSelectClause; import org.hibernate.query.sqm.tree.select.SqmSelectClause;
@ -195,7 +197,7 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
} }
@Override @Override
public Object visitQuerySpec(SqmQuerySpec querySpec) { public Object visitQuerySpec(SqmQuerySpec<?> querySpec) {
visitFromClause( querySpec.getFromClause() ); visitFromClause( querySpec.getFromClause() );
visitSelectClause( querySpec.getSelectClause() ); visitSelectClause( querySpec.getSelectClause() );
visitWhereClause( querySpec.getWhereClause() ); visitWhereClause( querySpec.getWhereClause() );
@ -453,21 +455,16 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
} }
@Override @Override
public Object visitGroupByClause(SqmGroupByClause clause) { public Object visitGroupByClause(List<SqmExpression<?>> groupByClauseExpressions) {
clause.visitGroupings( this::visitGrouping ); if ( groupByClauseExpressions != null ) {
return clause; groupByClauseExpressions.forEach( e -> e.accept( this ) );
}
return groupByClauseExpressions;
} }
@Override @Override
public Object visitGrouping(SqmGroupByClause.SqmGrouping grouping) { public Object visitHavingClause(SqmPredicate sqmPredicate) {
grouping.getExpression().accept( this ); return sqmPredicate.accept( this );
return grouping;
}
@Override
public Object visitHavingClause(SqmHavingClause clause) {
clause.getPredicate().accept( this );
return clause;
} }
@Override @Override
@ -587,15 +584,21 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
} }
@Override @Override
public Object visitLiteral(SqmLiteral literal) { public Object visitLiteral(SqmLiteral<?> literal) {
return literal; return literal;
} }
@Override @Override
public Object visitTuple(SqmTuple sqmTuple) { public Object visitTuple(SqmTuple<?> sqmTuple) {
return sqmTuple; return sqmTuple;
} }
@Override
public Object visitCollate(SqmCollate<?> sqmCollate) {
sqmCollate.getExpression().accept( this );
return sqmCollate;
}
@Override @Override
public Object visitBinaryArithmeticExpression(SqmBinaryArithmetic expression) { public Object visitBinaryArithmeticExpression(SqmBinaryArithmetic expression) {
return expression; return expression;

View File

@ -32,6 +32,7 @@ import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.internal.EmbeddedCollectionPart;
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart; import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.metamodel.model.domain.AllowableParameterType; import org.hibernate.metamodel.model.domain.AllowableParameterType;
@ -87,6 +88,7 @@ import org.hibernate.query.sqm.tree.expression.SqmByUnit;
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched; import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple; import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
import org.hibernate.query.sqm.tree.expression.SqmCastTarget; import org.hibernate.query.sqm.tree.expression.SqmCastTarget;
import org.hibernate.query.sqm.tree.expression.SqmCollate;
import org.hibernate.query.sqm.tree.expression.SqmDistinct; import org.hibernate.query.sqm.tree.expression.SqmDistinct;
import org.hibernate.query.sqm.tree.expression.SqmDurationUnit; import org.hibernate.query.sqm.tree.expression.SqmDurationUnit;
import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral; import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral;
@ -105,6 +107,7 @@ import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter;
import org.hibernate.query.sqm.tree.expression.SqmStar; import org.hibernate.query.sqm.tree.expression.SqmStar;
import org.hibernate.query.sqm.tree.expression.SqmToDuration; import org.hibernate.query.sqm.tree.expression.SqmToDuration;
import org.hibernate.query.sqm.tree.expression.SqmTrimSpecification; import org.hibernate.query.sqm.tree.expression.SqmTrimSpecification;
import org.hibernate.query.sqm.tree.expression.SqmTuple;
import org.hibernate.query.sqm.tree.expression.SqmUnaryOperation; import org.hibernate.query.sqm.tree.expression.SqmUnaryOperation;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin; import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmCrossJoin; import org.hibernate.query.sqm.tree.from.SqmCrossJoin;
@ -128,6 +131,7 @@ import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmOrPredicate; import org.hibernate.query.sqm.tree.predicate.SqmOrPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause; import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.SqmOrderByClause; import org.hibernate.query.sqm.tree.select.SqmOrderByClause;
import org.hibernate.query.sqm.tree.select.SqmQuerySpec; import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
@ -156,6 +160,7 @@ import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression; import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression; import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
import org.hibernate.sql.ast.tree.expression.CastTarget; import org.hibernate.sql.ast.tree.expression.CastTarget;
import org.hibernate.sql.ast.tree.expression.Collate;
import org.hibernate.sql.ast.tree.expression.Distinct; import org.hibernate.sql.ast.tree.expression.Distinct;
import org.hibernate.sql.ast.tree.expression.Duration; import org.hibernate.sql.ast.tree.expression.Duration;
import org.hibernate.sql.ast.tree.expression.DurationUnit; import org.hibernate.sql.ast.tree.expression.DurationUnit;
@ -166,6 +171,7 @@ import org.hibernate.sql.ast.tree.expression.Format;
import org.hibernate.sql.ast.tree.expression.JdbcLiteral; import org.hibernate.sql.ast.tree.expression.JdbcLiteral;
import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.expression.QueryLiteral; import org.hibernate.sql.ast.tree.expression.QueryLiteral;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Star; import org.hibernate.sql.ast.tree.expression.Star;
import org.hibernate.sql.ast.tree.expression.TrimSpecification; import org.hibernate.sql.ast.tree.expression.TrimSpecification;
import org.hibernate.sql.ast.tree.expression.UnaryOperation; import org.hibernate.sql.ast.tree.expression.UnaryOperation;
@ -180,7 +186,6 @@ import org.hibernate.sql.ast.tree.predicate.InListPredicate;
import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate; import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate;
import org.hibernate.sql.ast.tree.predicate.Junction; import org.hibernate.sql.ast.tree.predicate.Junction;
import org.hibernate.sql.ast.tree.predicate.LikePredicate; import org.hibernate.sql.ast.tree.predicate.LikePredicate;
import org.hibernate.sql.ast.tree.predicate.MemberOfPredicate;
import org.hibernate.sql.ast.tree.predicate.NegatedPredicate; import org.hibernate.sql.ast.tree.predicate.NegatedPredicate;
import org.hibernate.sql.ast.tree.predicate.NullnessPredicate; import org.hibernate.sql.ast.tree.predicate.NullnessPredicate;
import org.hibernate.sql.ast.tree.predicate.Predicate; import org.hibernate.sql.ast.tree.predicate.Predicate;
@ -404,7 +409,7 @@ public abstract class BaseSqmToSqlAstConverter
} }
@Override @Override
public QuerySpec visitQuerySpec(SqmQuerySpec sqmQuerySpec) { public QuerySpec visitQuerySpec(SqmQuerySpec<?> sqmQuerySpec) {
final QuerySpec sqlQuerySpec = new QuerySpec( processingStateStack.isEmpty(), sqmQuerySpec.getFromClause().getNumberOfRoots() ); final QuerySpec sqlQuerySpec = new QuerySpec( processingStateStack.isEmpty(), sqmQuerySpec.getFromClause().getNumberOfRoots() );
additionalRestrictions = null; additionalRestrictions = null;
@ -444,8 +449,10 @@ public abstract class BaseSqmToSqlAstConverter
sqlQuerySpec.applyPredicate( additionalRestrictions ); sqlQuerySpec.applyPredicate( additionalRestrictions );
} }
// todo : group-by sqlQuerySpec.setGroupByClauseExpressions( visitGroupByClause( sqmQuerySpec.getGroupByClauseExpressions() ) );
// todo : having if ( sqmQuerySpec.getHavingClausePredicate() != null ) {
sqlQuerySpec.setHavingClauseRestrictions( visitHavingClause( sqmQuerySpec.getHavingClausePredicate() ) );
}
if ( sqmQuerySpec.getOrderByClause() != null ) { if ( sqmQuerySpec.getOrderByClause() != null ) {
currentClauseStack.push( Clause.ORDER ); currentClauseStack.push( Clause.ORDER );
@ -493,6 +500,38 @@ public abstract class BaseSqmToSqlAstConverter
} }
} }
@Override
public List<Expression> visitGroupByClause(List<SqmExpression<?>> groupByClauseExpressions) {
if ( !groupByClauseExpressions.isEmpty() ) {
currentClauseStack.push( Clause.GROUP );
try {
List<Expression> expressions = new ArrayList<>( groupByClauseExpressions.size() );
for ( SqmExpression<?> groupByClauseExpression : groupByClauseExpressions ) {
expressions.add( (Expression) groupByClauseExpression.accept( this ) );
}
return expressions;
}
finally {
currentClauseStack.pop();
}
}
return Collections.emptyList();
}
@Override
public Predicate visitHavingClause(SqmPredicate sqmPredicate) {
if ( sqmPredicate == null ) {
return null;
}
currentClauseStack.push( Clause.HAVING );
try {
return (Predicate) sqmPredicate.accept( this );
}
finally {
currentClauseStack.pop();
}
}
@Override @Override
public Void visitOrderByClause(SqmOrderByClause orderByClause) { public Void visitOrderByClause(SqmOrderByClause orderByClause) {
super.visitOrderByClause( orderByClause ); super.visitOrderByClause( orderByClause );
@ -503,7 +542,7 @@ public abstract class BaseSqmToSqlAstConverter
public SortSpecification visitSortSpecification(SqmSortSpecification sortSpecification) { public SortSpecification visitSortSpecification(SqmSortSpecification sortSpecification) {
return new SortSpecification( return new SortSpecification(
(Expression) sortSpecification.getSortExpression().accept( this ), (Expression) sortSpecification.getSortExpression().accept( this ),
sortSpecification.getCollation(), null,
sortSpecification.getSortOrder(), sortSpecification.getSortOrder(),
sortSpecification.getNullPrecedence() sortSpecification.getNullPrecedence()
); );
@ -1001,7 +1040,7 @@ public abstract class BaseSqmToSqlAstConverter
// General expressions // General expressions
@Override @Override
public Expression visitLiteral(SqmLiteral literal) { public Expression visitLiteral(SqmLiteral<?> literal) {
if ( literal instanceof SqmLiteralNull ) { if ( literal instanceof SqmLiteralNull ) {
return new QueryLiteral<>( null, (BasicValuedMapping) inferableTypeAccessStack.getCurrent().get() ); return new QueryLiteral<>( null, (BasicValuedMapping) inferableTypeAccessStack.getCurrent().get() );
} }
@ -1196,6 +1235,24 @@ public abstract class BaseSqmToSqlAstConverter
return consumeSqmParameter( supplier.get() ); return consumeSqmParameter( supplier.get() );
} }
@Override
public Object visitTuple(SqmTuple<?> sqmTuple) {
final List<SqmExpression<?>> groupedExpressions = sqmTuple.getGroupedExpressions();
final int size = groupedExpressions.size();
final List<Expression> expressions = new ArrayList<>( size );
for ( int i = 0; i < size; i++ ) {
expressions.add( (Expression) groupedExpressions.get( i ).accept( this ) );
}
return new SqlTuple( expressions, null );
}
@Override
public Object visitCollate(SqmCollate<?> sqmCollate) {
return new Collate(
(Expression) sqmCollate.getExpression().accept( this ),
sqmCollate.getCollation()
);
}
@Override @Override
public Expression visitFunction(SqmFunction sqmFunction) { public Expression visitFunction(SqmFunction sqmFunction) {
@ -2209,7 +2266,7 @@ public abstract class BaseSqmToSqlAstConverter
} }
@Override @Override
public MemberOfPredicate visitMemberOfPredicate(SqmMemberOfPredicate predicate) { public InSubQueryPredicate visitMemberOfPredicate(SqmMemberOfPredicate predicate) {
final SqmPath<?> pluralPath = predicate.getPluralPath(); final SqmPath<?> pluralPath = predicate.getPluralPath();
final PluralAttributeMapping mappingModelExpressable = (PluralAttributeMapping) determineValueMapping(pluralPath); final PluralAttributeMapping mappingModelExpressable = (PluralAttributeMapping) determineValueMapping(pluralPath);
@ -2217,6 +2274,10 @@ public abstract class BaseSqmToSqlAstConverter
inferableTypeAccessStack.push( inferableTypeAccessStack.push(
() -> ( (EntityCollectionPart) mappingModelExpressable.getElementDescriptor() ).getKeyTargetMatchPart() ); () -> ( (EntityCollectionPart) mappingModelExpressable.getElementDescriptor() ).getKeyTargetMatchPart() );
} }
else if ( mappingModelExpressable.getElementDescriptor() instanceof EmbeddedCollectionPart ) {
inferableTypeAccessStack.push(
() -> mappingModelExpressable.getElementDescriptor() );
}
else { else {
inferableTypeAccessStack.push( () -> mappingModelExpressable ); inferableTypeAccessStack.push( () -> mappingModelExpressable );
} }
@ -2229,15 +2290,15 @@ public abstract class BaseSqmToSqlAstConverter
inferableTypeAccessStack.pop(); inferableTypeAccessStack.pop();
} }
return new MemberOfPredicate( return new InSubQueryPredicate(
lhs, lhs,
predicate.isNegated(), createMemberOfSubQuery( pluralPath, mappingModelExpressable ),
createMemberOfSubQuery( pluralPath, mappingModelExpressable ) predicate.isNegated()
); );
} }
private QuerySpec createMemberOfSubQuery(SqmPath<?> pluralPath, PluralAttributeMapping mappingModelExpressable) { private QuerySpec createMemberOfSubQuery(SqmPath<?> pluralPath, PluralAttributeMapping mappingModelExpressable) {
final QuerySpec querySpec = new QuerySpec( true ); final QuerySpec querySpec = new QuerySpec( false );
processingStateStack.push( processingStateStack.push(
new SqlAstQuerySpecProcessingStateImpl( new SqlAstQuerySpecProcessingStateImpl(
querySpec, querySpec,

View File

@ -54,10 +54,10 @@ public class EmbeddableValuedPathInterpretation<T> extends AbstractSqmPathInterp
); );
} }
private final Expression sqlExpression; private final SqlTuple sqlExpression;
public EmbeddableValuedPathInterpretation( public EmbeddableValuedPathInterpretation(
Expression sqlExpression, SqlTuple sqlExpression,
SqmEmbeddedValuedSimplePath<T> sqmPath, SqmEmbeddedValuedSimplePath<T> sqmPath,
EmbeddableValuedModelPart mapping, EmbeddableValuedModelPart mapping,
TableGroup tableGroup) { TableGroup tableGroup) {
@ -65,7 +65,7 @@ public class EmbeddableValuedPathInterpretation<T> extends AbstractSqmPathInterp
this.sqlExpression = sqlExpression; this.sqlExpression = sqlExpression;
} }
public Expression getSqlExpression() { public SqlTuple getSqlExpression() {
return sqlExpression; return sqlExpression;
} }
@ -81,22 +81,13 @@ public class EmbeddableValuedPathInterpretation<T> extends AbstractSqmPathInterp
@Override @Override
public void visitColumnReferences(Consumer<ColumnReference> columnReferenceConsumer) { public void visitColumnReferences(Consumer<ColumnReference> columnReferenceConsumer) {
if ( sqlExpression instanceof ColumnReference ) { for ( Expression expression : sqlExpression.getExpressions() ) {
columnReferenceConsumer.accept( (ColumnReference) sqlExpression );
}
else if ( sqlExpression instanceof SqlTuple ) {
final SqlTuple sqlTuple = (SqlTuple) sqlExpression;
for ( Expression expression : sqlTuple.getExpressions() ) {
if ( !( expression instanceof ColumnReference ) ) { if ( !( expression instanceof ColumnReference ) ) {
throw new IllegalArgumentException( "Expecting ColumnReference, found : " + expression ); throw new IllegalArgumentException( "Expecting ColumnReference, found : " + expression );
} }
columnReferenceConsumer.accept( (ColumnReference) expression ); columnReferenceConsumer.accept( (ColumnReference) expression );
} }
} }
else {
// error or warning...
}
}
@Override @Override
public List<ColumnReference> getColumnReferences() { public List<ColumnReference> getColumnReferences() {

View File

@ -13,6 +13,7 @@ import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
/** /**
@ -30,7 +31,7 @@ public class NonAggregatedCompositeValuedPathInterpretation<T> extends AbstractS
final NonAggregatedIdentifierMappingImpl mapping = (NonAggregatedIdentifierMappingImpl) tableGroup.getModelPart() final NonAggregatedIdentifierMappingImpl mapping = (NonAggregatedIdentifierMappingImpl) tableGroup.getModelPart()
.findSubPart( sqmPath.getReferencedPathSource().getPathName(), null ); .findSubPart( sqmPath.getReferencedPathSource().getPathName(), null );
return new NonAggregatedCompositeValuedPathInterpretation( return new NonAggregatedCompositeValuedPathInterpretation<>(
mapping.toSqlExpression( mapping.toSqlExpression(
tableGroup, tableGroup,
converter.getCurrentClauseStack().getCurrent(), converter.getCurrentClauseStack().getCurrent(),
@ -43,10 +44,10 @@ public class NonAggregatedCompositeValuedPathInterpretation<T> extends AbstractS
); );
} }
private final Expression sqlExpression; private final SqlTuple sqlExpression;
public NonAggregatedCompositeValuedPathInterpretation( public NonAggregatedCompositeValuedPathInterpretation(
Expression sqlExpression, SqlTuple sqlExpression,
SqmPath<T> sqmPath, SqmPath<T> sqmPath,
ModelPart mapping, ModelPart mapping,
TableGroup tableGroup) { TableGroup tableGroup) {
@ -54,6 +55,10 @@ public class NonAggregatedCompositeValuedPathInterpretation<T> extends AbstractS
this.sqlExpression = sqlExpression; this.sqlExpression = sqlExpression;
} }
public SqlTuple getSqlExpression() {
return sqlExpression;
}
@Override @Override
public void accept(SqlAstWalker sqlTreeWalker) { public void accept(SqlAstWalker sqlTreeWalker) {
sqlExpression.accept( sqlTreeWalker ); sqlExpression.accept( sqlTreeWalker );

View File

@ -9,6 +9,7 @@ package org.hibernate.query.sqm.sql.internal;
import java.util.List; import java.util.List;
import java.util.function.Function; import java.util.function.Function;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.model.domain.AllowableParameterType; import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.query.SemanticException; import org.hibernate.query.SemanticException;
@ -49,9 +50,13 @@ public class SqmParameterInterpretation implements Expression, DomainResultProdu
assert jdbcParameters != null; assert jdbcParameters != null;
assert jdbcParameters.size() > 0; assert jdbcParameters.size() > 0;
this.resolvedExpression = jdbcParameters.size() == 1 this.resolvedExpression = valueMapping instanceof EmbeddableValuedModelPart
? jdbcParameters.get( 0 ) ? new SqlTuple( jdbcParameters, valueMapping )
: new SqlTuple( jdbcParameters, valueMapping ); : jdbcParameters.get( 0 );
}
public Expression getResolvedExpression() {
return resolvedExpression;
} }
@Override @Override

View File

@ -30,6 +30,7 @@ public class JpaCriteriaParameter<T>
extends AbstractSqmExpression<T> extends AbstractSqmExpression<T>
implements SqmParameter<T>, QueryParameterImplementor<T>, DomainResultProducer<T> { implements SqmParameter<T>, QueryParameterImplementor<T>, DomainResultProducer<T> {
private final String name; private final String name;
private final T value;
private boolean allowsMultiValuedBinding; private boolean allowsMultiValuedBinding;
public JpaCriteriaParameter( public JpaCriteriaParameter(
@ -39,6 +40,7 @@ public class JpaCriteriaParameter<T>
NodeBuilder nodeBuilder) { NodeBuilder nodeBuilder) {
super( type, nodeBuilder ); super( type, nodeBuilder );
this.name = name; this.name = name;
this.value = null;
this.allowsMultiValuedBinding = allowsMultiValuedBinding; this.allowsMultiValuedBinding = allowsMultiValuedBinding;
} }
public JpaCriteriaParameter( public JpaCriteriaParameter(
@ -48,11 +50,21 @@ public class JpaCriteriaParameter<T>
this( null, type, allowsMultiValuedBinding, nodeBuilder ); this( null, type, allowsMultiValuedBinding, nodeBuilder );
} }
public JpaCriteriaParameter(AllowableParameterType<T> type, T value, NodeBuilder criteriaBuilder) {
super( type, criteriaBuilder );
this.name = null;
this.value = value;
}
@Override @Override
public String getName() { public String getName() {
return name; return name;
} }
public T getValue() {
return value;
}
@Override @Override
public Integer getPosition() { public Integer getPosition() {
// for criteria anyway, these cannot be positional // for criteria anyway, these cannot be positional

View File

@ -18,8 +18,8 @@ public class SqmAny<T> extends AbstractSqmExpression<T> {
private final SqmSubQuery<T> subquery; private final SqmSubQuery<T> subquery;
public SqmAny(SqmSubQuery<T> subquery, SqmExpressable<T> type, NodeBuilder criteriaBuilder) { public SqmAny(SqmSubQuery<T> subquery, NodeBuilder criteriaBuilder) {
super(type, criteriaBuilder); super( subquery.getNodeType(), criteriaBuilder );
this.subquery = subquery; this.subquery = subquery;
} }

View File

@ -116,7 +116,7 @@ public class SqmCaseSearched<R>
@Override @Override
public SqmCaseSearched<R> when(Expression<Boolean> condition, R result) { public SqmCaseSearched<R> when(Expression<Boolean> condition, R result) {
when( nodeBuilder().wrap( condition ), nodeBuilder().literal( result ) ); when( nodeBuilder().wrap( condition ), nodeBuilder().value( result ) );
return this; return this;
} }
@ -129,7 +129,7 @@ public class SqmCaseSearched<R>
@Override @Override
public JpaExpression<R> otherwise(R result) { public JpaExpression<R> otherwise(R result) {
otherwise( nodeBuilder().literal( result ) ); otherwise( nodeBuilder().value( result ) );
return this; return this;
} }

View File

@ -129,7 +129,7 @@ public class SqmCaseSimple<T,R>
@Override @Override
public JpaSimpleCase<T, R> when(T condition, R result) { public JpaSimpleCase<T, R> when(T condition, R result) {
when( nodeBuilder().literal( condition ), nodeBuilder().literal( result ) ); when( nodeBuilder().literal( condition ), nodeBuilder().value( result ) );
return this; return this;
} }
@ -142,7 +142,7 @@ public class SqmCaseSimple<T,R>
@Override @Override
public JpaSimpleCase<T, R> otherwise(R result) { public JpaSimpleCase<T, R> otherwise(R result) {
otherwise( nodeBuilder().literal( result ) ); otherwise( nodeBuilder().value( result ) );
return this; return this;
} }

View File

@ -69,7 +69,7 @@ public class SqmCoalesce<T> extends AbstractSqmExpression<T> implements JpaCoale
@Override @Override
public SqmCoalesce<T> value(T value) { public SqmCoalesce<T> value(T value) {
value( nodeBuilder().literal( value ) ); value( nodeBuilder().value( value ) );
return this; return this;
} }
@ -91,7 +91,7 @@ public class SqmCoalesce<T> extends AbstractSqmExpression<T> implements JpaCoale
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public SqmCoalesce<T> values(T... values) { public SqmCoalesce<T> values(T... values) {
for ( T value : values ) { for ( T value : values ) {
value( nodeBuilder().literal( value ) ); value( nodeBuilder().value( value ) );
} }
return this; return this;
} }

View File

@ -0,0 +1,38 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.sqm.tree.expression;
import org.hibernate.query.sqm.SemanticQueryWalker;
/**
* @author Christian Beikov
*/
public class SqmCollate<T> extends AbstractSqmExpression<T> {
private final SqmExpression<T> expression;
private final String collation;
public SqmCollate(SqmExpression<T> expression, String collation) {
super( expression.getNodeType(), expression.nodeBuilder() );
assert !(expression instanceof SqmTuple);
this.expression = expression;
this.collation = collation;
}
public SqmExpression<T> getExpression() {
return expression;
}
public String getCollation() {
return collation;
}
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitCollate( this );
}
}

View File

@ -18,8 +18,8 @@ public class SqmEvery<T> extends AbstractSqmExpression<T> {
private final SqmSubQuery<T> subquery; private final SqmSubQuery<T> subquery;
public SqmEvery(SqmSubQuery<T> subquery, SqmExpressable<T> type, NodeBuilder criteriaBuilder) { public SqmEvery(SqmSubQuery<T> subquery, NodeBuilder criteriaBuilder) {
super(type, criteriaBuilder); super( subquery.getNodeType(), criteriaBuilder );
this.subquery = subquery; this.subquery = subquery;
} }

View File

@ -11,6 +11,7 @@ import java.util.function.Consumer;
import org.hibernate.metamodel.model.domain.AllowableParameterType; import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode; import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.ast.tree.expression.JdbcParameter;
@ -50,8 +51,9 @@ public class SqmJpaCriteriaParameterWrapper<T>
@Override @Override
public AllowableParameterType<T> getNodeType() { public AllowableParameterType<T> getNodeType() {
if ( super.getNodeType() instanceof AllowableParameterType ) { SqmExpressable<T> nodeType = super.getNodeType();
return ( (AllowableParameterType<T>) super.getNodeType() ); if ( nodeType == null || nodeType instanceof AllowableParameterType ) {
return ( (AllowableParameterType<T>) nodeType );
} }
throw new IllegalStateException( "Expecting AllowableParameterType as node type" ); throw new IllegalStateException( "Expecting AllowableParameterType as node type" );

View File

@ -74,11 +74,11 @@ public class SqmInListPredicate<T> extends AbstractNegatableSqmPredicate impleme
public SqmInPredicate<T> value(Object value) { public SqmInPredicate<T> value(Object value) {
if ( value instanceof Collection ) { if ( value instanceof Collection ) {
( (Collection) value ).forEach( ( (Collection) value ).forEach(
v -> addExpression( nodeBuilder().literal( v ) ) v -> addExpression( nodeBuilder().value( v ) )
); );
return this; return this;
} }
addExpression( nodeBuilder().literal( value ) ); addExpression( nodeBuilder().value( value ) );
return this; return this;
} }

View File

@ -1,88 +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.sqm.tree.select;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
/**
* Models the GROUP-BY clause of a SqmQuerySpec
*
* @author Steve Ebersole
*/
public class SqmGroupByClause {
private List<SqmGrouping> groupings;
public List<SqmGrouping> getGroupings() {
return groupings;
}
public void visitGroupings(Consumer<SqmGrouping> consumer) {
if ( groupings != null ) {
groupings.forEach( consumer );
}
}
public void setGroupings(List<SqmGrouping> groupings) {
this.groupings = groupings;
}
public void addGrouping(SqmGrouping grouping) {
if ( groupings == null ) {
groupings = new ArrayList<>();
}
groupings.add( grouping );
}
public void addGrouping(SqmExpression groupExpression) {
addGrouping( new SqmGrouping( groupExpression, null ) );
}
public void addGrouping(SqmExpression groupExpression, String collation) {
addGrouping( new SqmGrouping( groupExpression, collation ) );
}
public void clearGroupings() {
if ( groupings != null ) {
groupings.clear();
}
}
public static class SqmGrouping {
private SqmExpression expression;
// todo (6.0) : special type besides String?
private String collation;
public SqmGrouping() {
}
public SqmGrouping(SqmExpression expression, String collation) {
this.expression = expression;
this.collation = collation;
}
public SqmExpression getExpression() {
return expression;
}
public void setExpression(SqmExpression expression) {
this.expression = expression;
}
public String getCollation() {
return collation;
}
public void setCollation(String collation) {
this.collation = collation;
}
}
}

View File

@ -1,33 +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.sqm.tree.select;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
/**
* Models the HAVING clause of a SqmQuerySpec
*
* @author Steve Ebersole
*/
public class SqmHavingClause {
private SqmPredicate predicate;
public SqmHavingClause() {
}
public SqmHavingClause(SqmPredicate predicate) {
this.predicate = predicate;
}
public SqmPredicate getPredicate() {
return predicate;
}
public void setPredicate(SqmPredicate predicate) {
this.predicate = predicate;
}
}

View File

@ -44,13 +44,13 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
private SqmSelectClause selectClause; private SqmSelectClause selectClause;
private SqmWhereClause whereClause; private SqmWhereClause whereClause;
private SqmGroupByClause groupByClause; private List<SqmExpression<?>> groupByClauseExpressions = Collections.emptyList();
private SqmHavingClause havingClause; private SqmPredicate havingClausePredicate;
private SqmOrderByClause orderByClause; private SqmOrderByClause orderByClause;
private SqmExpression limitExpression; private SqmExpression<?> limitExpression;
private SqmExpression offsetExpression; private SqmExpression<?> offsetExpression;
public SqmQuerySpec(NodeBuilder nodeBuilder) { public SqmQuerySpec(NodeBuilder nodeBuilder) {
this.nodeBuilder = nodeBuilder; this.nodeBuilder = nodeBuilder;
@ -100,20 +100,22 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
whereClause.applyPredicate( predicate ); whereClause.applyPredicate( predicate );
} }
public SqmGroupByClause getGroupByClause() { public List<SqmExpression<?>> getGroupByClauseExpressions() {
return groupByClause; return groupByClauseExpressions;
} }
public void setGroupByClause(SqmGroupByClause groupByClause) { public void setGroupByClauseExpressions(List<SqmExpression<?>> groupByClauseExpressions) {
this.groupByClause = groupByClause; this.groupByClauseExpressions = groupByClauseExpressions == null
? Collections.emptyList()
: groupByClauseExpressions;
} }
public SqmHavingClause getHavingClause() { public SqmPredicate getHavingClausePredicate() {
return havingClause; return havingClausePredicate;
} }
public void setHavingClause(SqmHavingClause havingClause) { public void setHavingClausePredicate(SqmPredicate havingClausePredicate) {
this.havingClause = havingClause; this.havingClausePredicate = havingClausePredicate;
} }
public SqmOrderByClause getOrderByClause() { public SqmOrderByClause getOrderByClause() {
@ -124,7 +126,7 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
this.orderByClause = orderByClause; this.orderByClause = orderByClause;
} }
public SqmExpression getLimitExpression() { public SqmExpression<?> getLimitExpression() {
return limitExpression; return limitExpression;
} }
@ -135,7 +137,7 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
this.limitExpression = limitExpression; this.limitExpression = limitExpression;
} }
public SqmExpression getOffsetExpression() { public SqmExpression<?> getOffsetExpression() {
return offsetExpression; return offsetExpression;
} }
@ -157,7 +159,7 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
} }
@Override @Override
public SqmQuerySpec setDistinct(boolean distinct) { public SqmQuerySpec<T> setDistinct(boolean distinct) {
assert getSelectClause() != null; assert getSelectClause() != null;
getSelectClause().makeDistinct( distinct ); getSelectClause().makeDistinct( distinct );
return this; return this;
@ -171,7 +173,7 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
} }
@Override @Override
public SqmQuerySpec setSelection(JpaSelection<T> selection) { public SqmQuerySpec<T> setSelection(JpaSelection<T> selection) {
assert getSelectClause() != null; assert getSelectClause() != null;
// NOTE : this call comes from JPA which inherently supports just a // NOTE : this call comes from JPA which inherently supports just a
// single (possibly "compound") selection // single (possibly "compound") selection
@ -187,7 +189,7 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
} }
@Override @Override
public SqmQuerySpec addRoot(JpaRoot<?> root) { public SqmQuerySpec<T> addRoot(JpaRoot<?> root) {
if ( getFromClause() == null ) { if ( getFromClause() == null ) {
setFromClause( new SqmFromClause() ); setFromClause( new SqmFromClause() );
} }
@ -231,90 +233,48 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
} }
@Override @Override
public List<SqmExpression> getGroupingExpressions() { public List<SqmExpression<?>> getGroupingExpressions() {
if ( getGroupByClause() == null ) { return groupByClauseExpressions;
return Collections.emptyList();
}
final List<SqmExpression> list = new ArrayList<>();
getGroupByClause().visitGroupings(
sqmGrouping -> list.add( sqmGrouping.getExpression() )
);
return list;
} }
@Override @Override
public SqmQuerySpec<T> setGroupingExpressions(List<? extends JpaExpression<?>> groupExpressions) { public SqmQuerySpec<T> setGroupingExpressions(List<? extends JpaExpression<?>> groupExpressions) {
if ( getGroupByClause() == null ) { this.groupByClauseExpressions = new ArrayList<>( groupExpressions.size() );
setGroupByClause( new SqmGroupByClause() );
}
else {
getGroupByClause().clearGroupings();
}
for ( JpaExpression<?> groupExpression : groupExpressions ) { for ( JpaExpression<?> groupExpression : groupExpressions ) {
getGroupByClause().addGrouping( (SqmExpression) groupExpression ); this.groupByClauseExpressions.add( (SqmExpression<?>) groupExpression );
} }
return this; return this;
} }
@Override @Override
public SqmQuerySpec<T> setGroupingExpressions(JpaExpression<?>... groupExpressions) { public SqmQuerySpec<T> setGroupingExpressions(JpaExpression<?>... groupExpressions) {
if ( getGroupByClause() == null ) { this.groupByClauseExpressions = new ArrayList<>( groupExpressions.length );
setGroupByClause( new SqmGroupByClause() );
}
else {
getGroupByClause().clearGroupings();
}
for ( JpaExpression<?> groupExpression : groupExpressions ) { for ( JpaExpression<?> groupExpression : groupExpressions ) {
getGroupByClause().addGrouping( (SqmExpression) groupExpression ); this.groupByClauseExpressions.add( (SqmExpression<?>) groupExpression );
} }
return this; return this;
} }
@Override @Override
public SqmPredicate getGroupRestriction() { public SqmPredicate getGroupRestriction() {
if ( getHavingClause() == null ) { return havingClausePredicate;
return null;
}
return getHavingClause().getPredicate();
} }
@Override @Override
public SqmQuerySpec<T> setGroupRestriction(JpaPredicate restriction) { public SqmQuerySpec<T> setGroupRestriction(JpaPredicate restriction) {
if ( getHavingClause() == null ) { havingClausePredicate = (SqmPredicate) restriction;
setHavingClause( new SqmHavingClause( (SqmPredicate) restriction ) );
}
else {
getHavingClause().setPredicate( (SqmPredicate) restriction );
}
return this; return this;
} }
@Override @Override
public SqmQuerySpec<T> setGroupRestriction(Expression<Boolean> restriction) { public SqmQuerySpec<T> setGroupRestriction(Expression<Boolean> restriction) {
final SqmPredicate predicate = nodeBuilder.wrap( restriction ); havingClausePredicate = nodeBuilder.wrap( restriction );
if ( getHavingClause() == null ) {
setHavingClause( new SqmHavingClause( predicate ));
}
else {
getHavingClause().setPredicate( predicate );
}
return this; return this;
} }
@Override @Override
public SqmQuerySpec<T> setGroupRestriction(Predicate... restrictions) { public SqmQuerySpec<T> setGroupRestriction(Predicate... restrictions) {
final SqmPredicate predicate = nodeBuilder.wrap( restrictions ); havingClausePredicate = nodeBuilder.wrap( restrictions );
if ( getHavingClause() == null ) {
setHavingClause( new SqmHavingClause( predicate ));
}
else {
getHavingClause().setPredicate( predicate );
}
return this; return this;
} }
@ -341,25 +301,25 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public SqmExpression getLimit() { public SqmExpression<?> getLimit() {
return getLimitExpression(); return getLimitExpression();
} }
@Override @Override
public SqmQuerySpec<T> setLimit(JpaExpression<?> limit) { public SqmQuerySpec<T> setLimit(JpaExpression<?> limit) {
setLimitExpression( (SqmExpression) limit ); setLimitExpression( (SqmExpression<?>) limit );
return this; return this;
} }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public SqmExpression getOffset() { public SqmExpression<?> getOffset() {
return getOffsetExpression(); return getOffsetExpression();
} }
@Override @Override
public SqmQuerySpec<T> setOffset(JpaExpression offset) { public SqmQuerySpec<T> setOffset(JpaExpression<?> offset) {
setOffsetExpression( (SqmExpression) offset ); setOffsetExpression( (SqmExpression<?>) offset );
return this; return this;
} }
} }

View File

@ -17,42 +17,31 @@ import org.hibernate.query.sqm.tree.expression.SqmExpression;
*/ */
public class SqmSortSpecification implements JpaOrder { public class SqmSortSpecification implements JpaOrder {
private final SqmExpression sortExpression; private final SqmExpression sortExpression;
private final String collation;
private final SortOrder sortOrder; private final SortOrder sortOrder;
private NullPrecedence nullPrecedence; private NullPrecedence nullPrecedence;
public SqmSortSpecification( public SqmSortSpecification(
SqmExpression sortExpression, SqmExpression sortExpression,
String collation,
SortOrder sortOrder, SortOrder sortOrder,
NullPrecedence nullPrecedence) { NullPrecedence nullPrecedence) {
this.sortExpression = sortExpression; this.sortExpression = sortExpression;
this.collation = collation;
this.sortOrder = sortOrder; this.sortOrder = sortOrder;
this.nullPrecedence = nullPrecedence; this.nullPrecedence = nullPrecedence;
} }
public SqmSortSpecification(SqmExpression sortExpression) { public SqmSortSpecification(SqmExpression sortExpression) {
this( sortExpression, null, SortOrder.ASCENDING, null ); this( sortExpression, SortOrder.ASCENDING, null );
} }
public SqmSortSpecification(SqmExpression sortExpression, SortOrder sortOrder) { public SqmSortSpecification(SqmExpression sortExpression, SortOrder sortOrder) {
this( sortExpression, null, sortOrder, null ); this( sortExpression, sortOrder, null );
}
public SqmSortSpecification(SqmExpression sortExpression, SortOrder sortOrder, NullPrecedence nullPrecedence) {
this( sortExpression, null, sortOrder, nullPrecedence );
} }
public SqmExpression getSortExpression() { public SqmExpression getSortExpression() {
return sortExpression; return sortExpression;
} }
public String getCollation() {
return collation;
}
public SortOrder getSortOrder() { public SortOrder getSortOrder() {
return sortOrder; return sortOrder;
} }
@ -75,7 +64,7 @@ public class SqmSortSpecification implements JpaOrder {
@Override @Override
public JpaOrder reverse() { public JpaOrder reverse() {
SortOrder newSortOrder = this.sortOrder == null ? SortOrder.DESCENDING : sortOrder.reverse(); SortOrder newSortOrder = this.sortOrder == null ? SortOrder.DESCENDING : sortOrder.reverse();
return new SqmSortSpecification( sortExpression, collation, newSortOrder, nullPrecedence ); return new SqmSortSpecification( sortExpression, newSortOrder, nullPrecedence );
} }
@Override @Override

View File

@ -14,6 +14,7 @@ import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression; import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression; import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
import org.hibernate.sql.ast.tree.expression.CastTarget; import org.hibernate.sql.ast.tree.expression.CastTarget;
import org.hibernate.sql.ast.tree.expression.Collate;
import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Distinct; import org.hibernate.sql.ast.tree.expression.Distinct;
import org.hibernate.sql.ast.tree.expression.Duration; import org.hibernate.sql.ast.tree.expression.Duration;
@ -45,7 +46,6 @@ import org.hibernate.sql.ast.tree.predicate.InListPredicate;
import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate; import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate;
import org.hibernate.sql.ast.tree.predicate.Junction; import org.hibernate.sql.ast.tree.predicate.Junction;
import org.hibernate.sql.ast.tree.predicate.LikePredicate; import org.hibernate.sql.ast.tree.predicate.LikePredicate;
import org.hibernate.sql.ast.tree.predicate.MemberOfPredicate;
import org.hibernate.sql.ast.tree.predicate.NegatedPredicate; import org.hibernate.sql.ast.tree.predicate.NegatedPredicate;
import org.hibernate.sql.ast.tree.predicate.NullnessPredicate; import org.hibernate.sql.ast.tree.predicate.NullnessPredicate;
import org.hibernate.sql.ast.tree.predicate.SelfRenderingPredicate; import org.hibernate.sql.ast.tree.predicate.SelfRenderingPredicate;
@ -114,6 +114,8 @@ public interface SqlAstWalker {
void visitTuple(SqlTuple tuple); void visitTuple(SqlTuple tuple);
void visitCollate(Collate collate);
void visitParameter(JdbcParameter jdbcParameter); void visitParameter(JdbcParameter jdbcParameter);
void visitJdbcLiteral(JdbcLiteral jdbcLiteral); void visitJdbcLiteral(JdbcLiteral jdbcLiteral);
@ -152,5 +154,4 @@ public interface SqlAstWalker {
void visitConversion(Conversion conversion); void visitConversion(Conversion conversion);
void visitMemberOfPredicate(MemberOfPredicate memberOfPredicate);
} }

View File

@ -6,11 +6,15 @@
*/ */
package org.hibernate.sql.ast.spi; package org.hibernate.sql.ast.spi;
import java.sql.Timestamp;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.TimeZone;
import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.NullPrecedence; import org.hibernate.NullPrecedence;
@ -18,6 +22,8 @@ import org.hibernate.SortOrder;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SessionLazyDelegatorBaseImpl;
import org.hibernate.internal.FilterJdbcParameter; import org.hibernate.internal.FilterJdbcParameter;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.Stack; import org.hibernate.internal.util.collections.Stack;
@ -28,9 +34,12 @@ import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.internal.BasicValuedCollectionPart; import org.hibernate.metamodel.mapping.internal.BasicValuedCollectionPart;
import org.hibernate.persister.entity.Loadable; import org.hibernate.persister.entity.Loadable;
import org.hibernate.query.QueryLiteralRendering; import org.hibernate.query.ComparisonOperator;
import org.hibernate.query.UnaryArithmeticOperator; import org.hibernate.query.UnaryArithmeticOperator;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.sql.internal.EmbeddableValuedPathInterpretation; import org.hibernate.query.sqm.sql.internal.EmbeddableValuedPathInterpretation;
import org.hibernate.query.sqm.sql.internal.NonAggregatedCompositeValuedPathInterpretation;
import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation;
import org.hibernate.query.sqm.tree.expression.Conversion; import org.hibernate.query.sqm.tree.expression.Conversion;
import org.hibernate.sql.ast.Clause; import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstJoinType; import org.hibernate.sql.ast.SqlAstJoinType;
@ -40,6 +49,7 @@ import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression; import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression; import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
import org.hibernate.sql.ast.tree.expression.CastTarget; import org.hibernate.sql.ast.tree.expression.CastTarget;
import org.hibernate.sql.ast.tree.expression.Collate;
import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Distinct; import org.hibernate.sql.ast.tree.expression.Distinct;
import org.hibernate.sql.ast.tree.expression.Duration; import org.hibernate.sql.ast.tree.expression.Duration;
@ -52,6 +62,7 @@ import org.hibernate.sql.ast.tree.expression.Format;
import org.hibernate.sql.ast.tree.expression.JdbcLiteral; import org.hibernate.sql.ast.tree.expression.JdbcLiteral;
import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.expression.Literal; import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.LiteralAsParameter;
import org.hibernate.sql.ast.tree.expression.QueryLiteral; import org.hibernate.sql.ast.tree.expression.QueryLiteral;
import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression; import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression;
import org.hibernate.sql.ast.tree.expression.SqlSelectionExpression; import org.hibernate.sql.ast.tree.expression.SqlSelectionExpression;
@ -74,7 +85,6 @@ import org.hibernate.sql.ast.tree.predicate.InListPredicate;
import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate; import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate;
import org.hibernate.sql.ast.tree.predicate.Junction; import org.hibernate.sql.ast.tree.predicate.Junction;
import org.hibernate.sql.ast.tree.predicate.LikePredicate; import org.hibernate.sql.ast.tree.predicate.LikePredicate;
import org.hibernate.sql.ast.tree.predicate.MemberOfPredicate;
import org.hibernate.sql.ast.tree.predicate.NegatedPredicate; import org.hibernate.sql.ast.tree.predicate.NegatedPredicate;
import org.hibernate.sql.ast.tree.predicate.NullnessPredicate; import org.hibernate.sql.ast.tree.predicate.NullnessPredicate;
import org.hibernate.sql.ast.tree.predicate.Predicate; import org.hibernate.sql.ast.tree.predicate.Predicate;
@ -84,28 +94,24 @@ import org.hibernate.sql.ast.tree.select.SelectClause;
import org.hibernate.sql.ast.tree.select.SortSpecification; import org.hibernate.sql.ast.tree.select.SortSpecification;
import org.hibernate.sql.exec.internal.JdbcParametersImpl; import org.hibernate.sql.exec.internal.JdbcParametersImpl;
import org.hibernate.sql.exec.spi.JdbcParameterBinder; import org.hibernate.sql.exec.spi.JdbcParameterBinder;
import org.hibernate.type.IntegerType;
import org.hibernate.type.descriptor.sql.JdbcLiteralFormatter; 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.descriptor.sql.SqlTypeDescriptorIndicators;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.query.TemporalUnit.NANOSECOND; import static org.hibernate.query.TemporalUnit.NANOSECOND;
import static org.hibernate.sql.ast.spi.SqlAppender.CLOSE_PARENTHESIS;
import static org.hibernate.sql.ast.spi.SqlAppender.COMA_SEPARATOR;
import static org.hibernate.sql.ast.spi.SqlAppender.EMPTY_STRING;
import static org.hibernate.sql.ast.spi.SqlAppender.NO_SEPARATOR;
import static org.hibernate.sql.ast.spi.SqlAppender.NULL_KEYWORD;
import static org.hibernate.sql.ast.spi.SqlAppender.OPEN_PARENTHESIS;
import static org.hibernate.sql.ast.spi.SqlAppender.PARAM_MARKER;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public abstract class AbstractSqlAstWalker public abstract class AbstractSqlAstWalker
implements SqlAstWalker, SqlTypeDescriptorIndicators { implements SqlAstWalker, SqlTypeDescriptorIndicators, SqlAppender {
private static final QueryLiteral<Integer> ONE_LITERAL = new QueryLiteral<>( 1, IntegerType.INSTANCE );
// pre-req state // pre-req state
private final SessionFactoryImplementor sessionFactory; private final SessionFactoryImplementor sessionFactory;
private final SqlAppender sqlAppender = this::appendSql;
// In-flight state // In-flight state
private final StringBuilder sqlBuffer = new StringBuilder(); private final StringBuilder sqlBuffer = new StringBuilder();
@ -118,6 +124,8 @@ public abstract class AbstractSqlAstWalker
private final Stack<Clause> clauseStack = new StandardStack<>(); private final Stack<Clause> clauseStack = new StandardStack<>();
private final Dialect dialect; private final Dialect dialect;
private transient AbstractSqmSelfRenderingFunctionDescriptor castFunction;
private transient LazySession session;
public Dialect getDialect() { public Dialect getDialect() {
return dialect; return dialect;
@ -133,10 +141,75 @@ public abstract class AbstractSqlAstWalker
return sessionFactory; return sessionFactory;
} }
protected AbstractSqmSelfRenderingFunctionDescriptor castFunction() {
if ( castFunction == null ) {
castFunction = (AbstractSqmSelfRenderingFunctionDescriptor) sessionFactory
.getQueryEngine()
.getSqmFunctionRegistry()
.findFunctionDescriptor( "cast" );
}
return castFunction;
}
protected SessionLazyDelegatorBaseImpl getSession() {
if ( session == null ) {
session = new LazySession( sessionFactory );
}
return session;
}
/**
* A lazy session implementation that is needed for rendering literals.
* Usually, only the {@link org.hibernate.type.descriptor.WrapperOptions} interface is needed,
* but for creating LOBs, it might be to have a full blown session.
*/
private static class LazySession extends SessionLazyDelegatorBaseImpl {
private final SessionFactoryImplementor sessionFactory;
private SessionImplementor session;
public LazySession(SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
}
public void cleanup() {
if ( session != null ) {
session.close();
session = null;
}
}
@Override
protected SessionImplementor delegate() {
if ( session == null ) {
session = (SessionImplementor) sessionFactory.openTemporarySession();
}
return session;
}
@Override
public boolean useStreamForLobBinding() {
return sessionFactory.getFastSessionServices().useStreamForLobBinding();
}
@Override
public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
return sessionFactory.getFastSessionServices().remapSqlTypeDescriptor( sqlTypeDescriptor );
}
@Override
public TimeZone getJdbcTimeZone() {
return sessionFactory.getSessionFactoryOptions().getJdbcTimeZone();
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// for tests, for now // for tests, for now
public String getSql() { public String getSql() {
if ( session != null ) {
session.cleanup();
session = null;
}
return sqlBuffer.toString(); return sqlBuffer.toString();
} }
@ -152,16 +225,16 @@ public abstract class AbstractSqlAstWalker
@SuppressWarnings("unused") @SuppressWarnings("unused")
protected SqlAppender getSqlAppender() { protected SqlAppender getSqlAppender() {
return sqlAppender; return this;
} }
@SuppressWarnings("WeakerAccess") @Override
protected void appendSql(String fragment) { public void appendSql(String fragment) {
sqlBuffer.append( fragment ); sqlBuffer.append( fragment );
} }
@SuppressWarnings("WeakerAccess") @Override
protected void appendSql(char fragment) { public void appendSql(char fragment) {
sqlBuffer.append( fragment ); sqlBuffer.append( fragment );
} }
@ -187,21 +260,20 @@ public abstract class AbstractSqlAstWalker
if ( !querySpec.isRoot() ) { if ( !querySpec.isRoot() ) {
appendSql( " (" ); appendSql( " (" );
} }
visitSelectClause( querySpec.getSelectClause() ); visitSelectClause( querySpec.getSelectClause() );
visitFromClause( querySpec.getFromClause() );
visitWhereClause( querySpec );
visitGroupByClause( querySpec );
visitHavingClause( querySpec );
visitOrderBy( querySpec );
visitLimitOffsetClause( querySpec );
FromClause fromClause = querySpec.getFromClause(); if ( !querySpec.isRoot() ) {
if ( fromClause == null || fromClause.getRoots().isEmpty() ) { appendSql( ")" );
String fromDual = getDialect().getFromDual();
if ( !fromDual.isEmpty() ) {
appendSql( " " );
appendSql( fromDual );
} }
} }
else {
visitFromClause( fromClause );
}
protected final void visitWhereClause(QuerySpec querySpec) {
final Predicate whereClauseRestrictions = querySpec.getWhereClauseRestrictions(); final Predicate whereClauseRestrictions = querySpec.getWhereClauseRestrictions();
if ( whereClauseRestrictions != null && !whereClauseRestrictions.isEmpty() ) { if ( whereClauseRestrictions != null && !whereClauseRestrictions.isEmpty() ) {
appendSql( " where " ); appendSql( " where " );
@ -214,11 +286,50 @@ public abstract class AbstractSqlAstWalker
clauseStack.pop(); clauseStack.pop();
} }
} }
}
protected final void visitGroupByClause(QuerySpec querySpec) {
List<Expression> groupByClauseExpressions = querySpec.getGroupByClauseExpressions();
if ( !groupByClauseExpressions.isEmpty() ) {
appendSql( " group by " );
clauseStack.push( Clause.GROUP );
String separator = NO_SEPARATOR;
try {
for ( Expression groupByClauseExpression : groupByClauseExpressions ) {
appendSql( separator );
groupByClauseExpression.accept( this );
separator = COMA_SEPARATOR;
}
}
finally {
clauseStack.pop();
}
}
}
protected final void visitHavingClause(QuerySpec querySpec) {
final Predicate havingClauseRestrictions = querySpec.getHavingClauseRestrictions();
if ( havingClauseRestrictions != null && !havingClauseRestrictions.isEmpty() ) {
appendSql( " having " );
clauseStack.push( Clause.HAVING );
try {
havingClauseRestrictions.accept( this );
}
finally {
clauseStack.pop();
}
}
}
protected final void visitOrderBy(QuerySpec querySpec) {
final List<SortSpecification> sortSpecifications = querySpec.getSortSpecifications(); final List<SortSpecification> sortSpecifications = querySpec.getSortSpecifications();
if ( sortSpecifications != null && !sortSpecifications.isEmpty() ) { if ( sortSpecifications != null && !sortSpecifications.isEmpty() ) {
appendSql( " order by " ); appendSql( " order by " );
clauseStack.push( Clause.ORDER );
try {
String separator = NO_SEPARATOR; String separator = NO_SEPARATOR;
for ( SortSpecification sortSpecification : sortSpecifications ) { for ( SortSpecification sortSpecification : sortSpecifications ) {
appendSql( separator ); appendSql( separator );
@ -226,11 +337,101 @@ public abstract class AbstractSqlAstWalker
separator = COMA_SEPARATOR; separator = COMA_SEPARATOR;
} }
} }
finally {
clauseStack.pop();
}
}
}
visitLimitOffsetClause( querySpec ); protected void emulateTupleComparison(final List<? extends Expression> lhsExpressions, final List<? extends Expression> rhsExpressions, ComparisonOperator operator) {
String separator = NO_SEPARATOR;
if ( !querySpec.isRoot() ) { final boolean isCurrentWhereClause = clauseStack.getCurrent() == Clause.WHERE;
appendSql( ")" ); if ( isCurrentWhereClause ) {
appendSql( OPEN_PARENTHESIS );
}
final int size = lhsExpressions.size();
final String operatorText = operator.sqlText();
assert size == rhsExpressions.size();
switch ( operator ) {
case EQUAL:
case NOT_EQUAL:
for ( int i = 0; i < size; i++ ) {
appendSql( separator );
lhsExpressions.get( i ).accept( this );
appendSql( operatorText );
rhsExpressions.get( i ).accept( this );
separator = " and ";
}
break;
case LESS_THAN_OR_EQUAL:
case GREATER_THAN_OR_EQUAL:
// Render (a, b) <= (1, 2) as: (a = 1 and b = 2) or (a < 1 or a = 1 and b < 2)
appendSql( OPEN_PARENTHESIS );
for ( int i = 0; i < size; i++ ) {
appendSql( separator );
lhsExpressions.get( i ).accept( this );
appendSql( operatorText );
rhsExpressions.get( i ).accept( this );
separator = " and ";
}
appendSql( CLOSE_PARENTHESIS );
appendSql( " or " );
separator = NO_SEPARATOR;
case LESS_THAN:
case GREATER_THAN:
// Render (a, b) < (1, 2) as: (a < 1 or a = 1 and b < 2)
appendSql( OPEN_PARENTHESIS );
for ( int i = 0; i < size; i++ ) {
int j = 0;
// Render the equals parts
for ( ; j < i; j++ ) {
appendSql( separator );
lhsExpressions.get( i ).accept( this );
appendSql( '=' );
rhsExpressions.get( i ).accept( this );
separator = " and ";
}
// Render the actual operator part for the current component
appendSql( separator );
lhsExpressions.get( i ).accept( this );
appendSql( operatorText );
rhsExpressions.get( i ).accept( this );
separator = " or ";
}
appendSql( CLOSE_PARENTHESIS );
break;
}
if ( isCurrentWhereClause ) {
appendSql( CLOSE_PARENTHESIS );
}
}
protected void renderSelectTupleComparison(final List<SqlSelection> lhsExpressions, SqlTuple tuple, ComparisonOperator operator) {
if ( dialect.supportsRowValueConstructorSyntax() ) {
appendSql( OPEN_PARENTHESIS );
String separator = NO_SEPARATOR;
for ( SqlSelection lhsExpression : lhsExpressions ) {
appendSql( separator );
lhsExpression.getExpression().accept( this );
separator = COMA_SEPARATOR;
}
appendSql( CLOSE_PARENTHESIS );
appendSql( " " );
appendSql( operator.sqlText() );
appendSql( " " );
tuple.accept( this );
}
else {
final List<Expression> lhs = new ArrayList<>( lhsExpressions.size() );
for ( SqlSelection lhsExpression : lhsExpressions ) {
lhs.add( lhsExpression.getExpression() );
}
emulateTupleComparison( lhs, tuple.getExpressions(), operator );
} }
} }
@ -258,12 +459,6 @@ public abstract class AbstractSqlAstWalker
sortSpecification.getSortExpression().accept( this ); sortSpecification.getSortExpression().accept( this );
final String collation = sortSpecification.getCollation();
if ( collation != null ) {
appendSql( " collate " );
appendSql( collation );
}
final SortOrder sortOrder = sortSpecification.getSortOrder(); final SortOrder sortOrder = sortSpecification.getSortOrder();
if ( sortOrder == SortOrder.ASCENDING ) { if ( sortOrder == SortOrder.ASCENDING ) {
appendSql( " asc" ); appendSql( " asc" );
@ -284,25 +479,25 @@ public abstract class AbstractSqlAstWalker
@Override @Override
public void visitLimitOffsetClause(QuerySpec querySpec) { public void visitLimitOffsetClause(QuerySpec querySpec) {
if ( querySpec.getOffsetClauseExpression() != null ) { if ( querySpec.getOffsetClauseExpression() != null ) {
renderOffset( querySpec ); renderOffset( querySpec.getOffsetClauseExpression() );
} }
if ( querySpec.getLimitClauseExpression() != null ) { if ( querySpec.getLimitClauseExpression() != null ) {
renderLimit( querySpec ); renderLimit( querySpec.getLimitClauseExpression() );
} }
} }
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
protected void renderOffset(QuerySpec querySpec) { protected void renderOffset(Expression offsetExpression) {
appendSql( " offset " ); appendSql( " offset " );
querySpec.getOffsetClauseExpression().accept( this ); offsetExpression.accept( this );
appendSql( " rows" ); appendSql( " rows" );
} }
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
protected void renderLimit(QuerySpec querySpec) { protected void renderLimit(Expression limitExpression) {
appendSql( " fetch first " ); appendSql( " fetch first " );
querySpec.getLimitClauseExpression().accept( this ); limitExpression.accept( this );
appendSql( " rows only" ); appendSql( " rows only" );
} }
@ -343,6 +538,14 @@ public abstract class AbstractSqlAstWalker
@Override @Override
public void visitFromClause(FromClause fromClause) { public void visitFromClause(FromClause fromClause) {
if ( fromClause == null || fromClause.getRoots().isEmpty() ) {
String fromDual = getDialect().getFromDual();
if ( !fromDual.isEmpty() ) {
appendSql( " " );
appendSql( fromDual );
}
}
else {
appendSql( " from " ); appendSql( " from " );
String separator = NO_SEPARATOR; String separator = NO_SEPARATOR;
@ -352,6 +555,7 @@ public abstract class AbstractSqlAstWalker
separator = COMA_SEPARATOR; separator = COMA_SEPARATOR;
} }
} }
}
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
protected void renderTableGroup(TableGroup tableGroup) { protected void renderTableGroup(TableGroup tableGroup) {
@ -399,12 +603,12 @@ public abstract class AbstractSqlAstWalker
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
protected void renderTableReference(TableReference tableReference) { protected void renderTableReference(TableReference tableReference) {
sqlAppender.appendSql( tableReference.getTableExpression() ); appendSql( tableReference.getTableExpression() );
final String identificationVariable = tableReference.getIdentificationVariable(); final String identificationVariable = tableReference.getIdentificationVariable();
if ( identificationVariable != null ) { if ( identificationVariable != null ) {
sqlAppender.appendSql( getDialect().getTableAliasSeparator() ); appendSql( getDialect().getTableAliasSeparator() );
sqlAppender.appendSql( identificationVariable ); appendSql( identificationVariable );
} }
} }
@ -416,14 +620,14 @@ public abstract class AbstractSqlAstWalker
} }
for ( TableReferenceJoin tableJoin : joins ) { for ( TableReferenceJoin tableJoin : joins ) {
sqlAppender.appendSql( EMPTY_STRING ); appendSql( EMPTY_STRING );
sqlAppender.appendSql( tableJoin.getJoinType().getText() ); appendSql( tableJoin.getJoinType().getText() );
sqlAppender.appendSql( " join " ); appendSql( " join " );
renderTableReference( tableJoin.getJoinedTableReference() ); renderTableReference( tableJoin.getJoinedTableReference() );
if ( tableJoin.getJoinPredicate() != null && !tableJoin.getJoinPredicate().isEmpty() ) { if ( tableJoin.getJoinPredicate() != null && !tableJoin.getJoinPredicate().isEmpty() ) {
sqlAppender.appendSql( " on " ); appendSql( " on " );
tableJoin.getJoinPredicate().accept( this ); tableJoin.getJoinPredicate().accept( this );
} }
} }
@ -590,6 +794,12 @@ public abstract class AbstractSqlAstWalker
} }
} }
@Override
public void visitCollate(Collate collate) {
collate.getExpression().accept( this );
dialect.appendCollate( this, collate.getCollation() );
}
@Override @Override
public void visitSqlSelectionExpression(SqlSelectionExpression expression) { public void visitSqlSelectionExpression(SqlSelectionExpression expression) {
final boolean useSelectionPosition = dialect.replaceResultVariableInOrderByClauseWithPosition(); final boolean useSelectionPosition = dialect.replaceResultVariableInOrderByClauseWithPosition();
@ -907,7 +1117,7 @@ public abstract class AbstractSqlAstWalker
@Override @Override
public void visitDuration(Duration duration) { public void visitDuration(Duration duration) {
duration.getMagnitude().accept( this ); duration.getMagnitude().accept( this );
sqlAppender.appendSql( appendSql(
duration.getUnit().conversionFactor( NANOSECOND, getDialect() ) duration.getUnit().conversionFactor( NANOSECOND, getDialect() )
); );
} }
@ -915,25 +1125,13 @@ public abstract class AbstractSqlAstWalker
@Override @Override
public void visitConversion(Conversion conversion) { public void visitConversion(Conversion conversion) {
conversion.getDuration().getMagnitude().accept( this ); conversion.getDuration().getMagnitude().accept( this );
sqlAppender.appendSql( appendSql(
conversion.getDuration().getUnit().conversionFactor( conversion.getDuration().getUnit().conversionFactor(
conversion.getUnit(), getDialect() conversion.getUnit(), getDialect()
) )
); );
} }
@Override
public void visitMemberOfPredicate(MemberOfPredicate memberOfPredicate) {
memberOfPredicate.getLeftHandExpression().accept( this );
if ( memberOfPredicate.isNegated() ) {
appendSql( " not " );
}
appendSql( " in (" );
visitQuerySpec( memberOfPredicate.getQuerySpec() );
appendSql( ")" );
}
@Override @Override
public void visitCaseSearchedExpression(CaseSearchedExpression caseSearchedExpression) { public void visitCaseSearchedExpression(CaseSearchedExpression caseSearchedExpression) {
dialect.getCaseExpressionWalker().visitCaseSearchedExpression( caseSearchedExpression, sqlBuffer, this ); dialect.getCaseExpressionWalker().visitCaseSearchedExpression( caseSearchedExpression, sqlBuffer, this );
@ -966,72 +1164,18 @@ public abstract class AbstractSqlAstWalker
every.getSubquery().accept( this ); every.getSubquery().accept( this );
} }
// @Override
// public void visitGenericParameter(GenericParameter parameter) {
// visitJdbcParameterBinder( parameter.getParameterBinder() );
//
// if ( parameter instanceof JdbcParameter ) {
// jdbcParameters.addParameter( (JdbcParameter) parameter );
// }
// }
protected void visitJdbcParameterBinder(JdbcParameterBinder jdbcParameterBinder) {
parameterBinders.add( jdbcParameterBinder );
// todo (6.0) : ? wrap in cast function call if the literal occurs in SELECT (?based on Dialect?)
appendSql( "?" );
}
// @Override
// public void visitNamedParameter(NamedParameter namedParameter) {
// visitJdbcParameterBinder( namedParameter );
// }
//
// @Override
// public void visitPositionalParameter(PositionalParameter positionalParameter) {
// visitJdbcParameterBinder( positionalParameter );
// }
@Override @Override
public void visitJdbcLiteral(JdbcLiteral jdbcLiteral) { public void visitJdbcLiteral(JdbcLiteral jdbcLiteral) {
renderAsLiteral( jdbcLiteral ); visitLiteral( jdbcLiteral );
} }
@Override @Override
public void visitQueryLiteral(QueryLiteral queryLiteral) { public void visitQueryLiteral(QueryLiteral queryLiteral) {
final QueryLiteralRendering queryLiteralRendering = getSessionFactory().getSessionFactoryOptions().getQueryLiteralRenderingMode(); visitLiteral( queryLiteral );
switch( queryLiteralRendering ) {
case AS_LITERAL: {
renderAsLiteral( queryLiteral );
break;
}
case AS_PARAM: {
visitJdbcParameterBinder( queryLiteral );
break;
}
case AUTO:
case AS_PARAM_OUTSIDE_SELECT: {
if ( clauseStack.getCurrent() == Clause.SELECT ) {
renderAsLiteral( queryLiteral );
}
else {
visitJdbcParameterBinder( queryLiteral );
}
break;
}
default: {
throw new IllegalArgumentException(
"Unrecognized QueryLiteralRendering : " + queryLiteralRendering
);
}
}
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void renderAsLiteral(Literal literal) { private void visitLiteral(Literal literal) {
if ( literal.getLiteralValue() == null ) { if ( literal.getLiteralValue() == null ) {
// todo : not sure we allow this "higher up" // todo : not sure we allow this "higher up"
appendSql( SqlAppender.NULL_KEYWORD ); appendSql( SqlAppender.NULL_KEYWORD );
@ -1040,15 +1184,27 @@ public abstract class AbstractSqlAstWalker
assert literal.getExpressionType().getJdbcTypeCount( getTypeConfiguration() ) == 1; assert literal.getExpressionType().getJdbcTypeCount( getTypeConfiguration() ) == 1;
final JdbcMapping jdbcMapping = literal.getJdbcMapping(); final JdbcMapping jdbcMapping = literal.getJdbcMapping();
final JdbcLiteralFormatter literalFormatter = jdbcMapping.getSqlTypeDescriptor().getJdbcLiteralFormatter( jdbcMapping.getJavaTypeDescriptor() ); final JdbcLiteralFormatter literalFormatter = jdbcMapping.getSqlTypeDescriptor().getJdbcLiteralFormatter( jdbcMapping.getJavaTypeDescriptor() );
if ( literalFormatter == null ) {
parameterBinders.add( literal );
if ( clauseStack.getCurrent() == Clause.SELECT && dialect.requiresCastingOfParametersInSelectClause() ) {
castFunction().render( this, Collections.singletonList( new LiteralAsParameter<>( literal ) ), this );
}
else {
parameterBinders.add( literal );
}
}
else {
appendSql( appendSql(
literalFormatter.toJdbcLiteral( literalFormatter.toJdbcLiteral(
literal.getLiteralValue(), literal.getLiteralValue(),
dialect, dialect,
null getSession()
) )
); );
} }
} }
}
@Override @Override
public void visitUnaryOperationExpression(UnaryOperation unaryOperationExpression) { public void visitUnaryOperationExpression(UnaryOperation unaryOperationExpression) {
@ -1069,7 +1225,7 @@ public abstract class AbstractSqlAstWalker
@Override @Override
public void visitSelfRenderingExpression(SelfRenderingExpression expression) { public void visitSelfRenderingExpression(SelfRenderingExpression expression) {
expression.renderToSql( sqlAppender, this, getSessionFactory() ); expression.renderToSql( this, this, getSessionFactory() );
} }
// @Override // @Override
@ -1118,6 +1274,17 @@ public abstract class AbstractSqlAstWalker
@Override @Override
public void visitInListPredicate(InListPredicate inListPredicate) { public void visitInListPredicate(InListPredicate inListPredicate) {
final SqlTuple lhsTuple;
if ( ( lhsTuple = getTuple( inListPredicate.getTestExpression() ) ) != null && !dialect.supportsRowValueConstructorSyntaxInInList() ) {
final ComparisonOperator comparisonOperator = inListPredicate.isNegated() ? ComparisonOperator.NOT_EQUAL : ComparisonOperator.EQUAL;
String separator = NO_SEPARATOR;
for ( Expression expression : inListPredicate.getListExpressions() ) {
appendSql( separator );
emulateTupleComparison( lhsTuple.getExpressions(), getTuple( expression ).getExpressions(), comparisonOperator );
separator = " or ";
}
}
else {
inListPredicate.getTestExpression().accept( this ); inListPredicate.getTestExpression().accept( this );
if ( inListPredicate.isNegated() ) { if ( inListPredicate.isNegated() ) {
appendSql( " not" ); appendSql( " not" );
@ -1136,9 +1303,40 @@ public abstract class AbstractSqlAstWalker
} }
appendSql( CLOSE_PARENTHESIS ); appendSql( CLOSE_PARENTHESIS );
} }
}
protected final SqlTuple getTuple(Expression expression) {
if ( expression instanceof SqlTuple ) {
return (SqlTuple) expression;
}
else if ( expression instanceof SqmParameterInterpretation ) {
final Expression resolvedExpression = ( (SqmParameterInterpretation) expression ).getResolvedExpression();
if ( resolvedExpression instanceof SqlTuple ) {
return (SqlTuple) resolvedExpression;
}
}
else if ( expression instanceof EmbeddableValuedPathInterpretation<?> ) {
return ( (EmbeddableValuedPathInterpretation<?>) expression ).getSqlExpression();
}
else if ( expression instanceof NonAggregatedCompositeValuedPathInterpretation<?> ) {
return ( (NonAggregatedCompositeValuedPathInterpretation<?>) expression ).getSqlExpression();
}
return null;
}
@Override @Override
public void visitInSubQueryPredicate(InSubQueryPredicate inSubQueryPredicate) { public void visitInSubQueryPredicate(InSubQueryPredicate inSubQueryPredicate) {
final SqlTuple lhsTuple;
if ( ( lhsTuple = getTuple( inSubQueryPredicate.getTestExpression() ) ) != null && !dialect.supportsRowValueConstructorSyntaxInInList() ) {
emulateTupleSubQueryPredicate(
inSubQueryPredicate,
inSubQueryPredicate.isNegated(),
inSubQueryPredicate.getSubQuery(),
lhsTuple,
ComparisonOperator.EQUAL
);
}
else {
inSubQueryPredicate.getTestExpression().accept( this ); inSubQueryPredicate.getTestExpression().accept( this );
if ( inSubQueryPredicate.isNegated() ) { if ( inSubQueryPredicate.isNegated() ) {
appendSql( " not" ); appendSql( " not" );
@ -1146,6 +1344,98 @@ public abstract class AbstractSqlAstWalker
appendSql( " in " ); appendSql( " in " );
visitQuerySpec( inSubQueryPredicate.getSubQuery() ); visitQuerySpec( inSubQueryPredicate.getSubQuery() );
} }
}
protected void emulateTupleSubQueryPredicate(
Predicate predicate,
boolean negated,
QuerySpec subQuery,
SqlTuple lhsTuple,
ComparisonOperator tupleComparisonOperator) {
if ( subQuery.getLimitClauseExpression() == null && subQuery.getOffsetClauseExpression() == null ) {
// We can only emulate the tuple sub query predicate as exists predicate when there are no limit/offsets
if ( negated ) {
appendSql( "not " );
}
appendSql( "exists (select 1" );
visitFromClause( subQuery.getFromClause() );
appendSql( " where " );
// TODO: use HAVING clause if it has a group by
clauseStack.push( Clause.WHERE );
try {
renderSelectTupleComparison(
subQuery.getSelectClause().getSqlSelections(),
lhsTuple,
tupleComparisonOperator
);
appendSql( " and (" );
final Predicate whereClauseRestrictions = subQuery.getWhereClauseRestrictions();
if ( whereClauseRestrictions != null ) {
whereClauseRestrictions.accept( this );
}
appendSql( ')' );
}
finally {
clauseStack.pop();
}
appendSql( ")" );
}
else {
// TODO: We could use nested queries and use row numbers to emulate this
throw new IllegalArgumentException( "Can't emulate in predicate with tuples and limit/offset: " + predicate );
}
}
/**
* An optimized emulation for relational tuple subquery comparisons.
* The idea of this method is to use limit 1 to select the max or min tuple and only compare against that.
*/
protected void emulateQuantifiedTupleSubQueryPredicate(
Predicate predicate,
QuerySpec subQuery,
SqlTuple lhsTuple,
ComparisonOperator tupleComparisonOperator) {
if ( subQuery.getLimitClauseExpression() == null && subQuery.getOffsetClauseExpression() == null ) {
// We can only emulate the tuple sub query predicate as exists predicate when there are no limit/offsets
lhsTuple.accept( this );
appendSql( " " );
appendSql( tupleComparisonOperator.sqlText() );
appendSql( " " );
appendSql( "(" );
visitSelectClause( subQuery.getSelectClause() );
visitFromClause( subQuery.getFromClause() );
visitWhereClause( subQuery );
appendSql( " order by " );
boolean asc = tupleComparisonOperator == ComparisonOperator.LESS_THAN || tupleComparisonOperator == ComparisonOperator.LESS_THAN_OR_EQUAL;
final List<SqlSelection> sqlSelections = subQuery.getSelectClause().getSqlSelections();
final String order;
if ( tupleComparisonOperator == ComparisonOperator.LESS_THAN || tupleComparisonOperator == ComparisonOperator.LESS_THAN_OR_EQUAL ) {
// Default order is asc so we don't need to specify the order explicitly
order = "";
}
else {
order = " desc";
}
appendSql( "1" );
appendSql( order );
for ( int i = 1; i < sqlSelections.size(); i++ ) {
appendSql( COMA_SEPARATOR );
appendSql( Integer.toString( i + 1 ) );
appendSql( order );
}
renderLimit( ONE_LITERAL );
appendSql( ")" );
}
else {
// TODO: We could use nested queries and use row numbers to emulate this
throw new IllegalArgumentException( "Can't emulate in predicate with tuples and limit/offset: " + predicate );
}
}
@Override @Override
public void visitExistsPredicate(ExistsPredicate existsPredicate) { public void visitExistsPredicate(ExistsPredicate existsPredicate) {
@ -1199,19 +1489,19 @@ public abstract class AbstractSqlAstWalker
@Override @Override
public void visitNullnessPredicate(NullnessPredicate nullnessPredicate) { public void visitNullnessPredicate(NullnessPredicate nullnessPredicate) {
final Expression expression = nullnessPredicate.getExpression(); final Expression expression = nullnessPredicate.getExpression();
if ( expression instanceof EmbeddableValuedPathInterpretation ) { final String predicateValue;
final EmbeddableValuedPathInterpretation embeddableValuedPathInterpretation = (EmbeddableValuedPathInterpretation) expression;
final Expression sqlExpression = embeddableValuedPathInterpretation.getSqlExpression();
String predicateValue;
if ( nullnessPredicate.isNegated() ) { if ( nullnessPredicate.isNegated() ) {
predicateValue = " is not null"; predicateValue = " is not null";
} }
else { else {
predicateValue = " is null"; predicateValue = " is null";
} }
if ( sqlExpression instanceof SqlTuple ) { if ( expression instanceof EmbeddableValuedPathInterpretation ) {
SqlTuple tuple = (SqlTuple) sqlExpression; final EmbeddableValuedPathInterpretation embeddableValuedPathInterpretation = (EmbeddableValuedPathInterpretation) expression;
final Expression sqlExpression = embeddableValuedPathInterpretation.getSqlExpression();
final SqlTuple tuple;
if ( ( tuple = getTuple( sqlExpression ) ) != null ) {
String separator = NO_SEPARATOR; String separator = NO_SEPARATOR;
boolean isCurrentWhereClause = clauseStack.getCurrent() == Clause.WHERE; boolean isCurrentWhereClause = clauseStack.getCurrent() == Clause.WHERE;
@ -1232,22 +1522,12 @@ public abstract class AbstractSqlAstWalker
} }
else { else {
expression.accept( this ); expression.accept( this );
if ( nullnessPredicate.isNegated() ) { appendSql( predicateValue );
appendSql( " is not null" );
}
else {
appendSql( " is null" );
}
} }
} }
else { else {
expression.accept( this ); expression.accept( this );
if ( nullnessPredicate.isNegated() ) { appendSql( predicateValue );
appendSql( " is not null" );
}
else {
appendSql( " is null" );
}
} }
} }
@ -1267,12 +1547,106 @@ public abstract class AbstractSqlAstWalker
// // transform this into a // // transform this into a
// } // }
// //
final SqlTuple lhsTuple;
final SqlTuple rhsTuple;
if ( ( lhsTuple = getTuple( comparisonPredicate.getLeftHandExpression() ) ) != null ) {
final Expression rhsExpression = comparisonPredicate.getRightHandExpression();
final boolean all;
final QuerySpec subquery;
// Handle emulation of quantified comparison
if ( rhsExpression instanceof QuerySpec ) {
subquery = (QuerySpec) rhsExpression;
all = true;
}
else if ( rhsExpression instanceof Every ) {
subquery = ( (Every) rhsExpression ).getSubquery();
all = true;
}
else if ( rhsExpression instanceof Any ) {
subquery = ( (Any) rhsExpression ).getSubquery();
all = false;
}
else {
subquery = null;
all = false;
}
final ComparisonOperator operator = comparisonPredicate.getOperator();
if ( subquery != null && !dialect.supportsRowValueConstructorSyntaxInQuantifiedPredicates() ) {
// For quantified relational comparisons, we can do an optimized emulation
if ( all && operator != ComparisonOperator.EQUAL && operator != ComparisonOperator.NOT_EQUAL && dialect.supportsRowValueConstructorSyntax() ) {
emulateQuantifiedTupleSubQueryPredicate(
comparisonPredicate,
subquery,
lhsTuple,
operator
);
}
else {
emulateTupleSubQueryPredicate(
comparisonPredicate,
all,
subquery,
lhsTuple,
all ? operator.negated() : operator
);
}
}
else if ( !dialect.supportsRowValueConstructorSyntax() ) {
rhsTuple = getTuple( rhsExpression );
assert rhsTuple != null;
emulateTupleComparison(
lhsTuple.getExpressions(),
rhsTuple.getExpressions(),
operator
);
}
else {
comparisonPredicate.getLeftHandExpression().accept( this );
appendSql( " " );
appendSql( operator.sqlText() );
appendSql( " " );
rhsExpression.accept( this );
}
}
else if ( ( rhsTuple = getTuple( comparisonPredicate.getRightHandExpression() ) ) != null ) {
final Expression lhsExpression = comparisonPredicate.getLeftHandExpression();
if ( lhsExpression instanceof QuerySpec ) {
final QuerySpec subquery = (QuerySpec) lhsExpression;
if ( dialect.supportsRowValueConstructorSyntax() ) {
lhsExpression.accept( this );
appendSql( " " );
appendSql( comparisonPredicate.getOperator().sqlText() );
appendSql( " " );
comparisonPredicate.getRightHandExpression().accept( this );
}
else {
emulateTupleSubQueryPredicate(
comparisonPredicate,
false,
subquery,
rhsTuple,
// Since we switch the order of operands, we have to invert the operator
comparisonPredicate.getOperator().invert()
);
}
}
else {
throw new IllegalStateException(
"Unsupported tuple comparison combination. LHS is neither a tuple nor a tuple subquery but RHS is a tuple: " + comparisonPredicate );
}
}
else {
comparisonPredicate.getLeftHandExpression().accept( this ); comparisonPredicate.getLeftHandExpression().accept( this );
appendSql( " " ); appendSql( " " );
appendSql( comparisonPredicate.getOperator().sqlText() ); appendSql( comparisonPredicate.getOperator().sqlText() );
appendSql( " " ); appendSql( " " );
comparisonPredicate.getRightHandExpression().accept( this ); comparisonPredicate.getRightHandExpression().accept( this );
} }
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -27,4 +27,18 @@ public interface SqlAppender {
* Add the passed fragment into the in-flight buffer * Add the passed fragment into the in-flight buffer
*/ */
void appendSql(String fragment); void appendSql(String fragment);
void appendSql(char fragment);
default void appendQuoted(String value, char quoteChar) {
appendSql( quoteChar );
for ( int i = 0; i < value.length(); i++ ) {
final char c = value.charAt( i );
if ( c == quoteChar ) {
appendSql( quoteChar );
}
appendSql( c );
}
appendSql( quoteChar );
}
} }

View File

@ -8,6 +8,7 @@ package org.hibernate.sql.ast.spi;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState; import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.SqlAstWalker;
@ -46,6 +47,11 @@ public interface SqlSelection {
return getValuesArrayPosition() + 1; return getValuesArrayPosition() + 1;
} }
/**
* The underlying expression.
*/
Expression getExpression();
/** /**
* Get the type of the expression * Get the type of the expression
*/ */

View File

@ -0,0 +1,58 @@
/*
* 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.tree.expression;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.mapping.SqlExpressable;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.tree.SqlAstNode;
/**
* @author Christian Beikov
*/
public class Collate implements Expression, SqlExpressable, SqlAstNode {
private final Expression expression;
private final String collation;
public Collate(Expression expression, String collation) {
this.expression = expression;
this.collation = collation;
}
public Expression getExpression() {
return expression;
}
public String getCollation() {
return collation;
}
@Override
public JdbcMapping getJdbcMapping() {
if ( expression instanceof SqlExpressable ) {
return ( (SqlExpressable) expression ).getJdbcMapping();
}
if ( getExpressionType() instanceof SqlExpressable ) {
return ( (SqlExpressable) getExpressionType() ).getJdbcMapping();
}
return null;
}
@Override
public MappingModelExpressable getExpressionType() {
return expression.getExpressionType();
}
@Override
public void accept(SqlAstWalker sqlTreeWalker) {
sqlTreeWalker.visitCollate( this );
}
}

View File

@ -0,0 +1,42 @@
/*
* 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.tree.expression;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlAppender;
/**
* A wrapper for a literal to render as parameter through a cast function.
*
* @see org.hibernate.sql.ast.spi.AbstractSqlAstWalker
*
* @author Christian beikov
*/
public class LiteralAsParameter<T> implements SelfRenderingExpression {
private final Literal literal;
public LiteralAsParameter(Literal literal) {
this.literal = literal;
}
@Override
public void renderToSql(SqlAppender sqlAppender, SqlAstWalker walker, SessionFactoryImplementor sessionFactory) {
sqlAppender.appendSql( "?" );
}
@Override
public MappingModelExpressable getExpressionType() {
return literal.getExpressionType();
}
public Literal getLiteral() {
return literal;
}
}

View File

@ -1,51 +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.tree.predicate;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.select.QuerySpec;
/**
* @author Andrea Boriero
*/
public class MemberOfPredicate implements Predicate {
private final Expression leftHandExpression;
private final QuerySpec querySpec;
private final boolean isNegated;
public MemberOfPredicate(
Expression leftHandExpression,
boolean isNegated,
QuerySpec querySpec) {
this.leftHandExpression = leftHandExpression;
this.isNegated = isNegated;
this.querySpec = querySpec;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public void accept(SqlAstWalker sqlTreeWalker) {
sqlTreeWalker.visitMemberOfPredicate( this );
}
public boolean isNegated() {
return isNegated;
}
public Expression getLeftHandExpression() {
return leftHandExpression;
}
public QuerySpec getQuerySpec() {
return querySpec;
}
}

View File

@ -7,6 +7,7 @@
package org.hibernate.sql.ast.tree.select; package org.hibernate.sql.ast.tree.select;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -38,6 +39,10 @@ public class QuerySpec implements SqlAstNode, PredicateContainer, Expression, Ct
private final SelectClause selectClause = new SelectClause(); private final SelectClause selectClause = new SelectClause();
private Predicate whereClauseRestrictions; private Predicate whereClauseRestrictions;
private List<Expression> groupByClauseExpressions = Collections.emptyList();
private Predicate havingClauseRestrictions;
private List<SortSpecification> sortSpecifications; private List<SortSpecification> sortSpecifications;
private Expression limitClauseExpression; private Expression limitClauseExpression;
private Expression offsetClauseExpression; private Expression offsetClauseExpression;
@ -77,6 +82,22 @@ public class QuerySpec implements SqlAstNode, PredicateContainer, Expression, Ct
this.whereClauseRestrictions = SqlAstTreeHelper.combinePredicates( this.whereClauseRestrictions, predicate ); this.whereClauseRestrictions = SqlAstTreeHelper.combinePredicates( this.whereClauseRestrictions, predicate );
} }
public List<Expression> getGroupByClauseExpressions() {
return groupByClauseExpressions;
}
public void setGroupByClauseExpressions(List<Expression> groupByClauseExpressions) {
this.groupByClauseExpressions = groupByClauseExpressions == null ? Collections.emptyList() : groupByClauseExpressions;
}
public Predicate getHavingClauseRestrictions() {
return havingClauseRestrictions;
}
public void setHavingClauseRestrictions(Predicate havingClauseRestrictions) {
this.havingClauseRestrictions = havingClauseRestrictions;
}
public List<SortSpecification> getSortSpecifications() { public List<SortSpecification> getSortSpecifications() {
return sortSpecifications; return sortSpecifications;
} }

View File

@ -10,6 +10,7 @@ import org.hibernate.NullPrecedence;
import org.hibernate.SortOrder; import org.hibernate.SortOrder;
import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.expression.Collate;
import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Expression;
/** /**
@ -17,7 +18,6 @@ import org.hibernate.sql.ast.tree.expression.Expression;
*/ */
public class SortSpecification implements SqlAstNode { public class SortSpecification implements SqlAstNode {
private final Expression sortExpression; private final Expression sortExpression;
private final String collation;
private final SortOrder sortOrder; private final SortOrder sortOrder;
private final NullPrecedence nullPrecedence; private final NullPrecedence nullPrecedence;
@ -26,8 +26,12 @@ public class SortSpecification implements SqlAstNode {
} }
public SortSpecification(Expression sortExpression, String collation, SortOrder sortOrder, NullPrecedence nullPrecedence) { public SortSpecification(Expression sortExpression, String collation, SortOrder sortOrder, NullPrecedence nullPrecedence) {
if ( collation == null ) {
this.sortExpression = sortExpression; this.sortExpression = sortExpression;
this.collation = collation; }
else {
this.sortExpression = new Collate( sortExpression, collation );
}
this.sortOrder = sortOrder; this.sortOrder = sortOrder;
this.nullPrecedence = nullPrecedence; this.nullPrecedence = nullPrecedence;
} }
@ -36,10 +40,6 @@ public class SortSpecification implements SqlAstNode {
return sortExpression; return sortExpression;
} }
public String getCollation() {
return collation;
}
public SortOrder getSortOrder() { public SortOrder getSortOrder() {
return sortOrder; return sortOrder;
} }

View File

@ -46,7 +46,8 @@ public class SqlSelectionImpl implements SqlSelection, SqlExpressionAccess {
this.sqlExpression = sqlExpression; this.sqlExpression = sqlExpression;
} }
public Expression getWrappedSqlExpression() { @Override
public Expression getExpression() {
return sqlExpression; return sqlExpression;
} }
@ -69,7 +70,7 @@ public class SqlSelectionImpl implements SqlSelection, SqlExpressionAccess {
@Override @Override
public MappingModelExpressable getExpressionType() { public MappingModelExpressable getExpressionType() {
return getWrappedSqlExpression().getExpressionType(); return getExpression().getExpressionType();
} }
@Override @Override

View File

@ -7,6 +7,8 @@
package org.hibernate.type.descriptor; package org.hibernate.type.descriptor;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField; import java.time.temporal.ChronoField;
@ -33,14 +35,18 @@ public final class DateTimeUtils {
public static final String FORMAT_STRING_TIMESTAMP = "yyyy-MM-dd HH:mm:ss"; public static final String FORMAT_STRING_TIMESTAMP = "yyyy-MM-dd HH:mm:ss";
public static final String FORMAT_STRING_TIMESTAMP_WITH_MILLIS = FORMAT_STRING_TIMESTAMP + ".SSS"; public static final String FORMAT_STRING_TIMESTAMP_WITH_MILLIS = FORMAT_STRING_TIMESTAMP + ".SSS";
public static final String FORMAT_STRING_TIMESTAMP_WITH_MICROS = FORMAT_STRING_TIMESTAMP + ".SSSSSS"; public static final String FORMAT_STRING_TIMESTAMP_WITH_MICROS = FORMAT_STRING_TIMESTAMP + ".SSSSSS";
public static final String FORMAT_STRING_TIMESTAMP_WITH_OFFSET = FORMAT_STRING_TIMESTAMP_WITH_MICROS + "xxx"; public static final String FORMAT_STRING_TIMESTAMP_WITH_MILLIS_AND_OFFSET = FORMAT_STRING_TIMESTAMP_WITH_MILLIS + "xxx";
public static final String FORMAT_STRING_TIMESTAMP_WITH_MICROS_AND_OFFSET = FORMAT_STRING_TIMESTAMP_WITH_MICROS + "xxx";
public static final DateTimeFormatter DATE_TIME_FORMATTER_DATE = DateTimeFormatter.ofPattern( FORMAT_STRING_DATE, Locale.ENGLISH ); public static final DateTimeFormatter DATE_TIME_FORMATTER_DATE = DateTimeFormatter.ofPattern( FORMAT_STRING_DATE, Locale.ENGLISH );
public static final DateTimeFormatter DATE_TIME_FORMATTER_TIME_WITH_OFFSET = DateTimeFormatter.ofPattern( FORMAT_STRING_TIME_WITH_OFFSET, Locale.ENGLISH ); public static final DateTimeFormatter DATE_TIME_FORMATTER_TIME_WITH_OFFSET = DateTimeFormatter.ofPattern( FORMAT_STRING_TIME_WITH_OFFSET, Locale.ENGLISH );
public static final DateTimeFormatter DATE_TIME_FORMATTER_TIME = DateTimeFormatter.ofPattern( FORMAT_STRING_TIME, Locale.ENGLISH ); public static final DateTimeFormatter DATE_TIME_FORMATTER_TIME = DateTimeFormatter.ofPattern( FORMAT_STRING_TIME, Locale.ENGLISH );
public static final DateTimeFormatter DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS = DateTimeFormatter.ofPattern(FORMAT_STRING_TIMESTAMP_WITH_MILLIS, Locale.ENGLISH ); public static final DateTimeFormatter DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS = DateTimeFormatter.ofPattern(FORMAT_STRING_TIMESTAMP_WITH_MILLIS, Locale.ENGLISH );
public static final DateTimeFormatter DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS = DateTimeFormatter.ofPattern(FORMAT_STRING_TIMESTAMP_WITH_MICROS, Locale.ENGLISH ); public static final DateTimeFormatter DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS = DateTimeFormatter.ofPattern(FORMAT_STRING_TIMESTAMP_WITH_MICROS, Locale.ENGLISH );
public static final DateTimeFormatter DATE_TIME_FORMATTER_TIMESTAMP_WITH_OFFSET = DateTimeFormatter.ofPattern( FORMAT_STRING_TIMESTAMP_WITH_OFFSET, Locale.ENGLISH ); public static final DateTimeFormatter DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS_AND_OFFSET = DateTimeFormatter.ofPattern(
FORMAT_STRING_TIMESTAMP_WITH_MILLIS_AND_OFFSET, Locale.ENGLISH );
public static final DateTimeFormatter DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS_AND_OFFSET = DateTimeFormatter.ofPattern(
FORMAT_STRING_TIMESTAMP_WITH_MICROS_AND_OFFSET, Locale.ENGLISH );
public static final String JDBC_ESCAPE_START_DATE = "{d '"; public static final String JDBC_ESCAPE_START_DATE = "{d '";
public static final String JDBC_ESCAPE_START_TIME = "{t '"; public static final String JDBC_ESCAPE_START_TIME = "{t '";
@ -65,6 +71,21 @@ public final class DateTimeUtils {
.optionalStart().appendZoneOrOffsetId().optionalEnd() .optionalStart().appendZoneOrOffsetId().optionalEnd()
.toFormatter(); .toFormatter();
private static final ThreadLocal<SimpleDateFormat> LOCAL_DATE_FORMAT = ThreadLocal.withInitial( DateTimeUtils::simpleDateFormatDate );
private static final ThreadLocal<SimpleDateFormat> LOCAL_TIME_FORMAT = ThreadLocal.withInitial( DateTimeUtils::simpleDateFormatTime );
private static final ThreadLocal<SimpleDateFormat> TIMESTAMP_WITH_MILLIS_FORMAT = ThreadLocal.withInitial(
() -> new SimpleDateFormat(
FORMAT_STRING_TIMESTAMP_WITH_MILLIS,
Locale.ENGLISH
)
);
private static final ThreadLocal<SimpleDateFormat> TIMESTAMP_WITH_MICROS_FORMAT = ThreadLocal.withInitial(
() -> new SimpleDateFormat(
FORMAT_STRING_TIMESTAMP_WITH_MICROS,
Locale.ENGLISH
)
);
/** /**
* Pattern used for parsing literal offset datetimes in HQL. * Pattern used for parsing literal offset datetimes in HQL.
* *
@ -82,35 +103,89 @@ public final class DateTimeUtils {
.appendOffset("+HH:mm", "+00") .appendOffset("+HH:mm", "+00")
.toFormatter(); .toFormatter();
public static String formatAsTimestampWithMicros(TemporalAccessor temporalAccessor) { public static String formatAsTimestampWithMicros(TemporalAccessor temporalAccessor, boolean supportsOffset, TimeZone jdbcTimeZone) {
return temporalAccessor.isSupported(ChronoField.OFFSET_SECONDS) if ( temporalAccessor.isSupported(ChronoField.OFFSET_SECONDS) ) {
? DATE_TIME_FORMATTER_TIMESTAMP_WITH_OFFSET.format( temporalAccessor ) if ( supportsOffset ) {
: DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS.format( temporalAccessor ); return DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS_AND_OFFSET.format( temporalAccessor );
}
else {
return DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS.format(
LocalDateTime.ofInstant(
Instant.from( temporalAccessor ),
jdbcTimeZone.toZoneId()
)
);
}
}
else {
return DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS.format( temporalAccessor );
}
} }
public static String formatAsTimestampWithMillis(TemporalAccessor temporalAccessor) { public static String formatAsTimestampWithMillis(TemporalAccessor temporalAccessor, boolean supportsOffset, TimeZone jdbcTimeZone) {
if ( temporalAccessor.isSupported(ChronoField.OFFSET_SECONDS) ) {
if ( supportsOffset ) {
return DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS_AND_OFFSET.format( temporalAccessor );
}
else {
return DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS.format(
LocalDateTime.ofInstant(
Instant.from( temporalAccessor ),
jdbcTimeZone.toZoneId()
)
);
}
}
else {
return DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS.format( temporalAccessor ); return DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS.format( temporalAccessor );
} }
}
public static String formatAsDate(TemporalAccessor temporalAccessor) { public static String formatAsDate(TemporalAccessor temporalAccessor) {
return DATE_TIME_FORMATTER_DATE.format( temporalAccessor ); return DATE_TIME_FORMATTER_DATE.format( temporalAccessor );
} }
public static String formatAsTime(TemporalAccessor temporalAccessor) { public static String formatAsTime(TemporalAccessor temporalAccessor, boolean supportsOffset, TimeZone jdbcTimeZone) {
if ( temporalAccessor.isSupported(ChronoField.OFFSET_SECONDS) ) { if ( temporalAccessor.isSupported(ChronoField.OFFSET_SECONDS) ) {
if ( supportsOffset ) {
return DATE_TIME_FORMATTER_TIME_WITH_OFFSET.format( temporalAccessor ); return DATE_TIME_FORMATTER_TIME_WITH_OFFSET.format( temporalAccessor );
} }
else {
return DATE_TIME_FORMATTER_TIME.format(
LocalDateTime.ofInstant(
Instant.from( temporalAccessor ),
jdbcTimeZone.toZoneId()
)
);
}
}
else { else {
return DATE_TIME_FORMATTER_TIME.format( temporalAccessor ); return DATE_TIME_FORMATTER_TIME.format( temporalAccessor );
} }
} }
public static String formatAsTimestampWithMillis(java.util.Date date) { public static String formatAsTimestampWithMillis(java.util.Date date, TimeZone jdbcTimeZone) {
return simpleDateFormatTimestampWithMillis().format( date ); final SimpleDateFormat simpleDateFormat = TIMESTAMP_WITH_MILLIS_FORMAT.get();
final TimeZone originalTimeZone = simpleDateFormat.getTimeZone();
try {
simpleDateFormat.setTimeZone( jdbcTimeZone );
return simpleDateFormat.format( date );
}
finally {
simpleDateFormat.setTimeZone( originalTimeZone );
}
} }
public static String formatAsTimestampWithMicros(java.util.Date date) { public static String formatAsTimestampWithMicros(java.util.Date date, TimeZone jdbcTimeZone) {
return simpleDateFormatTimestampWithMicros().format( date ); final SimpleDateFormat simpleDateFormat = TIMESTAMP_WITH_MICROS_FORMAT.get();
final TimeZone originalTimeZone = simpleDateFormat.getTimeZone();
try {
simpleDateFormat.setTimeZone( jdbcTimeZone );
return simpleDateFormat.format( date );
}
finally {
simpleDateFormat.setTimeZone( originalTimeZone );
}
} }
public static String wrapAsJdbcDateLiteral(String literal) { public static String wrapAsJdbcDateLiteral(String literal) {
@ -137,16 +212,8 @@ public final class DateTimeUtils {
return "timestamp '" + literal + "'"; return "timestamp '" + literal + "'";
} }
public static SimpleDateFormat simpleDateFormatTimestampWithMillis() {
return new SimpleDateFormat(FORMAT_STRING_TIMESTAMP_WITH_MILLIS, Locale.ENGLISH );
}
public static SimpleDateFormat simpleDateFormatTimestampWithMicros() {
return new SimpleDateFormat(FORMAT_STRING_TIMESTAMP_WITH_MICROS, Locale.ENGLISH );
}
public static String formatAsDate(java.util.Date date) { public static String formatAsDate(java.util.Date date) {
return simpleDateFormatDate().format( date ); return LOCAL_DATE_FORMAT.get().format( date );
} }
public static SimpleDateFormat simpleDateFormatDate() { public static SimpleDateFormat simpleDateFormatDate() {
@ -154,15 +221,23 @@ public final class DateTimeUtils {
} }
public static String formatAsTime(java.util.Date date) { public static String formatAsTime(java.util.Date date) {
return simpleDateFormatTime().format( date ); return LOCAL_TIME_FORMAT.get().format( date );
} }
public static SimpleDateFormat simpleDateFormatTime() { public static SimpleDateFormat simpleDateFormatTime() {
return new SimpleDateFormat( FORMAT_STRING_TIME, Locale.ENGLISH ); return new SimpleDateFormat( FORMAT_STRING_TIME, Locale.ENGLISH );
} }
public static String formatAsTimestampWithMillis(java.util.Calendar calendar) { public static String formatAsTimestampWithMillis(java.util.Calendar calendar, TimeZone jdbcTimeZone) {
return simpleDateFormatTimestampWithMillis( calendar.getTimeZone() ).format( calendar.getTime() ); final SimpleDateFormat simpleDateFormat = TIMESTAMP_WITH_MILLIS_FORMAT.get();
final TimeZone originalTimeZone = simpleDateFormat.getTimeZone();
try {
simpleDateFormat.setTimeZone( jdbcTimeZone );
return simpleDateFormat.format( calendar.getTime() );
}
finally {
simpleDateFormat.setTimeZone( originalTimeZone );
}
} }
public static SimpleDateFormat simpleDateFormatTimestampWithMillis(TimeZone timeZone) { public static SimpleDateFormat simpleDateFormatTimestampWithMillis(TimeZone timeZone) {
@ -171,8 +246,16 @@ public final class DateTimeUtils {
return formatter; return formatter;
} }
public static String formatAsTimestampWithMicros(java.util.Calendar calendar) { public static String formatAsTimestampWithMicros(java.util.Calendar calendar, TimeZone jdbcTimeZone) {
return simpleDateFormatTimestampWithMicros( calendar.getTimeZone() ).format( calendar.getTime() ); final SimpleDateFormat simpleDateFormat = TIMESTAMP_WITH_MICROS_FORMAT.get();
final TimeZone originalTimeZone = simpleDateFormat.getTimeZone();
try {
simpleDateFormat.setTimeZone( jdbcTimeZone );
return simpleDateFormat.format( calendar.getTime() );
}
finally {
simpleDateFormat.setTimeZone( originalTimeZone );
}
} }
public static SimpleDateFormat simpleDateFormatTimestampWithMicros(TimeZone timeZone) { public static SimpleDateFormat simpleDateFormatTimestampWithMicros(TimeZone timeZone) {
@ -182,7 +265,15 @@ public final class DateTimeUtils {
} }
public static String formatAsDate(java.util.Calendar calendar) { public static String formatAsDate(java.util.Calendar calendar) {
return simpleDateFormatDate( calendar.getTimeZone() ).format( calendar.getTime() ); final SimpleDateFormat simpleDateFormat = LOCAL_DATE_FORMAT.get();
final TimeZone originalTimeZone = simpleDateFormat.getTimeZone();
try {
simpleDateFormat.setTimeZone( calendar.getTimeZone() );
return simpleDateFormat.format( calendar.getTime() );
}
finally {
simpleDateFormat.setTimeZone( originalTimeZone );
}
} }
public static SimpleDateFormat simpleDateFormatDate(TimeZone timeZone) { public static SimpleDateFormat simpleDateFormatDate(TimeZone timeZone) {
@ -192,7 +283,15 @@ public final class DateTimeUtils {
} }
public static String formatAsTime(java.util.Calendar calendar) { public static String formatAsTime(java.util.Calendar calendar) {
return simpleDateFormatTime( calendar.getTimeZone() ).format( calendar.getTime() ); final SimpleDateFormat simpleDateFormat = LOCAL_TIME_FORMAT.get();
final TimeZone originalTimeZone = simpleDateFormat.getTimeZone();
try {
simpleDateFormat.setTimeZone( calendar.getTimeZone() );
return simpleDateFormat.format( calendar.getTime() );
}
finally {
simpleDateFormat.setTimeZone( originalTimeZone );
}
} }
public static SimpleDateFormat simpleDateFormatTime(TimeZone timeZone) { public static SimpleDateFormat simpleDateFormatTime(TimeZone timeZone) {

View File

@ -75,13 +75,13 @@ public class TimestampWithTimeZoneDescriptor implements SqlTypeDescriptor {
int index, int index,
WrapperOptions wrapperOptions) throws SQLException { WrapperOptions wrapperOptions) throws SQLException {
try { try {
final OffsetDateTime dateTime = javaTypeDescriptor.unwrap( value, OffsetDateTime.class, wrapperOptions.getSession() ); final OffsetDateTime dateTime = javaTypeDescriptor.unwrap( value, OffsetDateTime.class, wrapperOptions );
// supposed to be supported in JDBC 4.2 // supposed to be supported in JDBC 4.2
st.setObject( index, dateTime, Types.TIMESTAMP_WITH_TIMEZONE ); st.setObject( index, dateTime, Types.TIMESTAMP_WITH_TIMEZONE );
} }
catch (SQLException|AbstractMethodError e) { catch (SQLException|AbstractMethodError e) {
// fall back to treating it as a JDBC Timestamp // fall back to treating it as a JDBC Timestamp
final Timestamp timestamp = javaTypeDescriptor.unwrap( value, Timestamp.class, wrapperOptions.getSession() ); final Timestamp timestamp = javaTypeDescriptor.unwrap( value, Timestamp.class, wrapperOptions );
st.setTimestamp( index, timestamp ); st.setTimestamp( index, timestamp );
} }
} }
@ -94,13 +94,13 @@ public class TimestampWithTimeZoneDescriptor implements SqlTypeDescriptor {
WrapperOptions wrapperOptions) WrapperOptions wrapperOptions)
throws SQLException { throws SQLException {
try { try {
final OffsetDateTime dateTime = javaTypeDescriptor.unwrap( value, OffsetDateTime.class, wrapperOptions.getSession() ); final OffsetDateTime dateTime = javaTypeDescriptor.unwrap( value, OffsetDateTime.class, wrapperOptions );
// supposed to be supported in JDBC 4.2 // supposed to be supported in JDBC 4.2
st.setObject( name, dateTime, Types.TIMESTAMP_WITH_TIMEZONE ); st.setObject( name, dateTime, Types.TIMESTAMP_WITH_TIMEZONE );
} }
catch (SQLException|AbstractMethodError e) { catch (SQLException|AbstractMethodError e) {
// fall back to treating it as a JDBC Timestamp // fall back to treating it as a JDBC Timestamp
final Timestamp timestamp = javaTypeDescriptor.unwrap( value, Timestamp.class, wrapperOptions.getSession() ); final Timestamp timestamp = javaTypeDescriptor.unwrap( value, Timestamp.class, wrapperOptions );
st.setTimestamp( name, timestamp ); st.setTimestamp( name, timestamp );
} }
} }
@ -114,11 +114,11 @@ public class TimestampWithTimeZoneDescriptor implements SqlTypeDescriptor {
protected X doExtract(ResultSet rs, int position, WrapperOptions wrapperOptions) throws SQLException { protected X doExtract(ResultSet rs, int position, WrapperOptions wrapperOptions) throws SQLException {
try { try {
// supposed to be supported in JDBC 4.2 // supposed to be supported in JDBC 4.2
return javaTypeDescriptor.wrap( rs.getObject( position, OffsetDateTime.class ), wrapperOptions.getSession() ); return javaTypeDescriptor.wrap( rs.getObject( position, OffsetDateTime.class ), wrapperOptions );
} }
catch (SQLException|AbstractMethodError e) { catch (SQLException|AbstractMethodError e) {
// fall back to treating it as a JDBC Timestamp // fall back to treating it as a JDBC Timestamp
return javaTypeDescriptor.wrap( rs.getTimestamp( position ), wrapperOptions.getSession() ); return javaTypeDescriptor.wrap( rs.getTimestamp( position ), wrapperOptions );
} }
} }
@ -126,11 +126,11 @@ public class TimestampWithTimeZoneDescriptor implements SqlTypeDescriptor {
protected X doExtract(CallableStatement statement, int position, WrapperOptions wrapperOptions) throws SQLException { protected X doExtract(CallableStatement statement, int position, WrapperOptions wrapperOptions) throws SQLException {
try { try {
// supposed to be supported in JDBC 4.2 // supposed to be supported in JDBC 4.2
return javaTypeDescriptor.wrap( statement.getObject( position, OffsetDateTime.class ), wrapperOptions.getSession() ); return javaTypeDescriptor.wrap( statement.getObject( position, OffsetDateTime.class ), wrapperOptions );
} }
catch (SQLException|AbstractMethodError e) { catch (SQLException|AbstractMethodError e) {
// fall back to treating it as a JDBC Timestamp // fall back to treating it as a JDBC Timestamp
return javaTypeDescriptor.wrap( statement.getTimestamp( position ), wrapperOptions.getSession() ); return javaTypeDescriptor.wrap( statement.getTimestamp( position ), wrapperOptions );
} }
} }
@ -138,11 +138,11 @@ public class TimestampWithTimeZoneDescriptor implements SqlTypeDescriptor {
protected X doExtract(CallableStatement statement, String name, WrapperOptions wrapperOptions) throws SQLException { protected X doExtract(CallableStatement statement, String name, WrapperOptions wrapperOptions) throws SQLException {
try { try {
// supposed to be supported in JDBC 4.2 // supposed to be supported in JDBC 4.2
return javaTypeDescriptor.wrap( statement.getObject( name, OffsetDateTime.class ), wrapperOptions.getSession() ); return javaTypeDescriptor.wrap( statement.getObject( name, OffsetDateTime.class ), wrapperOptions );
} }
catch (SQLException|AbstractMethodError e) { catch (SQLException|AbstractMethodError e) {
// fall back to treating it as a JDBC Timestamp // fall back to treating it as a JDBC Timestamp
return javaTypeDescriptor.wrap( statement.getTimestamp( name ), wrapperOptions.getSession() ); return javaTypeDescriptor.wrap( statement.getTimestamp( name ), wrapperOptions );
} }
} }
}; };

View File

@ -7,6 +7,7 @@
package org.hibernate.type.descriptor.sql.internal; package org.hibernate.type.descriptor.sql.internal;
import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAccessor;
import java.util.TimeZone;
import javax.persistence.TemporalType; import javax.persistence.TemporalType;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
@ -27,23 +28,33 @@ public class JdbcLiteralFormatterTemporal extends BasicJdbcLiteralFormatter {
@Override @Override
public String toJdbcLiteral(Object value, Dialect dialect, SharedSessionContractImplementor session) { public String toJdbcLiteral(Object value, Dialect dialect, SharedSessionContractImplementor session) {
final TimeZone jdbcTimeZone;
if ( session == null || session.getJdbcTimeZone() == null ) {
jdbcTimeZone = TimeZone.getDefault();
}
else {
jdbcTimeZone = session.getJdbcTimeZone();
}
// for performance reasons, avoid conversions if we can // for performance reasons, avoid conversions if we can
if ( value instanceof java.util.Date ) { if ( value instanceof java.util.Date ) {
return dialect.formatDateTimeLiteral( return dialect.formatDateTimeLiteral(
(java.util.Date) value, (java.util.Date) value,
precision precision,
jdbcTimeZone
); );
} }
else if ( value instanceof java.util.Calendar ) { else if ( value instanceof java.util.Calendar ) {
return dialect.formatDateTimeLiteral( return dialect.formatDateTimeLiteral(
(java.util.Calendar) value, (java.util.Calendar) value,
precision precision,
jdbcTimeZone
); );
} }
else if ( value instanceof TemporalAccessor ) { else if ( value instanceof TemporalAccessor ) {
return dialect.formatDateTimeLiteral( return dialect.formatDateTimeLiteral(
(TemporalAccessor) value, (TemporalAccessor) value,
precision precision,
jdbcTimeZone
); );
} }
@ -51,19 +62,22 @@ public class JdbcLiteralFormatterTemporal extends BasicJdbcLiteralFormatter {
case DATE: { case DATE: {
return dialect.formatDateTimeLiteral( return dialect.formatDateTimeLiteral(
unwrap( value, java.sql.Date.class, session ), unwrap( value, java.sql.Date.class, session ),
precision precision,
jdbcTimeZone
); );
} }
case TIME: { case TIME: {
return dialect.formatDateTimeLiteral( return dialect.formatDateTimeLiteral(
unwrap( value, java.sql.Time.class, session ), unwrap( value, java.sql.Time.class, session ),
precision precision,
jdbcTimeZone
); );
} }
default: { default: {
return dialect.formatDateTimeLiteral( return dialect.formatDateTimeLiteral(
unwrap( value, java.util.Date.class, session ), unwrap( value, java.util.Date.class, session ),
precision precision,
jdbcTimeZone
); );
} }
} }

View File

@ -454,7 +454,6 @@ public class CompositeIdTest {
} }
@Test @Test
@FailureExpected(reason = "Criteria and EmbeddableId as predicate value has not yet been implemented")
public void testQueryInAndComposite(SessionFactoryScope scope) { public void testQueryInAndComposite(SessionFactoryScope scope) {
scope.inTransaction( scope.inTransaction(

View File

@ -76,7 +76,7 @@ public class OrderByColumnNameTest {
); );
} }
@Entity @Entity(name = "Product")
public static class Product { public static class Product {
@Id @Id
@GeneratedValue @GeneratedValue
@ -103,7 +103,7 @@ public class OrderByColumnNameTest {
} }
} }
@Entity @Entity(name = "Widgets")
@Inheritance(strategy = InheritanceType.JOINED) @Inheritance(strategy = InheritanceType.JOINED)
public static class Widgets { public static class Widgets {
private String name; private String name;
@ -134,13 +134,13 @@ public class OrderByColumnNameTest {
} }
@Entity @Entity(name = "Widget1")
public static class Widget1 extends org.hibernate.orm.test.annotations.collectionelement.Widgets { public static class Widget1 extends Widgets {
private String name1; private String name1;
} }
@Entity @Entity(name = "Widget2")
public static class Widget2 extends org.hibernate.orm.test.annotations.collectionelement.Widgets { public static class Widget2 extends Widgets {
private String name2; private String name2;
} }

View File

@ -41,12 +41,12 @@ public class Widgets {
this.id = id; this.id = id;
} }
@Entity @Entity(name = "Widget1")
public static class Widget1 extends Widgets{ public static class Widget1 extends Widgets{
private String name1; private String name1;
} }
@Entity @Entity(name = "Widget2")
public static class Widget2 extends Widgets{ public static class Widget2 extends Widgets{
private String name2; private String name2;
} }

View File

@ -32,7 +32,6 @@ import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.Hibernate; import org.hibernate.Hibernate;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
@ -642,8 +641,7 @@ public class MultipleSessionCollectionTest {
); );
} }
@Entity @Entity(name = "Parent")
@Table(name = "Parent")
public static class Parent { public static class Parent {
@Id @Id
@GeneratedValue @GeneratedValue
@ -665,8 +663,7 @@ public class MultipleSessionCollectionTest {
} }
@Entity @Entity(name = "Child")
@Table(name = "Child")
public static class Child { public static class Child {
@Id @Id
@GeneratedValue @GeneratedValue

View File

@ -72,7 +72,7 @@ public class Staff {
@Column(name="kooky") @Column(name="kooky")
@ColumnTransformer( @ColumnTransformer(
read = "cast( kooky as VARCHAR )" read = "cast( kooky as VARCHAR(255) )"
) )
public String getKooky() { return kooky; } public String getKooky() { return kooky; }
public void setKooky(String kooky) { this.kooky = kooky; } public void setKooky(String kooky) { this.kooky = kooky; }

View File

@ -221,19 +221,19 @@ public class InheritedEntityGraphTest {
} }
@Entity @Entity(name = "Bar")
public static class Bar { public static class Bar {
@Id @GeneratedValue @Id @GeneratedValue
public long id; public long id;
} }
@Entity @Entity(name = "Foo")
public static class Foo extends MappedSupperclass { public static class Foo extends MappedSupperclass {
} }
@Entity @Entity(name = "Foo2")
public static class Foo2 { public static class Foo2 {
@Id @GeneratedValue @Id @GeneratedValue
public long id; public long id;

View File

@ -222,7 +222,6 @@ public class DynamicFilterTest extends BaseNonConfigCoreFunctionalTestCase {
} }
@Test @Test
@FailureExpected(jiraKey = "none", message = "not implemented method of QueryParameterBindingsImpl in v6")
public void testHqlFilters() { public void testHqlFilters() {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HQL test // HQL test

View File

@ -107,7 +107,7 @@ public class JoinedSubclassWithEmbeddableTest {
} }
} }
@Entity @Entity(name = "Employee")
@Table(name = "employees") @Table(name = "employees")
public static class Employee extends Person { public static class Employee extends Person {
private Integer employeeNumber; private Integer employeeNumber;

View File

@ -107,7 +107,7 @@ public class SingleTableWithEmbeddableTest {
} }
} }
@Entity @Entity(name = "Employee")
@Table(name = "employees") @Table(name = "employees")
public static class Employee extends Person { public static class Employee extends Person {
private Integer employeeNumber; private Integer employeeNumber;

View File

@ -107,7 +107,7 @@ public class TablePerClassWithEmbeddableTest {
} }
} }
@Entity @Entity(name = "Employee")
@Table(name = "employees") @Table(name = "employees")
public static class Employee extends Person { public static class Employee extends Person {
private Integer employeeNumber; private Integer employeeNumber;

View File

@ -19,6 +19,7 @@ import org.hibernate.metamodel.model.domain.JpaMetamodel;
import org.hibernate.metamodel.model.domain.internal.JpaMetamodelImpl; import org.hibernate.metamodel.model.domain.internal.JpaMetamodelImpl;
import org.hibernate.metamodel.MappingMetamodel; import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.query.criteria.LiteralHandlingMode;
import org.hibernate.query.hql.HqlTranslator; import org.hibernate.query.hql.HqlTranslator;
import org.hibernate.query.hql.internal.StandardHqlTranslator; import org.hibernate.query.hql.internal.StandardHqlTranslator;
import org.hibernate.query.hql.spi.SqmCreationOptions; import org.hibernate.query.hql.spi.SqmCreationOptions;
@ -115,6 +116,7 @@ public class HqlTranslationNoFactoryTests {
final QueryEngine queryEngine = new QueryEngine( final QueryEngine queryEngine = new QueryEngine(
jpaMetamodel, jpaMetamodel,
LiteralHandlingMode.AUTO,
// we don't want strict JPA query compliance // we don't want strict JPA query compliance
false, false,
new NamedObjectRepositoryImpl( Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap() ), new NamedObjectRepositoryImpl( Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap() ),

View File

@ -25,6 +25,7 @@ import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.MapKeyEnumerated; import javax.persistence.MapKeyEnumerated;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal; import javax.persistence.Temporal;
import javax.persistence.TemporalType; import javax.persistence.TemporalType;
@ -283,6 +284,7 @@ public class ManyToManyHqlMemberOfQueryTest {
} }
@Entity(name = "Call") @Entity(name = "Call")
@Table(name = "phone_call")
public static class Call { public static class Call {
@Id @Id

View File

@ -26,6 +26,7 @@ import javax.persistence.ManyToOne;
import javax.persistence.MapKeyEnumerated; import javax.persistence.MapKeyEnumerated;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.OrderColumn; import javax.persistence.OrderColumn;
import javax.persistence.Table;
import javax.persistence.Temporal; import javax.persistence.Temporal;
import javax.persistence.TemporalType; import javax.persistence.TemporalType;
@ -283,6 +284,7 @@ public class OneToManyHqlMemberOfQueryTest {
} }
@Entity(name = "Call") @Entity(name = "Call")
@Table(name = "phone_call")
public static class Call { public static class Call {
@Id @Id

View File

@ -78,7 +78,7 @@ public class OneToOneLazyTest {
); );
} }
@Entity @Entity(name = "Book")
public static class Book { public static class Book {
@Id @Id
@ -109,7 +109,7 @@ public class OneToOneLazyTest {
} }
} }
@Entity @Entity(name = "Title")
public static class Title { public static class Title {
@Id @Id

View File

@ -10,12 +10,14 @@ import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.ParameterExpression; import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Root; import javax.persistence.criteria.Root;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.query.criteria.HibernateCriteriaBuilder; import org.hibernate.query.criteria.HibernateCriteriaBuilder;
import org.hibernate.query.criteria.JpaCriteriaQuery; import org.hibernate.query.criteria.JpaCriteriaQuery;
import org.hibernate.query.criteria.JpaRoot; import org.hibernate.query.criteria.JpaRoot;
import org.hibernate.testing.orm.domain.gambit.BasicEntity; import org.hibernate.testing.orm.domain.gambit.BasicEntity;
import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.RequiresDialect;
import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -106,7 +108,9 @@ public class BasicCriteriaExecutionTests {
); );
} }
// Doing ... where ? = ? ... is only allowed in a few DBs. Since this is useless, we don't bother to emulate this
@Test @Test
@RequiresDialect(H2Dialect.class)
public void testExecutingBasicCriteriaQueryParameterPredicate(SessionFactoryScope scope) { public void testExecutingBasicCriteriaQueryParameterPredicate(SessionFactoryScope scope) {
scope.inStatelessTransaction( scope.inStatelessTransaction(
session -> { session -> {
@ -123,7 +127,9 @@ public class BasicCriteriaExecutionTests {
); );
} }
// Doing ... where ? = ? ... is only allowed in a few DBs. Since this is useless, we don't bother to emulate this
@Test @Test
@RequiresDialect(H2Dialect.class)
public void testExecutingBasicCriteriaQueryParameterPredicateInStatelessSession(SessionFactoryScope scope) { public void testExecutingBasicCriteriaQueryParameterPredicateInStatelessSession(SessionFactoryScope scope) {
scope.inStatelessTransaction( scope.inStatelessTransaction(
session -> { session -> {

View File

@ -8,11 +8,16 @@ package org.hibernate.orm.test.query.hql;
import org.hibernate.boot.MetadataSources; import org.hibernate.boot.MetadataSources;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.junit5.SessionFactoryBasedFunctionalTest; import org.hibernate.testing.junit5.SessionFactoryBasedFunctionalTest;
import org.hibernate.testing.orm.domain.StandardDomainModel; import org.hibernate.testing.orm.domain.StandardDomainModel;
import org.hibernate.testing.orm.domain.gambit.EntityOfBasics; 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.DomainModel;
import org.hibernate.testing.orm.junit.FailureExpected; 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.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.testing.orm.junit.SessionFactoryScope;
@ -95,9 +100,9 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
public void testConcatFunctionParameters(SessionFactoryScope scope) { public void testConcatFunctionParameters(SessionFactoryScope scope) {
scope.inTransaction( scope.inTransaction(
session -> { session -> {
assertThat( session.createQuery("select :hello||:world").setParameter("hello","hello").setParameter("world","world").getSingleResult(), is("helloworld") ); assertThat( session.createQuery("select cast(:hello as String)||cast(:world as String)").setParameter("hello","hello").setParameter("world","world").getSingleResult(), is("helloworld") );
assertThat( session.createQuery("select ?1||?2").setParameter(1,"hello").setParameter(2,"world").getSingleResult(), is("helloworld") ); assertThat( session.createQuery("select cast(?1 as String)||cast(?2 as String)").setParameter(1,"hello").setParameter(2,"world").getSingleResult(), is("helloworld") );
assertThat( session.createQuery("select ?1||?1").setParameter(1,"hello").getSingleResult(), is("hellohello") ); assertThat( session.createQuery("select cast(?1 as String)||cast(?1 as String)").setParameter(1,"hello").getSingleResult(), is("hellohello") );
} }
); );
} }
@ -320,6 +325,7 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
} }
@Test @Test
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsPadWithChar.class)
public void testPadFunction(SessionFactoryScope scope) { public void testPadFunction(SessionFactoryScope scope) {
scope.inTransaction( scope.inTransaction(
session -> { session -> {
@ -955,11 +961,20 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
} }
@Test @Test
public void testGroupingFunctions() { public void testGrouping() {
inTransaction( inTransaction(
session -> { session -> {
session.createQuery("select max(e.theDouble), e.gender, e.theInt from EntityOfBasics e group by e.gender, e.theInt") session.createQuery("select max(e.theDouble), e.gender, e.theInt from EntityOfBasics e group by e.gender, e.theInt")
.list(); .list();
}
);
}
@Test
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsGroupByRollup.class)
public void testGroupingFunctions() {
inTransaction(
session -> {
session.createQuery("select avg(e.theDouble), e.gender, e.theInt from EntityOfBasics e group by rollup(e.gender, e.theInt)") session.createQuery("select avg(e.theDouble), e.gender, e.theInt from EntityOfBasics e group by rollup(e.gender, e.theInt)")
.list(); .list();
session.createQuery("select sum(e.theDouble), e.gender, e.theInt from EntityOfBasics e group by cube(e.gender, e.theInt)") session.createQuery("select sum(e.theDouble), e.gender, e.theInt from EntityOfBasics e group by cube(e.gender, e.theInt)")

View File

@ -70,8 +70,8 @@ public class LiteralTests {
public void testJdbcTimestampLiteral(SessionFactoryScope scope) { public void testJdbcTimestampLiteral(SessionFactoryScope scope) {
scope.inTransaction( scope.inTransaction(
session -> { session -> {
session.createQuery( "from EntityOfBasics e1 where e1.theDate = {ts 1999-12-31 12:30:00}" ).list(); session.createQuery( "from EntityOfBasics e1 where e1.theTimestamp = {ts 1999-12-31 12:30:00}" ).list();
session.createQuery( "from EntityOfBasics e1 where e1.theDate = {ts '1999-12-31 12:30:00'}" ).list(); session.createQuery( "from EntityOfBasics e1 where e1.theTimestamp = {ts '1999-12-31 12:30:00'}" ).list();
} }
); );
} }

View File

@ -35,8 +35,6 @@ import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.sql.results.graph.basic.BasicResultAssembler; import org.hibernate.sql.results.graph.basic.BasicResultAssembler;
import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.type.CustomType;
import org.hibernate.type.EnumType;
import org.hibernate.type.internal.StandardBasicTypeImpl; import org.hibernate.type.internal.StandardBasicTypeImpl;
import org.hibernate.testing.hamcrest.AssignableMatcher; import org.hibernate.testing.hamcrest.AssignableMatcher;
@ -170,7 +168,7 @@ public class SmokeTests {
assertThat( sqlSelection.getJdbcValueExtractor(), notNullValue() ); assertThat( sqlSelection.getJdbcValueExtractor(), notNullValue() );
assertThat( sqlSelection, instanceOf( SqlSelectionImpl.class ) ); assertThat( sqlSelection, instanceOf( SqlSelectionImpl.class ) );
final Expression selectedExpression = ( (SqlSelectionImpl) sqlSelection ).getWrappedSqlExpression(); final Expression selectedExpression = sqlSelection.getExpression();
assertThat( selectedExpression, instanceOf( ColumnReference.class ) ); assertThat( selectedExpression, instanceOf( ColumnReference.class ) );
final ColumnReference columnReference = (ColumnReference) selectedExpression; final ColumnReference columnReference = (ColumnReference) selectedExpression;
assertThat( columnReference.renderSqlFragment( scope.getSessionFactory() ), is( "s1_0.gender" ) ); assertThat( columnReference.renderSqlFragment( scope.getSessionFactory() ), is( "s1_0.gender" ) );

View File

@ -201,7 +201,7 @@ public class SmokeTests {
scope.inTransaction( scope.inTransaction(
session -> { session -> {
final QueryImplementor<String> query = session.createQuery( final QueryImplementor<String> query = session.createQuery(
"select :param from SimpleEntity e", "select cast(:param as String) from SimpleEntity e",
String.class String.class
); );
final String attribute1 = query.setParameter( "param", "items" ).uniqueResult(); final String attribute1 = query.setParameter( "param", "items" ).uniqueResult();

View File

@ -28,12 +28,10 @@ public class HHH13884Test {
@Test @Test
public void testDefaultSqmSortSpecificationReverse() { public void testDefaultSqmSortSpecificationReverse() {
SqmExpression sortExpression = mock( SqmExpression.class ); SqmExpression sortExpression = mock( SqmExpression.class );
String collation = "collation";
SqmSortSpecification order = new SqmSortSpecification( sortExpression, collation, ASCENDING, FIRST ); SqmSortSpecification order = new SqmSortSpecification( sortExpression, ASCENDING, FIRST );
assertEquals( sortExpression, order.getSortExpression() ); assertEquals( sortExpression, order.getSortExpression() );
assertEquals( collation, order.getCollation() );
assertEquals( ASCENDING, order.getSortOrder() ); assertEquals( ASCENDING, order.getSortOrder() );
assertEquals( FIRST, order.getNullPrecedence() ); assertEquals( FIRST, order.getNullPrecedence() );

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.testing.orm.junit; package org.hibernate.testing.orm.junit;
import org.hibernate.dialect.DerbyDialect;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
/** /**
@ -213,4 +214,16 @@ abstract public class DialectFeatureChecks {
return !dialect.supportsNullPrecedence(); return !dialect.supportsNullPrecedence();
} }
} }
public static class SupportsPadWithChar implements DialectFeatureCheck {
public boolean apply(Dialect dialect) {
return !(dialect instanceof DerbyDialect );
}
}
public static class SupportsGroupByRollup implements DialectFeatureCheck {
public boolean apply(Dialect dialect) {
return dialect.supportsGroupByRollup();
}
}
} }

View File

@ -9,7 +9,7 @@ import org.apache.tools.ant.filters.ReplaceTokens
plugins { plugins {
id 'java-gradle-plugin' id 'java-gradle-plugin'
id 'com.github.sebersole.testkit-junit5' version '0.9.5' id 'com.github.sebersole.testkit-junit5' version '1.0.1'
// for portal publishing // for portal publishing
id "com.gradle.plugin-publish" version "0.12.0" id "com.gradle.plugin-publish" version "0.12.0"