Add emulation for simple lateral joins and make use of lateral joins for min/max index/element paths if possible
This commit is contained in:
parent
ab954925e4
commit
fb30206387
|
@ -701,6 +701,11 @@ public class FirebirdDialect extends Dialect {
|
|||
return getVersion().isSameOrAfter( 3, 0 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLateral() {
|
||||
return getVersion().isSameOrAfter( 4, 0 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String translateExtractField(TemporalUnit unit) {
|
||||
switch ( unit ) {
|
||||
|
|
|
@ -341,6 +341,16 @@ public class InformixDialect extends Dialect {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsWindowFunctions() {
|
||||
return getVersion().isSameOrAfter( 12, 10 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLateral() {
|
||||
return getVersion().isSameOrAfter( 12, 10 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViolatedConstraintNameExtractor getViolatedConstraintNameExtractor() {
|
||||
return EXTRACTOR;
|
||||
|
|
|
@ -500,7 +500,11 @@ public class IngresDialect extends Dialect {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@Override
|
||||
public boolean supportsWindowFunctions() {
|
||||
return getVersion().isSameOrAfter( 10, 2 );
|
||||
}
|
||||
// Informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@Override
|
||||
public boolean doesReadCommittedCauseWritersToBlockReaders() {
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.hibernate.sql.ast.tree.expression.Any;
|
|||
import org.hibernate.sql.ast.tree.expression.Every;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.Summarization;
|
||||
import org.hibernate.sql.ast.tree.from.QueryPartTableReference;
|
||||
import org.hibernate.sql.ast.tree.select.QueryGroup;
|
||||
import org.hibernate.sql.ast.tree.select.QueryPart;
|
||||
import org.hibernate.sql.ast.tree.select.QuerySpec;
|
||||
|
@ -92,6 +93,11 @@ public class SQLiteSqlAstTranslator<T extends JdbcOperation> extends AbstractSql
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitQueryPartTableReference(QueryPartTableReference tableReference) {
|
||||
emulateQueryPartTableReferenceColumnAliasing( tableReference );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOffsetFetchClause(QueryPart queryPart) {
|
||||
if ( !isRowNumberingCurrentQueryPart() ) {
|
||||
|
|
|
@ -30,7 +30,7 @@ import org.hibernate.sql.exec.spi.JdbcOperation;
|
|||
import static org.hibernate.type.SqlTypes.*;
|
||||
|
||||
/**
|
||||
* SQL Dialect for Sybase Anywhere
|
||||
* SQL Dialect for Sybase/SQL Anywhere
|
||||
* (Tested on ASA 8.x)
|
||||
*/
|
||||
public class SybaseAnywhereDialect extends SybaseDialect {
|
||||
|
@ -135,6 +135,16 @@ public class SybaseAnywhereDialect extends SybaseDialect {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsWindowFunctions() {
|
||||
return getVersion().isSameOrAfter( 12 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLateral() {
|
||||
return getVersion().isSameOrAfter( 10 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentityColumnSupport getIdentityColumnSupport() {
|
||||
return new SybaseAnywhereIdentityColumnSupport();
|
||||
|
|
|
@ -379,6 +379,11 @@ public class TeradataDialect extends Dialect {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsWindowFunctions() {
|
||||
return getVersion().isSameOrAfter( 16, 10 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSelectClauseNullString(int sqlType) {
|
||||
String v = "null";
|
||||
|
|
|
@ -11,7 +11,6 @@ import java.util.List;
|
|||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.ComparisonOperator;
|
||||
import org.hibernate.query.IllegalQueryOperationException;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
|
@ -19,10 +18,11 @@ import org.hibernate.sql.ast.tree.Statement;
|
|||
import org.hibernate.sql.ast.tree.cte.CteStatement;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
|
||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||
import org.hibernate.sql.ast.tree.expression.Summarization;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||
import org.hibernate.sql.ast.tree.predicate.Junction;
|
||||
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
import org.hibernate.sql.ast.tree.select.QueryGroup;
|
||||
import org.hibernate.sql.ast.tree.select.QueryPart;
|
||||
|
@ -70,13 +70,12 @@ public class TimesTenSqlAstTranslator<T extends JdbcOperation> extends AbstractS
|
|||
}
|
||||
|
||||
final Predicate predicate;
|
||||
if ( tableGroupJoin.isLateral() ) {
|
||||
append( "lateral " );
|
||||
if ( tableGroupJoin.getPredicate() == null ) {
|
||||
predicate = new Junction( Junction.Nature.CONJUNCTION );
|
||||
if ( tableGroupJoin.getPredicate() == null ) {
|
||||
if ( tableGroupJoin.getJoinType() == SqlAstJoinType.CROSS ) {
|
||||
predicate = null;
|
||||
}
|
||||
else {
|
||||
predicate = tableGroupJoin.getPredicate();
|
||||
predicate = new BooleanExpressionPredicate( new QueryLiteral<>( true, getBooleanType() ) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -86,7 +85,7 @@ public class TimesTenSqlAstTranslator<T extends JdbcOperation> extends AbstractS
|
|||
renderTableGroup( tableGroupJoin.getJoinedGroup(), predicate, tableGroupJoinCollector );
|
||||
}
|
||||
else {
|
||||
renderTableGroup( tableGroupJoin.getJoinedGroup(), tableGroupJoinCollector );
|
||||
renderTableGroup( tableGroupJoin.getJoinedGroup(), null, tableGroupJoinCollector );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.hibernate.engine.config.spi.ConfigurationService.Converter;
|
|||
import org.hibernate.engine.config.spi.StandardConverters;
|
||||
import org.hibernate.engine.jdbc.*;
|
||||
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.jdbc.env.spi.*;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
|
@ -228,6 +229,26 @@ public abstract class AbstractHANADialect extends Dialect {
|
|||
return false;
|
||||
}
|
||||
|
||||
protected static DatabaseVersion createVersion(DialectResolutionInfo info) {
|
||||
// Parse the version according to https://answers.sap.com/questions/9760991/hana-sps-version-check.html
|
||||
final String versionString = info.getDatabaseVersion();
|
||||
int majorVersion = 1;
|
||||
int minorVersion = 0;
|
||||
int patchLevel = 0;
|
||||
final String[] components = versionString.split( "\\." );
|
||||
if ( components.length >= 3 ) {
|
||||
try {
|
||||
majorVersion = Integer.parseInt( components[0] );
|
||||
minorVersion = Integer.parseInt( components[1] );
|
||||
patchLevel = Integer.parseInt( components[2] );
|
||||
}
|
||||
catch (NumberFormatException ex) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
return DatabaseVersion.make( majorVersion, minorVersion, patchLevel );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String castPattern(CastType from, CastType to) {
|
||||
if ( to == CastType.BOOLEAN ) {
|
||||
|
@ -991,6 +1012,11 @@ public abstract class AbstractHANADialect extends Dialect {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLateral() {
|
||||
return getVersion().isSameOrAfter( 2, 0, 40 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsNoWait() {
|
||||
return true;
|
||||
|
|
|
@ -672,6 +672,11 @@ public class CockroachDialect extends Dialect {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLateral() {
|
||||
return getVersion().isSameOrAfter( 20, 1 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsNoWait() {
|
||||
return getVersion().isSameOrAfter( 20, 1 );
|
||||
|
|
|
@ -671,6 +671,11 @@ public class DB2Dialect extends Dialect {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLateral() {
|
||||
return getVersion().isSameOrAfter( 9, 1 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendDatetimeFormat(SqlAppender appender, String format) {
|
||||
//DB2 does not need nor support FM
|
||||
|
|
|
@ -99,6 +99,11 @@ public class DB2iDialect extends DB2Dialect {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLateral() {
|
||||
return getIVersion().isSameOrAfter( 7, 1 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlAstTranslatorFactory getSqlAstTranslatorFactory() {
|
||||
return new StandardSqlAstTranslatorFactory() {
|
||||
|
|
|
@ -42,7 +42,7 @@ public class DB2zDialect extends DB2Dialect {
|
|||
}
|
||||
|
||||
public DB2zDialect() {
|
||||
this( DatabaseVersion.make(7) );
|
||||
this( DatabaseVersion.make( 7 ) );
|
||||
}
|
||||
|
||||
public DB2zDialect(DatabaseVersion version) {
|
||||
|
@ -53,7 +53,7 @@ public class DB2zDialect extends DB2Dialect {
|
|||
@Override
|
||||
protected String columnType(int jdbcTypeCode) {
|
||||
// See https://www.ibm.com/support/knowledgecenter/SSEPEK_10.0.0/wnew/src/tpc/db2z_10_timestamptimezone.html
|
||||
if ( jdbcTypeCode==TIMESTAMP_WITH_TIMEZONE && version.isAfter(10) ) {
|
||||
if ( jdbcTypeCode==TIMESTAMP_WITH_TIMEZONE && version.isAfter(10) ) {
|
||||
return "timestamp with time zone";
|
||||
}
|
||||
return super.columnType(jdbcTypeCode);
|
||||
|
@ -95,6 +95,11 @@ public class DB2zDialect extends DB2Dialect {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLateral() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType, IntervalType intervalType) {
|
||||
StringBuilder pattern = new StringBuilder();
|
||||
|
|
|
@ -6,11 +6,18 @@
|
|||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.ComparisonOperator;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||
import org.hibernate.sql.ast.tree.from.FunctionTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.NamedTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.select.QueryPart;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperation;
|
||||
|
||||
|
@ -50,4 +57,24 @@ public class DB2zSqlAstTranslator<T extends JdbcOperation> extends DB2SqlAstTran
|
|||
renderComparisonStandard( lhs, operator, rhs );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean renderPrimaryTableReference(TableGroup tableGroup, LockMode lockMode) {
|
||||
final TableReference tableReference = tableGroup.getPrimaryTableReference();
|
||||
if ( tableReference instanceof NamedTableReference ) {
|
||||
return renderNamedTableReference( (NamedTableReference) tableReference, lockMode );
|
||||
}
|
||||
// DB2 z/OS we need the "table" qualifier for table valued functions or lateral sub-queries
|
||||
append( "table " );
|
||||
tableReference.accept( this );
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFunctionTableReference(FunctionTableReference tableReference) {
|
||||
// For the table qualifier we need parenthesis on DB2 z/OS
|
||||
append( OPEN_PARENTHESIS );
|
||||
tableReference.getFunctionExpression().accept( this );
|
||||
append( CLOSE_PARENTHESIS );
|
||||
renderDerivedTableReference( tableReference );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3503,6 +3503,16 @@ public abstract class Dialect implements ConversionContext {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this dialect support the SQL lateral keyword or a proprietary alternative=
|
||||
*
|
||||
* @return {@code true} if the underlying database supports lateral,
|
||||
* {@code false} otherwise. The default is {@code false}.
|
||||
*/
|
||||
public boolean supportsLateral() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public CallableStatementSupport getCallableStatementSupport() {
|
||||
// most databases do not support returning cursors (ref_cursor)...
|
||||
return StandardCallableStatementSupport.NO_REF_CURSOR_INSTANCE;
|
||||
|
|
|
@ -6,11 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
|
||||
/**
|
||||
* An SQL dialect for the SAP HANA Cloud column store.
|
||||
* <p>
|
||||
|
@ -30,7 +25,29 @@ import org.hibernate.type.StandardBasicTypes;
|
|||
public class HANACloudColumnStoreDialect extends HANAColumnStoreDialect {
|
||||
|
||||
public HANACloudColumnStoreDialect() {
|
||||
// No idea how the versioning scheme is here, but since this is deprecated anyway, keep it as is
|
||||
super( DatabaseVersion.make( 4 ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLateral() {
|
||||
// Couldn't find a reference since when this is supported
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsAsciiStringTypes() {
|
||||
return getVersion().isBefore( 4 );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean useUnicodeStringTypesDefault() {
|
||||
return getVersion().isSameOrAfter( 4 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUseUnicodeStringTypes() {
|
||||
return getVersion().isSameOrAfter( 4 ) || super.isUseUnicodeStringTypes();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,13 +35,15 @@ import org.hibernate.type.StandardBasicTypes;
|
|||
* @author <a href="mailto:jonathan.bregler@sap.com">Jonathan Bregler</a>
|
||||
*/
|
||||
public class HANAColumnStoreDialect extends AbstractHANADialect {
|
||||
|
||||
public HANAColumnStoreDialect(DialectResolutionInfo info) {
|
||||
this( info.makeCopy() );
|
||||
this( AbstractHANADialect.createVersion( info ) );
|
||||
registerKeywords( info );
|
||||
}
|
||||
|
||||
public HANAColumnStoreDialect() {
|
||||
this( DatabaseVersion.make( 3, 0 ) );
|
||||
// SAP HANA 1.0 SP12 is the default
|
||||
this( DatabaseVersion.make( 1, 0, 120 ) );
|
||||
}
|
||||
|
||||
public HANAColumnStoreDialect(DatabaseVersion version) {
|
||||
|
@ -172,17 +174,11 @@ public class HANAColumnStoreDialect extends AbstractHANADialect {
|
|||
|
||||
@Override
|
||||
protected boolean supportsAsciiStringTypes() {
|
||||
return getVersion().isBefore( 4 );
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean useUnicodeStringTypesDefault() {
|
||||
return getVersion().isSameOrAfter( 4 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUseUnicodeStringTypes() {
|
||||
return getVersion().isSameOrAfter( 4 )
|
||||
|| super.isUseUnicodeStringTypes();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,13 +32,14 @@ import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
|||
*/
|
||||
public class HANARowStoreDialect extends AbstractHANADialect {
|
||||
|
||||
public HANARowStoreDialect() {
|
||||
super( DatabaseVersion.make( 3, 0 ));
|
||||
public HANARowStoreDialect(DialectResolutionInfo info) {
|
||||
this( AbstractHANADialect.createVersion( info ) );
|
||||
registerKeywords( info );
|
||||
}
|
||||
|
||||
public HANARowStoreDialect(DialectResolutionInfo info) {
|
||||
this( info.makeCopy() );
|
||||
registerKeywords( info );
|
||||
public HANARowStoreDialect() {
|
||||
// SAP HANA 1.0 SPS12 R0 is the default
|
||||
this( DatabaseVersion.make( 1, 0, 120 ) );
|
||||
}
|
||||
|
||||
public HANARowStoreDialect(DatabaseVersion version) {
|
||||
|
|
|
@ -720,6 +720,11 @@ public class HSQLDialect extends Dialect {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLateral() {
|
||||
return getVersion().isSameOrAfter( 2, 6, 1 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresFloatCastingOfIntegerDivision() {
|
||||
return true;
|
||||
|
|
|
@ -33,6 +33,8 @@ import org.hibernate.type.StandardBasicTypes;
|
|||
* @author Gavin King
|
||||
*/
|
||||
public class MariaDBDialect extends MySQLDialect {
|
||||
private static final DatabaseVersion VERSION5 = DatabaseVersion.make( 5 );
|
||||
private static final DatabaseVersion VERSION57 = DatabaseVersion.make( 5, 7 );
|
||||
|
||||
public MariaDBDialect() {
|
||||
this( DatabaseVersion.make( 5 ) );
|
||||
|
@ -49,8 +51,8 @@ public class MariaDBDialect extends MySQLDialect {
|
|||
@Override
|
||||
public DatabaseVersion getMySQLVersion() {
|
||||
return getVersion().isBefore( 5, 3 )
|
||||
? DatabaseVersion.make( 5 )
|
||||
: DatabaseVersion.make( 5, 7 );
|
||||
? VERSION5
|
||||
: VERSION57;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.hibernate.sql.ast.tree.cte.CteStatement;
|
|||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||
import org.hibernate.sql.ast.tree.expression.Summarization;
|
||||
import org.hibernate.sql.ast.tree.from.QueryPartTableReference;
|
||||
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
|
||||
import org.hibernate.sql.ast.tree.select.QueryGroup;
|
||||
import org.hibernate.sql.ast.tree.select.QueryPart;
|
||||
|
@ -71,6 +72,11 @@ public class MariaDBSqlAstTranslator<T extends JdbcOperation> extends AbstractSq
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitQueryPartTableReference(QueryPartTableReference tableReference) {
|
||||
emulateQueryPartTableReferenceColumnAliasing( tableReference );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOffsetFetchClause(QueryPart queryPart) {
|
||||
if ( !isRowNumberingCurrentQueryPart() ) {
|
||||
|
|
|
@ -1179,6 +1179,11 @@ public class MySQLDialect extends Dialect {
|
|||
return getMySQLVersion().isSameOrAfter( 8, 2 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLateral() {
|
||||
return getMySQLVersion().isSameOrAfter( 8, 14 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsSkipLocked() {
|
||||
return getMySQLVersion().isSameOrAfter( 8 );
|
||||
|
|
|
@ -14,6 +14,8 @@ import org.hibernate.sql.ast.tree.cte.CteStatement;
|
|||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||
import org.hibernate.sql.ast.tree.expression.Summarization;
|
||||
import org.hibernate.sql.ast.tree.from.QueryPartTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.ValuesTableReference;
|
||||
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
|
||||
import org.hibernate.sql.ast.tree.select.QueryGroup;
|
||||
import org.hibernate.sql.ast.tree.select.QueryPart;
|
||||
|
@ -72,6 +74,21 @@ public class MySQLSqlAstTranslator<T extends JdbcOperation> extends AbstractSqlA
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitValuesTableReference(ValuesTableReference tableReference) {
|
||||
emulateValuesTableReferenceColumnAliasing( tableReference );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitQueryPartTableReference(QueryPartTableReference tableReference) {
|
||||
if ( getDialect().getVersion().isSameOrAfter( 8 ) ) {
|
||||
super.visitQueryPartTableReference( tableReference );
|
||||
}
|
||||
else {
|
||||
emulateQueryPartTableReferenceColumnAliasing( tableReference );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOffsetFetchClause(QueryPart queryPart) {
|
||||
if ( !isRowNumberingCurrentQueryPart() ) {
|
||||
|
|
|
@ -1061,6 +1061,11 @@ public class OracleDialect extends Dialect {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLateral() {
|
||||
return getVersion().isSameOrAfter( 12, 1 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsNoWait() {
|
||||
return getVersion().isSameOrAfter( 9 );
|
||||
|
|
|
@ -24,6 +24,8 @@ import org.hibernate.sql.ast.tree.expression.Literal;
|
|||
import org.hibernate.sql.ast.tree.expression.Over;
|
||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||
import org.hibernate.sql.ast.tree.expression.Summarization;
|
||||
import org.hibernate.sql.ast.tree.from.FunctionTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.QueryPartTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.UnionTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.ValuesTableReference;
|
||||
import org.hibernate.sql.ast.tree.insert.Values;
|
||||
|
@ -248,48 +250,20 @@ public class OracleSqlAstTranslator<T extends JdbcOperation> extends AbstractSql
|
|||
|
||||
@Override
|
||||
public void visitValuesTableReference(ValuesTableReference tableReference) {
|
||||
final List<Values> valuesList = tableReference.getValuesList();
|
||||
if ( valuesList.size() < 2 ) {
|
||||
super.visitValuesTableReference( tableReference );
|
||||
}
|
||||
else {
|
||||
append( '(' );
|
||||
// Oracle doesn't support a multi-values insert
|
||||
// So we render a select union emulation instead
|
||||
final Stack<Clause> clauseStack = getClauseStack();
|
||||
clauseStack.push( Clause.VALUES );
|
||||
try {
|
||||
// We render the first select statement with aliases
|
||||
clauseStack.push( Clause.SELECT );
|
||||
emulateValuesTableReferenceColumnAliasing( tableReference );
|
||||
}
|
||||
|
||||
try {
|
||||
appendSql( "select " );
|
||||
@Override
|
||||
public void visitQueryPartTableReference(QueryPartTableReference tableReference) {
|
||||
emulateQueryPartTableReferenceColumnAliasing( tableReference );
|
||||
}
|
||||
|
||||
renderCommaSeparatedSelectExpression(
|
||||
valuesList.get( 0 ).getExpressions(),
|
||||
tableReference.getColumnNames()
|
||||
);
|
||||
appendSql( getFromDualForSelectOnly() );
|
||||
}
|
||||
finally {
|
||||
clauseStack.pop();
|
||||
}
|
||||
// The others, without the aliases
|
||||
for ( int i = 1; i < valuesList.size(); i++ ) {
|
||||
appendSql( " union all " );
|
||||
renderExpressionsAsSubquery( valuesList.get( i ).getExpressions() );
|
||||
}
|
||||
}
|
||||
finally {
|
||||
clauseStack.pop();
|
||||
}
|
||||
append( ')' );
|
||||
final String identificationVariable = tableReference.getIdentificationVariable();
|
||||
if ( identificationVariable != null ) {
|
||||
append( WHITESPACE );
|
||||
append( tableReference.getIdentificationVariable() );
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void visitFunctionTableReference(FunctionTableReference tableReference) {
|
||||
append( "table(" );
|
||||
tableReference.getFunctionExpression().accept( this );
|
||||
append( CLOSE_PARENTHESIS );
|
||||
renderTableReferenceIdentificationVariable( tableReference );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1006,6 +1006,11 @@ public class PostgreSQLDialect extends Dialect {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLateral() {
|
||||
return getVersion().isSameOrAfter( 9, 3 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFetchClause(FetchClauseType type) {
|
||||
switch ( type ) {
|
||||
|
|
|
@ -562,6 +562,11 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLateral() {
|
||||
return getVersion().isSameOrAfter( 9 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFetchClause(FetchClauseType type) {
|
||||
return getVersion().isSameOrAfter( 11 );
|
||||
|
|
|
@ -24,9 +24,10 @@ import org.hibernate.sql.ast.tree.expression.Literal;
|
|||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||
import org.hibernate.sql.ast.tree.expression.Summarization;
|
||||
import org.hibernate.sql.ast.tree.from.NamedTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.from.UnionTableReference;
|
||||
import org.hibernate.sql.ast.tree.predicate.Junction;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
import org.hibernate.sql.ast.tree.select.QueryGroup;
|
||||
import org.hibernate.sql.ast.tree.select.QueryPart;
|
||||
|
@ -44,6 +45,8 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends Abstract
|
|||
|
||||
private static final String UNION_ALL = " union all ";
|
||||
|
||||
private Predicate lateralPredicate;
|
||||
|
||||
public SQLServerSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) {
|
||||
super( sessionFactory, statement );
|
||||
}
|
||||
|
@ -51,7 +54,7 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends Abstract
|
|||
@Override
|
||||
protected void renderTableGroupJoin(TableGroupJoin tableGroupJoin, List<TableGroupJoin> tableGroupJoinCollector) {
|
||||
appendSql( WHITESPACE );
|
||||
if ( tableGroupJoin.isLateral() ) {
|
||||
if ( tableGroupJoin.getJoinedGroup().isLateral() ) {
|
||||
if ( tableGroupJoin.getJoinType() == SqlAstJoinType.LEFT ) {
|
||||
appendSql( "outer apply " );
|
||||
}
|
||||
|
@ -66,19 +69,31 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends Abstract
|
|||
|
||||
final Predicate predicate = tableGroupJoin.getPredicate();
|
||||
if ( predicate != null && !predicate.isEmpty() ) {
|
||||
if ( tableGroupJoin.isLateral() ) {
|
||||
renderTableGroup( tableGroupJoin.getJoinedGroup(), tableGroupJoinCollector );
|
||||
addAdditionalWherePredicate( predicate );
|
||||
if ( tableGroupJoin.getJoinedGroup().isLateral() ) {
|
||||
// We have to inject the lateral predicate into the sub-query
|
||||
final Predicate lateralPredicate = this.lateralPredicate;
|
||||
this.lateralPredicate = predicate;
|
||||
renderTableGroup( tableGroupJoin.getJoinedGroup(), null, tableGroupJoinCollector );
|
||||
this.lateralPredicate = lateralPredicate;
|
||||
}
|
||||
else {
|
||||
renderTableGroup( tableGroupJoin.getJoinedGroup(), predicate, tableGroupJoinCollector );
|
||||
}
|
||||
}
|
||||
else {
|
||||
renderTableGroup( tableGroupJoin.getJoinedGroup(), tableGroupJoinCollector );
|
||||
renderTableGroup( tableGroupJoin.getJoinedGroup(), null, tableGroupJoinCollector );
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean renderPrimaryTableReference(TableGroup tableGroup, LockMode lockMode) {
|
||||
final TableReference tableReference = tableGroup.getPrimaryTableReference();
|
||||
if ( tableReference instanceof NamedTableReference ) {
|
||||
return renderNamedTableReference( (NamedTableReference) tableReference, lockMode );
|
||||
}
|
||||
tableReference.accept( this );
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean renderNamedTableReference(NamedTableReference tableReference, LockMode lockMode) {
|
||||
final String tableExpression = tableReference.getTableExpression();
|
||||
|
@ -237,6 +252,11 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends Abstract
|
|||
|
||||
@Override
|
||||
public void visitQueryGroup(QueryGroup queryGroup) {
|
||||
final Predicate lateralPredicate = this.lateralPredicate;
|
||||
if ( lateralPredicate != null ) {
|
||||
this.lateralPredicate = null;
|
||||
addAdditionalWherePredicate( lateralPredicate );
|
||||
}
|
||||
if ( shouldEmulateFetchClause( queryGroup ) ) {
|
||||
emulateFetchOffsetWithWindowFunctions( queryGroup, !isRowsOnlyFetchClauseType( queryGroup ) );
|
||||
}
|
||||
|
@ -255,6 +275,15 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends Abstract
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSelectClause(SelectClause selectClause) {
|
||||
if ( lateralPredicate != null ) {
|
||||
addAdditionalWherePredicate( lateralPredicate );
|
||||
lateralPredicate = null;
|
||||
}
|
||||
super.visitSelectClause( selectClause );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean needsRowsToSkip() {
|
||||
return getDialect().getVersion().isBefore( 9 );
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.dialect;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.ComparisonOperator;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
|
@ -19,9 +20,10 @@ import org.hibernate.sql.ast.tree.expression.Expression;
|
|||
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||
import org.hibernate.sql.ast.tree.expression.Summarization;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||
import org.hibernate.sql.ast.tree.predicate.Junction;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
import org.hibernate.sql.ast.tree.from.DerivedTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.NamedTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.select.QueryPart;
|
||||
import org.hibernate.sql.ast.tree.select.QuerySpec;
|
||||
import org.hibernate.sql.ast.tree.select.SelectClause;
|
||||
|
@ -118,40 +120,24 @@ public class SpannerSqlAstTranslator<T extends JdbcOperation> extends AbstractSq
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void renderTableGroupJoin(TableGroupJoin tableGroupJoin, List<TableGroupJoin> tableGroupJoinCollector) {
|
||||
appendSql( WHITESPACE );
|
||||
appendSql( tableGroupJoin.getJoinType().getText() );
|
||||
appendSql( "join " );
|
||||
|
||||
boolean correlated = false;
|
||||
final Predicate predicate;
|
||||
if ( tableGroupJoin.isLateral() ) {
|
||||
correlated = true;
|
||||
if ( tableGroupJoin.getPredicate() == null ) {
|
||||
predicate = new Junction( Junction.Nature.CONJUNCTION );
|
||||
}
|
||||
else {
|
||||
predicate = tableGroupJoin.getPredicate();
|
||||
}
|
||||
}
|
||||
else {
|
||||
predicate = tableGroupJoin.getPredicate();
|
||||
protected boolean renderPrimaryTableReference(TableGroup tableGroup, LockMode lockMode) {
|
||||
final TableReference tableReference = tableGroup.getPrimaryTableReference();
|
||||
if ( tableReference instanceof NamedTableReference ) {
|
||||
return renderNamedTableReference( (NamedTableReference) tableReference, lockMode );
|
||||
}
|
||||
final DerivedTableReference derivedTableReference = (DerivedTableReference) tableReference;
|
||||
final boolean correlated = derivedTableReference.isLateral();
|
||||
final boolean oldCorrelated = this.correlated;
|
||||
if ( correlated ) {
|
||||
this.correlated = true;
|
||||
appendSql( "unnest(array" );
|
||||
}
|
||||
if ( predicate != null && !predicate.isEmpty() ) {
|
||||
renderTableGroup( tableGroupJoin.getJoinedGroup(), predicate, tableGroupJoinCollector );
|
||||
}
|
||||
else {
|
||||
renderTableGroup( tableGroupJoin.getJoinedGroup(), tableGroupJoinCollector );
|
||||
}
|
||||
tableReference.accept( this );
|
||||
if ( correlated ) {
|
||||
this.correlated = oldCorrelated;
|
||||
appendSql( CLOSE_PARENTHESIS );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -23,13 +23,14 @@ import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
|
|||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
|
||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||
import org.hibernate.sql.ast.tree.expression.Summarization;
|
||||
import org.hibernate.sql.ast.tree.from.NamedTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||
import org.hibernate.sql.ast.tree.from.UnionTableReference;
|
||||
import org.hibernate.sql.ast.tree.predicate.Junction;
|
||||
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
import org.hibernate.sql.ast.tree.select.QueryGroup;
|
||||
import org.hibernate.sql.ast.tree.select.QueryPart;
|
||||
|
@ -124,13 +125,12 @@ public class SybaseASESqlAstTranslator<T extends JdbcOperation> extends Abstract
|
|||
}
|
||||
|
||||
final Predicate predicate;
|
||||
if ( tableGroupJoin.isLateral() ) {
|
||||
append( "lateral " );
|
||||
if ( tableGroupJoin.getPredicate() == null ) {
|
||||
predicate = new Junction( Junction.Nature.CONJUNCTION );
|
||||
if ( tableGroupJoin.getPredicate() == null ) {
|
||||
if ( tableGroupJoin.getJoinType() == SqlAstJoinType.CROSS ) {
|
||||
predicate = null;
|
||||
}
|
||||
else {
|
||||
predicate = tableGroupJoin.getPredicate();
|
||||
predicate = new BooleanExpressionPredicate( new QueryLiteral<>( true, getBooleanType() ) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -140,7 +140,7 @@ public class SybaseASESqlAstTranslator<T extends JdbcOperation> extends Abstract
|
|||
renderTableGroup( tableGroupJoin.getJoinedGroup(), predicate, tableGroupJoinCollector );
|
||||
}
|
||||
else {
|
||||
renderTableGroup( tableGroupJoin.getJoinedGroup(), tableGroupJoinCollector );
|
||||
renderTableGroup( tableGroupJoin.getJoinedGroup(), null, tableGroupJoinCollector );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,11 +229,16 @@ public class SybaseASESqlAstTranslator<T extends JdbcOperation> extends Abstract
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsDistinctFromPredicate() {
|
||||
return getDialect().getVersion().isSameOrAfter( 16, 3 );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
|
||||
// I think intersect is only supported in 16.0 SP3
|
||||
if ( getDialect().isAnsiNullOn() ) {
|
||||
if ( getDialect().getVersion().isSameOrAfter( 16, 3 ) ) {
|
||||
if ( supportsDistinctFromPredicate() ) {
|
||||
renderComparisonEmulateIntersect( lhs, operator, rhs );
|
||||
}
|
||||
else {
|
||||
|
@ -282,7 +287,7 @@ public class SybaseASESqlAstTranslator<T extends JdbcOperation> extends Abstract
|
|||
}
|
||||
}
|
||||
else {
|
||||
if ( getDialect().getVersion().isSameOrAfter( 16, 3 ) ) {
|
||||
if ( supportsDistinctFromPredicate() ) {
|
||||
renderComparisonEmulateIntersect( lhs, operator, rhs );
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -28,6 +28,8 @@ import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
|
|||
*/
|
||||
public class TiDBDialect extends MySQLDialect {
|
||||
|
||||
private static final DatabaseVersion VERSION57 = DatabaseVersion.make( 5, 7 );
|
||||
|
||||
public TiDBDialect() {
|
||||
this( DatabaseVersion.make(5, 4) );
|
||||
}
|
||||
|
@ -45,7 +47,7 @@ public class TiDBDialect extends MySQLDialect {
|
|||
@Override
|
||||
public DatabaseVersion getMySQLVersion() {
|
||||
// For simplicity’s sake, configure MySQL 5.7 compatibility
|
||||
return DatabaseVersion.make( 5, 7 );
|
||||
return VERSION57;
|
||||
}
|
||||
|
||||
private void registerKeywords() {
|
||||
|
|
|
@ -6,15 +6,13 @@
|
|||
*/
|
||||
package org.hibernate.query.results;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||
import org.hibernate.sql.ast.tree.from.AbstractTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
|
||||
|
||||
|
@ -23,97 +21,26 @@ import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class TableGroupImpl implements TableGroup {
|
||||
private final NavigablePath navigablePath;
|
||||
private final String alias;
|
||||
public class TableGroupImpl extends AbstractTableGroup {
|
||||
|
||||
private final TableReference primaryTableReference;
|
||||
private List<TableGroupJoin> tableGroupJoins;
|
||||
|
||||
private final ModelPartContainer container;
|
||||
private final String sourceAlias;
|
||||
|
||||
public TableGroupImpl(
|
||||
NavigablePath navigablePath,
|
||||
String alias,
|
||||
TableReference primaryTableReference,
|
||||
ModelPartContainer container,
|
||||
String sourceAlias) {
|
||||
this.navigablePath = navigablePath;
|
||||
this.alias = alias;
|
||||
ModelPartContainer container) {
|
||||
super( false, navigablePath, container, alias, null, null );
|
||||
this.primaryTableReference = primaryTableReference;
|
||||
this.container = container;
|
||||
this.sourceAlias = sourceAlias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigablePath getNavigablePath() {
|
||||
return navigablePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPartContainer getModelPart() {
|
||||
return container;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPartContainer getExpressionType() {
|
||||
return getModelPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAlias() {
|
||||
return sourceAlias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableGroupJoin> getTableGroupJoins() {
|
||||
return tableGroupJoins == null ? Collections.emptyList() : Collections.unmodifiableList( tableGroupJoins );
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableGroupJoin> getNestedTableGroupJoins() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseInnerJoins() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTableGroupJoin(TableGroupJoin join) {
|
||||
if ( tableGroupJoins == null ) {
|
||||
tableGroupJoins = new ArrayList<>();
|
||||
}
|
||||
assert !tableGroupJoins.contains( join );
|
||||
tableGroupJoins.add( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
addTableGroupJoin( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
if ( tableGroupJoins != null ) {
|
||||
tableGroupJoins.forEach( consumer );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
return getSourceAlias();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAffectedTableNames(Consumer<String> nameCollector) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -127,20 +54,7 @@ public class TableGroupImpl implements TableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
final TableReference tableReference = getTableReference( navigablePath, tableExpression, allowFkOptimization, true );
|
||||
if ( tableReference == null ) {
|
||||
throw new IllegalStateException( "Could not resolve binding for table `" + tableExpression + "`" );
|
||||
}
|
||||
|
||||
return tableReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(
|
||||
public TableReference getTableReferenceInternal(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
|
@ -148,15 +62,7 @@ public class TableGroupImpl implements TableGroup {
|
|||
if ( primaryTableReference.getTableReference( navigablePath , tableExpression, allowFkOptimization, resolve ) != null ) {
|
||||
return primaryTableReference;
|
||||
}
|
||||
|
||||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||
final TableReference primaryTableReference = tableGroupJoin.getJoinedGroup().getPrimaryTableReference();
|
||||
if ( primaryTableReference.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve ) != null ) {
|
||||
return primaryTableReference;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return super.getTableReferenceInternal( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -166,7 +166,7 @@ public class DynamicResultBuilderEntityStandard
|
|||
if ( lockMode != null ) {
|
||||
domainResultCreationState.getSqlAstCreationState().registerLockMode( tableAlias, lockMode );
|
||||
}
|
||||
return new TableGroupImpl( navigablePath, tableAlias, tableReference, entityMapping, tableAlias );
|
||||
return new TableGroupImpl( navigablePath, tableAlias, tableReference, entityMapping );
|
||||
}
|
||||
);
|
||||
final TableReference tableReference = tableGroup.getPrimaryTableReference();
|
||||
|
|
|
@ -471,7 +471,6 @@ public class CteInsertHandler implements InsertHandler {
|
|||
false,
|
||||
factory
|
||||
),
|
||||
null,
|
||||
null
|
||||
);
|
||||
final TableGroup rowsWithSequenceTableGroup = new CteTableGroup(
|
||||
|
@ -868,7 +867,6 @@ public class CteInsertHandler implements InsertHandler {
|
|||
false,
|
||||
factory
|
||||
),
|
||||
null,
|
||||
null
|
||||
);
|
||||
final TableGroup rootInsertCteTableGroup = new CteTableGroup(
|
||||
|
|
|
@ -273,8 +273,7 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
updatingTableGroup.getNavigablePath(),
|
||||
null,
|
||||
temporaryTableReference,
|
||||
entityDescriptor,
|
||||
null
|
||||
entityDescriptor
|
||||
);
|
||||
querySpec.getFromClause().addRoot( temporaryTableGroup );
|
||||
final InsertStatement insertStatement = new InsertStatement( dmlTableReference );
|
||||
|
@ -607,8 +606,7 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
false,
|
||||
sessionFactory
|
||||
),
|
||||
entityDescriptor,
|
||||
null
|
||||
entityDescriptor
|
||||
);
|
||||
querySpec.getFromClause().addRoot( temporaryTableGroup );
|
||||
final InsertStatement insertStatement = new InsertStatement( dmlTargetTableReference );
|
||||
|
|
|
@ -92,6 +92,8 @@ import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
|||
import org.hibernate.metamodel.model.domain.internal.CompositeSqmPathSource;
|
||||
import org.hibernate.metamodel.model.domain.internal.DiscriminatorSqmPath;
|
||||
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||
import org.hibernate.query.FetchClauseType;
|
||||
import org.hibernate.query.SortOrder;
|
||||
import org.hibernate.query.criteria.JpaPath;
|
||||
import org.hibernate.query.internal.QueryHelper;
|
||||
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
|
||||
|
@ -108,6 +110,8 @@ import org.hibernate.sql.ast.tree.expression.SelfRenderingSqlFragmentExpression;
|
|||
import org.hibernate.sql.ast.tree.from.CorrelatedPluralTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.NamedTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.PluralTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.QueryPartTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.QueryPartTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.exec.internal.VersionTypeSeedParameterSpecification;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
|
@ -3221,22 +3225,22 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
|
||||
@Override
|
||||
public Expression visitMaxElementPath(SqmMaxElementPath<?> path) {
|
||||
return createCorrelatedAggregateSubQuery( path, false, true );
|
||||
return createMinOrMaxIndexOrElement( path, false, true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression visitMinElementPath(SqmMinElementPath<?> path) {
|
||||
return createCorrelatedAggregateSubQuery( path, false, false );
|
||||
return createMinOrMaxIndexOrElement( path, false, false );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression visitMaxIndexPath(SqmMaxIndexPath<?> path) {
|
||||
return createCorrelatedAggregateSubQuery( path, true, true );
|
||||
return createMinOrMaxIndexOrElement( path, true, true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression visitMinIndexPath(SqmMinIndexPath<?> path) {
|
||||
return createCorrelatedAggregateSubQuery( path, true, false );
|
||||
return createMinOrMaxIndexOrElement( path, true, false );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -3388,6 +3392,19 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
};
|
||||
}
|
||||
|
||||
protected Expression createMinOrMaxIndexOrElement(
|
||||
AbstractSqmSpecificPluralPartPath<?> pluralPartPath,
|
||||
boolean index,
|
||||
boolean max) {
|
||||
// Try to create a lateral sub-query join if possible which allows the re-use of the expression
|
||||
if ( creationContext.getSessionFactory().getJdbcServices().getDialect().supportsLateral() ) {
|
||||
return createLateralJoinExpression( pluralPartPath, index, max );
|
||||
}
|
||||
else {
|
||||
return createCorrelatedAggregateSubQuery( pluralPartPath, index, max );
|
||||
}
|
||||
}
|
||||
|
||||
protected Expression createCorrelatedAggregateSubQuery(
|
||||
AbstractSqmSpecificPluralPartPath<?> pluralPartPath,
|
||||
boolean index,
|
||||
|
@ -3497,6 +3514,219 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
return subQuerySpec;
|
||||
}
|
||||
|
||||
protected Expression createLateralJoinExpression(
|
||||
AbstractSqmSpecificPluralPartPath<?> pluralPartPath,
|
||||
boolean index,
|
||||
boolean max) {
|
||||
prepareReusablePath( pluralPartPath.getLhs(), () -> null );
|
||||
|
||||
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) determineValueMapping(
|
||||
pluralPartPath.getPluralDomainPath() );
|
||||
final FromClauseAccess parentFromClauseAccess = getFromClauseAccess();
|
||||
final TableGroup parentTableGroup = parentFromClauseAccess.findTableGroup(
|
||||
pluralPartPath.getNavigablePath().getParent()
|
||||
);
|
||||
final CollectionPart collectionPart = index
|
||||
? pluralAttributeMapping.getIndexDescriptor()
|
||||
: pluralAttributeMapping.getElementDescriptor();
|
||||
final ModelPart modelPart;
|
||||
if ( collectionPart instanceof EntityAssociationMapping ) {
|
||||
modelPart = ( (EntityAssociationMapping) collectionPart ).getKeyTargetMatchPart();
|
||||
}
|
||||
else {
|
||||
modelPart = collectionPart;
|
||||
}
|
||||
final int jdbcTypeCount = modelPart.getJdbcTypeCount();
|
||||
final String pathName = ( max ? "max" : "min" ) + ( index ? "_index" : "_element" );
|
||||
final String identifierVariable = parentTableGroup.getPrimaryTableReference().getIdentificationVariable()
|
||||
+ "_" + pathName;
|
||||
final NavigablePath queryPath = new NavigablePath( parentTableGroup.getNavigablePath(), pathName, identifierVariable );
|
||||
TableGroup lateralTableGroup = parentFromClauseAccess.findTableGroup( queryPath );
|
||||
if ( lateralTableGroup == null ) {
|
||||
final QuerySpec subQuerySpec = new QuerySpec( false );
|
||||
pushProcessingState(
|
||||
new SqlAstQueryPartProcessingStateImpl(
|
||||
subQuerySpec,
|
||||
getCurrentProcessingState(),
|
||||
this,
|
||||
currentClauseStack::getCurrent
|
||||
)
|
||||
);
|
||||
try {
|
||||
final TableGroup tableGroup = pluralAttributeMapping.createRootTableGroup(
|
||||
true,
|
||||
pluralPartPath.getNavigablePath(),
|
||||
null,
|
||||
() -> subQuerySpec::applyPredicate,
|
||||
this,
|
||||
creationContext
|
||||
);
|
||||
final FilterPredicate filterPredicate = FilterHelper.createFilterPredicate(
|
||||
getLoadQueryInfluencers(),
|
||||
(Joinable) pluralAttributeMapping.getCollectionDescriptor(),
|
||||
tableGroup
|
||||
);
|
||||
if ( filterPredicate != null ) {
|
||||
subQuerySpec.applyPredicate( filterPredicate );
|
||||
}
|
||||
|
||||
getFromClauseAccess().registerTableGroup( pluralPartPath.getNavigablePath(), tableGroup );
|
||||
registerPluralTableGroupParts( tableGroup );
|
||||
subQuerySpec.getFromClause().addRoot( tableGroup );
|
||||
|
||||
final List<String> columnNames = new ArrayList<>( jdbcTypeCount );
|
||||
final List<ColumnReference> resultColumnReferences = new ArrayList<>( jdbcTypeCount );
|
||||
final NavigablePath navigablePath = pluralPartPath.getNavigablePath();
|
||||
modelPart.forEachSelectable(
|
||||
(selectionIndex, selectionMapping) -> {
|
||||
final ColumnReference columnReference = new ColumnReference(
|
||||
tableGroup.resolveTableReference(
|
||||
navigablePath,
|
||||
selectionMapping.getContainingTableExpression()
|
||||
),
|
||||
selectionMapping,
|
||||
creationContext.getSessionFactory()
|
||||
);
|
||||
final String columnName;
|
||||
if ( selectionMapping.isFormula() ) {
|
||||
columnName = "col" + columnNames.size();
|
||||
}
|
||||
else {
|
||||
columnName = selectionMapping.getSelectionExpression();
|
||||
}
|
||||
columnNames.add( columnName );
|
||||
subQuerySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
selectionIndex - 1,
|
||||
selectionIndex,
|
||||
columnReference
|
||||
)
|
||||
);
|
||||
subQuerySpec.addSortSpecification(
|
||||
new SortSpecification(
|
||||
columnReference,
|
||||
null,
|
||||
max ? SortOrder.DESCENDING : SortOrder.ASCENDING
|
||||
)
|
||||
);
|
||||
resultColumnReferences.add(
|
||||
new ColumnReference(
|
||||
identifierVariable,
|
||||
columnName,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
selectionMapping.getJdbcMapping(),
|
||||
creationContext.getSessionFactory()
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
subQuerySpec.setFetchClauseExpression(
|
||||
new QueryLiteral<>( 1, basicType( Integer.class ) ),
|
||||
FetchClauseType.ROWS_ONLY
|
||||
);
|
||||
subQuerySpec.applyPredicate(
|
||||
pluralAttributeMapping.getKeyDescriptor().generateJoinPredicate(
|
||||
parentFromClauseAccess.findTableGroup(
|
||||
pluralPartPath.getPluralDomainPath().getNavigablePath().getParent()
|
||||
),
|
||||
tableGroup,
|
||||
SqlAstJoinType.INNER,
|
||||
getSqlExpressionResolver(),
|
||||
creationContext
|
||||
)
|
||||
);
|
||||
lateralTableGroup = new QueryPartTableGroup(
|
||||
queryPath,
|
||||
null,
|
||||
subQuerySpec,
|
||||
identifierVariable,
|
||||
columnNames,
|
||||
true,
|
||||
false,
|
||||
creationContext.getSessionFactory()
|
||||
);
|
||||
if ( currentlyProcessingJoin == null ) {
|
||||
parentTableGroup.addTableGroupJoin(
|
||||
new TableGroupJoin(
|
||||
lateralTableGroup.getNavigablePath(),
|
||||
SqlAstJoinType.LEFT,
|
||||
lateralTableGroup
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
// In case this is used in the ON condition, we must prepend this lateral join
|
||||
final TableGroup targetTableGroup;
|
||||
if ( currentlyProcessingJoin.getLhs() == null ) {
|
||||
targetTableGroup = parentFromClauseAccess.getTableGroup(
|
||||
currentlyProcessingJoin.findRoot().getNavigablePath()
|
||||
);
|
||||
}
|
||||
else {
|
||||
targetTableGroup = parentFromClauseAccess.getTableGroup(
|
||||
currentlyProcessingJoin.getLhs().getNavigablePath()
|
||||
);
|
||||
}
|
||||
// Many databases would support modelling this as nested table group join,
|
||||
// but at least SQL Server doesn't like that, saying that the correlated columns can't be "bound"
|
||||
// Since there is no dependency on the currentlyProcessingJoin, we can safely prepend this join
|
||||
targetTableGroup.prependTableGroupJoin(
|
||||
currentlyProcessingJoin.getNavigablePath(),
|
||||
new TableGroupJoin(
|
||||
lateralTableGroup.getNavigablePath(),
|
||||
SqlAstJoinType.LEFT,
|
||||
lateralTableGroup
|
||||
)
|
||||
);
|
||||
}
|
||||
parentFromClauseAccess.registerTableGroup( lateralTableGroup.getNavigablePath(), lateralTableGroup );
|
||||
if ( jdbcTypeCount == 1 ) {
|
||||
return resultColumnReferences.get( 0 );
|
||||
}
|
||||
else {
|
||||
return new SqlTuple( resultColumnReferences, modelPart );
|
||||
}
|
||||
}
|
||||
finally {
|
||||
popProcessingStateStack();
|
||||
}
|
||||
}
|
||||
final QueryPartTableReference tableReference = (QueryPartTableReference) lateralTableGroup.getPrimaryTableReference();
|
||||
if ( jdbcTypeCount == 1 ) {
|
||||
return new ColumnReference(
|
||||
identifierVariable,
|
||||
tableReference.getColumnNames().get( 0 ),
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
modelPart.getJdbcMappings().get( 0 ),
|
||||
creationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
else {
|
||||
final List<ColumnReference> resultColumnReferences = new ArrayList<>( jdbcTypeCount );
|
||||
modelPart.forEachSelectable(
|
||||
(selectionIndex, selectionMapping) -> {
|
||||
resultColumnReferences.add(
|
||||
new ColumnReference(
|
||||
identifierVariable,
|
||||
tableReference.getColumnNames().get( selectionIndex ),
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
selectionMapping.getJdbcMapping(),
|
||||
creationContext.getSessionFactory()
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
return new SqlTuple( resultColumnReferences, modelPart );
|
||||
}
|
||||
}
|
||||
|
||||
private Expression withTreatRestriction(Expression expression, SqmPath<?> path) {
|
||||
final SqmPath<?> lhs = path.getLhs();
|
||||
if ( lhs instanceof SqmTreatedPath<?, ?> ) {
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.hibernate.persister.entity.EntityPersister;
|
|||
import org.hibernate.persister.entity.Queryable;
|
||||
import org.hibernate.persister.internal.SqlFragmentPredicate;
|
||||
import org.hibernate.query.IllegalQueryOperationException;
|
||||
import org.hibernate.query.SetOperator;
|
||||
import org.hibernate.query.sqm.sql.internal.SqmPathInterpretation;
|
||||
import org.hibernate.sql.ast.tree.cte.CteMaterialization;
|
||||
import org.hibernate.sql.ast.tree.cte.CteSearchClauseKind;
|
||||
|
@ -114,9 +115,11 @@ import org.hibernate.sql.ast.tree.from.FromClause;
|
|||
import org.hibernate.sql.ast.tree.from.FunctionTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.LazyTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.NamedTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.QueryPartTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.QueryPartTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
|
||||
import org.hibernate.sql.ast.tree.from.ValuesTableReference;
|
||||
|
@ -194,6 +197,8 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
private final Set<String> affectedTableNames = new HashSet<>();
|
||||
private MutationStatement dmlStatement;
|
||||
private boolean needsSelectAliases;
|
||||
// Column aliases that need to be injected
|
||||
private List<String> columnAliases;
|
||||
private Predicate additionalWherePredicate;
|
||||
// We must reset the queryPartForRowNumbering fields to null if a query part is visited that does not
|
||||
// contribute to the row numbering i.e. if the query part is a sub-query in the where clause.
|
||||
|
@ -206,6 +211,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
private transient AbstractSqmSelfRenderingFunctionDescriptor castFunction;
|
||||
private transient LazySessionWrapperOptions lazySessionWrapperOptions;
|
||||
private transient BasicType<Integer> integerType;
|
||||
private transient BasicType<Boolean> booleanType;
|
||||
|
||||
private SqlAstNodeRenderingMode parameterRenderingMode = SqlAstNodeRenderingMode.DEFAULT;
|
||||
|
||||
|
@ -258,6 +264,15 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
return integerType;
|
||||
}
|
||||
|
||||
public BasicType<Boolean> getBooleanType() {
|
||||
if ( booleanType == null ) {
|
||||
booleanType = sessionFactory.getTypeConfiguration()
|
||||
.getBasicTypeRegistry()
|
||||
.resolve( StandardBasicTypes.BOOLEAN );
|
||||
}
|
||||
return booleanType;
|
||||
}
|
||||
|
||||
/**
|
||||
* A lazy session implementation that is needed for rendering literals.
|
||||
* Usually, only the {@link WrapperOptions} interface is needed,
|
||||
|
@ -1418,9 +1433,13 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
this.queryPartForRowNumberingClauseDepth = -1;
|
||||
this.needsSelectAliases = false;
|
||||
}
|
||||
final boolean needsParenthesis = !queryGroup.isRoot();
|
||||
if ( needsParenthesis ) {
|
||||
appendSql( OPEN_PARENTHESIS );
|
||||
}
|
||||
// If we are row numbering the current query group, this means that we can't render the
|
||||
// order by and offset fetch clause, so we must do row counting on the query group level
|
||||
if ( queryPartForRowNumbering == queryGroup ) {
|
||||
if ( queryPartForRowNumbering == queryGroup || additionalWherePredicate != null && !additionalWherePredicate.isEmpty() ) {
|
||||
this.needsSelectAliases = true;
|
||||
queryGroupAlias = "grp_" + queryGroupAliasCounter + '_';
|
||||
queryGroupAliasCounter++;
|
||||
|
@ -1470,6 +1489,12 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
if ( queryGroupAlias != null ) {
|
||||
appendSql( ") " );
|
||||
appendSql( queryGroupAlias );
|
||||
if ( additionalWherePredicate != null && !additionalWherePredicate.isEmpty() ) {
|
||||
visitWhereClause( additionalWherePredicate );
|
||||
}
|
||||
}
|
||||
if ( needsParenthesis ) {
|
||||
appendSql( CLOSE_PARENTHESIS );
|
||||
}
|
||||
}
|
||||
finally {
|
||||
|
@ -1504,7 +1529,8 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
if ( currentQueryPart instanceof QueryGroup ) {
|
||||
// We always need query wrapping if we are in a query group and this query spec has a fetch clause
|
||||
// because of order by precedence in SQL
|
||||
if ( needsParenthesis = querySpec.hasOffsetOrFetchClause() ) {
|
||||
needsParenthesis = querySpec.hasOffsetOrFetchClause();
|
||||
if ( needsParenthesis ) {
|
||||
// If the parent is a query group with a fetch clause,
|
||||
// or if the database does not support simple query grouping, we must use a select wrapper
|
||||
if ( !supportsSimpleQueryGrouping() || currentQueryPart.hasOffsetOrFetchClause() ) {
|
||||
|
@ -2849,7 +2875,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
if ( !needsParenthesis || queryPart.isRoot() ) {
|
||||
appendSql( CLOSE_PARENTHESIS );
|
||||
}
|
||||
appendSql( WHITESPACE);
|
||||
appendSql( WHITESPACE );
|
||||
appendSql( alias );
|
||||
appendSql( " where " );
|
||||
final Stack<Clause> clauseStack = getClauseStack();
|
||||
|
@ -2905,6 +2931,12 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
}
|
||||
// todo: not sure if databases handle order by row number or the original ordering better..
|
||||
if ( offsetExpression == null ) {
|
||||
final Predicate additionalWherePredicate = this.additionalWherePredicate;
|
||||
if ( additionalWherePredicate != null && !additionalWherePredicate.isEmpty() ) {
|
||||
this.additionalWherePredicate = null;
|
||||
appendSql( " and " );
|
||||
additionalWherePredicate.accept( this );
|
||||
}
|
||||
if ( queryPart.isRoot() ) {
|
||||
switch ( fetchClauseType ) {
|
||||
case PERCENT_ONLY:
|
||||
|
@ -2929,6 +2961,12 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
appendSql( alias );
|
||||
appendSql( ".rn>" );
|
||||
offsetExpression.accept( this );
|
||||
final Predicate additionalWherePredicate = this.additionalWherePredicate;
|
||||
if ( additionalWherePredicate != null && !additionalWherePredicate.isEmpty() ) {
|
||||
this.additionalWherePredicate = null;
|
||||
appendSql( " and " );
|
||||
additionalWherePredicate.accept( this );
|
||||
}
|
||||
if ( queryPart.isRoot() ) {
|
||||
appendSql( " order by " );
|
||||
appendSql( alias );
|
||||
|
@ -3010,6 +3048,46 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
}
|
||||
final SqlAstNodeRenderingMode original = parameterRenderingMode;
|
||||
if ( needsSelectAliases || referenceStrategy == SelectItemReferenceStrategy.ALIAS && hasSelectAliasInGroupByClause() ) {
|
||||
String separator = NO_SEPARATOR;
|
||||
if ( columnAliases == null ) {
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
final SqlSelection sqlSelection = sqlSelections.get( i );
|
||||
appendSql( separator );
|
||||
if ( selectItemsToInline != null && selectItemsToInline.get( i ) ) {
|
||||
parameterRenderingMode = SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS;
|
||||
}
|
||||
else {
|
||||
parameterRenderingMode = SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER;
|
||||
}
|
||||
visitSqlSelection( sqlSelection );
|
||||
parameterRenderingMode = original;
|
||||
appendSql( " c" );
|
||||
appendSql( i );
|
||||
separator = COMA_SEPARATOR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
final SqlSelection sqlSelection = sqlSelections.get( i );
|
||||
appendSql( separator );
|
||||
if ( selectItemsToInline != null && selectItemsToInline.get( i ) ) {
|
||||
parameterRenderingMode = SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS;
|
||||
}
|
||||
else {
|
||||
parameterRenderingMode = SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER;
|
||||
}
|
||||
visitSqlSelection( sqlSelection );
|
||||
parameterRenderingMode = original;
|
||||
appendSql( WHITESPACE );
|
||||
appendSql( columnAliases.get( i ) );
|
||||
separator = COMA_SEPARATOR;
|
||||
}
|
||||
}
|
||||
if ( queryPartForRowNumbering != null ) {
|
||||
renderRowNumberingSelectItems( selectClause, queryPartForRowNumbering );
|
||||
}
|
||||
}
|
||||
else if ( columnAliases == null ) {
|
||||
String separator = NO_SEPARATOR;
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
final SqlSelection sqlSelection = sqlSelections.get( i );
|
||||
|
@ -3022,13 +3100,8 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
}
|
||||
visitSqlSelection( sqlSelection );
|
||||
parameterRenderingMode = original;
|
||||
appendSql( " c" );
|
||||
appendSql( i );
|
||||
separator = COMA_SEPARATOR;
|
||||
}
|
||||
if ( queryPartForRowNumbering != null ) {
|
||||
renderRowNumberingSelectItems( selectClause, queryPartForRowNumbering );
|
||||
}
|
||||
}
|
||||
else {
|
||||
String separator = NO_SEPARATOR;
|
||||
|
@ -3042,6 +3115,8 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
parameterRenderingMode = SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER;
|
||||
}
|
||||
visitSqlSelection( sqlSelection );
|
||||
appendSql( WHITESPACE );
|
||||
appendSql( columnAliases.get( i ) );
|
||||
parameterRenderingMode = original;
|
||||
separator = COMA_SEPARATOR;
|
||||
}
|
||||
|
@ -3486,7 +3561,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
String separator = NO_SEPARATOR;
|
||||
for ( TableGroup root : fromClause.getRoots() ) {
|
||||
appendSql( separator );
|
||||
renderTableGroup( root, null );
|
||||
renderRootTableGroup( root, null );
|
||||
separator = COMA_SEPARATOR;
|
||||
}
|
||||
}
|
||||
|
@ -3497,9 +3572,12 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected void renderTableGroup(TableGroup tableGroup, List<TableGroupJoin> tableGroupJoinCollector) {
|
||||
protected void renderRootTableGroup(TableGroup tableGroup, List<TableGroupJoin> tableGroupJoinCollector) {
|
||||
final LockMode effectiveLockMode = getEffectiveLockMode( tableGroup.getSourceAlias() );
|
||||
final boolean usesLockHint = renderTableReference( tableGroup.getPrimaryTableReference(), effectiveLockMode );
|
||||
final boolean usesLockHint = renderPrimaryTableReference( tableGroup, effectiveLockMode );
|
||||
if ( tableGroup.isLateral() && !getDialect().supportsLateral() ) {
|
||||
addAdditionalWherePredicate( determineLateralEmulationPredicate( tableGroup ) );
|
||||
}
|
||||
|
||||
renderTableReferenceJoins( tableGroup );
|
||||
processNestedTableGroupJoins( tableGroup, tableGroupJoinCollector );
|
||||
|
@ -3537,7 +3615,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
}
|
||||
|
||||
final LockMode effectiveLockMode = getEffectiveLockMode( tableGroup.getSourceAlias() );
|
||||
final boolean usesLockHint = renderTableReference( tableGroup.getPrimaryTableReference(), effectiveLockMode );
|
||||
final boolean usesLockHint = renderPrimaryTableReference( tableGroup, effectiveLockMode );
|
||||
final List<TableGroupJoin> tableGroupJoins;
|
||||
|
||||
if ( realTableGroup ) {
|
||||
|
@ -3559,8 +3637,22 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
tableGroupJoins = null;
|
||||
}
|
||||
|
||||
appendSql( " on " );
|
||||
predicate.accept( this );
|
||||
if ( predicate != null ) {
|
||||
appendSql( " on " );
|
||||
predicate.accept( this );
|
||||
}
|
||||
if ( tableGroup.isLateral() && !getDialect().supportsLateral() ) {
|
||||
final Predicate lateralEmulationPredicate = determineLateralEmulationPredicate( tableGroup );
|
||||
if ( lateralEmulationPredicate != null ) {
|
||||
if ( predicate == null ) {
|
||||
appendSql( " on " );
|
||||
}
|
||||
else {
|
||||
appendSql( " and " );
|
||||
}
|
||||
lateralEmulationPredicate.accept( this );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !realTableGroup ) {
|
||||
renderTableReferenceJoins( tableGroup );
|
||||
|
@ -3619,10 +3711,30 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
return false;
|
||||
}
|
||||
|
||||
protected boolean renderTableReference(TableReference tableReference, LockMode lockMode) {
|
||||
protected boolean renderPrimaryTableReference(TableGroup tableGroup, LockMode lockMode) {
|
||||
final TableReference tableReference = tableGroup.getPrimaryTableReference();
|
||||
if ( tableReference instanceof NamedTableReference ) {
|
||||
return renderNamedTableReference( (NamedTableReference) tableReference, lockMode );
|
||||
}
|
||||
final DerivedTableReference derivedTableReference = (DerivedTableReference) tableReference;
|
||||
if ( derivedTableReference.isLateral() ) {
|
||||
if ( getDialect().supportsLateral() ) {
|
||||
appendSql( "lateral" );
|
||||
}
|
||||
else if ( tableReference instanceof QueryPartTableReference ) {
|
||||
final QueryPartTableReference queryPartTableReference = (QueryPartTableReference) tableReference;
|
||||
final QueryPart emulationQueryPart = stripToSelectClause( queryPartTableReference.getQueryPart() );
|
||||
final QueryPartTableReference emulationTableReference = new QueryPartTableReference(
|
||||
emulationQueryPart,
|
||||
tableReference.getIdentificationVariable(),
|
||||
queryPartTableReference.getColumnNames(),
|
||||
false,
|
||||
sessionFactory
|
||||
);
|
||||
emulationTableReference.accept( this );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
tableReference.accept( this );
|
||||
return false;
|
||||
}
|
||||
|
@ -3633,11 +3745,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
registerAffectedTable( tableReference );
|
||||
final Clause currentClause = clauseStack.getCurrent();
|
||||
if ( rendersTableReferenceAlias( currentClause ) ) {
|
||||
final String identificationVariable = tableReference.getIdentificationVariable();
|
||||
if ( identificationVariable != null ) {
|
||||
appendSql( WHITESPACE );
|
||||
appendSql( identificationVariable );
|
||||
}
|
||||
renderTableReferenceIdentificationVariable( tableReference );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -3662,6 +3770,48 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
renderDerivedTableReference( tableReference );
|
||||
}
|
||||
|
||||
protected void emulateQueryPartTableReferenceColumnAliasing(QueryPartTableReference tableReference) {
|
||||
final List<String> columnAliases = this.columnAliases;
|
||||
this.columnAliases = tableReference.getColumnNames();
|
||||
tableReference.getQueryPart().accept( this );
|
||||
this.columnAliases = columnAliases;
|
||||
renderTableReferenceIdentificationVariable( tableReference );
|
||||
}
|
||||
|
||||
protected void emulateValuesTableReferenceColumnAliasing(ValuesTableReference tableReference) {
|
||||
final List<Values> valuesList = tableReference.getValuesList();
|
||||
append( '(' );
|
||||
final Stack<Clause> clauseStack = getClauseStack();
|
||||
clauseStack.push( Clause.VALUES );
|
||||
try {
|
||||
// We render the first select statement with aliases
|
||||
clauseStack.push( Clause.SELECT );
|
||||
|
||||
try {
|
||||
appendSql( "select " );
|
||||
|
||||
renderCommaSeparatedSelectExpression(
|
||||
valuesList.get( 0 ).getExpressions(),
|
||||
tableReference.getColumnNames()
|
||||
);
|
||||
appendSql( getFromDualForSelectOnly() );
|
||||
}
|
||||
finally {
|
||||
clauseStack.pop();
|
||||
}
|
||||
// The others, without the aliases
|
||||
for ( int i = 1; i < valuesList.size(); i++ ) {
|
||||
appendSql( " union all " );
|
||||
renderExpressionsAsSubquery( valuesList.get( i ).getExpressions() );
|
||||
}
|
||||
}
|
||||
finally {
|
||||
clauseStack.pop();
|
||||
}
|
||||
append( ')' );
|
||||
renderTableReferenceIdentificationVariable( tableReference );
|
||||
}
|
||||
|
||||
protected void renderDerivedTableReference(DerivedTableReference tableReference) {
|
||||
final String identificationVariable = tableReference.getIdentificationVariable();
|
||||
if ( identificationVariable != null ) {
|
||||
|
@ -3678,6 +3828,14 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
}
|
||||
}
|
||||
|
||||
protected final void renderTableReferenceIdentificationVariable(TableReference tableReference) {
|
||||
final String identificationVariable = tableReference.getIdentificationVariable();
|
||||
if ( identificationVariable != null ) {
|
||||
append( WHITESPACE );
|
||||
append( tableReference.getIdentificationVariable() );
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean rendersTableReferenceAlias(Clause clause) {
|
||||
// todo (6.0) : For now we just skip the alias rendering in the delete and update clauses
|
||||
// We need some dialect support if we want to support joins in delete and update statements
|
||||
|
@ -3762,13 +3920,12 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
appendSql( "join " );
|
||||
|
||||
final Predicate predicate;
|
||||
if ( tableGroupJoin.isLateral() ) {
|
||||
append( "lateral " );
|
||||
if ( tableGroupJoin.getPredicate() == null ) {
|
||||
predicate = new Junction( Junction.Nature.CONJUNCTION );
|
||||
if ( tableGroupJoin.getPredicate() == null ) {
|
||||
if ( tableGroupJoin.getJoinType() == SqlAstJoinType.CROSS ) {
|
||||
predicate = null;
|
||||
}
|
||||
else {
|
||||
predicate = tableGroupJoin.getPredicate();
|
||||
predicate = new BooleanExpressionPredicate( new QueryLiteral<>( true, getBooleanType() ) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -3778,10 +3935,158 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
renderTableGroup( tableGroupJoin.getJoinedGroup(), predicate, tableGroupJoinCollector );
|
||||
}
|
||||
else {
|
||||
renderTableGroup( tableGroupJoin.getJoinedGroup(), tableGroupJoinCollector );
|
||||
renderTableGroup( tableGroupJoin.getJoinedGroup(), null, tableGroupJoinCollector );
|
||||
}
|
||||
}
|
||||
|
||||
protected Predicate determineLateralEmulationPredicate(TableGroup tableGroup) {
|
||||
if ( tableGroup.getPrimaryTableReference() instanceof QueryPartTableReference ) {
|
||||
final QueryPartTableReference tableReference = (QueryPartTableReference) tableGroup.getPrimaryTableReference();
|
||||
final List<String> columnNames = tableReference.getColumnNames();
|
||||
final List<ColumnReference> columnReferences = new ArrayList<>( columnNames.size() );
|
||||
final List<ColumnReference> subColumnReferences = new ArrayList<>( columnNames.size() );
|
||||
final QueryPart queryPart = tableReference.getQueryPart();
|
||||
for ( String columnName : columnNames ) {
|
||||
columnReferences.add(
|
||||
new ColumnReference(
|
||||
tableReference,
|
||||
columnName,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
sessionFactory
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// The following optimization only makes sense if the necessary features are supported natively
|
||||
if ( ( columnReferences.size() == 1 || supportsRowValueConstructorSyntax() )
|
||||
&& supportsDistinctFromPredicate() ) {
|
||||
// Special case for limit 1 sub-queries to avoid double nested sub-query
|
||||
// ... x(c) on x.c is not distinct from (... fetch first 1 rows only)
|
||||
if ( queryPart.getFetchClauseType() == FetchClauseType.ROWS_ONLY
|
||||
&& queryPart.getFetchClauseExpression() instanceof QueryLiteral<?>
|
||||
&& Integer.valueOf( 1 )
|
||||
.equals( ( (QueryLiteral<?>) queryPart.getFetchClauseExpression() ).getLiteralValue() ) ) {
|
||||
return new ComparisonPredicate(
|
||||
new SqlTuple( columnReferences, tableGroup.getModelPart() ),
|
||||
ComparisonOperator.NOT_DISTINCT_FROM,
|
||||
queryPart
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Render with exists intersect sub-query if possible as that is shorter and more efficient
|
||||
// ... x(c) on exists(select x.c intersect ...)
|
||||
if ( supportsIntersect() ) {
|
||||
final QuerySpec lhsReferencesQuery = new QuerySpec( false );
|
||||
for ( ColumnReference columnReference : columnReferences ) {
|
||||
lhsReferencesQuery.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
1,
|
||||
0,
|
||||
columnReference
|
||||
)
|
||||
);
|
||||
}
|
||||
final List<QueryPart> queryParts = new ArrayList<>( 2 );
|
||||
queryParts.add( lhsReferencesQuery );
|
||||
queryParts.add( queryPart );
|
||||
return new ExistsPredicate(
|
||||
new QueryGroup( false, SetOperator.INTERSECT, queryParts ),
|
||||
false,
|
||||
getBooleanType()
|
||||
);
|
||||
}
|
||||
|
||||
// Double nested sub-query rendering if nothing else works
|
||||
// We try to avoid this as much as possible as it is not very efficient and some DBs don't like it
|
||||
// when a correlation happens in a sub-query that is not a direct child
|
||||
// ... x(c) on exists(select 1 from (...) synth_(c) where x.c = synth_.c)
|
||||
final QueryPartTableGroup subTableGroup = new QueryPartTableGroup(
|
||||
tableGroup.getNavigablePath(),
|
||||
(TableGroupProducer) tableGroup.getModelPart(),
|
||||
queryPart,
|
||||
"synth_",
|
||||
columnNames,
|
||||
false,
|
||||
true,
|
||||
sessionFactory
|
||||
);
|
||||
for ( String columnName : columnNames ) {
|
||||
subColumnReferences.add(
|
||||
new ColumnReference(
|
||||
subTableGroup.getPrimaryTableReference(),
|
||||
columnName,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
sessionFactory
|
||||
)
|
||||
);
|
||||
}
|
||||
final QuerySpec existsQuery = new QuerySpec( false, 1 );
|
||||
existsQuery.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
1,
|
||||
0,
|
||||
new QueryLiteral<>( 1, getIntegerType() )
|
||||
)
|
||||
);
|
||||
existsQuery.getFromClause().addRoot( subTableGroup );
|
||||
existsQuery.applyPredicate(
|
||||
new ComparisonPredicate(
|
||||
new SqlTuple( columnReferences, tableGroup.getModelPart() ),
|
||||
ComparisonOperator.NOT_DISTINCT_FROM,
|
||||
new SqlTuple( subColumnReferences, tableGroup.getModelPart() )
|
||||
)
|
||||
);
|
||||
|
||||
return new ExistsPredicate( existsQuery, false, getBooleanType() );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private QueryPart stripToSelectClause(QueryPart queryPart) {
|
||||
if ( queryPart instanceof QueryGroup ) {
|
||||
return stripToSelectClause( (QueryGroup) queryPart );
|
||||
}
|
||||
else {
|
||||
return stripToSelectClause( (QuerySpec) queryPart );
|
||||
}
|
||||
}
|
||||
|
||||
private QueryGroup stripToSelectClause(QueryGroup queryGroup) {
|
||||
final List<QueryPart> parts = new ArrayList<>( queryGroup.getQueryParts().size() );
|
||||
for ( QueryPart queryPart : queryGroup.getQueryParts() ) {
|
||||
parts.add( stripToSelectClause( queryPart ) );
|
||||
}
|
||||
|
||||
return new QueryGroup( queryGroup.isRoot(), queryGroup.getSetOperator(), parts );
|
||||
}
|
||||
|
||||
private QuerySpec stripToSelectClause(QuerySpec querySpec) {
|
||||
if ( querySpec.getGroupByClauseExpressions() != null && !querySpec.getGroupByClauseExpressions().isEmpty() ) {
|
||||
throw new UnsupportedOperationException( "Can't emulate lateral join for query spec with group by clause" );
|
||||
}
|
||||
if ( querySpec.getHavingClauseRestrictions() != null && !querySpec.getHavingClauseRestrictions().isEmpty() ) {
|
||||
throw new UnsupportedOperationException( "Can't emulate lateral join for query spec with having clause" );
|
||||
}
|
||||
final QuerySpec newQuerySpec = new QuerySpec( querySpec.isRoot(), querySpec.getFromClause().getRoots().size() );
|
||||
for ( TableGroup root : querySpec.getFromClause().getRoots() ) {
|
||||
newQuerySpec.getFromClause().addRoot( root );
|
||||
}
|
||||
for ( SqlSelection selection : querySpec.getSelectClause().getSqlSelections() ) {
|
||||
if ( AggregateFunctionChecker.hasAggregateFunctions( selection.getExpression() ) ) {
|
||||
throw new UnsupportedOperationException( "Can't emulate lateral join for query spec with aggregate function" );
|
||||
}
|
||||
newQuerySpec.getSelectClause().addSqlSelection( selection );
|
||||
}
|
||||
return newQuerySpec;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroup(TableGroup tableGroup) {
|
||||
// TableGroup and TableGroup handling should be performed as part of `#visitFromClause`...
|
||||
|
@ -4555,7 +4860,8 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
SubQueryRelationalRestrictionEmulationRenderer<X> renderer,
|
||||
ComparisonOperator tupleComparisonOperator) {
|
||||
final QuerySpec subQuery;
|
||||
if ( queryPart instanceof QuerySpec && queryPart.getFetchClauseExpression() == null && queryPart.getOffsetClauseExpression() == null ) {
|
||||
if ( queryPart instanceof QuerySpec && queryPart.getFetchClauseExpression() == null
|
||||
&& queryPart.getOffsetClauseExpression() == null ) {
|
||||
subQuery = (QuerySpec) queryPart;
|
||||
// We can only emulate the tuple sub query predicate as exists predicate when there are no limit/offsets
|
||||
if ( negated ) {
|
||||
|
@ -4573,8 +4879,8 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
appendSql( "exists (select 1" );
|
||||
visitFromClause( subQuery.getFromClause() );
|
||||
|
||||
if ( !subQuery.getGroupByClauseExpressions()
|
||||
.isEmpty() || subQuery.getHavingClauseRestrictions() != null ) {
|
||||
if ( !subQuery.getGroupByClauseExpressions().isEmpty()
|
||||
|| subQuery.getHavingClauseRestrictions() != null ) {
|
||||
// If we have a group by or having clause, we have to move the tuple comparison emulation to the HAVING clause
|
||||
visitWhereClause( subQuery.getWhereClauseRestrictions() );
|
||||
visitGroupByClause( subQuery, SelectItemReferenceStrategy.EXPRESSION );
|
||||
|
@ -5014,6 +5320,18 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this SQL dialect known to support some kind of distinct from predicate.
|
||||
* <p/>
|
||||
* Basically, does it support syntax like
|
||||
* "... where FIRST_NAME IS DISTINCT FROM LAST_NAME"
|
||||
*
|
||||
* @return True if this SQL dialect is known to support some kind of distinct from predicate; false otherwise
|
||||
*/
|
||||
protected boolean supportsDistinctFromPredicate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this dialect known to support what ANSI-SQL terms "row value
|
||||
* constructor" syntax; sometimes called tuple syntax.
|
||||
|
|
|
@ -65,6 +65,16 @@ public class AggregateFunctionChecker extends AbstractSqlAstWalker {
|
|||
|
||||
private static class AggregateFunctionException extends RuntimeException {}
|
||||
|
||||
public static boolean hasAggregateFunctions(Expression expression) {
|
||||
try {
|
||||
expression.accept( INSTANCE );
|
||||
return false;
|
||||
}
|
||||
catch (AggregateFunctionException ex) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasAggregateFunctions(QuerySpec querySpec) {
|
||||
try {
|
||||
querySpec.getSelectClause().accept( INSTANCE );
|
||||
|
|
|
@ -10,12 +10,10 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.tree.from.AbstractTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.NamedTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
|
||||
|
||||
|
@ -25,92 +23,29 @@ import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class CteTableGroup implements TableGroup {
|
||||
private final NavigablePath navigablePath;
|
||||
public class CteTableGroup extends AbstractTableGroup {
|
||||
private final NamedTableReference cteTableReference;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public CteTableGroup(NamedTableReference cteTableReference) {
|
||||
this.navigablePath = new NavigablePath( cteTableReference.getTableExpression() );
|
||||
this( false, cteTableReference );
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public CteTableGroup(boolean canUseInnerJoins, NamedTableReference cteTableReference) {
|
||||
super(
|
||||
canUseInnerJoins,
|
||||
new NavigablePath( cteTableReference.getTableExpression() ),
|
||||
null,
|
||||
cteTableReference.getIdentificationVariable(),
|
||||
null,
|
||||
null
|
||||
);
|
||||
this.cteTableReference = cteTableReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigablePath getNavigablePath() {
|
||||
return navigablePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAlias() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPartContainer getModelPart() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart getExpressionType() {
|
||||
return getModelPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableGroupJoin> getTableGroupJoins() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableGroupJoin> getNestedTableGroupJoins() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseInnerJoins() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
if ( cteTableReference.getTableExpression().equals( tableExpression ) ) {
|
||||
return cteTableReference;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
return cteTableReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupAlias() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTableGroupJoin(TableGroupJoin join) {
|
||||
throw new UnsupportedOperationException( );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
throw new UnsupportedOperationException( );
|
||||
return cteTableReference.getIdentificationVariable();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,10 +9,12 @@ package org.hibernate.sql.ast.tree.from;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.spi.SqlAliasBase;
|
||||
|
||||
|
@ -22,7 +24,7 @@ import org.hibernate.sql.ast.spi.SqlAliasBase;
|
|||
public abstract class AbstractTableGroup extends AbstractColumnReferenceQualifier implements TableGroup {
|
||||
private final boolean canUseInnerJoins;
|
||||
private final NavigablePath navigablePath;
|
||||
private final TableGroupProducer producer;
|
||||
private final ModelPartContainer modelPartContainer;
|
||||
private final String sourceAlias;
|
||||
private final SqlAliasBase sqlAliasBase;
|
||||
|
||||
|
@ -35,14 +37,14 @@ public abstract class AbstractTableGroup extends AbstractColumnReferenceQualifie
|
|||
public AbstractTableGroup(
|
||||
boolean canUseInnerJoins,
|
||||
NavigablePath navigablePath,
|
||||
TableGroupProducer producer,
|
||||
ModelPartContainer modelPartContainer,
|
||||
String sourceAlias,
|
||||
SqlAliasBase sqlAliasBase,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
super();
|
||||
this.canUseInnerJoins = canUseInnerJoins;
|
||||
this.navigablePath = navigablePath;
|
||||
this.producer = producer;
|
||||
this.modelPartContainer = modelPartContainer;
|
||||
this.sourceAlias = sourceAlias;
|
||||
this.sqlAliasBase = sqlAliasBase;
|
||||
this.sessionFactory = sessionFactory;
|
||||
|
@ -59,12 +61,12 @@ public abstract class AbstractTableGroup extends AbstractColumnReferenceQualifie
|
|||
|
||||
@Override
|
||||
public String getGroupAlias() {
|
||||
return sqlAliasBase.getAliasStem();
|
||||
return sqlAliasBase == null ? null : sqlAliasBase.getAliasStem();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableGroupProducer getModelPart() {
|
||||
return producer;
|
||||
public ModelPartContainer getModelPart() {
|
||||
return modelPartContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,6 +113,29 @@ public abstract class AbstractTableGroup extends AbstractColumnReferenceQualifie
|
|||
tableGroupJoins.add( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prependTableGroupJoin(NavigablePath navigablePath, TableGroupJoin join) {
|
||||
int i = 0;
|
||||
if ( tableGroupJoins != null ) {
|
||||
for ( ; i < tableGroupJoins.size(); i++ ) {
|
||||
if ( tableGroupJoins.get( i ).getNavigablePath() == navigablePath ) {
|
||||
tableGroupJoins.add( i, join );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
i = 0;
|
||||
if ( nestedTableGroupJoins != null ) {
|
||||
for ( ; i < nestedTableGroupJoins.size(); i++ ) {
|
||||
if ( nestedTableGroupJoins.get( i ).getNavigablePath() == navigablePath ) {
|
||||
nestedTableGroupJoins.add( i, join );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new NoSuchElementException("Table group for navigable path not found: " + navigablePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
if ( nestedTableGroupJoins == null ) {
|
||||
|
|
|
@ -56,6 +56,11 @@ public class CorrelatedTableGroup extends AbstractTableGroup {
|
|||
super.addTableGroupJoin( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prependTableGroupJoin(NavigablePath navigablePath, TableGroupJoin join) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
assert !getTableGroupJoins().contains( join );
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* 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.from;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public abstract class DelegatingTableGroup implements TableGroup {
|
||||
|
||||
protected abstract TableGroup getTableGroup();
|
||||
|
||||
@Override
|
||||
public ModelPart getExpressionType() {
|
||||
return getTableGroup().getExpressionType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression getSqlExpression() {
|
||||
return getTableGroup().getSqlExpression();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> target) {
|
||||
return getTableGroup().unwrap( target );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlSelection createSqlSelection(
|
||||
int jdbcPosition,
|
||||
int valuesArrayPosition,
|
||||
JavaType javaTypeDescriptor,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
return getTableGroup().createSqlSelection(
|
||||
jdbcPosition,
|
||||
valuesArrayPosition,
|
||||
javaTypeDescriptor,
|
||||
typeConfiguration
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
return resolveTableReference( navigablePath, tableExpression, true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(String tableExpression) {
|
||||
return resolveTableReference( null, tableExpression, true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
return getTableGroup().resolveTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
return getTableReference( navigablePath, tableExpression, true, false );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(String tableExpression) {
|
||||
return getTableReference( null, tableExpression, true, false );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization, boolean resolve) {
|
||||
return getTableGroup().getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigablePath getNavigablePath() {
|
||||
return getTableGroup().getNavigablePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupAlias() {
|
||||
return getTableGroup().getGroupAlias();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPartContainer getModelPart() {
|
||||
return getTableGroup().getModelPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAlias() {
|
||||
return getTableGroup().getSourceAlias();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableGroupJoin> getTableGroupJoins() {
|
||||
return getTableGroup().getTableGroupJoins();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableGroupJoin> getNestedTableGroupJoins() {
|
||||
return getTableGroup().getNestedTableGroupJoins();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseInnerJoins() {
|
||||
return getTableGroup().canUseInnerJoins();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLateral() {
|
||||
return getTableGroup().isLateral();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTableGroupJoin(TableGroupJoin join) {
|
||||
getTableGroup().addTableGroupJoin( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prependTableGroupJoin(NavigablePath navigablePath, TableGroupJoin join) {
|
||||
getTableGroup().prependTableGroupJoin( navigablePath, join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
getTableGroup().addNestedTableGroupJoin( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
getTableGroup().visitTableGroupJoins( consumer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
getTableGroup().visitNestedTableGroupJoins( consumer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAffectedTableNames(Consumer<String> nameCollector) {
|
||||
getTableGroup().applyAffectedTableNames( nameCollector );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getPrimaryTableReference() {
|
||||
return getTableGroup().getPrimaryTableReference();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableReferenceJoin> getTableReferenceJoins() {
|
||||
return getTableGroup().getTableReferenceJoins();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResult createDomainResult(
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return getTableGroup().createDomainResult( resultVariable, creationState );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applySqlSelections(DomainResultCreationState creationState) {
|
||||
getTableGroup().applySqlSelections( creationState );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(SqlAstWalker sqlTreeWalker) {
|
||||
getTableGroup().accept( sqlTreeWalker );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRealTableGroup() {
|
||||
return getTableGroup().isRealTableGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFetched() {
|
||||
return getTableGroup().isFetched();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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.from;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.tree.expression.FunctionExpression;
|
||||
|
||||
/**
|
||||
* A special table group for a table valued functions.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class FunctionTableGroup extends AbstractTableGroup {
|
||||
|
||||
private final FunctionTableReference functionTableReference;
|
||||
|
||||
public FunctionTableGroup(
|
||||
NavigablePath navigablePath,
|
||||
TableGroupProducer tableGroupProducer,
|
||||
FunctionExpression functionExpression,
|
||||
String sourceAlias,
|
||||
List<String> columnNames,
|
||||
boolean lateral,
|
||||
boolean canUseInnerJoins,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
super(
|
||||
canUseInnerJoins,
|
||||
navigablePath,
|
||||
tableGroupProducer,
|
||||
sourceAlias,
|
||||
null,
|
||||
sessionFactory
|
||||
);
|
||||
this.functionTableReference = new FunctionTableReference(
|
||||
functionExpression,
|
||||
sourceAlias,
|
||||
columnNames,
|
||||
lateral,
|
||||
sessionFactory
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLateral() {
|
||||
return getPrimaryTableReference().isLateral();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TableReference getTableReferenceInternal(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
if ( tableExpression == null ) {
|
||||
return getPrimaryTableReference();
|
||||
}
|
||||
for ( TableGroupJoin tableGroupJoin : getNestedTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
if ( groupTableReference != null ) {
|
||||
return groupTableReference;
|
||||
}
|
||||
}
|
||||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
if ( groupTableReference != null ) {
|
||||
return groupTableReference;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAffectedTableNames(Consumer<String> nameCollector) {
|
||||
functionTableReference.applyAffectedTableNames( nameCollector );
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionTableReference getPrimaryTableReference() {
|
||||
return functionTableReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableReferenceJoin> getTableReferenceJoins() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
}
|
|
@ -8,8 +8,8 @@ package org.hibernate.sql.ast.tree.from;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
@ -25,7 +25,7 @@ import org.hibernate.sql.ast.spi.SqlAliasBase;
|
|||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class LazyTableGroup extends AbstractColumnReferenceQualifier implements TableGroup {
|
||||
public class LazyTableGroup extends DelegatingTableGroup {
|
||||
|
||||
private final boolean canUseInnerJoins;
|
||||
private final NavigablePath navigablePath;
|
||||
|
@ -33,7 +33,6 @@ public class LazyTableGroup extends AbstractColumnReferenceQualifier implements
|
|||
private final TableGroupProducer producer;
|
||||
private final String sourceAlias;
|
||||
private final SqlAliasBase sqlAliasBase;
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
private final Supplier<TableGroup> tableGroupSupplier;
|
||||
private final TableGroup parentTableGroup;
|
||||
private final BiPredicate<NavigablePath, String> navigablePathChecker;
|
||||
|
@ -60,14 +59,13 @@ public class LazyTableGroup extends AbstractColumnReferenceQualifier implements
|
|||
this.tableGroupSupplier = tableGroupSupplier;
|
||||
this.navigablePathChecker = navigablePathChecker;
|
||||
this.parentTableGroup = parentTableGroup;
|
||||
this.sessionFactory = sessionFactory;
|
||||
|
||||
}
|
||||
|
||||
public TableGroup getUnderlyingTableGroup() {
|
||||
return tableGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableGroup getTableGroup() {
|
||||
if ( tableGroup != null ) {
|
||||
return tableGroup;
|
||||
|
@ -97,11 +95,6 @@ public class LazyTableGroup extends AbstractColumnReferenceQualifier implements
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getPrimaryTableReference() {
|
||||
return getTableGroup().getPrimaryTableReference();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableReferenceJoin> getTableReferenceJoins() {
|
||||
return tableGroup == null ? Collections.emptyList() : tableGroup.getTableReferenceJoins();
|
||||
|
@ -117,16 +110,6 @@ public class LazyTableGroup extends AbstractColumnReferenceQualifier implements
|
|||
return tableGroup == null ? Collections.emptyList() : tableGroup.getNestedTableGroupJoins();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTableGroupJoin(TableGroupJoin join) {
|
||||
getTableGroup().addTableGroupJoin( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
getTableGroup().addNestedTableGroupJoin( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
if ( tableGroup != null ) {
|
||||
|
@ -146,11 +129,6 @@ public class LazyTableGroup extends AbstractColumnReferenceQualifier implements
|
|||
return canUseInnerJoins;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLateral() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigablePath getNavigablePath() {
|
||||
return navigablePath;
|
||||
|
@ -176,11 +154,6 @@ public class LazyTableGroup extends AbstractColumnReferenceQualifier implements
|
|||
return sourceAlias;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SessionFactoryImplementor getSessionFactory() {
|
||||
return sessionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRealTableGroup() {
|
||||
return tableGroup != null && tableGroup.isRealTableGroup();
|
||||
|
@ -192,6 +165,39 @@ public class LazyTableGroup extends AbstractColumnReferenceQualifier implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isLateral() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
assert tableExpression != null;
|
||||
|
||||
final TableReference tableReference = getTableReferenceInternal(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
true
|
||||
);
|
||||
if ( tableReference == null ) {
|
||||
throw new IllegalStateException( "Could not resolve binding for table `" + tableExpression + "`" );
|
||||
}
|
||||
|
||||
return tableReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
return getTableReferenceInternal( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
}
|
||||
|
||||
protected TableReference getTableReferenceInternal(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
|
|
|
@ -17,7 +17,7 @@ import org.hibernate.query.NavigablePath;
|
|||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class MappedByTableGroup implements VirtualTableGroup {
|
||||
public class MappedByTableGroup extends DelegatingTableGroup implements VirtualTableGroup {
|
||||
|
||||
private final NavigablePath navigablePath;
|
||||
private final ModelPartContainer modelPart;
|
||||
|
@ -41,6 +41,11 @@ public class MappedByTableGroup implements VirtualTableGroup {
|
|||
this.navigablePathChecker = navigablePathChecker;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TableGroup getTableGroup() {
|
||||
return underlyingTableGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigablePath getNavigablePath() {
|
||||
return navigablePath;
|
||||
|
@ -67,9 +72,17 @@ public class MappedByTableGroup implements VirtualTableGroup {
|
|||
return modelPart;
|
||||
}
|
||||
|
||||
// Don't provide access to table group joins as this is table group is just a "named reference"
|
||||
// The underlying table group contains the joins and will render them
|
||||
|
||||
@Override
|
||||
public String getSourceAlias() {
|
||||
return underlyingTableGroup.getSourceAlias();
|
||||
public boolean isRealTableGroup() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLateral() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -82,26 +95,6 @@ public class MappedByTableGroup implements VirtualTableGroup {
|
|||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRealTableGroup() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseInnerJoins() {
|
||||
return underlyingTableGroup.canUseInnerJoins();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTableGroupJoin(TableGroupJoin join) {
|
||||
underlyingTableGroup.addTableGroupJoin( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
underlyingTableGroup.addNestedTableGroupJoin( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
// No-op
|
||||
|
@ -112,19 +105,9 @@ public class MappedByTableGroup implements VirtualTableGroup {
|
|||
// No-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAffectedTableNames(Consumer<String> nameCollector) {
|
||||
underlyingTableGroup.applyAffectedTableNames( nameCollector );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getPrimaryTableReference() {
|
||||
return underlyingTableGroup.getPrimaryTableReference();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableReferenceJoin> getTableReferenceJoins() {
|
||||
return underlyingTableGroup.getTableReferenceJoins();
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -108,6 +108,11 @@ public class MutatingTableReferenceGroupWrapper implements VirtualTableGroup {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prependTableGroupJoin(NavigablePath navigablePath, TableGroupJoin join) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -120,6 +120,13 @@ public class OneToManyTableGroup extends AbstractColumnReferenceQualifier implem
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prependTableGroupJoin(NavigablePath navigablePath, TableGroupJoin join) {
|
||||
if ( join.getJoinedGroup() != elementTableGroup ) {
|
||||
elementTableGroup.prependTableGroupJoin( navigablePath, join );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
if ( join.getJoinedGroup() != elementTableGroup ) {
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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.from;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.tree.select.QueryPart;
|
||||
|
||||
/**
|
||||
* A special table group for a sub-queries.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class QueryPartTableGroup extends AbstractTableGroup {
|
||||
|
||||
private final QueryPartTableReference queryPartTableReference;
|
||||
|
||||
public QueryPartTableGroup(
|
||||
NavigablePath navigablePath,
|
||||
TableGroupProducer tableGroupProducer,
|
||||
QueryPart queryPart,
|
||||
String sourceAlias,
|
||||
List<String> columnNames,
|
||||
boolean lateral,
|
||||
boolean canUseInnerJoins,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
super(
|
||||
canUseInnerJoins,
|
||||
navigablePath,
|
||||
tableGroupProducer,
|
||||
sourceAlias,
|
||||
null,
|
||||
sessionFactory
|
||||
);
|
||||
this.queryPartTableReference = new QueryPartTableReference(
|
||||
queryPart,
|
||||
sourceAlias,
|
||||
columnNames,
|
||||
lateral,
|
||||
sessionFactory
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLateral() {
|
||||
return getPrimaryTableReference().isLateral();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TableReference getTableReferenceInternal(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
if ( tableExpression == null ) {
|
||||
return getPrimaryTableReference();
|
||||
}
|
||||
for ( TableGroupJoin tableGroupJoin : getNestedTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
if ( groupTableReference != null ) {
|
||||
return groupTableReference;
|
||||
}
|
||||
}
|
||||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
if ( groupTableReference != null ) {
|
||||
return groupTableReference;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAffectedTableNames(Consumer<String> nameCollector) {
|
||||
queryPartTableReference.applyAffectedTableNames( nameCollector );
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryPartTableReference getPrimaryTableReference() {
|
||||
return queryPartTableReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableReferenceJoin> getTableReferenceJoins() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
}
|
|
@ -6,8 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.sql.ast.tree.from;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
@ -17,109 +15,47 @@ import org.hibernate.query.NavigablePath;
|
|||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class StandardVirtualTableGroup implements VirtualTableGroup {
|
||||
private final NavigablePath navigablePath;
|
||||
private final ModelPartContainer modelPart;
|
||||
public class StandardVirtualTableGroup extends AbstractTableGroup implements VirtualTableGroup {
|
||||
private final TableGroup underlyingTableGroup;
|
||||
private final boolean fetched;
|
||||
|
||||
private List<TableGroupJoin> tableGroupJoins;
|
||||
private List<TableGroupJoin> nestedTableGroupJoins;
|
||||
|
||||
public StandardVirtualTableGroup(
|
||||
NavigablePath navigablePath,
|
||||
ModelPartContainer modelPart,
|
||||
TableGroup underlyingTableGroup,
|
||||
boolean fetched) {
|
||||
this.navigablePath = navigablePath;
|
||||
this.modelPart = modelPart;
|
||||
super(
|
||||
underlyingTableGroup.canUseInnerJoins(),
|
||||
navigablePath,
|
||||
modelPart,
|
||||
underlyingTableGroup.getSourceAlias(),
|
||||
null,
|
||||
null
|
||||
);
|
||||
this.underlyingTableGroup = underlyingTableGroup;
|
||||
this.fetched = fetched;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigablePath getNavigablePath() {
|
||||
return navigablePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPartContainer getExpressionType() {
|
||||
return getModelPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupAlias() {
|
||||
// none, although we could also delegate to the underlyingTableGroup's group-alias
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFetched() {
|
||||
return fetched;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPartContainer getModelPart() {
|
||||
return modelPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAlias() {
|
||||
return underlyingTableGroup.getSourceAlias();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableGroupJoin> getTableGroupJoins() {
|
||||
return tableGroupJoins == null ? Collections.emptyList() : Collections.unmodifiableList( tableGroupJoins );
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableGroupJoin> getNestedTableGroupJoins() {
|
||||
return nestedTableGroupJoins == null ? Collections.emptyList() : Collections.unmodifiableList( nestedTableGroupJoins );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRealTableGroup() {
|
||||
return nestedTableGroupJoins != null && !nestedTableGroupJoins.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseInnerJoins() {
|
||||
return underlyingTableGroup.canUseInnerJoins();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTableGroupJoin(TableGroupJoin join) {
|
||||
if ( tableGroupJoins == null ) {
|
||||
tableGroupJoins = new ArrayList<>();
|
||||
}
|
||||
assert !tableGroupJoins.contains( join );
|
||||
tableGroupJoins.add( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
if ( nestedTableGroupJoins == null ) {
|
||||
nestedTableGroupJoins = new ArrayList<>();
|
||||
}
|
||||
assert !nestedTableGroupJoins.contains( join );
|
||||
nestedTableGroupJoins.add( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
if ( tableGroupJoins != null ) {
|
||||
tableGroupJoins.forEach( consumer );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
if ( nestedTableGroupJoins != null ) {
|
||||
nestedTableGroupJoins.forEach( consumer );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAffectedTableNames(Consumer<String> nameCollector) {
|
||||
underlyingTableGroup.applyAffectedTableNames( nameCollector );
|
||||
|
@ -136,25 +72,7 @@ public class StandardVirtualTableGroup implements VirtualTableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
final TableReference tableReference = getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
true
|
||||
);
|
||||
if ( tableReference == null ) {
|
||||
throw new IllegalStateException( "Could not resolve binding for table `" + tableExpression + "`" );
|
||||
}
|
||||
|
||||
return tableReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(
|
||||
public TableReference getTableReferenceInternal(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
|
@ -168,23 +86,7 @@ public class StandardVirtualTableGroup implements VirtualTableGroup {
|
|||
if ( tableReference != null ) {
|
||||
return tableReference;
|
||||
}
|
||||
for ( TableGroupJoin tableGroupJoin : getNestedTableGroupJoins() ) {
|
||||
final TableReference primaryTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
if ( primaryTableReference != null ) {
|
||||
return primaryTableReference;
|
||||
}
|
||||
}
|
||||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||
final TableReference primaryTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
if ( primaryTableReference != null ) {
|
||||
return primaryTableReference;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return super.getTableReferenceInternal( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -47,12 +47,16 @@ public interface TableGroup extends SqlAstNode, ColumnReferenceQualifier, SqmPat
|
|||
boolean canUseInnerJoins();
|
||||
|
||||
default boolean isLateral() {
|
||||
return getPrimaryTableReference() instanceof DerivedTableReference
|
||||
&& ( (DerivedTableReference) getPrimaryTableReference() ).isLateral();
|
||||
return false;
|
||||
}
|
||||
|
||||
void addTableGroupJoin(TableGroupJoin join);
|
||||
|
||||
/**
|
||||
* Adds the given table group join before a join as found via the given navigable path.
|
||||
*/
|
||||
void prependTableGroupJoin(NavigablePath navigablePath, TableGroupJoin join);
|
||||
|
||||
/**
|
||||
* A nested table group join is a join against a table group,
|
||||
* that is ensured to be joined against the primary table reference and table reference joins in isolation,
|
||||
|
@ -136,12 +140,6 @@ public interface TableGroup extends SqlAstNode, ColumnReferenceQualifier, SqmPat
|
|||
);
|
||||
}
|
||||
|
||||
default ColumnReference locateColumnReferenceByName(String name) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Cannot call #locateColumnReferenceByName on this type of TableGroup"
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void accept(SqlAstWalker sqlTreeWalker) {
|
||||
sqlTreeWalker.visitTableGroup( this );
|
||||
|
|
|
@ -19,14 +19,7 @@ import org.hibernate.query.NavigablePath;
|
|||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
public class UnionTableGroup implements VirtualTableGroup {
|
||||
private final boolean canUseInnerJoins;
|
||||
private final NavigablePath navigablePath;
|
||||
private List<TableGroupJoin> tableGroupJoins;
|
||||
private List<TableGroupJoin> nestedTableGroupJoins;
|
||||
|
||||
private final UnionSubclassEntityPersister modelPart;
|
||||
private final String sourceAlias;
|
||||
public class UnionTableGroup extends AbstractTableGroup implements VirtualTableGroup {
|
||||
private final UnionTableReference tableReference;
|
||||
|
||||
public UnionTableGroup(
|
||||
|
@ -35,88 +28,8 @@ public class UnionTableGroup implements VirtualTableGroup {
|
|||
UnionTableReference tableReference,
|
||||
UnionSubclassEntityPersister modelPart,
|
||||
String sourceAlias) {
|
||||
this.canUseInnerJoins = canUseInnerJoins;
|
||||
this.navigablePath = navigablePath;
|
||||
super( canUseInnerJoins, navigablePath, modelPart, sourceAlias, null, null );
|
||||
this.tableReference = tableReference;
|
||||
this.modelPart = modelPart;
|
||||
this.sourceAlias = sourceAlias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigablePath getNavigablePath() {
|
||||
return navigablePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart getExpressionType() {
|
||||
return getModelPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupAlias() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPartContainer getModelPart() {
|
||||
return modelPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAlias() {
|
||||
return sourceAlias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableGroupJoin> getTableGroupJoins() {
|
||||
return tableGroupJoins == null ? Collections.emptyList() : Collections.unmodifiableList( tableGroupJoins );
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableGroupJoin> getNestedTableGroupJoins() {
|
||||
return nestedTableGroupJoins == null ? Collections.emptyList() : Collections.unmodifiableList( nestedTableGroupJoins );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRealTableGroup() {
|
||||
return nestedTableGroupJoins != null && !nestedTableGroupJoins.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseInnerJoins() {
|
||||
return canUseInnerJoins;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTableGroupJoin(TableGroupJoin join) {
|
||||
if ( tableGroupJoins == null ) {
|
||||
tableGroupJoins = new ArrayList<>();
|
||||
}
|
||||
assert !tableGroupJoins.contains( join );
|
||||
tableGroupJoins.add( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
if ( nestedTableGroupJoins == null ) {
|
||||
nestedTableGroupJoins = new ArrayList<>();
|
||||
}
|
||||
assert !nestedTableGroupJoins.contains( join );
|
||||
nestedTableGroupJoins.add( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
if ( tableGroupJoins != null ) {
|
||||
tableGroupJoins.forEach( consumer );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
if ( nestedTableGroupJoins != null ) {
|
||||
nestedTableGroupJoins.forEach( consumer );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -134,40 +47,14 @@ public class UnionTableGroup implements VirtualTableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(
|
||||
public TableReference getTableReferenceInternal(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
return resolveTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
if ( tableReference.getTableReference( navigablePath, tableExpression, allowFkOptimization, true ) != null ) {
|
||||
if ( tableReference.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve ) != null ) {
|
||||
return tableReference;
|
||||
}
|
||||
if ( nestedTableGroupJoins != null ) {
|
||||
for ( TableGroupJoin tableGroupJoin : nestedTableGroupJoins ) {
|
||||
final TableReference tableReference = tableGroupJoin.getJoinedGroup()
|
||||
.resolveTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
if ( tableReference != null ) {
|
||||
return tableReference;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( tableGroupJoins != null ) {
|
||||
for ( TableGroupJoin tableGroupJoin : tableGroupJoins ) {
|
||||
final TableReference tableReference = tableGroupJoin.getJoinedGroup()
|
||||
.resolveTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
if ( tableReference != null ) {
|
||||
return tableReference;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return super.getTableReferenceInternal( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ public class ValuesTableGroup extends AbstractTableGroup {
|
|||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
if ( getModelPart().containsTableReference( tableExpression ) ) {
|
||||
if ( ( (TableGroupProducer) getModelPart() ).containsTableReference( tableExpression ) ) {
|
||||
return getPrimaryTableReference();
|
||||
}
|
||||
for ( TableGroupJoin tableGroupJoin : getNestedTableGroupJoins() ) {
|
||||
|
|
|
@ -16,6 +16,11 @@ import org.hibernate.sql.ast.tree.expression.Expression;
|
|||
public class BooleanExpressionPredicate extends AbstractPredicate {
|
||||
private final Expression expression;
|
||||
|
||||
public BooleanExpressionPredicate(Expression expression) {
|
||||
super( expression.getExpressionType(), false );
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public BooleanExpressionPredicate(Expression expression, boolean negated, JdbcMappingContainer expressionType) {
|
||||
super( expressionType, negated );
|
||||
this.expression = expression;
|
||||
|
|
|
@ -48,6 +48,9 @@ public class MapIndexFormulaTest {
|
|||
session.createQuery(
|
||||
"from Group g join g.users u where g.name = 'something' and maxindex(u) = 'nada'" )
|
||||
.list();
|
||||
session.createQuery(
|
||||
"from Group g join g.users u where g.name = 'something' and maxindex(u) = 'nada' and maxindex(u) = 'nada'" )
|
||||
.list();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,10 +8,7 @@
|
|||
package org.hibernate.envers.function;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.ordering.OrderByFragment;
|
||||
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
|
||||
|
@ -29,11 +26,10 @@ import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
|||
import org.hibernate.query.sqm.tree.SqmTypedNode;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
|
||||
import org.hibernate.sql.ast.spi.SqlAstQueryPartProcessingState;
|
||||
import org.hibernate.sql.ast.tree.from.DelegatingTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.NamedTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
|
||||
import org.hibernate.sql.ast.tree.select.QuerySpec;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
|
@ -110,7 +106,7 @@ public class OrderByFragmentFunction extends AbstractSqmFunctionDescriptor {
|
|||
};
|
||||
}
|
||||
|
||||
private static class AuditingTableGroup implements TableGroup {
|
||||
private static class AuditingTableGroup extends DelegatingTableGroup {
|
||||
|
||||
private final TableGroup delegate;
|
||||
private final String auditTableExpression;
|
||||
|
@ -123,8 +119,8 @@ public class OrderByFragmentFunction extends AbstractSqmFunctionDescriptor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ModelPart getExpressionType() {
|
||||
return delegate.getExpressionType();
|
||||
protected TableGroup getTableGroup() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -135,7 +131,7 @@ public class OrderByFragmentFunction extends AbstractSqmFunctionDescriptor {
|
|||
if ( tableExpression.equals( normalTableExpression ) ) {
|
||||
tableExpression = auditTableExpression;
|
||||
}
|
||||
return delegate.resolveTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
return super.resolveTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -147,77 +143,7 @@ public class OrderByFragmentFunction extends AbstractSqmFunctionDescriptor {
|
|||
if ( tableExpression.equals( normalTableExpression ) ) {
|
||||
tableExpression = auditTableExpression;
|
||||
}
|
||||
return delegate.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigablePath getNavigablePath() {
|
||||
return delegate.getNavigablePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupAlias() {
|
||||
return delegate.getGroupAlias();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPartContainer getModelPart() {
|
||||
return delegate.getModelPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAlias() {
|
||||
return delegate.getSourceAlias();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableGroupJoin> getTableGroupJoins() {
|
||||
return delegate.getTableGroupJoins();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableGroupJoin> getNestedTableGroupJoins() {
|
||||
return delegate.getNestedTableGroupJoins();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseInnerJoins() {
|
||||
return delegate.canUseInnerJoins();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTableGroupJoin(TableGroupJoin join) {
|
||||
delegate.addTableGroupJoin( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
delegate.addNestedTableGroupJoin( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
delegate.visitTableGroupJoins( consumer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
delegate.visitNestedTableGroupJoins( consumer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAffectedTableNames(Consumer<String> nameCollector) {
|
||||
delegate.applyAffectedTableNames( nameCollector );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getPrimaryTableReference() {
|
||||
return delegate.getPrimaryTableReference();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableReferenceJoin> getTableReferenceJoins() {
|
||||
return delegate.getTableReferenceJoins();
|
||||
return super.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue