HHH-16392 Add column qualifier support to Dialect

This commit is contained in:
Marco Belladelli 2023-04-11 18:08:49 +02:00
parent a9080f5f7d
commit c86c2b8300
8 changed files with 86 additions and 56 deletions

View File

@ -24,6 +24,7 @@ import org.hibernate.boot.model.FunctionContributions;
import org.hibernate.boot.model.TypeContributions; import org.hibernate.boot.model.TypeContributions;
import org.hibernate.cfg.Environment; import org.hibernate.cfg.Environment;
import org.hibernate.dialect.BooleanDecoder; import org.hibernate.dialect.BooleanDecoder;
import org.hibernate.dialect.DmlTargetColumnQualifierSupport;
import org.hibernate.dialect.DatabaseVersion; import org.hibernate.dialect.DatabaseVersion;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.OracleBooleanJdbcType; import org.hibernate.dialect.OracleBooleanJdbcType;
@ -96,7 +97,6 @@ import org.hibernate.type.SqlTypes;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType; import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
import org.hibernate.type.descriptor.jdbc.BlobJdbcType; import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.OracleJsonBlobJdbcType; import org.hibernate.type.descriptor.jdbc.OracleJsonBlobJdbcType;
@ -1443,4 +1443,9 @@ public class OracleLegacyDialect extends Dialect {
public String rowId(String rowId) { public String rowId(String rowId) {
return "rowid"; return "rowid";
} }
@Override
public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() {
return DmlTargetColumnQualifierSupport.TABLE_ALIAS;
}
} }

View File

@ -514,14 +514,6 @@ public class OracleLegacySqlAstTranslator<T extends JdbcOperation> extends Abstr
return getDialect().supportsFetchClause( FetchClauseType.ROWS_ONLY ); return getDialect().supportsFetchClause( FetchClauseType.ROWS_ONLY );
} }
@Override
protected boolean renderNamedTableReference(NamedTableReference tableReference, LockMode lockMode) {
appendSql( tableReference.getTableExpression() );
registerAffectedTable( tableReference );
renderTableReferenceIdentificationVariable( tableReference );
return false;
}
@Override @Override
protected void visitSetAssignment(Assignment assignment) { protected void visitSetAssignment(Assignment assignment) {
final List<ColumnReference> columnReferences = assignment.getAssignable().getColumnReferences(); final List<ColumnReference> columnReferences = assignment.getAssignable().getColumnReferences();
@ -549,15 +541,4 @@ public class OracleLegacySqlAstTranslator<T extends JdbcOperation> extends Abstr
assignment.getAssignedValue().accept( this ); assignment.getAssignedValue().accept( this );
} }
} }
@Override
public void visitColumnReference(ColumnReference columnReference) {
columnReference.appendReadExpression( this );
}
@Override
public void visitAggregateColumnWriteExpression(AggregateColumnWriteExpression aggregateColumnWriteExpression) {
aggregateColumnWriteExpression.appendWriteExpression( this, this );
}
} }

View File

@ -5224,4 +5224,13 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
public String getRowIdColumnString(String rowId) { public String getRowIdColumnString(String rowId) {
return null; return null;
} }
/**
* Get the minimum {@link DmlTargetColumnQualifierSupport} required by this dialect.
*
* @return the column qualifier support required by this dialect
*/
public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() {
return DmlTargetColumnQualifierSupport.NONE;
}
} }

View File

@ -0,0 +1,32 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.dialect;
/**
* Indicates the level of qualifier support used by
* the dialect when referencing a column.
*
* @author Marco Belladelli
*/
public enum DmlTargetColumnQualifierSupport {
/**
* Qualify the column using the table expression,
* ignoring a possible table alias.
*/
TABLE_EXPRESSION,
/**
* Qualify the column using the table alias, whenever available,
* and fallback to the table expression.
*/
TABLE_ALIAS,
/**
* No need to explicitly qualify the column.
*/
NONE;
}

View File

@ -1467,4 +1467,9 @@ public class OracleDialect extends Dialect {
final OracleSqlAstTranslator<?> translator = new OracleSqlAstTranslator<>( factory, optionalTableUpdate ); final OracleSqlAstTranslator<?> translator = new OracleSqlAstTranslator<>( factory, optionalTableUpdate );
return translator.createMergeOperation( optionalTableUpdate ); return translator.createMergeOperation( optionalTableUpdate );
} }
@Override
public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() {
return DmlTargetColumnQualifierSupport.TABLE_ALIAS;
}
} }

