HHH-14153 clean up BasicExecutor and friends
introduces InsertExecutor and UpdateExecutor since we're going to be introducing specific optimizations relating to single-table updates relates to HHH-14153
This commit is contained in:
parent
d1119d320a
commit
264e71a916
|
@ -29,18 +29,16 @@ import org.hibernate.hql.internal.QueryExecutionRequestException;
|
|||
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
|
||||
import org.hibernate.hql.internal.antlr.HqlTokenTypes;
|
||||
import org.hibernate.hql.internal.antlr.SqlTokenTypes;
|
||||
import org.hibernate.hql.internal.ast.exec.BasicExecutor;
|
||||
import org.hibernate.hql.internal.ast.exec.DeleteExecutor;
|
||||
import org.hibernate.hql.internal.ast.exec.InsertExecutor;
|
||||
import org.hibernate.hql.internal.ast.exec.MultiTableDeleteExecutor;
|
||||
import org.hibernate.hql.internal.ast.exec.MultiTableUpdateExecutor;
|
||||
import org.hibernate.hql.internal.ast.exec.StatementExecutor;
|
||||
import org.hibernate.hql.internal.ast.exec.UpdateExecutor;
|
||||
import org.hibernate.hql.internal.ast.tree.AggregatedSelectExpression;
|
||||
import org.hibernate.hql.internal.ast.tree.FromElement;
|
||||
import org.hibernate.hql.internal.ast.tree.InsertStatement;
|
||||
import org.hibernate.hql.internal.ast.tree.QueryNode;
|
||||
import org.hibernate.hql.internal.ast.tree.Statement;
|
||||
import org.hibernate.hql.internal.ast.tree.UpdateStatement;
|
||||
import org.hibernate.hql.internal.ast.util.ASTPrinter;
|
||||
import org.hibernate.hql.internal.ast.util.ASTUtil;
|
||||
import org.hibernate.hql.internal.ast.util.NodeTraverser;
|
||||
import org.hibernate.hql.internal.ast.util.TokenPrinters;
|
||||
|
@ -597,7 +595,6 @@ public class QueryTranslatorImpl implements FilterTranslator {
|
|||
}
|
||||
|
||||
private StatementExecutor buildAppropriateStatementExecutor(HqlSqlWalker walker) {
|
||||
final Statement statement = (Statement) walker.getAST();
|
||||
if ( walker.getStatementType() == HqlSqlTokenTypes.DELETE ) {
|
||||
final FromElement fromElement = walker.getFinalFromClause().getFromElement();
|
||||
final Queryable persister = fromElement.getQueryable();
|
||||
|
@ -605,7 +602,7 @@ public class QueryTranslatorImpl implements FilterTranslator {
|
|||
return new MultiTableDeleteExecutor( walker );
|
||||
}
|
||||
else {
|
||||
return new DeleteExecutor( walker, persister );
|
||||
return new DeleteExecutor( walker );
|
||||
}
|
||||
}
|
||||
else if ( walker.getStatementType() == HqlSqlTokenTypes.UPDATE ) {
|
||||
|
@ -618,11 +615,11 @@ public class QueryTranslatorImpl implements FilterTranslator {
|
|||
return new MultiTableUpdateExecutor( walker );
|
||||
}
|
||||
else {
|
||||
return new BasicExecutor( walker, persister );
|
||||
return new UpdateExecutor( walker );
|
||||
}
|
||||
}
|
||||
else if ( walker.getStatementType() == HqlSqlTokenTypes.INSERT ) {
|
||||
return new BasicExecutor( walker, ( (InsertStatement) statement ).getIntoClause().getQueryable() );
|
||||
return new InsertExecutor( walker );
|
||||
}
|
||||
else {
|
||||
throw new QueryException( "Unexpected statement type" );
|
||||
|
|
|
@ -8,7 +8,6 @@ package org.hibernate.hql.internal.ast.exec;
|
|||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
|
@ -17,46 +16,22 @@ 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;
|
||||
import org.hibernate.param.ParameterSpecification;
|
||||
import org.hibernate.persister.entity.Queryable;
|
||||
|
||||
import antlr.RecognitionException;
|
||||
|
||||
/**
|
||||
* Implementation of BasicExecutor.
|
||||
* Base implementation of {@link StatementExecutor}.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class BasicExecutor implements StatementExecutor {
|
||||
private final Queryable persister;
|
||||
private final String sql;
|
||||
private final List parameterSpecifications;
|
||||
public abstract class BasicExecutor implements StatementExecutor {
|
||||
|
||||
public BasicExecutor(HqlSqlWalker walker, Queryable persister) {
|
||||
final Queryable persister;
|
||||
String sql;
|
||||
List<ParameterSpecification> parameterSpecifications;
|
||||
|
||||
public BasicExecutor(Queryable persister) {
|
||||
this.persister = persister;
|
||||
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();
|
||||
}
|
||||
catch ( RecognitionException e ) {
|
||||
throw QuerySyntaxException.convert( e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -65,42 +40,43 @@ public class BasicExecutor implements StatementExecutor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int execute(QueryParameters parameters, SharedSessionContractImplementor session) throws HibernateException {
|
||||
return doExecute(
|
||||
parameters,
|
||||
session,
|
||||
session.getJdbcServices().getDialect()
|
||||
.addSqlHintOrComment(
|
||||
sql,
|
||||
parameters,
|
||||
session.getFactory().getSessionFactoryOptions().isCommentsEnabled()
|
||||
),
|
||||
parameterSpecifications
|
||||
);
|
||||
}
|
||||
|
||||
protected int doExecute(QueryParameters parameters, SharedSessionContractImplementor session, String sql,
|
||||
List parameterSpecifications) throws HibernateException {
|
||||
public int execute(QueryParameters parameters, SharedSessionContractImplementor session)
|
||||
throws HibernateException {
|
||||
|
||||
BulkOperationCleanupAction action = new BulkOperationCleanupAction( session, persister );
|
||||
if ( session.isEventSource() ) {
|
||||
( (EventSource) session ).getActionQueue().addAction( action );
|
||||
( (EventSource) session).getActionQueue().addAction( action );
|
||||
}
|
||||
else {
|
||||
action.getAfterTransactionCompletionProcess().doAfterTransactionCompletion( true, session );
|
||||
}
|
||||
|
||||
PreparedStatement st = null;
|
||||
RowSelection selection = parameters.getRowSelection();
|
||||
return doExecute(
|
||||
session.getJdbcServices().getDialect()
|
||||
.addSqlHintOrComment(
|
||||
sql,
|
||||
parameters,
|
||||
session.getFactory().getSessionFactoryOptions().isCommentsEnabled()
|
||||
),
|
||||
parameters,
|
||||
parameterSpecifications,
|
||||
session
|
||||
);
|
||||
}
|
||||
|
||||
int doExecute(String sql, QueryParameters parameters,
|
||||
List<ParameterSpecification> parameterSpecifications,
|
||||
SharedSessionContractImplementor session)
|
||||
throws HibernateException{
|
||||
try {
|
||||
PreparedStatement st = null;
|
||||
try {
|
||||
st = session.getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );
|
||||
Iterator paramSpecItr = parameterSpecifications.iterator();
|
||||
int pos = 1;
|
||||
while ( paramSpecItr.hasNext() ) {
|
||||
final ParameterSpecification paramSpec = (ParameterSpecification) paramSpecItr.next();
|
||||
pos += paramSpec.bind( st, parameters, session, pos );
|
||||
for ( ParameterSpecification parameter: parameterSpecifications) {
|
||||
pos += parameter.bind( st, parameters, session, pos );
|
||||
}
|
||||
RowSelection selection = parameters.getRowSelection();
|
||||
if ( selection != null ) {
|
||||
if ( selection.getTimeout() != null ) {
|
||||
st.setQueryTimeout( selection.getTimeout() );
|
||||
|
@ -117,7 +93,9 @@ public class BasicExecutor implements StatementExecutor {
|
|||
}
|
||||
}
|
||||
catch( SQLException sqle ) {
|
||||
throw session.getJdbcServices().getSqlExceptionHelper().convert( sqle, "could not execute update query", sql );
|
||||
throw session.getJdbcServices().getSqlExceptionHelper()
|
||||
.convert( sqle, "could not execute update query", sql);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,13 +17,12 @@ import org.hibernate.engine.spi.QueryParameters;
|
|||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.hql.internal.ast.HqlSqlWalker;
|
||||
import org.hibernate.hql.internal.ast.QuerySyntaxException;
|
||||
import org.hibernate.hql.internal.ast.SqlGenerator;
|
||||
import org.hibernate.hql.internal.ast.tree.DeleteStatement;
|
||||
import org.hibernate.hql.internal.ast.tree.FromElement;
|
||||
import org.hibernate.metamodel.spi.MetamodelImplementor;
|
||||
import org.hibernate.param.ParameterSpecification;
|
||||
import org.hibernate.persister.collection.AbstractCollectionPersister;
|
||||
import org.hibernate.persister.entity.Queryable;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.Joinable;
|
||||
import org.hibernate.sql.Delete;
|
||||
import org.hibernate.type.CollectionType;
|
||||
import org.hibernate.type.ComponentType;
|
||||
|
@ -36,8 +35,10 @@ import antlr.collections.AST;
|
|||
|
||||
|
||||
/**
|
||||
* Provides deletions in addition to the basic SQL delete statement being executed. Ex: cascading the delete into a
|
||||
* many-to-many join table.
|
||||
* Executes HQL bulk deletes against a single table.
|
||||
*
|
||||
* Provides deletions in addition to the basic SQL delete statement being executed.
|
||||
* Ex: cascading the delete into a many-to-many join table.
|
||||
*
|
||||
* @author Brett Meyer
|
||||
*/
|
||||
|
@ -45,14 +46,22 @@ public class DeleteExecutor extends BasicExecutor {
|
|||
private static final Logger LOG = Logger.getLogger( DeleteExecutor.class );
|
||||
|
||||
private final List<String> deletes = new ArrayList<>();
|
||||
private List<ParameterSpecification> parameterSpecifications;
|
||||
|
||||
public DeleteExecutor(HqlSqlWalker walker, Queryable persister) {
|
||||
super( walker, persister );
|
||||
|
||||
public DeleteExecutor(HqlSqlWalker walker) {
|
||||
super( walker.getFinalFromClause().getFromElement().getQueryable() );
|
||||
|
||||
final SessionFactoryImplementor factory = walker.getSessionFactoryHelper().getFactory();
|
||||
final Dialect dialect = factory.getJdbcServices().getJdbcEnvironment().getDialect();
|
||||
|
||||
|
||||
try {
|
||||
SqlGenerator gen = new SqlGenerator( factory );
|
||||
gen.statement( walker.getAST() );
|
||||
sql = gen.getSQL();
|
||||
gen.getParseErrorHandler().throwQueryException();
|
||||
}
|
||||
catch ( RecognitionException e ) {
|
||||
throw QuerySyntaxException.convert( e );
|
||||
}
|
||||
|
||||
try {
|
||||
final DeleteStatement deleteStatement = (DeleteStatement) walker.getAST();
|
||||
|
||||
|
@ -72,12 +81,13 @@ public class DeleteExecutor extends BasicExecutor {
|
|||
|
||||
final boolean commentsEnabled = factory.getSessionFactoryOptions().isCommentsEnabled();
|
||||
final MetamodelImplementor metamodel = factory.getMetamodel();
|
||||
final Dialect dialect = factory.getJdbcServices().getJdbcEnvironment().getDialect();
|
||||
final boolean notSupportingTuplesInSubqueries = !dialect.supportsTuplesInSubqueries();
|
||||
// If many-to-many, delete the FK row in the collection table.
|
||||
for ( Type type : persister.getPropertyTypes() ) {
|
||||
if ( type.isCollectionType() ) {
|
||||
final CollectionType cType = (CollectionType) type;
|
||||
final AbstractCollectionPersister cPersister = (AbstractCollectionPersister) metamodel.collectionPersister( cType.getRole() );
|
||||
final CollectionPersister cPersister = metamodel.collectionPersister( cType.getRole() );
|
||||
if ( cPersister.isManyToMany() ) {
|
||||
Type keyType = cPersister.getKeyType();
|
||||
String[] columnNames;
|
||||
|
@ -106,14 +116,15 @@ public class DeleteExecutor extends BasicExecutor {
|
|||
);
|
||||
}
|
||||
else {
|
||||
Joinable joinable = (Joinable) cPersister;
|
||||
StringBuilder whereBuilder = new StringBuilder();
|
||||
whereBuilder.append( '(' );
|
||||
append( ", ", cPersister.getKeyColumnNames(), whereBuilder );
|
||||
append( ", ", joinable.getKeyColumnNames(), whereBuilder );
|
||||
whereBuilder.append( ") in (select " );
|
||||
append( ", ", columnNames, whereBuilder );
|
||||
final String where = whereBuilder.append(" from ")
|
||||
.append( persister.getTableName() ).append( idSubselectWhere ).append( ")" ).toString();
|
||||
final Delete delete = new Delete().setTableName( cPersister.getTableName() ).setWhere( where );
|
||||
final Delete delete = new Delete().setTableName( joinable.getTableName() ).setWhere( where );
|
||||
if ( commentsEnabled ) {
|
||||
delete.setComment( "delete FKs in join table" );
|
||||
}
|
||||
|
@ -139,7 +150,7 @@ public class DeleteExecutor extends BasicExecutor {
|
|||
@Override
|
||||
public int execute(QueryParameters parameters, SharedSessionContractImplementor session) throws HibernateException {
|
||||
for (String delete : deletes) {
|
||||
doExecute( parameters, session, delete, parameterSpecifications );
|
||||
doExecute( delete, parameters, parameterSpecifications, session );
|
||||
}
|
||||
|
||||
// finally, execute the original sql statement
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package org.hibernate.hql.internal.ast.exec;
|
||||
|
||||
import antlr.RecognitionException;
|
||||
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;
|
||||
import org.hibernate.hql.internal.ast.tree.InsertStatement;
|
||||
import org.hibernate.hql.internal.ast.tree.Statement;
|
||||
import org.hibernate.param.ParameterSpecification;
|
||||
import org.hibernate.persister.entity.Queryable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Executes HQL insert statements.
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class InsertExecutor extends BasicExecutor {
|
||||
public InsertExecutor(HqlSqlWalker walker) {
|
||||
super( ( (InsertStatement) walker.getAST() ).getIntoClause().getQueryable() );
|
||||
try {
|
||||
SqlGenerator gen = new SqlGenerator( walker.getSessionFactoryHelper().getFactory() );
|
||||
gen.statement( walker.getAST() );
|
||||
sql = gen.getSQL();
|
||||
gen.getParseErrorHandler().throwQueryException();
|
||||
parameterSpecifications = gen.getCollectedParameters();
|
||||
}
|
||||
catch ( RecognitionException e ) {
|
||||
throw QuerySyntaxException.convert( e );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package org.hibernate.hql.internal.ast.exec;
|
||||
|
||||
import antlr.RecognitionException;
|
||||
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;
|
||||
import org.hibernate.param.ParameterSpecification;
|
||||
import org.hibernate.persister.entity.Queryable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Executes HQL bulk updates against a single table.
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class UpdateExecutor extends BasicExecutor {
|
||||
public UpdateExecutor(HqlSqlWalker walker) {
|
||||
super( walker.getFinalFromClause().getFromElement().getQueryable() );
|
||||
try {
|
||||
SqlGenerator gen = new SqlGenerator( walker.getSessionFactoryHelper().getFactory() );
|
||||
gen.statement( walker.getAST() );
|
||||
// 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 + ".", "" );
|
||||
gen.getParseErrorHandler().throwQueryException();
|
||||
parameterSpecifications = gen.getCollectedParameters();
|
||||
}
|
||||
catch ( RecognitionException e ) {
|
||||
throw QuerySyntaxException.convert( e );
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue