HHH-16392 Add column qualifier support to Dialect

This commit is contained in:
Marco Belladelli 2023-04-11 18:08:49 +02:00
parent 094f243413
commit 792a355865
No known key found for this signature in database
GPG Key ID: D1D0C3030AE3AA35
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.cfg.Environment;
import org.hibernate.dialect.BooleanDecoder;
import org.hibernate.dialect.DmlTargetColumnQualifierSupport;
import org.hibernate.dialect.DatabaseVersion;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.OracleBooleanJdbcType;
@ -96,7 +97,6 @@ import org.hibernate.type.SqlTypes;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
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.JdbcType;
import org.hibernate.type.descriptor.jdbc.OracleJsonBlobJdbcType;
@ -1443,4 +1443,9 @@ public class OracleLegacyDialect extends Dialect {
public String rowId(String 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 );
}
@Override
protected boolean renderNamedTableReference(NamedTableReference tableReference, LockMode lockMode) {
appendSql( tableReference.getTableExpression() );
registerAffectedTable( tableReference );
renderTableReferenceIdentificationVariable( tableReference );
return false;
}
@Override
protected void visitSetAssignment(Assignment assignment) {
final List<ColumnReference> columnReferences = assignment.getAssignable().getColumnReferences();
@ -549,15 +541,4 @@ public class OracleLegacySqlAstTranslator<T extends JdbcOperation> extends Abstr
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

@ -5247,4 +5247,13 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
public String getRowIdColumnString(String rowId) {
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

@ -1449,4 +1449,9 @@ public class OracleDialect extends Dialect {
final OracleSqlAstTranslator<?> translator = new OracleSqlAstTranslator<>( factory, 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 );
}
@Override
protected boolean renderNamedTableReference(NamedTableReference tableReference, LockMode lockMode) {
appendSql( tableReference.getTableExpression() );
registerAffectedTable( tableReference );
renderTableReferenceIdentificationVariable( tableReference );
return false;
}
@Override
protected void visitSetAssignment(Assignment assignment) {
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
protected void renderMergeTargetAlias() {
appendSql( " t" );

View File

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

View File

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