View File

@ -512,14 +512,6 @@ public class OracleSqlAstTranslator<T extends JdbcOperation> extends SqlAstTrans
return getDialect().supportsFetchClause( FetchClauseType.ROWS_ONLY ); return getDialect().supportsFetchClause( FetchClauseType.ROWS_ONLY );
} }
@Override
protected boolean renderNamedTableReference(NamedTableReference tableReference, LockMode lockMode) {
appendSql( tableReference.getTableExpression() );
registerAffectedTable( tableReference );
renderTableReferenceIdentificationVariable( tableReference );
return false;
}
@Override @Override
protected void visitSetAssignment(Assignment assignment) { protected void visitSetAssignment(Assignment assignment) {
final List<ColumnReference> columnReferences = assignment.getAssignable().getColumnReferences(); final List<ColumnReference> columnReferences = assignment.getAssignable().getColumnReferences();
@ -548,16 +540,6 @@ public class OracleSqlAstTranslator<T extends JdbcOperation> extends SqlAstTrans
} }
} }
@Override
public void visitColumnReference(ColumnReference columnReference) {
columnReference.appendReadExpression( this );
}
@Override
public void visitAggregateColumnWriteExpression(AggregateColumnWriteExpression aggregateColumnWriteExpression) {
aggregateColumnWriteExpression.appendWriteExpression( this, this );
}
@Override @Override
protected void renderMergeTargetAlias() { protected void renderMergeTargetAlias() {
appendSql( " t" ); appendSql( " t" );

View File

@ -34,6 +34,7 @@ import org.hibernate.Internal;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.QueryException; import org.hibernate.QueryException;
import org.hibernate.boot.model.process.internal.InferredBasicValueResolver; import org.hibernate.boot.model.process.internal.InferredBasicValueResolver;
import org.hibernate.dialect.DmlTargetColumnQualifierSupport;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.function.TimestampaddFunction; import org.hibernate.dialect.function.TimestampaddFunction;
import org.hibernate.dialect.function.TimestampdiffFunction; import org.hibernate.dialect.function.TimestampdiffFunction;
@ -831,7 +832,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
(filterPredicate) -> additionalRestrictions = combinePredicates( additionalRestrictions, filterPredicate), (filterPredicate) -> additionalRestrictions = combinePredicates( additionalRestrictions, filterPredicate),
entityDescriptor, entityDescriptor,
rootTableGroup, rootTableGroup,
AbstractSqlAstTranslator.rendersTableReferenceAlias( Clause.UPDATE ), getDialect().getDmlTargetColumnQualifierSupport() == DmlTargetColumnQualifierSupport.TABLE_ALIAS,
getLoadQueryInfluencers(), getLoadQueryInfluencers(),
this this
); );
@ -1088,7 +1089,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
(filterPredicate) -> additionalRestrictions = combinePredicates( additionalRestrictions, filterPredicate), (filterPredicate) -> additionalRestrictions = combinePredicates( additionalRestrictions, filterPredicate),
entityDescriptor, entityDescriptor,
rootTableGroup, rootTableGroup,
AbstractSqlAstTranslator.rendersTableReferenceAlias( Clause.DELETE ), getDialect().getDmlTargetColumnQualifierSupport() == DmlTargetColumnQualifierSupport.TABLE_ALIAS,
getLoadQueryInfluencers(), getLoadQueryInfluencers(),
this this
); );

View File

