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

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

View File

@ -277,15 +277,7 @@ mapKeyNavigablePath
// GROUP BY clause
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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -22,6 +22,7 @@ import org.hibernate.engine.jdbc.Size;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.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

View File

@ -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 );

View File

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

View File

@ -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;

View File

@ -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 );
}
};
}

View File

@ -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

View File

@ -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 );
}

View File

@ -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 )

View File

@ -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 );

View File

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

View File

@ -13,6 +13,7 @@ import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.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,

View File

@ -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() {

View File

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

View File

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

View File

@ -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)) {

View File

@ -0,0 +1,21 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query;
/**
* The kind of type of a cast target.
*
* @see CastType
*
* @author Christian Beikov
*/
public enum CastTypeKind {
BOOLEAN,
NUMERIC,
TEMPORAL,
TEXT
}

View File

@ -12,10 +12,16 @@ package org.hibernate.query;
*/
public enum ComparisonOperator {
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();
}

View File

@ -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

View File

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

View File

@ -6,7 +6,9 @@
*/
package org.hibernate.query.hql.internal;
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(),

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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() {

View File

@ -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);

View File

@ -52,6 +52,8 @@ import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.query.sqm.tree.SqmDmlStatement;
import org.hibernate.query.sqm.tree.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) {

View File

@ -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
);

View File

@ -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;

View File

@ -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 )
);
}
}

View File

@ -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;

View File

@ -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,

View File

@ -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() {

View File

@ -13,6 +13,7 @@ import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.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 );

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

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

View File

@ -18,8 +18,8 @@ public class SqmEvery<T> extends AbstractSqmExpression<T> {
private final SqmSubQuery<T> subquery;
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;
}

View File

@ -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" );

View File

@ -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;
}

View File

@ -1,88 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.sqm.tree.select;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
/**
* Models the GROUP-BY clause of a SqmQuerySpec
*
* @author Steve Ebersole
*/
public class SqmGroupByClause {
private List<SqmGrouping> groupings;
public List<SqmGrouping> getGroupings() {
return groupings;
}
public void visitGroupings(Consumer<SqmGrouping> consumer) {
if ( groupings != null ) {
groupings.forEach( consumer );
}
}
public void setGroupings(List<SqmGrouping> groupings) {
this.groupings = groupings;
}
public void addGrouping(SqmGrouping grouping) {
if ( groupings == null ) {
groupings = new ArrayList<>();
}
groupings.add( grouping );
}
public void addGrouping(SqmExpression groupExpression) {
addGrouping( new SqmGrouping( groupExpression, null ) );
}
public void addGrouping(SqmExpression groupExpression, String collation) {
addGrouping( new SqmGrouping( groupExpression, collation ) );
}
public void clearGroupings() {
if ( groupings != null ) {
groupings.clear();
}
}
public static class SqmGrouping {
private SqmExpression expression;
// todo (6.0) : special type besides String?
private String collation;
public SqmGrouping() {
}
public SqmGrouping(SqmExpression expression, String collation) {
this.expression = expression;
this.collation = collation;
}
public SqmExpression getExpression() {
return expression;
}
public void setExpression(SqmExpression expression) {
this.expression = expression;
}
public String getCollation() {
return collation;
}
public void setCollation(String collation) {
this.collation = collation;
}
}
}

View File

@ -1,33 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.sqm.tree.select;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
/**
* Models the HAVING clause of a SqmQuerySpec
*
* @author Steve Ebersole
*/
public class SqmHavingClause {
private SqmPredicate predicate;
public SqmHavingClause() {
}
public SqmHavingClause(SqmPredicate predicate) {
this.predicate = predicate;
}
public SqmPredicate getPredicate() {
return predicate;
}
public void setPredicate(SqmPredicate predicate) {
this.predicate = predicate;
}
}

View File

@ -44,13 +44,13 @@ public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseCo
private SqmSelectClause selectClause;
private 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;
}
}

View File

@ -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

View File

@ -14,6 +14,7 @@ import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.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);
}

View File

@ -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 );
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -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 );
}
}

View File

@ -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
*/

View File

@ -0,0 +1,58 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.ast.tree.expression;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.mapping.SqlExpressable;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.tree.SqlAstNode;
/**
* @author Christian Beikov
*/
public class Collate implements Expression, SqlExpressable, SqlAstNode {
private final Expression expression;
private final String collation;
public Collate(Expression expression, String collation) {
this.expression = expression;
this.collation = collation;
}
public Expression getExpression() {
return expression;
}
public String getCollation() {
return collation;
}
@Override
public JdbcMapping getJdbcMapping() {
if ( expression instanceof SqlExpressable ) {
return ( (SqlExpressable) expression ).getJdbcMapping();
}
if ( getExpressionType() instanceof SqlExpressable ) {
return ( (SqlExpressable) getExpressionType() ).getJdbcMapping();
}
return null;
}
@Override
public MappingModelExpressable getExpressionType() {
return expression.getExpressionType();
}
@Override
public void accept(SqlAstWalker sqlTreeWalker) {
sqlTreeWalker.visitCollate( this );
}
}

View File

@ -0,0 +1,42 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.ast.tree.expression;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlAppender;
/**
* A wrapper for a literal to render as parameter through a cast function.
*
* @see org.hibernate.sql.ast.spi.AbstractSqlAstWalker
*
* @author Christian beikov
*/
public class LiteralAsParameter<T> implements SelfRenderingExpression {
private final Literal literal;
public LiteralAsParameter(Literal literal) {
this.literal = literal;
}
@Override
public void renderToSql(SqlAppender sqlAppender, SqlAstWalker walker, SessionFactoryImplementor sessionFactory) {
sqlAppender.appendSql( "?" );
}
@Override
public MappingModelExpressable getExpressionType() {
return literal.getExpressionType();
}
public Literal getLiteral() {
return literal;
}
}

View File

@ -1,51 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.ast.tree.predicate;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.select.QuerySpec;
/**
* @author Andrea Boriero
*/
public class MemberOfPredicate implements Predicate {
private final Expression leftHandExpression;
private final QuerySpec querySpec;
private final boolean isNegated;
public MemberOfPredicate(
Expression leftHandExpression,
boolean isNegated,
QuerySpec querySpec) {
this.leftHandExpression = leftHandExpression;
this.isNegated = isNegated;
this.querySpec = querySpec;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public void accept(SqlAstWalker sqlTreeWalker) {
sqlTreeWalker.visitMemberOfPredicate( this );
}
public boolean isNegated() {
return isNegated;
}
public Expression getLeftHandExpression() {
return leftHandExpression;
}
public QuerySpec getQuerySpec() {
return querySpec;
}
}

View File

@ -7,6 +7,7 @@
package org.hibernate.sql.ast.tree.select;
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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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) {

View File

@ -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 );
}
}
};

View File

@ -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
);
}
}

View File

@ -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(

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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; }

View File

@ -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;

View File

@ -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

View File

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

View File

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

View File

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

View File

@ -19,6 +19,7 @@ import org.hibernate.metamodel.model.domain.JpaMetamodel;
import org.hibernate.metamodel.model.domain.internal.JpaMetamodelImpl;
import org.hibernate.metamodel.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() ),

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 -> {

View File

@ -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)")

View File

@ -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();
}
);
}

View File

@ -35,8 +35,6 @@ import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.sql.results.graph.basic.BasicResultAssembler;
import org.hibernate.sql.results.graph.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" ) );

View File

@ -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();

View File

@ -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() );

View File

@ -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();
}
}
}

View File

@ -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"