HHH-14153 optimize away temp table for single-table HQL update

When a HQL bulk update query only touches a single table,
use BasicExecutor instead of MultiTableUpdateExecutor.

This is an alternate implementation to the one proposed by
@NathanQingyangXu in #3508 and loosely based on that work.
This commit is contained in:
Gavin King 2020-08-23 10:33:56 +02:00
parent 59d40c3bf5
commit d1119d320a
3 changed files with 19 additions and 7 deletions

View File

@ -141,7 +141,7 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
private ArrayList<ParameterSpecification> parameterSpecs = new ArrayList<>();
private int numberOfParametersInSetClause;
private ArrayList assignmentSpecifications = new ArrayList();
private ArrayList<AssignmentSpecification> assignmentSpecifications = new ArrayList<>();
private JoinType impliedJoinType = JoinType.INNER_JOIN;
@ -1393,7 +1393,7 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
}
}
public ArrayList getAssignmentSpecifications() {
public ArrayList<AssignmentSpecification> getAssignmentSpecifications() {
return assignmentSpecifications;
}

View File

@ -63,6 +63,8 @@ import antlr.RecognitionException;
import antlr.TokenStreamException;
import antlr.collections.AST;
import static java.util.Collections.singleton;
/**
* A QueryTranslator that uses an Antlr-based parser.
*
@ -609,10 +611,10 @@ public class QueryTranslatorImpl implements FilterTranslator {
else if ( walker.getStatementType() == HqlSqlTokenTypes.UPDATE ) {
final FromElement fromElement = walker.getFinalFromClause().getFromElement();
final Queryable persister = fromElement.getQueryable();
if ( persister.isMultiTable() ) {
// even here, if only properties mapped to the "base table" are referenced
// in the set and where clauses, this could be handled by the BasicDelegate.
// TODO : decide if it is better performance-wise to doAfterTransactionCompletion that check, or to simply use the MultiTableUpdateDelegate
boolean affectsExtraTables = persister.isMultiTable()
&& !singleton( persister.getTableName() ).containsAll( walker.getQuerySpaces() );
if ( affectsExtraTables ) {
return new MultiTableUpdateExecutor( walker );
}
else {

View File

@ -17,6 +17,7 @@ import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.spi.EventSource;
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
import org.hibernate.hql.internal.ast.HqlSqlWalker;
import org.hibernate.hql.internal.ast.QuerySyntaxException;
import org.hibernate.hql.internal.ast.SqlGenerator;
@ -40,7 +41,16 @@ public class BasicExecutor implements StatementExecutor {
try {
SqlGenerator gen = new SqlGenerator( walker.getSessionFactoryHelper().getFactory() );
gen.statement( walker.getAST() );
if ( walker.getStatementType() == HqlSqlTokenTypes.UPDATE ) {
// workaround for a problem where HqlSqlWalker actually generates
// broken SQL with undefined aliases in the where clause, because
// that is what MultiTableUpdateExecutor is expecting to get
String alias = walker.getFinalFromClause().getFromElement().getTableAlias();
sql = gen.getSQL().replace( alias + ".", "" );
}
else {
sql = gen.getSQL();
}
gen.getParseErrorHandler().throwQueryException();
parameterSpecifications = gen.getCollectedParameters();
}