Fix a few test issues, implement tuple emulation, group by support and support configuring criteria value handling mode
This commit is contained in:
parent
b9e7cc3c93
commit
d9446e7c77
|
@ -277,15 +277,7 @@ mapKeyNavigablePath
|
|||
// GROUP BY clause
|
||||
|
||||
groupByClause
|
||||
: GROUP BY groupingSpecification
|
||||
;
|
||||
|
||||
groupingSpecification
|
||||
: groupingValue ( COMMA groupingValue )*
|
||||
;
|
||||
|
||||
groupingValue
|
||||
: expression collationSpecification?
|
||||
: GROUP BY expression ( COMMA expression )*
|
||||
;
|
||||
|
||||
|
||||
|
@ -312,7 +304,7 @@ orderByFragment
|
|||
;
|
||||
|
||||
sortSpecification
|
||||
: sortExpression collationSpecification? orderingSpecification? nullsPrecedence?
|
||||
: sortExpression orderingSpecification? nullsPrecedence?
|
||||
;
|
||||
|
||||
nullsPrecedence
|
||||
|
@ -320,8 +312,8 @@ nullsPrecedence
|
|||
;
|
||||
|
||||
sortExpression
|
||||
: identifier
|
||||
| INTEGER_LITERAL
|
||||
: identifier collationSpecification?
|
||||
| INTEGER_LITERAL collationSpecification?
|
||||
| expression
|
||||
;
|
||||
|
||||
|
@ -406,15 +398,15 @@ expression
|
|||
//highest to lowest precedence
|
||||
: LEFT_PAREN expression RIGHT_PAREN # GroupedExpression
|
||||
| LEFT_PAREN subQuery RIGHT_PAREN # SubQueryExpression
|
||||
| caseList # CaseExpression
|
||||
| literal # LiteralExpression
|
||||
| parameter # ParameterExpression
|
||||
| caseList collationSpecification? # CaseExpression
|
||||
| literal collationSpecification? # LiteralExpression
|
||||
| parameter collationSpecification? # ParameterExpression
|
||||
| entityTypeReference # EntityTypeExpression
|
||||
| entityIdReference # EntityIdExpression
|
||||
| entityVersionReference # EntityVersionExpression
|
||||
| entityNaturalIdReference # EntityNaturalIdExpression
|
||||
| path # PathExpression
|
||||
| function # FunctionExpression
|
||||
| entityIdReference collationSpecification? # EntityIdExpression
|
||||
| entityVersionReference collationSpecification? # EntityVersionExpression
|
||||
| entityNaturalIdReference collationSpecification? # EntityNaturalIdExpression
|
||||
| path collationSpecification? # PathExpression
|
||||
| function collationSpecification? # FunctionExpression
|
||||
| signOperator expression # UnaryExpression
|
||||
| expression datetimeField # ToDurationExpression
|
||||
| expression BY datetimeField # FromDurationExpression
|
||||
|
@ -568,7 +560,9 @@ day: INTEGER_LITERAL;
|
|||
hour: INTEGER_LITERAL;
|
||||
minute: INTEGER_LITERAL;
|
||||
second: INTEGER_LITERAL | FLOAT_LITERAL;
|
||||
zoneId: STRING_LITERAL;
|
||||
zoneId
|
||||
: IDENTIFIER (SLASH IDENTIFIER)?
|
||||
| STRING_LITERAL;
|
||||
|
||||
jdbcTimestampLiteral
|
||||
: TIMESTAMP_ESCAPE_START (dateTime | genericTemporalLiteralText) RIGHT_BRACE
|
||||
|
|
|
@ -572,6 +572,8 @@ public class DB2Dialect extends Dialect {
|
|||
// Therefore here we overwrite the sql type descriptors to
|
||||
// use the non-N variants which are supported.
|
||||
switch ( sqlCode ) {
|
||||
case Types.BOOLEAN:
|
||||
return SmallIntTypeDescriptor.INSTANCE;
|
||||
case Types.NCHAR:
|
||||
return CharTypeDescriptor.INSTANCE;
|
||||
case Types.NCLOB:
|
||||
|
@ -678,6 +680,11 @@ public class DB2Dialect extends Dialect {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsGroupByRollup() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String translateDatetimeFormat(String format) {
|
||||
//DB2 does not need nor support FM
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.dialect;
|
|||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.function.CastStrEmulation;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.DerbyConcatEmulation;
|
||||
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.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.CastType;
|
||||
import org.hibernate.query.CastTypeKind;
|
||||
import org.hibernate.query.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
|
||||
|
@ -41,7 +43,9 @@ import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNo
|
|||
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
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.TimestampTypeDescriptor;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
@ -87,11 +91,14 @@ public class DerbyDialect extends Dialect {
|
|||
registerColumnType( Types.BIT, 1, "boolean" ); //no bit
|
||||
registerColumnType( Types.BIT, "smallint" ); //no bit
|
||||
registerColumnType( Types.TINYINT, "smallint" ); //no tinyint
|
||||
registerColumnType( Types.CHAR, "char(1)" );
|
||||
|
||||
//HHH-12827: map them both to the same type to
|
||||
// avoid problems with schema update
|
||||
// registerColumnType( Types.DECIMAL, "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, 254, "char($l) for bit data" );
|
||||
|
@ -165,7 +172,7 @@ public class DerbyDialect extends Dialect {
|
|||
queryEngine.getSqmFunctionRegistry().register( "concat", new DerbyConcatEmulation() );
|
||||
|
||||
//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 )
|
||||
.setExactArgumentCount( 2 )
|
||||
.setArgumentListSignature("(string, length)")
|
||||
|
@ -252,6 +259,12 @@ public class DerbyDialect extends Dialect {
|
|||
return "case ?1 when false then 0 when true then 1 end";
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -440,9 +453,16 @@ public class DerbyDialect extends Dialect {
|
|||
}
|
||||
|
||||
protected SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) {
|
||||
return sqlCode == Types.NUMERIC
|
||||
? DecimalTypeDescriptor.INSTANCE
|
||||
: super.getSqlTypeDescriptorOverride(sqlCode);
|
||||
switch ( sqlCode ) {
|
||||
case Types.BOOLEAN:
|
||||
return SmallIntTypeDescriptor.INSTANCE;
|
||||
case Types.NUMERIC:
|
||||
return DecimalTypeDescriptor.INSTANCE;
|
||||
case Types.TIMESTAMP_WITH_TIMEZONE:
|
||||
return TimestampTypeDescriptor.INSTANCE;
|
||||
default:
|
||||
return super.getSqlTypeDescriptorOverride(sqlCode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -738,4 +758,9 @@ public class DerbyDialect extends Dialect {
|
|||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsGroupByRollup() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ import org.hibernate.sql.*;
|
|||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.spi.ANSICaseExpressionWalker;
|
||||
import org.hibernate.sql.ast.spi.CaseExpressionWalker;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
||||
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl;
|
||||
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
|
||||
|
@ -2590,6 +2591,22 @@ public abstract class Dialect implements ConversionContext {
|
|||
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},
|
||||
* does it offer such support in IN lists as well?
|
||||
|
@ -2604,6 +2621,17 @@ public abstract class Dialect implements ConversionContext {
|
|||
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.
|
||||
* {@link java.sql.PreparedStatement#setBinaryStream}).
|
||||
|
@ -3164,6 +3192,14 @@ public abstract class Dialect implements ConversionContext {
|
|||
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()},
|
||||
* {@link Connection#createNClob()} or {@link Connection#createClob()}.
|
||||
|
@ -3575,55 +3611,62 @@ public abstract class Dialect implements ConversionContext {
|
|||
return wrapAsJdbcTimeLiteral( time );
|
||||
}
|
||||
|
||||
public String formatDateTimeLiteral(TemporalAccessor temporalAccessor, TemporalType precision) {
|
||||
public String formatDateTimeLiteral(
|
||||
TemporalAccessor temporalAccessor,
|
||||
TemporalType precision,
|
||||
TimeZone jdbcTimeZone) {
|
||||
switch ( precision ) {
|
||||
case DATE:
|
||||
return wrapDateLiteral( formatAsDate( temporalAccessor ) );
|
||||
case TIME:
|
||||
return wrapTimeLiteral( formatAsTime(temporalAccessor) );
|
||||
return wrapTimeLiteral( formatAsTime( temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone ) );
|
||||
case TIMESTAMP:
|
||||
return wrapTimestampLiteral( formatAsTimestamp(temporalAccessor) );
|
||||
return wrapTimestampLiteral( formatAsTimestamp( temporalAccessor, jdbcTimeZone ) );
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
protected String formatAsTimestamp(TemporalAccessor temporalAccessor) {
|
||||
return formatAsTimestampWithMicros(temporalAccessor);
|
||||
protected String formatAsTimestamp(TemporalAccessor temporalAccessor, TimeZone jdbcTimeZone) {
|
||||
return formatAsTimestampWithMicros( temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
|
||||
}
|
||||
|
||||
public String formatDateTimeLiteral(Date date, TemporalType precision) {
|
||||
public String formatDateTimeLiteral(Date date, TemporalType precision, TimeZone jdbcTimeZone) {
|
||||
switch ( precision ) {
|
||||
case DATE:
|
||||
return wrapDateLiteral( formatAsDate( date ) );
|
||||
case TIME:
|
||||
return wrapTimeLiteral( formatAsTime( date ) );
|
||||
case TIMESTAMP:
|
||||
return wrapTimestampLiteral( formatAsTimestamp(date) );
|
||||
return wrapTimestampLiteral( formatAsTimestamp( date, jdbcTimeZone) );
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
protected String formatAsTimestamp(Date date) {
|
||||
return formatAsTimestampWithMicros(date);
|
||||
protected String formatAsTimestamp(Date date, TimeZone jdbcTimeZone) {
|
||||
return formatAsTimestampWithMicros( date, jdbcTimeZone );
|
||||
}
|
||||
|
||||
public String formatDateTimeLiteral(Calendar calendar, TemporalType precision) {
|
||||
public String formatDateTimeLiteral(Calendar calendar, TemporalType precision, TimeZone jdbcTimeZone) {
|
||||
switch ( precision ) {
|
||||
case DATE:
|
||||
return wrapDateLiteral( formatAsDate( calendar ) );
|
||||
case TIME:
|
||||
return wrapTimeLiteral( formatAsTime( calendar ) );
|
||||
case TIMESTAMP:
|
||||
return wrapTimestampLiteral( formatAsTimestamp(calendar) );
|
||||
return wrapTimestampLiteral( formatAsTimestamp( calendar, jdbcTimeZone ) );
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
protected String formatAsTimestamp(Calendar calendar) {
|
||||
return formatAsTimestampWithMicros(calendar);
|
||||
protected String formatAsTimestamp(Calendar calendar, TimeZone jdbcTimeZone) {
|
||||
return formatAsTimestampWithMicros( calendar, jdbcTimeZone );
|
||||
}
|
||||
|
||||
public boolean supportsTemporalLiteralOffset() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// deprecated limit/offset support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.hibernate.engine.jdbc.Size;
|
|||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
import org.hibernate.exception.LockAcquisitionException;
|
||||
import org.hibernate.exception.LockTimeoutException;
|
||||
|
@ -49,6 +50,7 @@ import java.sql.Types;
|
|||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
@ -491,18 +493,18 @@ public class FirebirdDialect extends Dialect {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String formatAsTimestamp(Date date) {
|
||||
return formatAsTimestampWithMillis(date);
|
||||
protected String formatAsTimestamp(Date date, TimeZone jdbcTimeZone) {
|
||||
return formatAsTimestampWithMillis( date, jdbcTimeZone );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String formatAsTimestamp(Calendar calendar) {
|
||||
return formatAsTimestampWithMillis(calendar);
|
||||
protected String formatAsTimestamp(Calendar calendar, TimeZone jdbcTimeZone) {
|
||||
return formatAsTimestampWithMillis( calendar, jdbcTimeZone );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String formatAsTimestamp(TemporalAccessor temporalAccessor) {
|
||||
return formatAsTimestampWithMillis(temporalAccessor);
|
||||
protected String formatAsTimestamp(TemporalAccessor temporalAccessor, TimeZone jdbcTimeZone) {
|
||||
return formatAsTimestampWithMillis( temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -196,6 +196,11 @@ public class H2Dialect extends Dialect {
|
|||
return "datediff(?1, ?2, ?3)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTemporalLiteralOffset() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toBooleanValueString(boolean bool) {
|
||||
return String.valueOf( bool );
|
||||
|
|
|
@ -918,4 +918,9 @@ public class MySQLDialect extends Dialect {
|
|||
boolean supportsAliasLocks() {
|
||||
return getVersion() >= 800;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsGroupByRollup() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -794,6 +794,11 @@ public class OracleDialect extends Dialect {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsGroupByRollup() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInExpressionCountLimit() {
|
||||
return PARAM_LIST_SIZE_LIMIT;
|
||||
|
|
|
@ -605,6 +605,11 @@ public class PostgreSQLDialect extends Dialect {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatementSupport getCallableStatementSupport() {
|
||||
return PostgresCallableStatementSupport.INSTANCE;
|
||||
|
@ -765,6 +770,11 @@ public class PostgreSQLDialect extends Dialect {
|
|||
return getVersion() >= 950;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsGroupByRollup() {
|
||||
return getVersion() >= 950;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void augmentRecognizedTableTypes(List<String> tableTypesList) {
|
||||
super.augmentRecognizedTableTypes( tableTypesList );
|
||||
|
@ -832,7 +842,7 @@ public class PostgreSQLDialect extends Dialect {
|
|||
X value,
|
||||
int index,
|
||||
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
|
||||
|
@ -841,7 +851,7 @@ public class PostgreSQLDialect extends Dialect {
|
|||
X value,
|
||||
String name,
|
||||
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 ) {
|
||||
@Override
|
||||
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
|
||||
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
|
||||
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 );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -353,6 +353,11 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
|||
return getVersion() >= 9;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsGroupByRollup() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SequenceSupport getSequenceSupport() {
|
||||
return getVersion() < 11
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -200,7 +200,7 @@ public final class FastSessionServices {
|
|||
return elr.getEventListenerGroup( type );
|
||||
}
|
||||
|
||||
SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
|
||||
public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
|
||||
if ( !sqlTypeDescriptor.canBeRemapped() ) {
|
||||
return sqlTypeDescriptor;
|
||||
}
|
||||
|
@ -288,6 +288,10 @@ public final class FastSessionServices {
|
|||
return defaultJdbcObservers;
|
||||
}
|
||||
|
||||
public boolean useStreamForLobBinding() {
|
||||
return useStreamForLobBinding;
|
||||
}
|
||||
|
||||
public void firePostLoadEvent(final PostLoadEvent postLoadEvent) {
|
||||
eventListenerGroup_POST_LOAD.fireEventOnEachListener( postLoadEvent, PostLoadEventListener::onPostLoad );
|
||||
}
|
||||
|
|
|
@ -221,7 +221,7 @@ public class SessionImpl
|
|||
//There might be custom properties for this session that affect the LockOptions state
|
||||
LockOptionsHelper.applyPropertiesToLockOptions( this.properties, this::getLockOptionsForWrite );
|
||||
}
|
||||
getSession().setCacheMode( fastSessionServices.initialSessionCacheMode );
|
||||
setCacheMode( fastSessionServices.initialSessionCacheMode );
|
||||
|
||||
// NOTE : pulse() already handles auto-join-ability correctly
|
||||
getTransactionCoordinator().pulse();
|
||||
|
@ -235,7 +235,7 @@ public class SessionImpl
|
|||
else {
|
||||
initialMode = ConfigurationHelper.getFlushMode( getSessionProperty( AvailableSettings.FLUSH_MODE ), FlushMode.AUTO );
|
||||
}
|
||||
getSession().setHibernateFlushMode( initialMode );
|
||||
setHibernateFlushMode( initialMode );
|
||||
}
|
||||
|
||||
if ( log.isTraceEnabled() ) {
|
||||
|
@ -2872,7 +2872,7 @@ public class SessionImpl
|
|||
LockOptionsHelper.applyPropertiesToLockOptions( properties, this::getLockOptionsForWrite );
|
||||
}
|
||||
else if ( JPA_SHARED_CACHE_RETRIEVE_MODE.equals( propertyName ) || JPA_SHARED_CACHE_STORE_MODE.equals( propertyName ) ) {
|
||||
getSession().setCacheMode(
|
||||
setCacheMode(
|
||||
CacheModeHelper.interpretCacheMode(
|
||||
determineCacheStoreMode( properties ),
|
||||
determineCacheRetrieveMode( properties )
|
||||
|
|
|
@ -37,7 +37,6 @@ import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
|||
import org.hibernate.sql.exec.spi.JdbcSelect;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
|
||||
import org.hibernate.type.SerializableType;
|
||||
|
||||
/**
|
||||
* Batch support for natural-id multi loading
|
||||
|
@ -139,10 +138,17 @@ public class MultiNaturalIdLoadingBatcher {
|
|||
|
||||
if ( needsExecution ) {
|
||||
while ( jdbcParamItr.hasNext() ) {
|
||||
final JdbcParameterBindings jdbcParamBindingsRef = jdbcParamBindings;
|
||||
final Iterator<JdbcParameter> jdbcParamItrRef = jdbcParamItr;
|
||||
// pad the remaining parameters with null
|
||||
jdbcParamBindings.addBinding(
|
||||
jdbcParamItr.next(),
|
||||
new JdbcParameterBindingImpl( SerializableType.INSTANCE, null )
|
||||
entityDescriptor.getNaturalIdMapping().visitJdbcValues(
|
||||
null,
|
||||
Clause.IRRELEVANT,
|
||||
(jdbcValue, jdbcMapping) -> jdbcParamBindingsRef.addBinding(
|
||||
jdbcParamItrRef.next(),
|
||||
new JdbcParameterBindingImpl( jdbcMapping, jdbcValue )
|
||||
),
|
||||
session
|
||||
);
|
||||
}
|
||||
final List<E> batchResults = performLoad( jdbcParamBindings, session );
|
||||
|
|
|
@ -241,7 +241,7 @@ public abstract class AbstractCompositeIdentifierMapping
|
|||
}
|
||||
|
||||
@Override
|
||||
public Expression toSqlExpression(
|
||||
public SqlTuple toSqlExpression(
|
||||
TableGroup tableGroup,
|
||||
Clause clause,
|
||||
SqmToSqlAstConverter walker,
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
|||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||
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.TableGroupJoinProducer;
|
||||
import org.hibernate.sql.results.graph.Fetchable;
|
||||
|
@ -54,7 +55,7 @@ public interface EmbeddableValuedModelPart extends ModelPart, Fetchable, Fetchab
|
|||
return null;
|
||||
}
|
||||
|
||||
Expression toSqlExpression(
|
||||
SqlTuple toSqlExpression(
|
||||
TableGroup tableGroup,
|
||||
Clause clause,
|
||||
SqmToSqlAstConverter walker,
|
||||
|
|
|
@ -27,36 +27,7 @@ public class MappingModelHelper {
|
|||
SessionFactoryImplementor sessionFactory) {
|
||||
final int jdbcTypeCount = modelPart.getJdbcTypeCount( sessionFactory.getTypeConfiguration() );
|
||||
|
||||
if ( jdbcTypeCount == 1 ) {
|
||||
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 {
|
||||
if ( modelPart instanceof EmbeddableValuedModelPart ) {
|
||||
final List<ColumnReference> columnReferences = new ArrayList<>( jdbcTypeCount );
|
||||
modelPart.visitColumns(
|
||||
(table, column, isFormula, readFragment, writeFragment, jdbcMapping) -> {
|
||||
|
@ -91,6 +62,35 @@ public class MappingModelHelper {
|
|||
);
|
||||
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() {
|
||||
|
|
|
@ -223,7 +223,7 @@ public class EmbeddedAttributeMapping
|
|||
}
|
||||
|
||||
@Override
|
||||
public Expression toSqlExpression(
|
||||
public SqlTuple toSqlExpression(
|
||||
TableGroup tableGroup,
|
||||
Clause clause,
|
||||
SqmToSqlAstConverter walker,
|
||||
|
|
|
@ -210,7 +210,7 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
|
|||
}
|
||||
|
||||
@Override
|
||||
public Expression toSqlExpression(
|
||||
public SqlTuple toSqlExpression(
|
||||
TableGroup tableGroup,
|
||||
Clause clause,
|
||||
SqmToSqlAstConverter walker,
|
||||
|
|
|
@ -33,13 +33,23 @@ import java.time.*;
|
|||
* @author Gavin King
|
||||
*/
|
||||
public enum CastType {
|
||||
STRING,
|
||||
BOOLEAN,
|
||||
INTEGER, LONG, FLOAT, DOUBLE, FIXED,
|
||||
DATE, TIME, TIMESTAMP,
|
||||
OFFSET_TIMESTAMP, ZONE_TIMESTAMP,
|
||||
NULL,
|
||||
OTHER;
|
||||
STRING(CastTypeKind.TEXT),
|
||||
BOOLEAN(CastTypeKind.BOOLEAN),
|
||||
INTEGER(CastTypeKind.NUMERIC), LONG(CastTypeKind.NUMERIC), FLOAT(CastTypeKind.NUMERIC), DOUBLE(CastTypeKind.NUMERIC), FIXED(CastTypeKind.NUMERIC),
|
||||
DATE(CastTypeKind.TEMPORAL), TIME(CastTypeKind.TEMPORAL), TIMESTAMP(CastTypeKind.TEMPORAL),
|
||||
OFFSET_TIMESTAMP(CastTypeKind.TEMPORAL), ZONE_TIMESTAMP(CastTypeKind.TEMPORAL),
|
||||
NULL(null),
|
||||
OTHER(null);
|
||||
|
||||
private final CastTypeKind kind;
|
||||
|
||||
CastType(CastTypeKind kind) {
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
public CastTypeKind getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
public static CastType from(Class javaClass) {
|
||||
if (String.class.equals(javaClass)) {
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -12,10 +12,16 @@ package org.hibernate.query;
|
|||
*/
|
||||
public enum ComparisonOperator {
|
||||
EQUAL {
|
||||
@Override
|
||||
public ComparisonOperator negated() {
|
||||
return NOT_EQUAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonOperator invert() {
|
||||
return EQUAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sqlText() {
|
||||
return "=";
|
||||
|
@ -23,10 +29,16 @@ public enum ComparisonOperator {
|
|||
},
|
||||
|
||||
NOT_EQUAL {
|
||||
@Override
|
||||
public ComparisonOperator negated() {
|
||||
return EQUAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonOperator invert() {
|
||||
return NOT_EQUAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sqlText() {
|
||||
return "!=";
|
||||
|
@ -34,10 +46,16 @@ public enum ComparisonOperator {
|
|||
},
|
||||
|
||||
LESS_THAN {
|
||||
@Override
|
||||
public ComparisonOperator negated() {
|
||||
return GREATER_THAN_OR_EQUAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonOperator invert() {
|
||||
return GREATER_THAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sqlText() {
|
||||
return "<";
|
||||
|
@ -45,10 +63,16 @@ public enum ComparisonOperator {
|
|||
},
|
||||
|
||||
LESS_THAN_OR_EQUAL {
|
||||
@Override
|
||||
public ComparisonOperator negated() {
|
||||
return GREATER_THAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonOperator invert() {
|
||||
return GREATER_THAN_OR_EQUAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sqlText() {
|
||||
return "<=";
|
||||
|
@ -56,10 +80,16 @@ public enum ComparisonOperator {
|
|||
},
|
||||
|
||||
GREATER_THAN {
|
||||
@Override
|
||||
public ComparisonOperator negated() {
|
||||
return LESS_THAN_OR_EQUAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonOperator invert() {
|
||||
return LESS_THAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sqlText() {
|
||||
return ">";
|
||||
|
@ -67,10 +97,16 @@ public enum ComparisonOperator {
|
|||
},
|
||||
|
||||
GREATER_THAN_OR_EQUAL {
|
||||
@Override
|
||||
public ComparisonOperator negated() {
|
||||
return LESS_THAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonOperator invert() {
|
||||
return LESS_THAN_OR_EQUAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sqlText() {
|
||||
return ">=";
|
||||
|
@ -78,5 +114,6 @@ public enum ComparisonOperator {
|
|||
};
|
||||
|
||||
public abstract ComparisonOperator negated();
|
||||
public abstract ComparisonOperator invert();
|
||||
public abstract String sqlText();
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import javax.persistence.criteria.Subquery;
|
|||
import org.hibernate.NullPrecedence;
|
||||
import org.hibernate.SortOrder;
|
||||
import org.hibernate.metamodel.model.domain.DomainType;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
<T> SqmExpression<T> value(T value);
|
||||
|
||||
<V, C extends Collection<V>> JpaExpression<Collection<V>> values(C collection);
|
||||
|
||||
@Override
|
||||
|
|
|
@ -94,5 +94,5 @@ public interface JpaQueryStructure<T> extends JpaCriteriaNode {
|
|||
|
||||
<X> JpaExpression<X> getOffset();
|
||||
|
||||
JpaQueryStructure<T> setOffset(JpaExpression offset);
|
||||
JpaQueryStructure<T> setOffset(JpaExpression<?> offset);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
*/
|
||||
package org.hibernate.query.hql.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
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.SqmDynamicInstantiationArgument;
|
||||
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.SqmQuerySpec;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectClause;
|
||||
|
@ -188,7 +188,8 @@ public class QuerySplitter {
|
|||
sqmQuerySpec.setFromClause( visitFromClause( querySpec.getFromClause() ) );
|
||||
sqmQuerySpec.setSelectClause( visitSelectClause( querySpec.getSelectClause() ) );
|
||||
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() ) );
|
||||
if ( querySpec.getLimitExpression() != null ) {
|
||||
sqmQuerySpec.setLimitExpression( (SqmExpression) querySpec.getLimitExpression().accept( this ) );
|
||||
|
@ -218,33 +219,23 @@ public class QuerySplitter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmGroupByClause visitGroupByClause(SqmGroupByClause clause) {
|
||||
if ( clause == null ) {
|
||||
return null;
|
||||
public List<SqmExpression<?>> visitGroupByClause(List<SqmExpression<?>> groupByClauseExpressions) {
|
||||
if ( groupByClauseExpressions.isEmpty() ) {
|
||||
return groupByClauseExpressions;
|
||||
}
|
||||
final SqmGroupByClause result = new SqmGroupByClause();
|
||||
clause.visitGroupings(
|
||||
grouping -> result.addGrouping(
|
||||
(SqmExpression) grouping.getExpression().accept( this ),
|
||||
grouping.getCollation()
|
||||
)
|
||||
);
|
||||
return result;
|
||||
List<SqmExpression<?>> expressions = new ArrayList<>( groupByClauseExpressions.size() );
|
||||
for ( SqmExpression<?> groupByClauseExpression : groupByClauseExpressions ) {
|
||||
expressions.add( (SqmExpression<?>) groupByClauseExpression.accept( this ) );
|
||||
}
|
||||
return expressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmGroupByClause.SqmGrouping visitGrouping(SqmGroupByClause.SqmGrouping grouping) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmHavingClause visitHavingClause(SqmHavingClause clause) {
|
||||
if ( clause == null || clause.getPredicate() == null ) {
|
||||
public SqmPredicate visitHavingClause(SqmPredicate sqmPredicate) {
|
||||
if ( sqmPredicate == null ) {
|
||||
return null;
|
||||
}
|
||||
return new SqmHavingClause(
|
||||
(SqmPredicate) clause.getPredicate().accept( this )
|
||||
);
|
||||
return (SqmPredicate) sqmPredicate.accept( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -598,7 +589,6 @@ public class QuerySplitter {
|
|||
public SqmSortSpecification visitSortSpecification(SqmSortSpecification sortSpecification) {
|
||||
return new SqmSortSpecification(
|
||||
(SqmExpression) sortSpecification.getSortExpression().accept( this ),
|
||||
sortSpecification.getCollation(),
|
||||
sortSpecification.getSortOrder(),
|
||||
sortSpecification.getNullPrecedence()
|
||||
);
|
||||
|
@ -638,7 +628,7 @@ public class QuerySplitter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmLiteral visitLiteral(SqmLiteral literal) {
|
||||
public SqmLiteral visitLiteral(SqmLiteral<?> literal) {
|
||||
return new SqmLiteral(
|
||||
literal.getLiteralValue(),
|
||||
literal.getNodeType(),
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -6,23 +6,23 @@
|
|||
*/
|
||||
package org.hibernate.query.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.QueryParameterException;
|
||||
import org.hibernate.cache.spi.QueryKey;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.query.QueryParameter;
|
||||
import org.hibernate.query.spi.ParameterMetadataImplementor;
|
||||
import org.hibernate.query.spi.QueryParameterBinding;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
/**
|
||||
* Manages the group of QueryParameterBinding for a particular query.
|
||||
|
@ -179,21 +179,50 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||
|
||||
@Override
|
||||
public QueryKey.ParameterBindingsMemento generateQueryKeyMemento() {
|
||||
// todo (6.0) : need to decide how to handle
|
||||
if ( parameterMetadata.getParameterCount() == 0 && CollectionHelper.isEmpty( parameterBindingMap ) ) {
|
||||
return new QueryKey.ParameterBindingsMemento() {
|
||||
final int size = parameterBindingMap.size();
|
||||
final Object[] values = new Object[size];
|
||||
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
|
||||
public int hashCode() {
|
||||
return QueryParameterBindingsImpl.class.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof QueryKey.ParameterBindingsMemento;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,11 @@ public class SqlSelectionImpl implements SqlSelection, Expression, SqlExpression
|
|||
return valuesArrayPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression getExpression() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingModelExpressable getExpressionType() {
|
||||
return valueMapping;
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.Incubating;
|
||||
import org.hibernate.boot.spi.BootstrapContext;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
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.metamodel.model.domain.JpaMetamodel;
|
||||
import org.hibernate.query.QueryLogging;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
import org.hibernate.query.hql.HqlTranslator;
|
||||
import org.hibernate.query.hql.internal.StandardHqlTranslator;
|
||||
import org.hibernate.query.hql.spi.SqmCreationOptions;
|
||||
|
@ -68,6 +70,7 @@ public class QueryEngine {
|
|||
|
||||
return new QueryEngine(
|
||||
() -> sessionFactory.getRuntimeMetamodels().getJpaMetamodel(),
|
||||
sessionFactory.getSessionFactoryOptions().getCriteriaLiteralHandlingMode(),
|
||||
metadata.buildNamedQueryRepository( sessionFactory ),
|
||||
hqlTranslator,
|
||||
sqmTranslatorFactory,
|
||||
|
@ -89,6 +92,7 @@ public class QueryEngine {
|
|||
|
||||
public QueryEngine(
|
||||
Supplier<JpaMetamodel> jpaMetamodelAccess,
|
||||
LiteralHandlingMode criteriaLiteralHandlingMode,
|
||||
NamedObjectRepository namedObjectRepository,
|
||||
HqlTranslator hqlTranslator,
|
||||
SqmTranslatorFactory sqmTranslatorFactory,
|
||||
|
@ -106,7 +110,8 @@ public class QueryEngine {
|
|||
this.criteriaBuilder = new SqmCriteriaNodeBuilder(
|
||||
this,
|
||||
jpaMetamodelAccess,
|
||||
serviceRegistry
|
||||
serviceRegistry,
|
||||
criteriaLiteralHandlingMode
|
||||
);
|
||||
|
||||
this.sqmFunctionRegistry = new SqmFunctionRegistry();
|
||||
|
@ -132,6 +137,7 @@ public class QueryEngine {
|
|||
*/
|
||||
public QueryEngine(
|
||||
JpaMetamodel jpaMetamodel,
|
||||
LiteralHandlingMode criteriaLiteralHandlingMode,
|
||||
boolean useStrictJpaCompliance,
|
||||
NamedObjectRepository namedObjectRepository,
|
||||
NativeQueryInterpreter nativeQueryInterpreter,
|
||||
|
@ -147,7 +153,8 @@ public class QueryEngine {
|
|||
this.criteriaBuilder = new SqmCriteriaNodeBuilder(
|
||||
this,
|
||||
() -> jpaMetamodel,
|
||||
serviceRegistry
|
||||
serviceRegistry,
|
||||
criteriaLiteralHandlingMode
|
||||
);
|
||||
|
||||
final SqmCreationContext sqmCreationContext = new SqmCreationContext() {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.query.sqm;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.query.sqm.tree.cte.SqmCteConsumer;
|
||||
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.SqmCastTarget;
|
||||
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.JpaCriteriaParameter;
|
||||
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.SqmNullnessPredicate;
|
||||
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.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.SqmOrderByClause;
|
||||
import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
|
||||
|
@ -165,11 +167,9 @@ public interface SemanticQueryWalker<T> {
|
|||
|
||||
T visitValues(SqmValues values);
|
||||
|
||||
T visitGroupByClause(SqmGroupByClause clause);
|
||||
T visitGroupByClause(List<SqmExpression<?>> groupByClauseExpressions);
|
||||
|
||||
T visitGrouping(SqmGroupByClause.SqmGrouping grouping);
|
||||
|
||||
T visitHavingClause(SqmHavingClause clause);
|
||||
T visitHavingClause(SqmPredicate clause);
|
||||
|
||||
T visitDynamicInstantiation(SqmDynamicInstantiation<?> sqmDynamicInstantiation);
|
||||
|
||||
|
@ -189,6 +189,8 @@ public interface SemanticQueryWalker<T> {
|
|||
|
||||
T visitTuple(SqmTuple<?> sqmTuple);
|
||||
|
||||
T visitCollate(SqmCollate<?> sqmCollate);
|
||||
|
||||
T visitBinaryArithmeticExpression(SqmBinaryArithmetic<?> expression);
|
||||
|
||||
T visitSubQueryExpression(SqmSubQuery<?> expression);
|
||||
|
@ -200,6 +202,7 @@ public interface SemanticQueryWalker<T> {
|
|||
T visitSearchedCaseExpression(SqmCaseSearched<?> expression);
|
||||
|
||||
T visitAny(SqmAny<?> sqmAny);
|
||||
|
||||
T visitEvery(SqmEvery<?> sqmEvery);
|
||||
|
||||
T visitPositionalParameterExpression(SqmPositionalParameter<?> expression);
|
||||
|
|
|
@ -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.SqmStatement;
|
||||
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.from.SqmRoot;
|
||||
import org.hibernate.query.sqm.tree.insert.SqmInsertStatement;
|
||||
|
@ -230,6 +232,17 @@ public class QuerySqmImpl<R>
|
|||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.hibernate.NotYetImplementedFor6Exception;
|
|||
import org.hibernate.NullPrecedence;
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.SortOrder;
|
||||
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
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.JpaExpression;
|
||||
import org.hibernate.query.criteria.JpaSelection;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
import org.hibernate.query.internal.QueryHelper;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
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.update.SqmUpdateStatement;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
|
@ -124,21 +127,25 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
return new SqmCriteriaNodeBuilder(
|
||||
sf.getQueryEngine(),
|
||||
() -> sf.getRuntimeMetamodels().getJpaMetamodel(),
|
||||
sf.getServiceRegistry()
|
||||
sf.getServiceRegistry(),
|
||||
sf.getSessionFactoryOptions().getCriteriaLiteralHandlingMode()
|
||||
);
|
||||
}
|
||||
|
||||
private final QueryEngine queryEngine;
|
||||
private final Supplier<JpaMetamodel> domainModelAccess;
|
||||
private final ServiceRegistry serviceRegistry;
|
||||
private final LiteralHandlingMode criteriaLiteralHandlingMode;
|
||||
|
||||
public SqmCriteriaNodeBuilder(
|
||||
QueryEngine queryEngine,
|
||||
Supplier<JpaMetamodel> domainModelAccess,
|
||||
ServiceRegistry serviceRegistry) {
|
||||
ServiceRegistry serviceRegistry,
|
||||
LiteralHandlingMode criteriaLiteralHandlingMode) {
|
||||
this.queryEngine = queryEngine;
|
||||
this.domainModelAccess = domainModelAccess;
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
this.criteriaLiteralHandlingMode = criteriaLiteralHandlingMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -573,17 +580,17 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
|
||||
@Override
|
||||
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
|
||||
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
|
||||
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
|
||||
|
@ -610,7 +617,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
return createSqmArithmeticNode(
|
||||
BinaryArithmeticOperator.SUBTRACT,
|
||||
(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) {
|
||||
return createSqmArithmeticNode(
|
||||
BinaryArithmeticOperator.SUBTRACT,
|
||||
literal( x ),
|
||||
value( x ),
|
||||
(SqmExpression) y
|
||||
);
|
||||
}
|
||||
|
@ -637,7 +644,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
return createSqmArithmeticNode(
|
||||
BinaryArithmeticOperator.QUOT,
|
||||
(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) {
|
||||
return createSqmArithmeticNode(
|
||||
BinaryArithmeticOperator.QUOT,
|
||||
literal( x ),
|
||||
value( x ),
|
||||
(SqmExpression) y
|
||||
);
|
||||
}
|
||||
|
@ -664,7 +671,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
return createSqmArithmeticNode(
|
||||
BinaryArithmeticOperator.MODULO,
|
||||
(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) {
|
||||
return createSqmArithmeticNode(
|
||||
BinaryArithmeticOperator.MODULO,
|
||||
literal( x ),
|
||||
value( x ),
|
||||
(SqmExpression) y
|
||||
);
|
||||
}
|
||||
|
@ -882,7 +889,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
@Override
|
||||
public SqmExpression<String> concat(Expression<String> x, String y) {
|
||||
final SqmExpression xSqmExpression = (SqmExpression) x;
|
||||
final SqmExpression ySqmExpression = literal( y );
|
||||
final SqmExpression ySqmExpression = value( y );
|
||||
//noinspection unchecked
|
||||
return getFunctionDescriptor( "concat" ).generateSqmExpression(
|
||||
asList( xSqmExpression, ySqmExpression ),
|
||||
|
@ -898,7 +905,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
|
||||
@Override
|
||||
public SqmExpression<String> concat(String x, Expression<String> y) {
|
||||
final SqmExpression xSqmExpression = literal( x );
|
||||
final SqmExpression xSqmExpression = value( x );
|
||||
final SqmExpression ySqmExpression = (SqmExpression) y;
|
||||
//noinspection unchecked
|
||||
return getFunctionDescriptor( "concat" ).generateSqmExpression(
|
||||
|
@ -915,8 +922,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
|
||||
@Override
|
||||
public SqmExpression<String> concat(String x, String y) {
|
||||
final SqmExpression xSqmExpression = literal( x );
|
||||
final SqmExpression ySqmExpression = literal( y );
|
||||
final SqmExpression xSqmExpression = value( x );
|
||||
final SqmExpression ySqmExpression = value( y );
|
||||
//noinspection unchecked
|
||||
return getFunctionDescriptor( "concat" ).generateSqmExpression(
|
||||
asList( xSqmExpression, ySqmExpression ),
|
||||
|
@ -958,7 +965,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
public SqmFunction<String> substring(Expression<String> source, int from) {
|
||||
return createSubstringNode(
|
||||
(SqmExpression) source,
|
||||
literal( from ),
|
||||
value( from ),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
@ -976,8 +983,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
public SqmFunction<String> substring(Expression<String> source, int from, int len) {
|
||||
return createSubstringNode(
|
||||
(SqmExpression) source,
|
||||
literal( from ),
|
||||
literal( len )
|
||||
value( from ),
|
||||
value( len )
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1148,7 +1155,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
public SqmFunction<Integer> locate(Expression<String> source, String pattern) {
|
||||
return createLocateFunctionNode(
|
||||
(SqmExpression<String>) source,
|
||||
literal( pattern ),
|
||||
value( pattern ),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
@ -1166,8 +1173,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
public SqmFunction<Integer> locate(Expression<String> source, String pattern, int startPosition) {
|
||||
return createLocateFunctionNode(
|
||||
(SqmExpression<String>) source,
|
||||
literal( pattern ),
|
||||
literal( startPosition )
|
||||
value( pattern ),
|
||||
value( startPosition )
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1280,6 +1287,27 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
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
|
||||
public <V, C extends Collection<V>> SqmExpression<Collection<V>> values(C collection) {
|
||||
throw new NotYetImplementedFor6Exception();
|
||||
|
@ -1326,7 +1354,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
|
||||
@Override
|
||||
public <Y> JpaCoalesce<Y> coalesce(Expression<? extends Y> x, Y y) {
|
||||
return coalesce( x, literal( y ) );
|
||||
return coalesce( x, value( y ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1338,7 +1366,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
@Override
|
||||
public <Y> SqmExpression<Y> nullif(Expression<Y> x, Y y) {
|
||||
//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) {
|
||||
|
@ -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) {
|
||||
return new SqmBetweenPredicate(
|
||||
(SqmExpression) value,
|
||||
literal( lower ),
|
||||
literal( upper ),
|
||||
value( lower ),
|
||||
value( upper ),
|
||||
false,
|
||||
this
|
||||
);
|
||||
|
@ -1520,7 +1548,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
return new SqmComparisonPredicate(
|
||||
(SqmExpression<?>) x,
|
||||
ComparisonOperator.EQUAL,
|
||||
literal( y ),
|
||||
value( y ),
|
||||
this
|
||||
);
|
||||
}
|
||||
|
@ -1540,7 +1568,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
return new SqmComparisonPredicate(
|
||||
(SqmExpression<?>) x,
|
||||
ComparisonOperator.NOT_EQUAL,
|
||||
literal( y ),
|
||||
value( y ),
|
||||
this
|
||||
);
|
||||
}
|
||||
|
@ -1560,7 +1588,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
return new SqmComparisonPredicate(
|
||||
(SqmExpression<?>) x,
|
||||
ComparisonOperator.GREATER_THAN,
|
||||
literal( y ),
|
||||
value( y ),
|
||||
this
|
||||
);
|
||||
}
|
||||
|
@ -1580,7 +1608,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
return new SqmComparisonPredicate(
|
||||
(SqmExpression<?>) x,
|
||||
ComparisonOperator.GREATER_THAN_OR_EQUAL,
|
||||
literal( y ),
|
||||
value( y ),
|
||||
this
|
||||
);
|
||||
}
|
||||
|
@ -1600,7 +1628,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
return new SqmComparisonPredicate(
|
||||
(SqmExpression<?>) x,
|
||||
ComparisonOperator.LESS_THAN,
|
||||
literal( y ),
|
||||
value( y ),
|
||||
this
|
||||
);
|
||||
}
|
||||
|
@ -1620,7 +1648,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
return new SqmComparisonPredicate(
|
||||
(SqmExpression<?>) x,
|
||||
ComparisonOperator.LESS_THAN_OR_EQUAL,
|
||||
literal( y ),
|
||||
value( y ),
|
||||
this
|
||||
);
|
||||
}
|
||||
|
@ -1640,7 +1668,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
return new SqmComparisonPredicate(
|
||||
(SqmExpression<?>) x,
|
||||
ComparisonOperator.GREATER_THAN,
|
||||
literal( y ),
|
||||
value( y ),
|
||||
this
|
||||
);
|
||||
}
|
||||
|
@ -1660,7 +1688,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
return new SqmComparisonPredicate(
|
||||
(SqmExpression<?>) x,
|
||||
ComparisonOperator.GREATER_THAN_OR_EQUAL,
|
||||
literal( y ),
|
||||
value( y ),
|
||||
this
|
||||
);
|
||||
}
|
||||
|
@ -1680,7 +1708,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
return new SqmComparisonPredicate(
|
||||
(SqmExpression<?>) x,
|
||||
ComparisonOperator.LESS_THAN,
|
||||
literal( y ),
|
||||
value( y ),
|
||||
this
|
||||
);
|
||||
}
|
||||
|
@ -1700,7 +1728,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
return new SqmComparisonPredicate(
|
||||
(SqmExpression<?>) x,
|
||||
ComparisonOperator.LESS_THAN_OR_EQUAL,
|
||||
literal( y ),
|
||||
value( y ),
|
||||
this
|
||||
);
|
||||
}
|
||||
|
@ -1748,7 +1776,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
public SqmPredicate like(Expression<String> searchString, String pattern) {
|
||||
return new SqmLikePredicate(
|
||||
(SqmExpression) searchString,
|
||||
literal( pattern ),
|
||||
value( pattern ),
|
||||
this
|
||||
);
|
||||
}
|
||||
|
@ -1777,7 +1805,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
public SqmPredicate like(Expression<String> searchString, String pattern, Expression<Character> escapeChar) {
|
||||
return new SqmLikePredicate(
|
||||
(SqmExpression) searchString,
|
||||
literal( pattern ),
|
||||
value( pattern ),
|
||||
(SqmExpression) escapeChar,
|
||||
this
|
||||
);
|
||||
|
@ -1787,7 +1815,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
|
|||
public SqmPredicate like(Expression<String> searchString, String pattern, char escapeChar) {
|
||||
return new SqmLikePredicate(
|
||||
(SqmExpression) searchString,
|
||||
literal( pattern ),
|
||||
value( pattern ),
|
||||
literal( escapeChar ),
|
||||
this
|
||||
);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.query.sqm.internal;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
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.SqmCastTarget;
|
||||
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.SqmDistinct;
|
||||
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.SqmNullnessPredicate;
|
||||
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.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.SqmQuerySpec;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectClause;
|
||||
|
@ -394,21 +395,18 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
|
|||
// query-spec
|
||||
|
||||
@Override
|
||||
public Object visitQuerySpec(SqmQuerySpec querySpec) {
|
||||
public Object visitQuerySpec(SqmQuerySpec<?> querySpec) {
|
||||
processStanza(
|
||||
"query-spec",
|
||||
() -> {
|
||||
visitSelectClause( querySpec.getSelectClause() );
|
||||
|
||||
visitFromClause( querySpec.getFromClause() );
|
||||
|
||||
visitGroupByClause( querySpec.getGroupByClause() );
|
||||
visitHavingClause( querySpec.getHavingClause() );
|
||||
|
||||
visitWhereClause( querySpec.getWhereClause() );
|
||||
|
||||
visitOrderByClause( querySpec.getOrderByClause() );
|
||||
visitGroupByClause( querySpec.getGroupByClauseExpressions() );
|
||||
visitHavingClause( querySpec.getHavingClausePredicate() );
|
||||
|
||||
visitOrderByClause( querySpec.getOrderByClause() );
|
||||
visitLimitExpression( querySpec.getLimitExpression() );
|
||||
visitOffsetExpression( querySpec.getOffsetExpression() );
|
||||
}
|
||||
|
@ -418,11 +416,11 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object visitGroupByClause(SqmGroupByClause clause) {
|
||||
if ( clause != null ) {
|
||||
public Object visitGroupByClause(List<SqmExpression<?>> groupByClauseExpressions) {
|
||||
if ( groupByClauseExpressions != null && !groupByClauseExpressions.isEmpty() ) {
|
||||
processStanza(
|
||||
"group-by",
|
||||
() -> clause.visitGroupings( this::visitGrouping )
|
||||
() -> groupByClauseExpressions.forEach( e -> e.accept( this ) )
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -430,21 +428,11 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object visitGrouping(SqmGroupByClause.SqmGrouping grouping) {
|
||||
processStanza(
|
||||
"grouping",
|
||||
() -> grouping.getExpression().accept( this )
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitHavingClause(SqmHavingClause clause) {
|
||||
if ( clause != null ) {
|
||||
public Object visitHavingClause(SqmPredicate predicate) {
|
||||
if ( predicate != null ) {
|
||||
processStanza(
|
||||
"having",
|
||||
() -> clause.getPredicate().accept( this )
|
||||
() -> predicate.accept( this )
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -912,6 +900,11 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitCollate(SqmCollate<?> sqmCollate) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitBinaryArithmeticExpression(SqmBinaryArithmetic expression) {
|
||||
return null;
|
||||
|
|
|
@ -231,7 +231,7 @@ public class SqmUtil {
|
|||
final JdbcParameter jdbcParameter = jdbcParams.get( i );
|
||||
jdbcParameterBindings.addBinding(
|
||||
jdbcParameter,
|
||||
new JdbcParameterBindingImpl( StandardBasicTypes.SERIALIZABLE, null )
|
||||
new JdbcParameterBindingImpl( null, null )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.query.sqm.spi;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||
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.SqmCastTarget;
|
||||
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.SqmDurationUnit;
|
||||
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.SqmNullnessPredicate;
|
||||
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.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.SqmQuerySpec;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectClause;
|
||||
|
@ -195,7 +197,7 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object visitQuerySpec(SqmQuerySpec querySpec) {
|
||||
public Object visitQuerySpec(SqmQuerySpec<?> querySpec) {
|
||||
visitFromClause( querySpec.getFromClause() );
|
||||
visitSelectClause( querySpec.getSelectClause() );
|
||||
visitWhereClause( querySpec.getWhereClause() );
|
||||
|
@ -453,21 +455,16 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object visitGroupByClause(SqmGroupByClause clause) {
|
||||
clause.visitGroupings( this::visitGrouping );
|
||||
return clause;
|
||||
public Object visitGroupByClause(List<SqmExpression<?>> groupByClauseExpressions) {
|
||||
if ( groupByClauseExpressions != null ) {
|
||||
groupByClauseExpressions.forEach( e -> e.accept( this ) );
|
||||
}
|
||||
return groupByClauseExpressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitGrouping(SqmGroupByClause.SqmGrouping grouping) {
|
||||
grouping.getExpression().accept( this );
|
||||
return grouping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitHavingClause(SqmHavingClause clause) {
|
||||
clause.getPredicate().accept( this );
|
||||
return clause;
|
||||
public Object visitHavingClause(SqmPredicate sqmPredicate) {
|
||||
return sqmPredicate.accept( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -587,15 +584,21 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object visitLiteral(SqmLiteral literal) {
|
||||
public Object visitLiteral(SqmLiteral<?> literal) {
|
||||
return literal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitTuple(SqmTuple sqmTuple) {
|
||||
public Object visitTuple(SqmTuple<?> sqmTuple) {
|
||||
return sqmTuple;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitCollate(SqmCollate<?> sqmCollate) {
|
||||
sqmCollate.getExpression().accept( this );
|
||||
return sqmCollate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitBinaryArithmeticExpression(SqmBinaryArithmetic expression) {
|
||||
return expression;
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
|||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.EmbeddedCollectionPart;
|
||||
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
|
||||
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
|
||||
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.SqmCaseSimple;
|
||||
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.SqmDurationUnit;
|
||||
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.SqmToDuration;
|
||||
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.from.SqmAttributeJoin;
|
||||
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.SqmNullnessPredicate;
|
||||
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.select.SqmOrderByClause;
|
||||
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.CaseSimpleExpression;
|
||||
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.Duration;
|
||||
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.JdbcParameter;
|
||||
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.TrimSpecification;
|
||||
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.Junction;
|
||||
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.NullnessPredicate;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
|
@ -404,7 +409,7 @@ public abstract class BaseSqmToSqlAstConverter
|
|||
}
|
||||
|
||||
@Override
|
||||
public QuerySpec visitQuerySpec(SqmQuerySpec sqmQuerySpec) {
|
||||
public QuerySpec visitQuerySpec(SqmQuerySpec<?> sqmQuerySpec) {
|
||||
final QuerySpec sqlQuerySpec = new QuerySpec( processingStateStack.isEmpty(), sqmQuerySpec.getFromClause().getNumberOfRoots() );
|
||||
|
||||
additionalRestrictions = null;
|
||||
|
@ -444,8 +449,10 @@ public abstract class BaseSqmToSqlAstConverter
|
|||
sqlQuerySpec.applyPredicate( additionalRestrictions );
|
||||
}
|
||||
|
||||
// todo : group-by
|
||||
// todo : having
|
||||
sqlQuerySpec.setGroupByClauseExpressions( visitGroupByClause( sqmQuerySpec.getGroupByClauseExpressions() ) );
|
||||
if ( sqmQuerySpec.getHavingClausePredicate() != null ) {
|
||||
sqlQuerySpec.setHavingClauseRestrictions( visitHavingClause( sqmQuerySpec.getHavingClausePredicate() ) );
|
||||
}
|
||||
|
||||
if ( sqmQuerySpec.getOrderByClause() != null ) {
|
||||
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
|
||||
public Void visitOrderByClause(SqmOrderByClause orderByClause) {
|
||||
super.visitOrderByClause( orderByClause );
|
||||
|
@ -503,7 +542,7 @@ public abstract class BaseSqmToSqlAstConverter
|
|||
public SortSpecification visitSortSpecification(SqmSortSpecification sortSpecification) {
|
||||
return new SortSpecification(
|
||||
(Expression) sortSpecification.getSortExpression().accept( this ),
|
||||
sortSpecification.getCollation(),
|
||||
null,
|
||||
sortSpecification.getSortOrder(),
|
||||
sortSpecification.getNullPrecedence()
|
||||
);
|
||||
|
@ -1001,7 +1040,7 @@ public abstract class BaseSqmToSqlAstConverter
|
|||
// General expressions
|
||||
|
||||
@Override
|
||||
public Expression visitLiteral(SqmLiteral literal) {
|
||||
public Expression visitLiteral(SqmLiteral<?> literal) {
|
||||
if ( literal instanceof SqmLiteralNull ) {
|
||||
return new QueryLiteral<>( null, (BasicValuedMapping) inferableTypeAccessStack.getCurrent().get() );
|
||||
}
|
||||
|
@ -1196,6 +1235,24 @@ public abstract class BaseSqmToSqlAstConverter
|
|||
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
|
||||
public Expression visitFunction(SqmFunction sqmFunction) {
|
||||
|
@ -2209,7 +2266,7 @@ public abstract class BaseSqmToSqlAstConverter
|
|||
}
|
||||
|
||||
@Override
|
||||
public MemberOfPredicate visitMemberOfPredicate(SqmMemberOfPredicate predicate) {
|
||||
public InSubQueryPredicate visitMemberOfPredicate(SqmMemberOfPredicate predicate) {
|
||||
final SqmPath<?> pluralPath = predicate.getPluralPath();
|
||||
final PluralAttributeMapping mappingModelExpressable = (PluralAttributeMapping) determineValueMapping(pluralPath);
|
||||
|
||||
|
@ -2217,6 +2274,10 @@ public abstract class BaseSqmToSqlAstConverter
|
|||
inferableTypeAccessStack.push(
|
||||
() -> ( (EntityCollectionPart) mappingModelExpressable.getElementDescriptor() ).getKeyTargetMatchPart() );
|
||||
}
|
||||
else if ( mappingModelExpressable.getElementDescriptor() instanceof EmbeddedCollectionPart ) {
|
||||
inferableTypeAccessStack.push(
|
||||
() -> mappingModelExpressable.getElementDescriptor() );
|
||||
}
|
||||
else {
|
||||
inferableTypeAccessStack.push( () -> mappingModelExpressable );
|
||||
}
|
||||
|
@ -2229,15 +2290,15 @@ public abstract class BaseSqmToSqlAstConverter
|
|||
inferableTypeAccessStack.pop();
|
||||
}
|
||||
|
||||
return new MemberOfPredicate(
|
||||
return new InSubQueryPredicate(
|
||||
lhs,
|
||||
predicate.isNegated(),
|
||||
createMemberOfSubQuery( pluralPath, mappingModelExpressable )
|
||||
createMemberOfSubQuery( pluralPath, mappingModelExpressable ),
|
||||
predicate.isNegated()
|
||||
);
|
||||
}
|
||||
|
||||
private QuerySpec createMemberOfSubQuery(SqmPath<?> pluralPath, PluralAttributeMapping mappingModelExpressable) {
|
||||
final QuerySpec querySpec = new QuerySpec( true );
|
||||
final QuerySpec querySpec = new QuerySpec( false );
|
||||
processingStateStack.push(
|
||||
new SqlAstQuerySpecProcessingStateImpl(
|
||||
querySpec,
|
||||
|
|
|
@ -54,10 +54,10 @@ public class EmbeddableValuedPathInterpretation<T> extends AbstractSqmPathInterp
|
|||
);
|
||||
}
|
||||
|
||||
private final Expression sqlExpression;
|
||||
private final SqlTuple sqlExpression;
|
||||
|
||||
public EmbeddableValuedPathInterpretation(
|
||||
Expression sqlExpression,
|
||||
SqlTuple sqlExpression,
|
||||
SqmEmbeddedValuedSimplePath<T> sqmPath,
|
||||
EmbeddableValuedModelPart mapping,
|
||||
TableGroup tableGroup) {
|
||||
|
@ -65,7 +65,7 @@ public class EmbeddableValuedPathInterpretation<T> extends AbstractSqmPathInterp
|
|||
this.sqlExpression = sqlExpression;
|
||||
}
|
||||
|
||||
public Expression getSqlExpression() {
|
||||
public SqlTuple getSqlExpression() {
|
||||
return sqlExpression;
|
||||
}
|
||||
|
||||
|
@ -81,22 +81,13 @@ public class EmbeddableValuedPathInterpretation<T> extends AbstractSqmPathInterp
|
|||
|
||||
@Override
|
||||
public void visitColumnReferences(Consumer<ColumnReference> columnReferenceConsumer) {
|
||||
if ( sqlExpression instanceof ColumnReference ) {
|
||||
columnReferenceConsumer.accept( (ColumnReference) sqlExpression );
|
||||
}
|
||||
else if ( sqlExpression instanceof SqlTuple ) {
|
||||
final SqlTuple sqlTuple = (SqlTuple) sqlExpression;
|
||||
for ( Expression expression : sqlTuple.getExpressions() ) {
|
||||
for ( Expression expression : sqlExpression.getExpressions() ) {
|
||||
if ( !( expression instanceof ColumnReference ) ) {
|
||||
throw new IllegalArgumentException( "Expecting ColumnReference, found : " + expression );
|
||||
}
|
||||
columnReferenceConsumer.accept( (ColumnReference) expression );
|
||||
}
|
||||
}
|
||||
else {
|
||||
// error or warning...
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ColumnReference> getColumnReferences() {
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath;
|
|||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
|
||||
/**
|
||||
|
@ -30,7 +31,7 @@ public class NonAggregatedCompositeValuedPathInterpretation<T> extends AbstractS
|
|||
final NonAggregatedIdentifierMappingImpl mapping = (NonAggregatedIdentifierMappingImpl) tableGroup.getModelPart()
|
||||
.findSubPart( sqmPath.getReferencedPathSource().getPathName(), null );
|
||||
|
||||
return new NonAggregatedCompositeValuedPathInterpretation(
|
||||
return new NonAggregatedCompositeValuedPathInterpretation<>(
|
||||
mapping.toSqlExpression(
|
||||
tableGroup,
|
||||
converter.getCurrentClauseStack().getCurrent(),
|
||||
|
@ -43,10 +44,10 @@ public class NonAggregatedCompositeValuedPathInterpretation<T> extends AbstractS
|
|||
);
|
||||
}
|
||||
|
||||
private final Expression sqlExpression;
|
||||
private final SqlTuple sqlExpression;
|
||||
|
||||
public NonAggregatedCompositeValuedPathInterpretation(
|
||||
Expression sqlExpression,
|
||||
SqlTuple sqlExpression,
|
||||
SqmPath<T> sqmPath,
|
||||
ModelPart mapping,
|
||||
TableGroup tableGroup) {
|
||||
|
@ -54,6 +55,10 @@ public class NonAggregatedCompositeValuedPathInterpretation<T> extends AbstractS
|
|||
this.sqlExpression = sqlExpression;
|
||||
}
|
||||
|
||||
public SqlTuple getSqlExpression() {
|
||||
return sqlExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(SqlAstWalker sqlTreeWalker) {
|
||||
sqlExpression.accept( sqlTreeWalker );
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.query.sqm.sql.internal;
|
|||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.metamodel.model.domain.AllowableParameterType;
|
||||
import org.hibernate.query.SemanticException;
|
||||
|
@ -49,9 +50,13 @@ public class SqmParameterInterpretation implements Expression, DomainResultProdu
|
|||
assert jdbcParameters != null;
|
||||
assert jdbcParameters.size() > 0;
|
||||
|
||||
this.resolvedExpression = jdbcParameters.size() == 1
|
||||
? jdbcParameters.get( 0 )
|
||||
: new SqlTuple( jdbcParameters, valueMapping );
|
||||
this.resolvedExpression = valueMapping instanceof EmbeddableValuedModelPart
|
||||
? new SqlTuple( jdbcParameters, valueMapping )
|
||||
: jdbcParameters.get( 0 );
|
||||
}
|
||||
|
||||
public Expression getResolvedExpression() {
|
||||
return resolvedExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,6 +30,7 @@ public class JpaCriteriaParameter<T>
|
|||
extends AbstractSqmExpression<T>
|
||||
implements SqmParameter<T>, QueryParameterImplementor<T>, DomainResultProducer<T> {
|
||||
private final String name;
|
||||
private final T value;
|
||||
private boolean allowsMultiValuedBinding;
|
||||
|
||||
public JpaCriteriaParameter(
|
||||
|
@ -39,6 +40,7 @@ public class JpaCriteriaParameter<T>
|
|||
NodeBuilder nodeBuilder) {
|
||||
super( type, nodeBuilder );
|
||||
this.name = name;
|
||||
this.value = null;
|
||||
this.allowsMultiValuedBinding = allowsMultiValuedBinding;
|
||||
}
|
||||
public JpaCriteriaParameter(
|
||||
|
@ -48,11 +50,21 @@ public class JpaCriteriaParameter<T>
|
|||
this( null, type, allowsMultiValuedBinding, nodeBuilder );
|
||||
}
|
||||
|
||||
public JpaCriteriaParameter(AllowableParameterType<T> type, T value, NodeBuilder criteriaBuilder) {
|
||||
super( type, criteriaBuilder );
|
||||
this.name = null;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPosition() {
|
||||
// for criteria anyway, these cannot be positional
|
||||
|
|
|
@ -18,8 +18,8 @@ public class SqmAny<T> extends AbstractSqmExpression<T> {
|
|||
|
||||
private final SqmSubQuery<T> subquery;
|
||||
|
||||
public SqmAny(SqmSubQuery<T> subquery, SqmExpressable<T> type, NodeBuilder criteriaBuilder) {
|
||||
super(type, criteriaBuilder);
|
||||
public SqmAny(SqmSubQuery<T> subquery, NodeBuilder criteriaBuilder) {
|
||||
super( subquery.getNodeType(), criteriaBuilder );
|
||||
this.subquery = subquery;
|
||||
}
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ public class SqmCaseSearched<R>
|
|||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ public class SqmCaseSearched<R>
|
|||
|
||||
@Override
|
||||
public JpaExpression<R> otherwise(R result) {
|
||||
otherwise( nodeBuilder().literal( result ) );
|
||||
otherwise( nodeBuilder().value( result ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ public class SqmCaseSimple<T,R>
|
|||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -142,7 +142,7 @@ public class SqmCaseSimple<T,R>
|
|||
|
||||
@Override
|
||||
public JpaSimpleCase<T, R> otherwise(R result) {
|
||||
otherwise( nodeBuilder().literal( result ) );
|
||||
otherwise( nodeBuilder().value( result ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ public class SqmCoalesce<T> extends AbstractSqmExpression<T> implements JpaCoale
|
|||
|
||||
@Override
|
||||
public SqmCoalesce<T> value(T value) {
|
||||
value( nodeBuilder().literal( value ) );
|
||||
value( nodeBuilder().value( value ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ public class SqmCoalesce<T> extends AbstractSqmExpression<T> implements JpaCoale
|
|||
@SuppressWarnings("unchecked")
|
||||
public SqmCoalesce<T> values(T... values) {
|
||||
for ( T value : values ) {
|
||||
value( nodeBuilder().literal( value ) );
|
||||
value( nodeBuilder().value( value ) );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -18,8 +18,8 @@ public class SqmEvery<T> extends AbstractSqmExpression<T> {
|
|||
|
||||
private final SqmSubQuery<T> subquery;
|
||||
|
||||
public SqmEvery(SqmSubQuery<T> subquery, SqmExpressable<T> type, NodeBuilder criteriaBuilder) {
|
||||
super(type, criteriaBuilder);
|
||||
public SqmEvery(SqmSubQuery<T> subquery, NodeBuilder criteriaBuilder) {
|
||||
super( subquery.getNodeType(), criteriaBuilder );
|
||||
this.subquery = subquery;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.function.Consumer;
|
|||
import org.hibernate.metamodel.model.domain.AllowableParameterType;
|
||||
import org.hibernate.query.sqm.NodeBuilder;
|
||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||
import org.hibernate.query.sqm.SqmExpressable;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
|
||||
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
||||
|
||||
|
@ -50,8 +51,9 @@ public class SqmJpaCriteriaParameterWrapper<T>
|
|||
|
||||
@Override
|
||||
public AllowableParameterType<T> getNodeType() {
|
||||
if ( super.getNodeType() instanceof AllowableParameterType ) {
|
||||
return ( (AllowableParameterType<T>) super.getNodeType() );
|
||||
SqmExpressable<T> nodeType = super.getNodeType();
|
||||
if ( nodeType == null || nodeType instanceof AllowableParameterType ) {
|
||||
return ( (AllowableParameterType<T>) nodeType );
|
||||
}
|
||||
|
||||
throw new IllegalStateException( "Expecting AllowableParameterType as node type" );
|
||||
|
|
|
@ -74,11 +74,11 @@ public class SqmInListPredicate<T> extends AbstractNegatableSqmPredicate impleme
|
|||
public SqmInPredicate<T> value(Object value) {
|
||||
if ( value instanceof Collection ) {
|
||||
( (Collection) value ).forEach(
|
||||
v -> addExpression( nodeBuilder().literal( v ) )
|
||||
v -> addExpression( nodeBuilder().value( v ) )
|
||||
);
|
||||
return this;
|
||||
}
|
||||
addExpression( nodeBuilder().literal( value ) );
|
||||
addExpression( nodeBuilder().value( value ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -44,13 +44,13 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
|
|||
private SqmSelectClause selectClause;
|
||||
private SqmWhereClause whereClause;
|
||||
|
||||
private SqmGroupByClause groupByClause;
|
||||
private SqmHavingClause havingClause;
|
||||
private List<SqmExpression<?>> groupByClauseExpressions = Collections.emptyList();
|
||||
private SqmPredicate havingClausePredicate;
|
||||
|
||||
private SqmOrderByClause orderByClause;
|
||||
|
||||
private SqmExpression limitExpression;
|
||||
private SqmExpression offsetExpression;
|
||||
private SqmExpression<?> limitExpression;
|
||||
private SqmExpression<?> offsetExpression;
|
||||
|
||||
public SqmQuerySpec(NodeBuilder nodeBuilder) {
|
||||
this.nodeBuilder = nodeBuilder;
|
||||
|
@ -100,20 +100,22 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
|
|||
whereClause.applyPredicate( predicate );
|
||||
}
|
||||
|
||||
public SqmGroupByClause getGroupByClause() {
|
||||
return groupByClause;
|
||||
public List<SqmExpression<?>> getGroupByClauseExpressions() {
|
||||
return groupByClauseExpressions;
|
||||
}
|
||||
|
||||
public void setGroupByClause(SqmGroupByClause groupByClause) {
|
||||
this.groupByClause = groupByClause;
|
||||
public void setGroupByClauseExpressions(List<SqmExpression<?>> groupByClauseExpressions) {
|
||||
this.groupByClauseExpressions = groupByClauseExpressions == null
|
||||
? Collections.emptyList()
|
||||
: groupByClauseExpressions;
|
||||
}
|
||||
|
||||
public SqmHavingClause getHavingClause() {
|
||||
return havingClause;
|
||||
public SqmPredicate getHavingClausePredicate() {
|
||||
return havingClausePredicate;
|
||||
}
|
||||
|
||||
public void setHavingClause(SqmHavingClause havingClause) {
|
||||
this.havingClause = havingClause;
|
||||
public void setHavingClausePredicate(SqmPredicate havingClausePredicate) {
|
||||
this.havingClausePredicate = havingClausePredicate;
|
||||
}
|
||||
|
||||
public SqmOrderByClause getOrderByClause() {
|
||||
|
@ -124,7 +126,7 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
|
|||
this.orderByClause = orderByClause;
|
||||
}
|
||||
|
||||
public SqmExpression getLimitExpression() {
|
||||
public SqmExpression<?> getLimitExpression() {
|
||||
return limitExpression;
|
||||
}
|
||||
|
||||
|
@ -135,7 +137,7 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
|
|||
this.limitExpression = limitExpression;
|
||||
}
|
||||
|
||||
public SqmExpression getOffsetExpression() {
|
||||
public SqmExpression<?> getOffsetExpression() {
|
||||
return offsetExpression;
|
||||
}
|
||||
|
||||
|
@ -157,7 +159,7 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmQuerySpec setDistinct(boolean distinct) {
|
||||
public SqmQuerySpec<T> setDistinct(boolean distinct) {
|
||||
assert getSelectClause() != null;
|
||||
getSelectClause().makeDistinct( distinct );
|
||||
return this;
|
||||
|
@ -171,7 +173,7 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmQuerySpec setSelection(JpaSelection<T> selection) {
|
||||
public SqmQuerySpec<T> setSelection(JpaSelection<T> selection) {
|
||||
assert getSelectClause() != null;
|
||||
// NOTE : this call comes from JPA which inherently supports just a
|
||||
// single (possibly "compound") selection
|
||||
|
@ -187,7 +189,7 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmQuerySpec addRoot(JpaRoot<?> root) {
|
||||
public SqmQuerySpec<T> addRoot(JpaRoot<?> root) {
|
||||
if ( getFromClause() == null ) {
|
||||
setFromClause( new SqmFromClause() );
|
||||
}
|
||||
|
@ -231,90 +233,48 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<SqmExpression> getGroupingExpressions() {
|
||||
if ( getGroupByClause() == null ) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final List<SqmExpression> list = new ArrayList<>();
|
||||
getGroupByClause().visitGroupings(
|
||||
sqmGrouping -> list.add( sqmGrouping.getExpression() )
|
||||
);
|
||||
return list;
|
||||
public List<SqmExpression<?>> getGroupingExpressions() {
|
||||
return groupByClauseExpressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmQuerySpec<T> setGroupingExpressions(List<? extends JpaExpression<?>> groupExpressions) {
|
||||
if ( getGroupByClause() == null ) {
|
||||
setGroupByClause( new SqmGroupByClause() );
|
||||
}
|
||||
else {
|
||||
getGroupByClause().clearGroupings();
|
||||
}
|
||||
|
||||
this.groupByClauseExpressions = new ArrayList<>( groupExpressions.size() );
|
||||
for ( JpaExpression<?> groupExpression : groupExpressions ) {
|
||||
getGroupByClause().addGrouping( (SqmExpression) groupExpression );
|
||||
this.groupByClauseExpressions.add( (SqmExpression<?>) groupExpression );
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmQuerySpec<T> setGroupingExpressions(JpaExpression<?>... groupExpressions) {
|
||||
if ( getGroupByClause() == null ) {
|
||||
setGroupByClause( new SqmGroupByClause() );
|
||||
}
|
||||
else {
|
||||
getGroupByClause().clearGroupings();
|
||||
}
|
||||
|
||||
this.groupByClauseExpressions = new ArrayList<>( groupExpressions.length );
|
||||
for ( JpaExpression<?> groupExpression : groupExpressions ) {
|
||||
getGroupByClause().addGrouping( (SqmExpression) groupExpression );
|
||||
this.groupByClauseExpressions.add( (SqmExpression<?>) groupExpression );
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPredicate getGroupRestriction() {
|
||||
if ( getHavingClause() == null ) {
|
||||
return null;
|
||||
}
|
||||
return getHavingClause().getPredicate();
|
||||
return havingClausePredicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmQuerySpec<T> setGroupRestriction(JpaPredicate restriction) {
|
||||
if ( getHavingClause() == null ) {
|
||||
setHavingClause( new SqmHavingClause( (SqmPredicate) restriction ) );
|
||||
}
|
||||
else {
|
||||
getHavingClause().setPredicate( (SqmPredicate) restriction );
|
||||
}
|
||||
havingClausePredicate = (SqmPredicate) restriction;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmQuerySpec<T> setGroupRestriction(Expression<Boolean> restriction) {
|
||||
final SqmPredicate predicate = nodeBuilder.wrap( restriction );
|
||||
if ( getHavingClause() == null ) {
|
||||
setHavingClause( new SqmHavingClause( predicate ));
|
||||
}
|
||||
else {
|
||||
getHavingClause().setPredicate( predicate );
|
||||
}
|
||||
havingClausePredicate = nodeBuilder.wrap( restriction );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmQuerySpec<T> setGroupRestriction(Predicate... restrictions) {
|
||||
final SqmPredicate predicate = nodeBuilder.wrap( restrictions );
|
||||
if ( getHavingClause() == null ) {
|
||||
setHavingClause( new SqmHavingClause( predicate ));
|
||||
}
|
||||
else {
|
||||
getHavingClause().setPredicate( predicate );
|
||||
}
|
||||
havingClausePredicate = nodeBuilder.wrap( restrictions );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -341,25 +301,25 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
|
|||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public SqmExpression getLimit() {
|
||||
public SqmExpression<?> getLimit() {
|
||||
return getLimitExpression();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmQuerySpec<T> setLimit(JpaExpression<?> limit) {
|
||||
setLimitExpression( (SqmExpression) limit );
|
||||
setLimitExpression( (SqmExpression<?>) limit );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public SqmExpression getOffset() {
|
||||
public SqmExpression<?> getOffset() {
|
||||
return getOffsetExpression();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmQuerySpec<T> setOffset(JpaExpression offset) {
|
||||
setOffsetExpression( (SqmExpression) offset );
|
||||
public SqmQuerySpec<T> setOffset(JpaExpression<?> offset) {
|
||||
setOffsetExpression( (SqmExpression<?>) offset );
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,42 +17,31 @@ import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
|||
*/
|
||||
public class SqmSortSpecification implements JpaOrder {
|
||||
private final SqmExpression sortExpression;
|
||||
private final String collation;
|
||||
private final SortOrder sortOrder;
|
||||
|
||||
private NullPrecedence nullPrecedence;
|
||||
|
||||
public SqmSortSpecification(
|
||||
SqmExpression sortExpression,
|
||||
String collation,
|
||||
SortOrder sortOrder,
|
||||
NullPrecedence nullPrecedence) {
|
||||
this.sortExpression = sortExpression;
|
||||
this.collation = collation;
|
||||
this.sortOrder = sortOrder;
|
||||
this.nullPrecedence = nullPrecedence;
|
||||
}
|
||||
|
||||
public SqmSortSpecification(SqmExpression sortExpression) {
|
||||
this( sortExpression, null, SortOrder.ASCENDING, null );
|
||||
this( sortExpression, SortOrder.ASCENDING, null );
|
||||
}
|
||||
|
||||
public SqmSortSpecification(SqmExpression sortExpression, SortOrder sortOrder) {
|
||||
this( sortExpression, null, sortOrder, null );
|
||||
}
|
||||
|
||||
public SqmSortSpecification(SqmExpression sortExpression, SortOrder sortOrder, NullPrecedence nullPrecedence) {
|
||||
this( sortExpression, null, sortOrder, nullPrecedence );
|
||||
this( sortExpression, sortOrder, null );
|
||||
}
|
||||
|
||||
public SqmExpression getSortExpression() {
|
||||
return sortExpression;
|
||||
}
|
||||
|
||||
public String getCollation() {
|
||||
return collation;
|
||||
}
|
||||
|
||||
public SortOrder getSortOrder() {
|
||||
return sortOrder;
|
||||
}
|
||||
|
@ -75,7 +64,7 @@ public class SqmSortSpecification implements JpaOrder {
|
|||
@Override
|
||||
public JpaOrder reverse() {
|
||||
SortOrder newSortOrder = this.sortOrder == null ? SortOrder.DESCENDING : sortOrder.reverse();
|
||||
return new SqmSortSpecification( sortExpression, collation, newSortOrder, nullPrecedence );
|
||||
return new SqmSortSpecification( sortExpression, newSortOrder, nullPrecedence );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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.CaseSimpleExpression;
|
||||
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.Distinct;
|
||||
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.Junction;
|
||||
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.NullnessPredicate;
|
||||
import org.hibernate.sql.ast.tree.predicate.SelfRenderingPredicate;
|
||||
|
@ -114,6 +114,8 @@ public interface SqlAstWalker {
|
|||
|
||||
void visitTuple(SqlTuple tuple);
|
||||
|
||||
void visitCollate(Collate collate);
|
||||
|
||||
void visitParameter(JdbcParameter jdbcParameter);
|
||||
|
||||
void visitJdbcLiteral(JdbcLiteral jdbcLiteral);
|
||||
|
@ -152,5 +154,4 @@ public interface SqlAstWalker {
|
|||
|
||||
void visitConversion(Conversion conversion);
|
||||
|
||||
void visitMemberOfPredicate(MemberOfPredicate memberOfPredicate);
|
||||
}
|
||||
|
|
|
@ -6,11 +6,15 @@
|
|||
*/
|
||||
package org.hibernate.sql.ast.spi;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.NullPrecedence;
|
||||
|
@ -18,6 +22,8 @@ import org.hibernate.SortOrder;
|
|||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
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.util.StringHelper;
|
||||
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.internal.BasicValuedCollectionPart;
|
||||
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.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
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.sql.ast.Clause;
|
||||
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.CaseSimpleExpression;
|
||||
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.Distinct;
|
||||
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.JdbcParameter;
|
||||
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.SelfRenderingExpression;
|
||||
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.Junction;
|
||||
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.NullnessPredicate;
|
||||
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.exec.internal.JdbcParametersImpl;
|
||||
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.SqlTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
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
|
||||
*/
|
||||
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
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
private final SqlAppender sqlAppender = this::appendSql;
|
||||
|
||||
// In-flight state
|
||||
private final StringBuilder sqlBuffer = new StringBuilder();
|
||||
|
@ -118,6 +124,8 @@ public abstract class AbstractSqlAstWalker
|
|||
private final Stack<Clause> clauseStack = new StandardStack<>();
|
||||
|
||||
private final Dialect dialect;
|
||||
private transient AbstractSqmSelfRenderingFunctionDescriptor castFunction;
|
||||
private transient LazySession session;
|
||||
|
||||
public Dialect getDialect() {
|
||||
return dialect;
|
||||
|
@ -133,10 +141,75 @@ public abstract class AbstractSqlAstWalker
|
|||
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
|
||||
public String getSql() {
|
||||
if ( session != null ) {
|
||||
session.cleanup();
|
||||
session = null;
|
||||
}
|
||||
return sqlBuffer.toString();
|
||||
}
|
||||
|
||||
|
@ -152,16 +225,16 @@ public abstract class AbstractSqlAstWalker
|
|||
|
||||
@SuppressWarnings("unused")
|
||||
protected SqlAppender getSqlAppender() {
|
||||
return sqlAppender;
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected void appendSql(String fragment) {
|
||||
@Override
|
||||
public void appendSql(String fragment) {
|
||||
sqlBuffer.append( fragment );
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected void appendSql(char fragment) {
|
||||
@Override
|
||||
public void appendSql(char fragment) {
|
||||
sqlBuffer.append( fragment );
|
||||
}
|
||||
|
||||
|
@ -187,21 +260,20 @@ public abstract class AbstractSqlAstWalker
|
|||
if ( !querySpec.isRoot() ) {
|
||||
appendSql( " (" );
|
||||
}
|
||||
|
||||
visitSelectClause( querySpec.getSelectClause() );
|
||||
visitFromClause( querySpec.getFromClause() );
|
||||
visitWhereClause( querySpec );
|
||||
visitGroupByClause( querySpec );
|
||||
visitHavingClause( querySpec );
|
||||
visitOrderBy( querySpec );
|
||||
visitLimitOffsetClause( querySpec );
|
||||
|
||||
FromClause fromClause = querySpec.getFromClause();
|
||||
if ( fromClause == null || fromClause.getRoots().isEmpty() ) {
|
||||
String fromDual = getDialect().getFromDual();
|
||||
if ( !fromDual.isEmpty() ) {
|
||||
appendSql( " " );
|
||||
appendSql( fromDual );
|
||||
if ( !querySpec.isRoot() ) {
|
||||
appendSql( ")" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
visitFromClause( fromClause );
|
||||
}
|
||||
|
||||
protected final void visitWhereClause(QuerySpec querySpec) {
|
||||
final Predicate whereClauseRestrictions = querySpec.getWhereClauseRestrictions();
|
||||
if ( whereClauseRestrictions != null && !whereClauseRestrictions.isEmpty() ) {
|
||||
appendSql( " where " );
|
||||
|
@ -214,11 +286,50 @@ public abstract class AbstractSqlAstWalker
|
|||
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();
|
||||
if ( sortSpecifications != null && !sortSpecifications.isEmpty() ) {
|
||||
appendSql( " order by " );
|
||||
|
||||
clauseStack.push( Clause.ORDER );
|
||||
try {
|
||||
String separator = NO_SEPARATOR;
|
||||
for ( SortSpecification sortSpecification : sortSpecifications ) {
|
||||
appendSql( separator );
|
||||
|
@ -226,11 +337,101 @@ public abstract class AbstractSqlAstWalker
|
|||
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() ) {
|
||||
appendSql( ")" );
|
||||
final boolean isCurrentWhereClause = clauseStack.getCurrent() == Clause.WHERE;
|
||||
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 );
|
||||
|
||||
final String collation = sortSpecification.getCollation();
|
||||
if ( collation != null ) {
|
||||
appendSql( " collate " );
|
||||
appendSql( collation );
|
||||
}
|
||||
|
||||
final SortOrder sortOrder = sortSpecification.getSortOrder();
|
||||
if ( sortOrder == SortOrder.ASCENDING ) {
|
||||
appendSql( " asc" );
|
||||
|
@ -284,25 +479,25 @@ public abstract class AbstractSqlAstWalker
|
|||
@Override
|
||||
public void visitLimitOffsetClause(QuerySpec querySpec) {
|
||||
if ( querySpec.getOffsetClauseExpression() != null ) {
|
||||
renderOffset( querySpec );
|
||||
renderOffset( querySpec.getOffsetClauseExpression() );
|
||||
}
|
||||
|
||||
if ( querySpec.getLimitClauseExpression() != null ) {
|
||||
renderLimit( querySpec );
|
||||
renderLimit( querySpec.getLimitClauseExpression() );
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected void renderOffset(QuerySpec querySpec) {
|
||||
protected void renderOffset(Expression offsetExpression) {
|
||||
appendSql( " offset " );
|
||||
querySpec.getOffsetClauseExpression().accept( this );
|
||||
offsetExpression.accept( this );
|
||||
appendSql( " rows" );
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected void renderLimit(QuerySpec querySpec) {
|
||||
protected void renderLimit(Expression limitExpression) {
|
||||
appendSql( " fetch first " );
|
||||
querySpec.getLimitClauseExpression().accept( this );
|
||||
limitExpression.accept( this );
|
||||
appendSql( " rows only" );
|
||||
}
|
||||
|
||||
|
@ -343,6 +538,14 @@ public abstract class AbstractSqlAstWalker
|
|||
|
||||
@Override
|
||||
public void visitFromClause(FromClause fromClause) {
|
||||
if ( fromClause == null || fromClause.getRoots().isEmpty() ) {
|
||||
String fromDual = getDialect().getFromDual();
|
||||
if ( !fromDual.isEmpty() ) {
|
||||
appendSql( " " );
|
||||
appendSql( fromDual );
|
||||
}
|
||||
}
|
||||
else {
|
||||
appendSql( " from " );
|
||||
|
||||
String separator = NO_SEPARATOR;
|
||||
|
@ -352,6 +555,7 @@ public abstract class AbstractSqlAstWalker
|
|||
separator = COMA_SEPARATOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected void renderTableGroup(TableGroup tableGroup) {
|
||||
|
@ -399,12 +603,12 @@ public abstract class AbstractSqlAstWalker
|
|||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected void renderTableReference(TableReference tableReference) {
|
||||
sqlAppender.appendSql( tableReference.getTableExpression() );
|
||||
appendSql( tableReference.getTableExpression() );
|
||||
|
||||
final String identificationVariable = tableReference.getIdentificationVariable();
|
||||
if ( identificationVariable != null ) {
|
||||
sqlAppender.appendSql( getDialect().getTableAliasSeparator() );
|
||||
sqlAppender.appendSql( identificationVariable );
|
||||
appendSql( getDialect().getTableAliasSeparator() );
|
||||
appendSql( identificationVariable );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -416,14 +620,14 @@ public abstract class AbstractSqlAstWalker
|
|||
}
|
||||
|
||||
for ( TableReferenceJoin tableJoin : joins ) {
|
||||
sqlAppender.appendSql( EMPTY_STRING );
|
||||
sqlAppender.appendSql( tableJoin.getJoinType().getText() );
|
||||
sqlAppender.appendSql( " join " );
|
||||
appendSql( EMPTY_STRING );
|
||||
appendSql( tableJoin.getJoinType().getText() );
|
||||
appendSql( " join " );
|
||||
|
||||
renderTableReference( tableJoin.getJoinedTableReference() );
|
||||
|
||||
if ( tableJoin.getJoinPredicate() != null && !tableJoin.getJoinPredicate().isEmpty() ) {
|
||||
sqlAppender.appendSql( " on " );
|
||||
appendSql( " on " );
|
||||
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
|
||||
public void visitSqlSelectionExpression(SqlSelectionExpression expression) {
|
||||
final boolean useSelectionPosition = dialect.replaceResultVariableInOrderByClauseWithPosition();
|
||||
|
@ -907,7 +1117,7 @@ public abstract class AbstractSqlAstWalker
|
|||
@Override
|
||||
public void visitDuration(Duration duration) {
|
||||
duration.getMagnitude().accept( this );
|
||||
sqlAppender.appendSql(
|
||||
appendSql(
|
||||
duration.getUnit().conversionFactor( NANOSECOND, getDialect() )
|
||||
);
|
||||
}
|
||||
|
@ -915,25 +1125,13 @@ public abstract class AbstractSqlAstWalker
|
|||
@Override
|
||||
public void visitConversion(Conversion conversion) {
|
||||
conversion.getDuration().getMagnitude().accept( this );
|
||||
sqlAppender.appendSql(
|
||||
appendSql(
|
||||
conversion.getDuration().getUnit().conversionFactor(
|
||||
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
|
||||
public void visitCaseSearchedExpression(CaseSearchedExpression caseSearchedExpression) {
|
||||
dialect.getCaseExpressionWalker().visitCaseSearchedExpression( caseSearchedExpression, sqlBuffer, this );
|
||||
|
@ -966,72 +1164,18 @@ public abstract class AbstractSqlAstWalker
|
|||
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
|
||||
public void visitJdbcLiteral(JdbcLiteral jdbcLiteral) {
|
||||
renderAsLiteral( jdbcLiteral );
|
||||
visitLiteral( jdbcLiteral );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitQueryLiteral(QueryLiteral queryLiteral) {
|
||||
final QueryLiteralRendering queryLiteralRendering = getSessionFactory().getSessionFactoryOptions().getQueryLiteralRenderingMode();
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
visitLiteral( queryLiteral );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void renderAsLiteral(Literal literal) {
|
||||
private void visitLiteral(Literal literal) {
|
||||
if ( literal.getLiteralValue() == null ) {
|
||||
// todo : not sure we allow this "higher up"
|
||||
appendSql( SqlAppender.NULL_KEYWORD );
|
||||
|
@ -1040,15 +1184,27 @@ public abstract class AbstractSqlAstWalker
|
|||
assert literal.getExpressionType().getJdbcTypeCount( getTypeConfiguration() ) == 1;
|
||||
final JdbcMapping jdbcMapping = literal.getJdbcMapping();
|
||||
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(
|
||||
literalFormatter.toJdbcLiteral(
|
||||
literal.getLiteralValue(),
|
||||
dialect,
|
||||
null
|
||||
getSession()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitUnaryOperationExpression(UnaryOperation unaryOperationExpression) {
|
||||
|
@ -1069,7 +1225,7 @@ public abstract class AbstractSqlAstWalker
|
|||
|
||||
@Override
|
||||
public void visitSelfRenderingExpression(SelfRenderingExpression expression) {
|
||||
expression.renderToSql( sqlAppender, this, getSessionFactory() );
|
||||
expression.renderToSql( this, this, getSessionFactory() );
|
||||
}
|
||||
|
||||
// @Override
|
||||
|
@ -1118,6 +1274,17 @@ public abstract class AbstractSqlAstWalker
|
|||
|
||||
@Override
|
||||
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 );
|
||||
if ( inListPredicate.isNegated() ) {
|
||||
appendSql( " not" );
|
||||
|
@ -1136,9 +1303,40 @@ public abstract class AbstractSqlAstWalker
|
|||
}
|
||||
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
|
||||
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 );
|
||||
if ( inSubQueryPredicate.isNegated() ) {
|
||||
appendSql( " not" );
|
||||
|
@ -1146,6 +1344,98 @@ public abstract class AbstractSqlAstWalker
|
|||
appendSql( " in " );
|
||||
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
|
||||
public void visitExistsPredicate(ExistsPredicate existsPredicate) {
|
||||
|
@ -1199,19 +1489,19 @@ public abstract class AbstractSqlAstWalker
|
|||
@Override
|
||||
public void visitNullnessPredicate(NullnessPredicate nullnessPredicate) {
|
||||
final Expression expression = nullnessPredicate.getExpression();
|
||||
if ( expression instanceof EmbeddableValuedPathInterpretation ) {
|
||||
final EmbeddableValuedPathInterpretation embeddableValuedPathInterpretation = (EmbeddableValuedPathInterpretation) expression;
|
||||
|
||||
final Expression sqlExpression = embeddableValuedPathInterpretation.getSqlExpression();
|
||||
String predicateValue;
|
||||
final String predicateValue;
|
||||
if ( nullnessPredicate.isNegated() ) {
|
||||
predicateValue = " is not null";
|
||||
}
|
||||
else {
|
||||
predicateValue = " is null";
|
||||
}
|
||||
if ( sqlExpression instanceof SqlTuple ) {
|
||||
SqlTuple tuple = (SqlTuple) sqlExpression;
|
||||
if ( expression instanceof EmbeddableValuedPathInterpretation ) {
|
||||
final EmbeddableValuedPathInterpretation embeddableValuedPathInterpretation = (EmbeddableValuedPathInterpretation) expression;
|
||||
|
||||
final Expression sqlExpression = embeddableValuedPathInterpretation.getSqlExpression();
|
||||
final SqlTuple tuple;
|
||||
if ( ( tuple = getTuple( sqlExpression ) ) != null ) {
|
||||
String separator = NO_SEPARATOR;
|
||||
|
||||
boolean isCurrentWhereClause = clauseStack.getCurrent() == Clause.WHERE;
|
||||
|
@ -1232,22 +1522,12 @@ public abstract class AbstractSqlAstWalker
|
|||
}
|
||||
else {
|
||||
expression.accept( this );
|
||||
if ( nullnessPredicate.isNegated() ) {
|
||||
appendSql( " is not null" );
|
||||
}
|
||||
else {
|
||||
appendSql( " is null" );
|
||||
}
|
||||
appendSql( predicateValue );
|
||||
}
|
||||
}
|
||||
else {
|
||||
expression.accept( this );
|
||||
if ( nullnessPredicate.isNegated() ) {
|
||||
appendSql( " is not null" );
|
||||
}
|
||||
else {
|
||||
appendSql( " is null" );
|
||||
}
|
||||
appendSql( predicateValue );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1267,12 +1547,106 @@ public abstract class AbstractSqlAstWalker
|
|||
// // 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 );
|
||||
appendSql( " " );
|
||||
appendSql( comparisonPredicate.getOperator().sqlText() );
|
||||
appendSql( " " );
|
||||
comparisonPredicate.getRightHandExpression().accept( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -27,4 +27,18 @@ public interface SqlAppender {
|
|||
* Add the passed fragment into the in-flight buffer
|
||||
*/
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.sql.ast.spi;
|
|||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
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.RowProcessingState;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
|
@ -46,6 +47,11 @@ public interface SqlSelection {
|
|||
return getValuesArrayPosition() + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* The underlying expression.
|
||||
*/
|
||||
Expression getExpression();
|
||||
|
||||
/**
|
||||
* Get the type of the expression
|
||||
*/
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.sql.ast.tree.select;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
@ -38,6 +39,10 @@ public class QuerySpec implements SqlAstNode, PredicateContainer, Expression, Ct
|
|||
private final SelectClause selectClause = new SelectClause();
|
||||
|
||||
private Predicate whereClauseRestrictions;
|
||||
|
||||
private List<Expression> groupByClauseExpressions = Collections.emptyList();
|
||||
private Predicate havingClauseRestrictions;
|
||||
|
||||
private List<SortSpecification> sortSpecifications;
|
||||
private Expression limitClauseExpression;
|
||||
private Expression offsetClauseExpression;
|
||||
|
@ -77,6 +82,22 @@ public class QuerySpec implements SqlAstNode, PredicateContainer, Expression, Ct
|
|||
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() {
|
||||
return sortSpecifications;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.hibernate.NullPrecedence;
|
|||
import org.hibernate.SortOrder;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.Collate;
|
||||
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 {
|
||||
private final Expression sortExpression;
|
||||
private final String collation;
|
||||
private final SortOrder sortOrder;
|
||||
private final NullPrecedence nullPrecedence;
|
||||
|
||||
|
@ -26,8 +26,12 @@ public class SortSpecification implements SqlAstNode {
|
|||
}
|
||||
|
||||
public SortSpecification(Expression sortExpression, String collation, SortOrder sortOrder, NullPrecedence nullPrecedence) {
|
||||
if ( collation == null ) {
|
||||
this.sortExpression = sortExpression;
|
||||
this.collation = collation;
|
||||
}
|
||||
else {
|
||||
this.sortExpression = new Collate( sortExpression, collation );
|
||||
}
|
||||
this.sortOrder = sortOrder;
|
||||
this.nullPrecedence = nullPrecedence;
|
||||
}
|
||||
|
@ -36,10 +40,6 @@ public class SortSpecification implements SqlAstNode {
|
|||
return sortExpression;
|
||||
}
|
||||
|
||||
public String getCollation() {
|
||||
return collation;
|
||||
}
|
||||
|
||||
public SortOrder getSortOrder() {
|
||||
return sortOrder;
|
||||
}
|
||||
|
|
|
@ -46,7 +46,8 @@ public class SqlSelectionImpl implements SqlSelection, SqlExpressionAccess {
|
|||
this.sqlExpression = sqlExpression;
|
||||
}
|
||||
|
||||
public Expression getWrappedSqlExpression() {
|
||||
@Override
|
||||
public Expression getExpression() {
|
||||
return sqlExpression;
|
||||
}
|
||||
|
||||
|
@ -69,7 +70,7 @@ public class SqlSelectionImpl implements SqlSelection, SqlExpressionAccess {
|
|||
|
||||
@Override
|
||||
public MappingModelExpressable getExpressionType() {
|
||||
return getWrappedSqlExpression().getExpressionType();
|
||||
return getExpression().getExpressionType();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
package org.hibernate.type.descriptor;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
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_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_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_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_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_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_TIME = "{t '";
|
||||
|
@ -65,6 +71,21 @@ public final class DateTimeUtils {
|
|||
.optionalStart().appendZoneOrOffsetId().optionalEnd()
|
||||
.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.
|
||||
*
|
||||
|
@ -82,35 +103,89 @@ public final class DateTimeUtils {
|
|||
.appendOffset("+HH:mm", "+00")
|
||||
.toFormatter();
|
||||
|
||||
public static String formatAsTimestampWithMicros(TemporalAccessor temporalAccessor) {
|
||||
return temporalAccessor.isSupported(ChronoField.OFFSET_SECONDS)
|
||||
? DATE_TIME_FORMATTER_TIMESTAMP_WITH_OFFSET.format( temporalAccessor )
|
||||
: DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS.format( temporalAccessor );
|
||||
public static String formatAsTimestampWithMicros(TemporalAccessor temporalAccessor, boolean supportsOffset, TimeZone jdbcTimeZone) {
|
||||
if ( temporalAccessor.isSupported(ChronoField.OFFSET_SECONDS) ) {
|
||||
if ( supportsOffset ) {
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatAsDate(TemporalAccessor 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 ( supportsOffset ) {
|
||||
return DATE_TIME_FORMATTER_TIME_WITH_OFFSET.format( temporalAccessor );
|
||||
}
|
||||
else {
|
||||
return DATE_TIME_FORMATTER_TIME.format(
|
||||
LocalDateTime.ofInstant(
|
||||
Instant.from( temporalAccessor ),
|
||||
jdbcTimeZone.toZoneId()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return DATE_TIME_FORMATTER_TIME.format( temporalAccessor );
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatAsTimestampWithMillis(java.util.Date date) {
|
||||
return simpleDateFormatTimestampWithMillis().format( date );
|
||||
public static String formatAsTimestampWithMillis(java.util.Date date, TimeZone jdbcTimeZone) {
|
||||
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) {
|
||||
return simpleDateFormatTimestampWithMicros().format( date );
|
||||
public static String formatAsTimestampWithMicros(java.util.Date date, TimeZone jdbcTimeZone) {
|
||||
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) {
|
||||
|
@ -137,16 +212,8 @@ public final class DateTimeUtils {
|
|||
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) {
|
||||
return simpleDateFormatDate().format( date );
|
||||
return LOCAL_DATE_FORMAT.get().format( date );
|
||||
}
|
||||
|
||||
public static SimpleDateFormat simpleDateFormatDate() {
|
||||
|
@ -154,15 +221,23 @@ public final class DateTimeUtils {
|
|||
}
|
||||
|
||||
public static String formatAsTime(java.util.Date date) {
|
||||
return simpleDateFormatTime().format( date );
|
||||
return LOCAL_TIME_FORMAT.get().format( date );
|
||||
}
|
||||
|
||||
public static SimpleDateFormat simpleDateFormatTime() {
|
||||
return new SimpleDateFormat( FORMAT_STRING_TIME, Locale.ENGLISH );
|
||||
}
|
||||
|
||||
public static String formatAsTimestampWithMillis(java.util.Calendar calendar) {
|
||||
return simpleDateFormatTimestampWithMillis( calendar.getTimeZone() ).format( calendar.getTime() );
|
||||
public static String formatAsTimestampWithMillis(java.util.Calendar calendar, TimeZone jdbcTimeZone) {
|
||||
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) {
|
||||
|
@ -171,8 +246,16 @@ public final class DateTimeUtils {
|
|||
return formatter;
|
||||
}
|
||||
|
||||
public static String formatAsTimestampWithMicros(java.util.Calendar calendar) {
|
||||
return simpleDateFormatTimestampWithMicros( calendar.getTimeZone() ).format( calendar.getTime() );
|
||||
public static String formatAsTimestampWithMicros(java.util.Calendar calendar, TimeZone jdbcTimeZone) {
|
||||
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) {
|
||||
|
@ -182,7 +265,15 @@ public final class DateTimeUtils {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
@ -192,7 +283,15 @@ public final class DateTimeUtils {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -75,13 +75,13 @@ public class TimestampWithTimeZoneDescriptor implements SqlTypeDescriptor {
|
|||
int index,
|
||||
WrapperOptions wrapperOptions) throws SQLException {
|
||||
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
|
||||
st.setObject( index, dateTime, Types.TIMESTAMP_WITH_TIMEZONE );
|
||||
}
|
||||
catch (SQLException|AbstractMethodError e) {
|
||||
// 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 );
|
||||
}
|
||||
}
|
||||
|
@ -94,13 +94,13 @@ public class TimestampWithTimeZoneDescriptor implements SqlTypeDescriptor {
|
|||
WrapperOptions wrapperOptions)
|
||||
throws SQLException {
|
||||
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
|
||||
st.setObject( name, dateTime, Types.TIMESTAMP_WITH_TIMEZONE );
|
||||
}
|
||||
catch (SQLException|AbstractMethodError e) {
|
||||
// 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 );
|
||||
}
|
||||
}
|
||||
|
@ -114,11 +114,11 @@ public class TimestampWithTimeZoneDescriptor implements SqlTypeDescriptor {
|
|||
protected X doExtract(ResultSet rs, int position, WrapperOptions wrapperOptions) throws SQLException {
|
||||
try {
|
||||
// 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) {
|
||||
// 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 {
|
||||
try {
|
||||
// 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) {
|
||||
// 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 {
|
||||
try {
|
||||
// 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) {
|
||||
// fall back to treating it as a JDBC Timestamp
|
||||
return javaTypeDescriptor.wrap( statement.getTimestamp( name ), wrapperOptions.getSession() );
|
||||
return javaTypeDescriptor.wrap( statement.getTimestamp( name ), wrapperOptions );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.type.descriptor.sql.internal;
|
||||
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.TimeZone;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
|
@ -27,23 +28,33 @@ public class JdbcLiteralFormatterTemporal extends BasicJdbcLiteralFormatter {
|
|||
|
||||
@Override
|
||||
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
|
||||
if ( value instanceof java.util.Date ) {
|
||||
return dialect.formatDateTimeLiteral(
|
||||
(java.util.Date) value,
|
||||
precision
|
||||
precision,
|
||||
jdbcTimeZone
|
||||
);
|
||||
}
|
||||
else if ( value instanceof java.util.Calendar ) {
|
||||
return dialect.formatDateTimeLiteral(
|
||||
(java.util.Calendar) value,
|
||||
precision
|
||||
precision,
|
||||
jdbcTimeZone
|
||||
);
|
||||
}
|
||||
else if ( value instanceof TemporalAccessor ) {
|
||||
return dialect.formatDateTimeLiteral(
|
||||
(TemporalAccessor) value,
|
||||
precision
|
||||
precision,
|
||||
jdbcTimeZone
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -51,19 +62,22 @@ public class JdbcLiteralFormatterTemporal extends BasicJdbcLiteralFormatter {
|
|||
case DATE: {
|
||||
return dialect.formatDateTimeLiteral(
|
||||
unwrap( value, java.sql.Date.class, session ),
|
||||
precision
|
||||
precision,
|
||||
jdbcTimeZone
|
||||
);
|
||||
}
|
||||
case TIME: {
|
||||
return dialect.formatDateTimeLiteral(
|
||||
unwrap( value, java.sql.Time.class, session ),
|
||||
precision
|
||||
precision,
|
||||
jdbcTimeZone
|
||||
);
|
||||
}
|
||||
default: {
|
||||
return dialect.formatDateTimeLiteral(
|
||||
unwrap( value, java.util.Date.class, session ),
|
||||
precision
|
||||
precision,
|
||||
jdbcTimeZone
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -454,7 +454,6 @@ public class CompositeIdTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected(reason = "Criteria and EmbeddableId as predicate value has not yet been implemented")
|
||||
public void testQueryInAndComposite(SessionFactoryScope scope) {
|
||||
|
||||
scope.inTransaction(
|
||||
|
|
|
@ -76,7 +76,7 @@ public class OrderByColumnNameTest {
|
|||
);
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Entity(name = "Product")
|
||||
public static class Product {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
|
@ -103,7 +103,7 @@ public class OrderByColumnNameTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Entity(name = "Widgets")
|
||||
@Inheritance(strategy = InheritanceType.JOINED)
|
||||
public static class Widgets {
|
||||
private String name;
|
||||
|
@ -134,13 +134,13 @@ public class OrderByColumnNameTest {
|
|||
|
||||
}
|
||||
|
||||
@Entity
|
||||
public static class Widget1 extends org.hibernate.orm.test.annotations.collectionelement.Widgets {
|
||||
@Entity(name = "Widget1")
|
||||
public static class Widget1 extends Widgets {
|
||||
private String name1;
|
||||
}
|
||||
|
||||
@Entity
|
||||
public static class Widget2 extends org.hibernate.orm.test.annotations.collectionelement.Widgets {
|
||||
@Entity(name = "Widget2")
|
||||
public static class Widget2 extends Widgets {
|
||||
private String name2;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,12 +41,12 @@ public class Widgets {
|
|||
this.id = id;
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Entity(name = "Widget1")
|
||||
public static class Widget1 extends Widgets{
|
||||
private String name1;
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Entity(name = "Widget2")
|
||||
public static class Widget2 extends Widgets{
|
||||
private String name2;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@ import javax.persistence.GeneratedValue;
|
|||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.HibernateException;
|
||||
|
@ -642,8 +641,7 @@ public class MultipleSessionCollectionTest {
|
|||
);
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "Parent")
|
||||
@Entity(name = "Parent")
|
||||
public static class Parent {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
|
@ -665,8 +663,7 @@ public class MultipleSessionCollectionTest {
|
|||
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "Child")
|
||||
@Entity(name = "Child")
|
||||
public static class Child {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
|
|
|
@ -72,7 +72,7 @@ public class Staff {
|
|||
|
||||
@Column(name="kooky")
|
||||
@ColumnTransformer(
|
||||
read = "cast( kooky as VARCHAR )"
|
||||
read = "cast( kooky as VARCHAR(255) )"
|
||||
)
|
||||
public String getKooky() { return kooky; }
|
||||
public void setKooky(String kooky) { this.kooky = kooky; }
|
||||
|
|
|
@ -221,19 +221,19 @@ public class InheritedEntityGraphTest {
|
|||
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Entity(name = "Bar")
|
||||
public static class Bar {
|
||||
@Id @GeneratedValue
|
||||
public long id;
|
||||
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Entity(name = "Foo")
|
||||
public static class Foo extends MappedSupperclass {
|
||||
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Entity(name = "Foo2")
|
||||
public static class Foo2 {
|
||||
@Id @GeneratedValue
|
||||
public long id;
|
||||
|
|
|
@ -222,7 +222,6 @@ public class DynamicFilterTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected(jiraKey = "none", message = "not implemented method of QueryParameterBindingsImpl in v6")
|
||||
public void testHqlFilters() {
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// HQL test
|
||||
|
|
|
@ -107,7 +107,7 @@ public class JoinedSubclassWithEmbeddableTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Entity(name = "Employee")
|
||||
@Table(name = "employees")
|
||||
public static class Employee extends Person {
|
||||
private Integer employeeNumber;
|
||||
|
|
|
@ -107,7 +107,7 @@ public class SingleTableWithEmbeddableTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Entity(name = "Employee")
|
||||
@Table(name = "employees")
|
||||
public static class Employee extends Person {
|
||||
private Integer employeeNumber;
|
||||
|
|
|
@ -107,7 +107,7 @@ public class TablePerClassWithEmbeddableTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Entity(name = "Employee")
|
||||
@Table(name = "employees")
|
||||
public static class Employee extends Person {
|
||||
private Integer employeeNumber;
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.hibernate.metamodel.model.domain.JpaMetamodel;
|
|||
import org.hibernate.metamodel.model.domain.internal.JpaMetamodelImpl;
|
||||
import org.hibernate.metamodel.MappingMetamodel;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
import org.hibernate.query.hql.HqlTranslator;
|
||||
import org.hibernate.query.hql.internal.StandardHqlTranslator;
|
||||
import org.hibernate.query.hql.spi.SqmCreationOptions;
|
||||
|
@ -115,6 +116,7 @@ public class HqlTranslationNoFactoryTests {
|
|||
|
||||
final QueryEngine queryEngine = new QueryEngine(
|
||||
jpaMetamodel,
|
||||
LiteralHandlingMode.AUTO,
|
||||
// we don't want strict JPA query compliance
|
||||
false,
|
||||
new NamedObjectRepositoryImpl( Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap() ),
|
||||
|
|
|
@ -25,6 +25,7 @@ import javax.persistence.ManyToMany;
|
|||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.MapKeyEnumerated;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
|
@ -283,6 +284,7 @@ public class ManyToManyHqlMemberOfQueryTest {
|
|||
}
|
||||
|
||||
@Entity(name = "Call")
|
||||
@Table(name = "phone_call")
|
||||
public static class Call {
|
||||
|
||||
@Id
|
||||
|
|
|
@ -26,6 +26,7 @@ import javax.persistence.ManyToOne;
|
|||
import javax.persistence.MapKeyEnumerated;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OrderColumn;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
|
@ -283,6 +284,7 @@ public class OneToManyHqlMemberOfQueryTest {
|
|||
}
|
||||
|
||||
@Entity(name = "Call")
|
||||
@Table(name = "phone_call")
|
||||
public static class Call {
|
||||
|
||||
@Id
|
||||
|
|
|
@ -78,7 +78,7 @@ public class OneToOneLazyTest {
|
|||
);
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Entity(name = "Book")
|
||||
public static class Book {
|
||||
|
||||
@Id
|
||||
|
@ -109,7 +109,7 @@ public class OneToOneLazyTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Entity(name = "Title")
|
||||
public static class Title {
|
||||
|
||||
@Id
|
||||
|
|
|
@ -10,12 +10,14 @@ import javax.persistence.criteria.CriteriaQuery;
|
|||
import javax.persistence.criteria.ParameterExpression;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
|
||||
import org.hibernate.query.criteria.JpaCriteriaQuery;
|
||||
import org.hibernate.query.criteria.JpaRoot;
|
||||
|
||||
import org.hibernate.testing.orm.domain.gambit.BasicEntity;
|
||||
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.SessionFactoryScope;
|
||||
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
|
||||
@RequiresDialect(H2Dialect.class)
|
||||
public void testExecutingBasicCriteriaQueryParameterPredicate(SessionFactoryScope scope) {
|
||||
scope.inStatelessTransaction(
|
||||
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
|
||||
@RequiresDialect(H2Dialect.class)
|
||||
public void testExecutingBasicCriteriaQueryParameterPredicateInStatelessSession(SessionFactoryScope scope) {
|
||||
scope.inStatelessTransaction(
|
||||
session -> {
|
||||
|
|
|
@ -8,11 +8,16 @@ package org.hibernate.orm.test.query.hql;
|
|||
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
||||
import org.hibernate.testing.DialectChecks;
|
||||
import org.hibernate.testing.junit5.SessionFactoryBasedFunctionalTest;
|
||||
import org.hibernate.testing.orm.domain.StandardDomainModel;
|
||||
import org.hibernate.testing.orm.domain.gambit.EntityOfBasics;
|
||||
import org.hibernate.testing.orm.junit.DialectFeatureCheck;
|
||||
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.FailureExpected;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
|
@ -95,9 +100,9 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
|
|||
public void testConcatFunctionParameters(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
assertThat( session.createQuery("select :hello||:world").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 ?1||?1").setParameter(1,"hello").getSingleResult(), is("hellohello") );
|
||||
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 cast(?1 as String)||cast(?2 as String)").setParameter(1,"hello").setParameter(2,"world").getSingleResult(), is("helloworld") );
|
||||
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
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsPadWithChar.class)
|
||||
public void testPadFunction(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
|
@ -955,11 +961,20 @@ public class FunctionTests extends SessionFactoryBasedFunctionalTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testGroupingFunctions() {
|
||||
public void testGrouping() {
|
||||
inTransaction(
|
||||
session -> {
|
||||
session.createQuery("select max(e.theDouble), e.gender, e.theInt from EntityOfBasics e group by e.gender, e.theInt")
|
||||
.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)")
|
||||
.list();
|
||||
session.createQuery("select sum(e.theDouble), e.gender, e.theInt from EntityOfBasics e group by cube(e.gender, e.theInt)")
|
||||
|
|
|
@ -70,8 +70,8 @@ public class LiteralTests {
|
|||
public void testJdbcTimestampLiteral(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "from EntityOfBasics e1 where e1.theDate = {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();
|
||||
session.createQuery( "from EntityOfBasics e1 where e1.theTimestamp = {ts '1999-12-31 12:30:00'}" ).list();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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.DomainResult;
|
||||
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.testing.hamcrest.AssignableMatcher;
|
||||
|
@ -170,7 +168,7 @@ public class SmokeTests {
|
|||
assertThat( sqlSelection.getJdbcValueExtractor(), notNullValue() );
|
||||
|
||||
assertThat( sqlSelection, instanceOf( SqlSelectionImpl.class ) );
|
||||
final Expression selectedExpression = ( (SqlSelectionImpl) sqlSelection ).getWrappedSqlExpression();
|
||||
final Expression selectedExpression = sqlSelection.getExpression();
|
||||
assertThat( selectedExpression, instanceOf( ColumnReference.class ) );
|
||||
final ColumnReference columnReference = (ColumnReference) selectedExpression;
|
||||
assertThat( columnReference.renderSqlFragment( scope.getSessionFactory() ), is( "s1_0.gender" ) );
|
||||
|
|
|
@ -201,7 +201,7 @@ public class SmokeTests {
|
|||
scope.inTransaction(
|
||||
session -> {
|
||||
final QueryImplementor<String> query = session.createQuery(
|
||||
"select :param from SimpleEntity e",
|
||||
"select cast(:param as String) from SimpleEntity e",
|
||||
String.class
|
||||
);
|
||||
final String attribute1 = query.setParameter( "param", "items" ).uniqueResult();
|
||||
|
|
|
@ -28,12 +28,10 @@ public class HHH13884Test {
|
|||
@Test
|
||||
public void testDefaultSqmSortSpecificationReverse() {
|
||||
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( collation, order.getCollation() );
|
||||
assertEquals( ASCENDING, order.getSortOrder() );
|
||||
assertEquals( FIRST, order.getNullPrecedence() );
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.testing.orm.junit;
|
||||
|
||||
import org.hibernate.dialect.DerbyDialect;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
|
||||
/**
|
||||
|
@ -213,4 +214,16 @@ abstract public class DialectFeatureChecks {
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import org.apache.tools.ant.filters.ReplaceTokens
|
|||
|
||||
plugins {
|
||||
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
|
||||
id "com.gradle.plugin-publish" version "0.12.0"
|
||||
|
|
Loading…
Reference in New Issue