@ -27,6 +27,7 @@ import java.util.function.Supplier;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
import org.hibernate.QueryException; import org.hibernate.QueryException;
import org.hibernate.dialect.DmlTargetColumnQualifierSupport;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.RowLockStrategy; import org.hibernate.dialect.RowLockStrategy;
import org.hibernate.dialect.SelectItemReferenceStrategy; import org.hibernate.dialect.SelectItemReferenceStrategy;
@ -5478,13 +5479,13 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
} }
} }
public static boolean rendersTableReferenceAlias(Clause clause) { protected boolean rendersTableReferenceAlias(Clause clause) {
// todo (6.0) : For now we just skip the alias rendering in the delete and update clauses // 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 // We need some dialect support if we want to support joins in delete and update statements
switch ( clause ) { switch ( clause ) {
case DELETE: case DELETE:
case UPDATE: case UPDATE:
return false; return getDialect().getDmlTargetColumnQualifierSupport() == DmlTargetColumnQualifierSupport.TABLE_ALIAS;
} }
return true; return true;
} }
@ -6018,19 +6019,24 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
public void visitColumnReference(ColumnReference columnReference) { public void visitColumnReference(ColumnReference columnReference) {
final String dmlTargetTableAlias = getDmlTargetTableAlias(); final String dmlTargetTableAlias = getDmlTargetTableAlias();
if ( dmlTargetTableAlias != null && dmlTargetTableAlias.equals( columnReference.getQualifier() ) ) { if ( dmlTargetTableAlias != null && dmlTargetTableAlias.equals( columnReference.getQualifier() ) ) {
// todo (6.0) : use the Dialect to determine how to handle column references final DmlTargetColumnQualifierSupport qualifierSupport = getDialect().getDmlTargetColumnQualifierSupport();
// - specifically should they use the table-alias, the table-expression final String qualifier;
// or neither for its qualifier if ( qualifierSupport == DmlTargetColumnQualifierSupport.TABLE_ALIAS ) {
qualifier = dmlTargetTableAlias;
final String tableExpression = getCurrentDmlStatement().getTargetTable().getTableExpression(); }
// Qualify the column reference with the table expression only in subqueries // Qualify the column reference with the table expression also when in subqueries
final boolean qualifyColumn = !queryPartStack.isEmpty(); else if ( qualifierSupport != DmlTargetColumnQualifierSupport.NONE || !queryPartStack.isEmpty() ) {
qualifier = getCurrentDmlStatement().getTargetTable().getTableExpression();
}
else {
qualifier = null;
}
if ( columnReference.isColumnExpressionFormula() ) { if ( columnReference.isColumnExpressionFormula() ) {
// For formulas, we have to replace the qualifier as the alias was already rendered into the formula // For formulas, we have to replace the qualifier as the alias was already rendered into the formula
// This is fine for now as this is only temporary anyway until we render aliases for table references // This is fine for now as this is only temporary anyway until we render aliases for table references
final String replacement; final String replacement;
if ( qualifyColumn ) { if ( qualifier != null ) {
replacement = "$1" + tableExpression + ".$3"; replacement = "$1" + qualifier + ".$3";
} }
else { else {
replacement = "$1$3"; replacement = "$1$3";
@ -6041,7 +6047,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
); );
} }
else { else {
columnReference.appendReadExpression( this, qualifyColumn ? tableExpression : null ); columnReference.appendReadExpression( this, qualifier );
} }
} }
else { else {
@ -6054,10 +6060,19 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
final String dmlTargetTableAlias = getDmlTargetTableAlias(); final String dmlTargetTableAlias = getDmlTargetTableAlias();
final ColumnReference columnReference = aggregateColumnWriteExpression.getColumnReference(); final ColumnReference columnReference = aggregateColumnWriteExpression.getColumnReference();
if ( dmlTargetTableAlias != null && dmlTargetTableAlias.equals( columnReference.getQualifier() ) ) { if ( dmlTargetTableAlias != null && dmlTargetTableAlias.equals( columnReference.getQualifier() ) ) {
final String tableExpression = getCurrentDmlStatement().getTargetTable().getTableExpression(); final DmlTargetColumnQualifierSupport qualifierSupport = getDialect().getDmlTargetColumnQualifierSupport();
// Qualify the column reference with the table expression only in subqueries final String qualifier;
final boolean qualifyColumn = !queryPartStack.isEmpty(); if ( qualifierSupport == DmlTargetColumnQualifierSupport.TABLE_ALIAS ) {
aggregateColumnWriteExpression.appendWriteExpression( this, this, qualifyColumn ? tableExpression : null ); qualifier = dmlTargetTableAlias;
}
// Qualify the column reference with the table expression also when in subqueries
else if ( qualifierSupport != DmlTargetColumnQualifierSupport.NONE || !queryPartStack.isEmpty() ) {
qualifier = getCurrentDmlStatement().getTargetTable().getTableExpression();
}
else {
qualifier = null;
}
aggregateColumnWriteExpression.appendWriteExpression( this, this, qualifier );
} }
else { else {
aggregateColumnWriteExpression.appendWriteExpression( this, this ); aggregateColumnWriteExpression.appendWriteExpression( this, this );