Working support for simple HQL DELETE -> SqmDeleteStatement translation
This commit is contained in:
parent
8dd63c372d
commit
30ad3eabe5
|
@ -14,6 +14,8 @@ import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData;
|
|||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
import org.hibernate.service.Service;
|
||||
import org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl;
|
||||
import org.hibernate.sql.exec.internal.StandardJdbcMutationExecutor;
|
||||
import org.hibernate.sql.exec.spi.JdbcMutationExecutor;
|
||||
import org.hibernate.sql.exec.spi.JdbcSelectExecutor;
|
||||
|
||||
/**
|
||||
|
@ -84,4 +86,12 @@ public interface JdbcServices extends Service {
|
|||
default JdbcSelectExecutor getJdbcSelectExecutor() {
|
||||
return JdbcSelectExecutorStandardImpl.INSTANCE;
|
||||
}
|
||||
|
||||
default JdbcMutationExecutor getJdbcDeleteExecutor() {
|
||||
return StandardJdbcMutationExecutor.INSTANCE;
|
||||
}
|
||||
|
||||
default JdbcMutationExecutor getJdbcUpdateExecutor() {
|
||||
return StandardJdbcMutationExecutor.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -618,7 +618,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
queryString,
|
||||
interpretationCache.resolveHqlInterpretation(
|
||||
queryString,
|
||||
s -> queryEngine.getHqlTranslator().interpret( queryString )
|
||||
s -> queryEngine.getHqlTranslator().translate( queryString )
|
||||
),
|
||||
resultClass,
|
||||
this
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.hibernate.engine.spi.LoadQueryInfluencers;
|
|||
import org.hibernate.loader.spi.Loadable;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.sql.ast.JoinType;
|
||||
import org.hibernate.sql.ast.spi.SqlAliasBase;
|
||||
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
|
||||
|
@ -109,6 +110,10 @@ public interface EntityMappingType extends ManagedMappingType, Loadable {
|
|||
return false;
|
||||
}
|
||||
|
||||
default SqmMultiTableMutationStrategy getSqmMultiTableMutationStrategy(){
|
||||
return getEntityPersister().getSqmMultiTableMutationStrategy();
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Special model parts - identifier, discriminator, etc
|
||||
|
||||
|
|
|
@ -187,7 +187,6 @@ public class EmbeddedAttributeMapping
|
|||
SqlAstCreationState sqlAstCreationState) {
|
||||
final List<ColumnReference> columnReferences = CollectionHelper.arrayList( attrColumnNames.length );
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( getContainingTableExpression() );
|
||||
|
||||
getEmbeddableTypeDescriptor().visitJdbcTypes(
|
||||
new Consumer<JdbcMapping>() {
|
||||
private int index = 0;
|
||||
|
|
|
@ -28,7 +28,7 @@ public interface HqlTranslator {
|
|||
*
|
||||
* @return The semantic representation of the incoming query.
|
||||
*/
|
||||
SqmStatement interpret(String hql);
|
||||
SqmStatement translate(String hql);
|
||||
|
||||
/**
|
||||
* Give the translator a chance to "shut down" if it needs to
|
||||
|
|
|
@ -124,7 +124,7 @@ public class NamedHqlQueryMementoImpl extends AbstractNamedQueryMemento implemen
|
|||
|
||||
@Override
|
||||
public void validate(QueryEngine queryEngine) {
|
||||
queryEngine.getHqlTranslator().interpret( getHqlString() );
|
||||
queryEngine.getHqlTranslator().translate( getHqlString() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -343,12 +343,17 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
|
||||
parameterCollector = deleteStatement;
|
||||
|
||||
processingStateStack.push( new SqmDmlCreationProcessingState( deleteStatement, this ) );
|
||||
final SqmDmlCreationProcessingState sqmDeleteCreationState = new SqmDmlCreationProcessingState(
|
||||
deleteStatement,
|
||||
this
|
||||
);
|
||||
|
||||
sqmDeleteCreationState.getPathRegistry().register( root );
|
||||
|
||||
processingStateStack.push( sqmDeleteCreationState );
|
||||
try {
|
||||
if ( ctx.whereClause() != null && ctx.whereClause().predicate() != null ) {
|
||||
deleteStatement.getWhereClause().setPredicate(
|
||||
(SqmPredicate) ctx.whereClause().predicate().accept( this )
|
||||
);
|
||||
deleteStatement.applyPredicate( (SqmPredicate) ctx.whereClause().predicate().accept( this ) );
|
||||
}
|
||||
|
||||
return deleteStatement;
|
||||
|
@ -792,6 +797,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
log.debugf( "Attempting to resolve path [%s] as entity reference...", entityName );
|
||||
EntityDomainType reference = null;
|
||||
try {
|
||||
entityName = creationContext.getJpaMetamodel().qualifyImportableName( entityName );
|
||||
reference = creationContext.getJpaMetamodel().entity( entityName );
|
||||
}
|
||||
catch (Exception ignore) {
|
||||
|
|
|
@ -38,7 +38,7 @@ public class StandardHqlTranslator implements HqlTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmStatement interpret(String query) {
|
||||
public SqmStatement translate(String query) {
|
||||
final HqlParser.StatementContext hqlParseTree = parseHql( query );
|
||||
|
||||
// then we perform semantic analysis and build the semantic representation...
|
||||
|
|
|
@ -28,13 +28,15 @@ import org.hibernate.query.hql.spi.SqmCreationOptions;
|
|||
import org.hibernate.query.internal.QueryInterpretationCacheDisabledImpl;
|
||||
import org.hibernate.query.internal.QueryInterpretationCacheStandardImpl;
|
||||
import org.hibernate.query.named.NamedQueryRepository;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.internal.SqmCreationOptionsStandard;
|
||||
import org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder;
|
||||
import org.hibernate.query.sqm.produce.function.SqmFunctionRegistry;
|
||||
import org.hibernate.query.sqm.spi.SqmCreationContext;
|
||||
import org.hibernate.query.sqm.sql.SimpleSqmDeleteToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.sql.SqmSelectToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
|
||||
import org.hibernate.query.sqm.sql.internal.StandardSqmDeleteToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.sql.internal.StandardSqmSelectToSqlAstConverter;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||
|
@ -160,6 +162,21 @@ public class QueryEngine {
|
|||
creationContext
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleSqmDeleteToSqlAstConverter createSimpleDeleteConverter(
|
||||
QueryOptions queryOptions,
|
||||
DomainParameterXref domainParameterXref,
|
||||
QueryParameterBindings domainParameterBindings,
|
||||
LoadQueryInfluencers influencers,
|
||||
SqlAstCreationContext creationContext) {
|
||||
return new StandardSqmDeleteToSqlAstConverter(
|
||||
creationContext,
|
||||
queryOptions,
|
||||
domainParameterXref,
|
||||
domainParameterBindings
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ import org.hibernate.query.spi.ScrollableResultsImplementor;
|
|||
import org.hibernate.query.spi.SelectQueryPlan;
|
||||
import org.hibernate.query.sqm.sql.SqmSelectToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
|
||||
import org.hibernate.query.sqm.sql.internal.SqmSelectInterpretation;
|
||||
import org.hibernate.query.sqm.sql.SqmSelectInterpretation;
|
||||
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
|
|
|
@ -8,7 +8,6 @@ package org.hibernate.query.sqm.internal;
|
|||
|
||||
import org.hibernate.query.spi.NonSelectQueryPlan;
|
||||
import org.hibernate.query.sqm.mutation.spi.DeleteHandler;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
|
||||
/**
|
||||
|
@ -17,10 +16,7 @@ import org.hibernate.sql.exec.spi.ExecutionContext;
|
|||
public class MultiTableDeleteQueryPlan implements NonSelectQueryPlan {
|
||||
private final DeleteHandler deleteHandler;
|
||||
|
||||
public MultiTableDeleteQueryPlan(
|
||||
SqmDeleteStatement sqmDeleteStatement,
|
||||
DeleteHandler deleteHandler,
|
||||
ExecutionContext executionContext) {
|
||||
public MultiTableDeleteQueryPlan(DeleteHandler deleteHandler) {
|
||||
this.deleteHandler = deleteHandler;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ import org.hibernate.query.spi.QueryParameterImplementor;
|
|||
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
||||
import org.hibernate.query.spi.SelectQueryPlan;
|
||||
import org.hibernate.query.sqm.SqmExpressable;
|
||||
import org.hibernate.query.sqm.mutation.spi.DeleteHandler;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.UpdateHandler;
|
||||
import org.hibernate.query.sqm.tree.SqmDmlStatement;
|
||||
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||
|
@ -92,7 +92,7 @@ public class QuerySqmImpl<R>
|
|||
|
||||
final SessionFactoryImplementor factory = producer.getFactory();
|
||||
|
||||
this.sqmStatement = factory.getQueryEngine().getHqlTranslator().interpret( hqlString );
|
||||
this.sqmStatement = factory.getQueryEngine().getHqlTranslator().translate( hqlString );
|
||||
|
||||
if ( resultType != null ) {
|
||||
if ( sqmStatement instanceof SqmDmlStatement ) {
|
||||
|
@ -532,7 +532,7 @@ public class QuerySqmImpl<R>
|
|||
return buildUpdateQueryPlan();
|
||||
}
|
||||
|
||||
throw new NotYetImplementedException( "Query#executeUpdate not yet implemented" );
|
||||
throw new NotYetImplementedException( "Query#executeUpdate for Statements of type [" + getSqmStatement() + "not yet supported" );
|
||||
}
|
||||
|
||||
private NonSelectQueryPlan buildDeleteQueryPlan() {
|
||||
|
@ -541,13 +541,19 @@ public class QuerySqmImpl<R>
|
|||
final String entityNameToDelete = sqmDelete.getTarget().getReferencedPathSource().getHibernateEntityName();
|
||||
final EntityPersister entityDescriptor = getSessionFactory().getDomainModel().findEntityDescriptor( entityNameToDelete );
|
||||
|
||||
final DeleteHandler deleteHandler = entityDescriptor.getSqmMultiTableMutationStrategy().buildDeleteHandler(
|
||||
sqmDelete,
|
||||
domainParameterXref,
|
||||
this::getSessionFactory
|
||||
);
|
||||
|
||||
return new DeleteQueryPlanImpl( sqmDelete, deleteHandler, this );
|
||||
final SqmMultiTableMutationStrategy multiTableStrategy = entityDescriptor.getSqmMultiTableMutationStrategy();
|
||||
if ( multiTableStrategy == null ) {
|
||||
return new SimpleDeleteQueryPlan( sqmDelete, domainParameterXref );
|
||||
}
|
||||
else {
|
||||
return new MultiTableDeleteQueryPlan(
|
||||
multiTableStrategy.buildDeleteHandler(
|
||||
sqmDelete,
|
||||
domainParameterXref,
|
||||
this::getSessionFactory
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private NonSelectQueryPlan buildUpdateQueryPlan() {
|
||||
|
|
|
@ -6,57 +6,109 @@
|
|||
*/
|
||||
package org.hibernate.query.sqm.internal;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.spi.NonSelectQueryPlan;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||
import org.hibernate.query.sqm.sql.SimpleSqmDeleteInterpretation;
|
||||
import org.hibernate.query.sqm.sql.SimpleSqmDeleteToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
|
||||
import org.hibernate.sql.ast.SqlAstDeleteTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
//import org.hibernate.sql.ast.consume.spi.SqlDeleteToJdbcDeleteConverter;
|
||||
//import org.hibernate.sql.ast.produce.sqm.spi.SqmDeleteInterpretation;
|
||||
//import org.hibernate.sql.ast.produce.sqm.spi.SqmDeleteToSqlAstConverterSimple;
|
||||
//import org.hibernate.sql.exec.internal.JdbcMutationExecutorImpl;
|
||||
//import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
//import org.hibernate.sql.exec.spi.JdbcMutation;
|
||||
//
|
||||
//import static org.hibernate.query.internal.QueryHelper.buildJdbcParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.JdbcDelete;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameter;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SimpleDeleteQueryPlan implements NonSelectQueryPlan {
|
||||
private final SqmDeleteStatement sqmStatement;
|
||||
private final SqmDeleteStatement sqmDelete;
|
||||
private final DomainParameterXref domainParameterXref;
|
||||
|
||||
public SimpleDeleteQueryPlan(SqmDeleteStatement sqmStatement) {
|
||||
this.sqmStatement = sqmStatement;
|
||||
domainParameterXref = DomainParameterXref.from( sqmStatement );
|
||||
private JdbcDelete jdbcDelete;
|
||||
private Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamsXref;
|
||||
|
||||
// todo (6.0) : here is where we need to perform the conversion into SQL AST
|
||||
public SimpleDeleteQueryPlan(
|
||||
SqmDeleteStatement sqmDelete,
|
||||
DomainParameterXref domainParameterXref) {
|
||||
this.sqmDelete = sqmDelete;
|
||||
this.domainParameterXref = domainParameterXref;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(ExecutionContext executionContext) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
// final SqmDeleteInterpretation sqmInterpretation = SqmDeleteToSqlAstConverterSimple.interpret(
|
||||
// sqmStatement,
|
||||
// executionContext.getQueryOptions(),
|
||||
// domainParameterXref,
|
||||
// executionContext.getDomainParameterBindingContext().getQueryParameterBindings(),
|
||||
// executionContext.getSession()
|
||||
// );
|
||||
//
|
||||
// // the converter should enforce this, simple assertion here
|
||||
// assert sqmInterpretation.getSqlDeletes().size() == 1;
|
||||
//
|
||||
// final JdbcMutation jdbcDelete = SqlDeleteToJdbcDeleteConverter.interpret(
|
||||
// sqmInterpretation.getSqlDeletes().get( 0 ),
|
||||
// executionContext.getSession().getSessionFactory()
|
||||
// );
|
||||
//
|
||||
//
|
||||
// return JdbcMutationExecutorImpl.WITH_AFTER_STATEMENT_CALL.execute(
|
||||
// jdbcDelete,
|
||||
// buildJdbcParameterBindings( sqmStatement, sqmInterpretation, executionContext ),
|
||||
// executionContext
|
||||
// );
|
||||
final SessionFactoryImplementor factory = executionContext.getSession().getFactory();
|
||||
final JdbcServices jdbcServices = factory.getJdbcServices();
|
||||
|
||||
if ( jdbcDelete == null ) {
|
||||
final QueryEngine queryEngine = factory.getQueryEngine();
|
||||
|
||||
final SqmTranslatorFactory converterFactory = queryEngine.getSqmTranslatorFactory();
|
||||
final SimpleSqmDeleteToSqlAstConverter converter = converterFactory.createSimpleDeleteConverter(
|
||||
executionContext.getQueryOptions(),
|
||||
domainParameterXref,
|
||||
executionContext.getQueryParameterBindings(),
|
||||
executionContext.getLoadQueryInfluencers(),
|
||||
factory
|
||||
);
|
||||
|
||||
final SimpleSqmDeleteInterpretation sqmInterpretation = converter.interpret( sqmDelete );
|
||||
|
||||
final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment();
|
||||
final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory();
|
||||
|
||||
final SqlAstDeleteTranslator sqlAstTranslator = sqlAstTranslatorFactory.buildDeleteConverter( factory );
|
||||
|
||||
jdbcDelete = sqlAstTranslator.translate( sqmInterpretation.getSqlAst() );
|
||||
|
||||
this.jdbcParamsXref = SqmUtil.generateJdbcParamsXref(
|
||||
domainParameterXref,
|
||||
sqmInterpretation::getJdbcParamsBySqmParam
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
final JdbcParameterBindings jdbcParameterBindings = SqmUtil.createJdbcParameterBindings(
|
||||
executionContext.getQueryParameterBindings(),
|
||||
domainParameterXref,
|
||||
jdbcParamsXref,
|
||||
// todo (6.0) : ugh. this one is important
|
||||
null,
|
||||
executionContext.getSession()
|
||||
);
|
||||
|
||||
final LogicalConnectionImplementor logicalConnection = executionContext.getSession()
|
||||
.getJdbcCoordinator()
|
||||
.getLogicalConnection();
|
||||
|
||||
return jdbcServices.getJdbcDeleteExecutor().execute(
|
||||
jdbcDelete,
|
||||
jdbcParameterBindings,
|
||||
sql -> {
|
||||
try {
|
||||
return logicalConnection.getPhysicalConnection().prepareStatement( sql );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw jdbcServices.getSqlExceptionHelper().convert(
|
||||
e,
|
||||
"Error performing DELETE",
|
||||
sql
|
||||
);
|
||||
}
|
||||
},
|
||||
(integer, preparedStatement) -> {},
|
||||
executionContext
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
* == From HQL/JPQL
|
||||
*
|
||||
* `SemanticQueryProducer` defines just a single method for producing SQM based on HQL:
|
||||
* {@link org.hibernate.query.hql.HqlTranslator#interpret}.
|
||||
* {@link org.hibernate.query.hql.HqlTranslator#translate}.
|
||||
* See {@link org.hibernate.query.hql.internal} for details
|
||||
*
|
||||
*
|
||||
|
|
|
@ -414,7 +414,7 @@ public abstract class BaseSqmToSqlAstConverter
|
|||
return null;
|
||||
}
|
||||
|
||||
Predicate additionalRestrictions;
|
||||
protected Predicate additionalRestrictions;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected void consumeFromClauseRoot(SqmRoot<?> sqmRoot) {
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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.query.sqm.sql;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameter;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SimpleSqmDeleteInterpretation implements SqmInterpretation {
|
||||
private final DeleteStatement sqlAst;
|
||||
private final Map<SqmParameter, List<JdbcParameter>> jdbcParamMap;
|
||||
|
||||
public SimpleSqmDeleteInterpretation(
|
||||
DeleteStatement sqlAst,
|
||||
Map<SqmParameter, List<JdbcParameter>> jdbcParamMap) {
|
||||
this.sqlAst = sqlAst;
|
||||
this.jdbcParamMap = jdbcParamMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeleteStatement getSqlAst() {
|
||||
return sqlAst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<SqmParameter, List<JdbcParameter>> getJdbcParamsBySqmParam() {
|
||||
return jdbcParamMap;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* 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.query.sqm.sql;
|
||||
|
||||
import org.hibernate.query.sqm.spi.JdbcParameterBySqmParameterAccess;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SimpleSqmDeleteToSqlAstConverter extends SqmToSqlAstConverter, JdbcParameterBySqmParameterAccess {
|
||||
SimpleSqmDeleteInterpretation interpret(SqmDeleteStatement statement);
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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.query.sqm.sql;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameter;
|
||||
|
||||
/**
|
||||
* Information obtained from the interpretation of an SqmStatement
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SqmInterpretation {
|
||||
Statement getSqlAst();
|
||||
Map<SqmParameter, List<JdbcParameter>> getJdbcParamsBySqmParam();
|
||||
}
|
|
@ -4,12 +4,12 @@
|
|||
* 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.query.sqm.sql.internal;
|
||||
package org.hibernate.query.sqm.sql;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.query.sqm.sql.internal.StandardSqmSelectToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameter;
|
||||
|
@ -21,7 +21,7 @@ import org.hibernate.sql.exec.spi.JdbcParameter;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SqmSelectInterpretation {
|
||||
public class SqmSelectInterpretation implements SqmInterpretation {
|
||||
private final SelectStatement sqlAst;
|
||||
private final Map<SqmParameter,List<JdbcParameter>> jdbcParamsBySqmParam;
|
||||
|
||||
|
@ -32,10 +32,12 @@ public class SqmSelectInterpretation {
|
|||
this.jdbcParamsBySqmParam = jdbcParamsBySqmParam;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelectStatement getSqlAst() {
|
||||
return sqlAst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<SqmParameter, List<JdbcParameter>> getJdbcParamsBySqmParam() {
|
||||
return jdbcParamsBySqmParam;
|
||||
}
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.query.sqm.sql;
|
||||
|
||||
import org.hibernate.query.sqm.spi.JdbcParameterBySqmParameterAccess;
|
||||
import org.hibernate.query.sqm.sql.internal.SqmSelectInterpretation;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,10 +10,10 @@ import org.hibernate.engine.spi.LoadQueryInfluencers;
|
|||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.sql.SqmSelectToSqlAstConverter;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||
|
||||
/**
|
||||
* Factory for various
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SqmTranslatorFactory {
|
||||
|
@ -24,5 +24,12 @@ public interface SqmTranslatorFactory {
|
|||
LoadQueryInfluencers influencers,
|
||||
SqlAstCreationContext creationContext);
|
||||
|
||||
SimpleSqmDeleteToSqlAstConverter createSimpleDeleteConverter(
|
||||
QueryOptions queryOptions,
|
||||
DomainParameterXref domainParameterXref,
|
||||
QueryParameterBindings domainParameterBindings,
|
||||
LoadQueryInfluencers influencers,
|
||||
SqlAstCreationContext creationContext);
|
||||
|
||||
// todo (6.0) : update, delete, etc converters...
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ public class EmbeddableValuedPathInterpretation<T> implements AssignableSqmPathI
|
|||
return new EmbeddableValuedPathInterpretation<>(
|
||||
mapping.toSqlExpression(
|
||||
tableGroup,
|
||||
|
||||
converter.getCurrentClauseStack().getCurrent(),
|
||||
converter,
|
||||
converter
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* 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.query.sqm.sql.internal;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.sql.SimpleSqmDeleteInterpretation;
|
||||
import org.hibernate.query.sqm.sql.SimpleSqmDeleteToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.JoinType;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||
import org.hibernate.sql.ast.spi.SqlAstTreeHelper;
|
||||
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class StandardSqmDeleteToSqlAstConverter
|
||||
extends BaseSqmToSqlAstConverter
|
||||
implements SimpleSqmDeleteToSqlAstConverter {
|
||||
|
||||
public StandardSqmDeleteToSqlAstConverter(
|
||||
SqlAstCreationContext creationContext,
|
||||
QueryOptions queryOptions,
|
||||
DomainParameterXref domainParameterXref,
|
||||
QueryParameterBindings domainParameterBindings) {
|
||||
super( creationContext, queryOptions, domainParameterXref, domainParameterBindings );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleSqmDeleteInterpretation interpret(SqmDeleteStatement statement) {
|
||||
final DeleteStatement deleteStatement = visitDeleteStatement( statement );
|
||||
return new SimpleSqmDeleteInterpretation(
|
||||
deleteStatement,
|
||||
getJdbcParamsBySqmParam()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeleteStatement visitDeleteStatement(SqmDeleteStatement statement) {
|
||||
final String entityName = statement.getTarget().getEntityName();
|
||||
final EntityPersister entityDescriptor = getCreationContext().getDomainModel().getEntityDescriptor( entityName );
|
||||
assert entityDescriptor != null;
|
||||
|
||||
getProcessingStateStack().push(
|
||||
new SqlAstProcessingStateImpl(
|
||||
null,
|
||||
this,
|
||||
getCurrentClauseStack()::getCurrent
|
||||
)
|
||||
);
|
||||
|
||||
try {
|
||||
final NavigablePath rootPath = new NavigablePath( entityName );
|
||||
final TableGroup rootTableGroup = entityDescriptor.createRootTableGroup(
|
||||
rootPath,
|
||||
null,
|
||||
JoinType.LEFT,
|
||||
LockMode.WRITE,
|
||||
stem -> getSqlAliasBaseGenerator().createSqlAliasBase( stem ),
|
||||
getSqlExpressionResolver(),
|
||||
() -> predicate -> additionalRestrictions = predicate,
|
||||
getCreationContext()
|
||||
);
|
||||
getFromClauseIndex().registerTableGroup( rootPath, rootTableGroup );
|
||||
|
||||
if ( ! rootTableGroup.getTableReferenceJoins().isEmpty() ) {
|
||||
throw new HibernateException( "Not expecting multiple table references for an SQM DELETE" );
|
||||
}
|
||||
|
||||
Predicate suppliedPredicate = null;
|
||||
final SqmWhereClause whereClause = statement.getWhereClause();
|
||||
if ( whereClause != null && whereClause.getPredicate() != null ) {
|
||||
getCurrentClauseStack().push( Clause.WHERE );
|
||||
try {
|
||||
suppliedPredicate = (Predicate) whereClause.getPredicate().accept( this );
|
||||
}
|
||||
finally {
|
||||
getCurrentClauseStack().pop();
|
||||
}
|
||||
}
|
||||
|
||||
return new DeleteStatement(
|
||||
rootTableGroup.getPrimaryTableReference(),
|
||||
SqlAstTreeHelper.combinePredicates( suppliedPredicate, additionalRestrictions )
|
||||
);
|
||||
}
|
||||
finally {
|
||||
getProcessingStateStack().pop();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,6 +30,7 @@ import org.hibernate.query.spi.QueryOptions;
|
|||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.sql.SqmSelectInterpretation;
|
||||
import org.hibernate.query.sqm.sql.SqmSelectToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
|
||||
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement;
|
|||
import org.hibernate.query.sqm.tree.from.SqmRoot;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
|
||||
import org.hibernate.sql.ast.spi.SqlAstTreeHelper;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -61,6 +62,18 @@ public class SqmDeleteStatement<T>
|
|||
return whereClause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyPredicate(SqmPredicate predicate) {
|
||||
if ( predicate == null ) {
|
||||
return;
|
||||
}
|
||||
if ( whereClause == null ) {
|
||||
whereClause = new SqmWhereClause( nodeBuilder() );
|
||||
}
|
||||
|
||||
whereClause.applyPredicate( predicate );
|
||||
}
|
||||
|
||||
public void setWhereClause(SqmWhereClause whereClause) {
|
||||
this.whereClause = whereClause;
|
||||
}
|
||||
|
|
|
@ -13,4 +13,6 @@ package org.hibernate.query.sqm.tree.predicate;
|
|||
*/
|
||||
public interface SqmWhereClauseContainer {
|
||||
SqmWhereClause getWhereClause();
|
||||
|
||||
void applyPredicate(SqmPredicate accept);
|
||||
}
|
||||
|
|
|
@ -86,6 +86,19 @@ public class SqmQuerySpec<T> implements SqmNode, SqmFromClauseContainer, SqmWher
|
|||
this.whereClause = whereClause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyPredicate(SqmPredicate predicate) {
|
||||
if ( predicate == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( whereClause == null ) {
|
||||
whereClause = new SqmWhereClause( nodeBuilder() );
|
||||
}
|
||||
|
||||
whereClause.applyPredicate( predicate );
|
||||
}
|
||||
|
||||
public SqmGroupByClause getGroupByClause() {
|
||||
return groupByClause;
|
||||
}
|
||||
|
|
|
@ -77,6 +77,19 @@ public class SqmUpdateStatement<T>
|
|||
return whereClause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyPredicate(SqmPredicate predicate) {
|
||||
if ( predicate == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( whereClause == null ) {
|
||||
whereClause = new SqmWhereClause( nodeBuilder() );
|
||||
}
|
||||
|
||||
whereClause.applyPredicate( predicate );
|
||||
}
|
||||
|
||||
public void setWhereClause(SqmWhereClause whereClause) {
|
||||
this.whereClause = whereClause;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.hibernate.sql.ast.spi.SqlAstToJdbcOperationConverter;
|
||||
import org.hibernate.sql.ast.spi.SqlSelectAstWalker;
|
||||
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
|
||||
import org.hibernate.sql.exec.spi.JdbcDelete;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SqlAstDeleteTranslator extends SqlSelectAstWalker, SqlAstToJdbcOperationConverter {
|
||||
JdbcDelete translate(DeleteStatement sqlAst);
|
||||
}
|
|
@ -13,6 +13,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
*/
|
||||
public interface SqlAstTranslatorFactory {
|
||||
SqlAstSelectTranslator buildSelectConverter(SessionFactoryImplementor sessionFactory);
|
||||
SqlAstDeleteTranslator buildDeleteConverter(SessionFactoryImplementor sessionFactory);
|
||||
|
||||
// todo (6.0) : update, delete, etc
|
||||
}
|
||||
|
|
|
@ -27,6 +27,10 @@ public class SqlAstTreeHelper {
|
|||
return incomingRestriction;
|
||||
}
|
||||
|
||||
if ( incomingRestriction == null ) {
|
||||
return baseRestriction;
|
||||
}
|
||||
|
||||
final Junction combinedPredicate;
|
||||
|
||||
if ( baseRestriction instanceof Junction ) {
|
||||
|
|
|
@ -6,12 +6,9 @@
|
|||
*/
|
||||
package org.hibernate.sql.ast.spi;
|
||||
|
||||
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
public interface SqlSelectAstWalker extends SqlAstWalker {
|
||||
void visitSelectQuery(SelectStatement selectQuery);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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.spi;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.sql.ast.SqlAstDeleteTranslator;
|
||||
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.exec.spi.JdbcDelete;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class StandardSqlAstDeleteTranslator
|
||||
extends AbstractSqlAstToJdbcOperationConverter
|
||||
implements SqlAstDeleteTranslator {
|
||||
public StandardSqlAstDeleteTranslator(SessionFactoryImplementor sessionFactory) {
|
||||
super( sessionFactory );
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcDelete translate(DeleteStatement sqlAst) {
|
||||
appendSql( "delete from " );
|
||||
appendSql( sqlAst.getTargetTable().getTableExpression() );
|
||||
|
||||
sqlAst.getRestriction().accept( this );
|
||||
|
||||
return new JdbcDelete() {
|
||||
@Override
|
||||
public String getSql() {
|
||||
return StandardSqlAstDeleteTranslator.this.getSql();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JdbcParameterBinder> getParameterBinders() {
|
||||
return StandardSqlAstDeleteTranslator.this.getParameterBinders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAffectedTableNames() {
|
||||
return getAffectedTableExpressions();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitColumnReference(ColumnReference columnReference) {
|
||||
// generally we do not want to render the qualifier
|
||||
appendSql( columnReference.getColumnExpression() );
|
||||
}
|
||||
}
|
|
@ -67,8 +67,4 @@ public class StandardSqlAstSelectTranslator
|
|||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSelectQuery(SelectStatement selectQuery) {
|
||||
visitQuerySpec( selectQuery.getQuerySpec() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.sql.ast.spi;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.sql.ast.SqlAstDeleteTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.SqlAstSelectTranslator;
|
||||
|
||||
|
@ -18,4 +19,9 @@ public class StandardSqlAstTranslatorFactory implements SqlAstTranslatorFactory
|
|||
public SqlAstSelectTranslator buildSelectConverter(SessionFactoryImplementor sessionFactory) {
|
||||
return new StandardSqlAstSelectTranslator( sessionFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlAstDeleteTranslator buildDeleteConverter(SessionFactoryImplementor sessionFactory) {
|
||||
return new StandardSqlAstDeleteTranslator( sessionFactory );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ColumnReference implements Expression {
|
||||
private final String qualifier;
|
||||
private final String columnExpression;
|
||||
private final String referenceExpression;
|
||||
private final JdbcMapping jdbcMapping;
|
||||
|
||||
|
@ -34,20 +36,11 @@ public class ColumnReference implements Expression {
|
|||
String columnExpression,
|
||||
JdbcMapping jdbcMapping,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
this(
|
||||
qualifier == null
|
||||
? columnExpression
|
||||
: qualifier + "." + columnExpression,
|
||||
jdbcMapping,
|
||||
sessionFactory
|
||||
);
|
||||
}
|
||||
|
||||
public ColumnReference(
|
||||
String referenceExpression,
|
||||
JdbcMapping jdbcMapping,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
this.referenceExpression = referenceExpression;
|
||||
this.qualifier = qualifier;
|
||||
this.columnExpression = columnExpression;
|
||||
this.referenceExpression = qualifier == null
|
||||
? columnExpression
|
||||
: qualifier + "." + columnExpression;
|
||||
this.jdbcMapping = jdbcMapping;
|
||||
}
|
||||
|
||||
|
@ -59,6 +52,14 @@ public class ColumnReference implements Expression {
|
|||
this( tableReference.getIdentificationVariable(), columnExpression, jdbcMapping, sessionFactory );
|
||||
}
|
||||
|
||||
public String getQualifier() {
|
||||
return qualifier;
|
||||
}
|
||||
|
||||
public String getColumnExpression() {
|
||||
return columnExpression;
|
||||
}
|
||||
|
||||
public String getExpressionText() {
|
||||
return referenceExpression;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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.exec.internal;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcDelete;
|
||||
import org.hibernate.sql.exec.spi.JdbcMutation;
|
||||
import org.hibernate.sql.exec.spi.JdbcMutationExecutor;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class StandardJdbcMutationExecutor implements JdbcMutationExecutor {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final StandardJdbcMutationExecutor INSTANCE = new StandardJdbcMutationExecutor();
|
||||
|
||||
@Override
|
||||
public int execute(
|
||||
JdbcMutation jdbcMutation,
|
||||
JdbcParameterBindings jdbcParameterBindings,
|
||||
Function<String, PreparedStatement> statementCreator,
|
||||
BiConsumer<Integer, PreparedStatement> expectationCheck,
|
||||
ExecutionContext executionContext) {
|
||||
final LogicalConnectionImplementor logicalConnection = executionContext.getSession()
|
||||
.getJdbcCoordinator()
|
||||
.getLogicalConnection();
|
||||
|
||||
final JdbcServices jdbcServices = executionContext.getSession().getFactory().getServiceRegistry().getService(
|
||||
JdbcServices.class );
|
||||
|
||||
final String sql = jdbcMutation.getSql();
|
||||
try {
|
||||
// prepare the query
|
||||
final PreparedStatement preparedStatement = statementCreator.apply( sql );
|
||||
|
||||
try {
|
||||
if ( executionContext.getQueryOptions().getTimeout() != null ) {
|
||||
preparedStatement.setQueryTimeout( executionContext.getQueryOptions().getTimeout() );
|
||||
}
|
||||
|
||||
// bind parameters
|
||||
// todo : validate that all query parameters were bound?
|
||||
int paramBindingPosition = 1;
|
||||
for ( JdbcParameterBinder parameterBinder : jdbcMutation.getParameterBinders() ) {
|
||||
parameterBinder.bindParameterValue(
|
||||
preparedStatement,
|
||||
paramBindingPosition++,
|
||||
jdbcParameterBindings,
|
||||
executionContext
|
||||
);
|
||||
}
|
||||
int rows = preparedStatement.executeUpdate();
|
||||
expectationCheck.accept( rows, preparedStatement );
|
||||
return rows;
|
||||
}
|
||||
finally {
|
||||
logicalConnection.getResourceRegistry().release( preparedStatement );
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw jdbcServices.getSqlExceptionHelper().convert(
|
||||
e,
|
||||
"JDBC exception executing SQL [" + sql + "]"
|
||||
);
|
||||
}
|
||||
finally {
|
||||
executionContext.afterStatement( logicalConnection );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,24 +7,16 @@
|
|||
package org.hibernate.sql.exec.spi;
|
||||
|
||||
import org.hibernate.engine.spi.CollectionKey;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ExecutionContext {
|
||||
default Object resolveEntityInstance(EntityKey entityKey, boolean eager) {
|
||||
return StandardEntityInstanceResolver.resolveEntityInstance(
|
||||
entityKey,
|
||||
eager,
|
||||
getSession()
|
||||
);
|
||||
}
|
||||
|
||||
SharedSessionContractImplementor getSession();
|
||||
|
||||
QueryOptions getQueryOptions();
|
||||
|
@ -43,4 +35,12 @@ public interface ExecutionContext {
|
|||
default CollectionKey getCollectionKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to allow delaying calls to {@link LogicalConnectionImplementor#afterStatement()}.
|
||||
* Mainly used in the case of batching and multi-table mutations
|
||||
*/
|
||||
default void afterStatement(LogicalConnectionImplementor logicalConnection) {
|
||||
logicalConnection.afterStatement();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* 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.exec.spi;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface JdbcDelete extends JdbcMutation {
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* 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.exec.spi;
|
||||
|
||||
/**
|
||||
* Classification of JdbcDelete and JdbcUpdate operations
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface JdbcMutation extends JdbcOperation {
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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.exec.spi;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Executor for JdbcDelete and JdbcUpdate operations
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface JdbcMutationExecutor {
|
||||
/**
|
||||
* Perform the execution
|
||||
*/
|
||||
int execute(
|
||||
JdbcMutation jdbcMutation,
|
||||
JdbcParameterBindings jdbcParameterBindings,
|
||||
Function<String, PreparedStatement> statementCreator,
|
||||
BiConsumer<Integer, PreparedStatement> expectationCheck,
|
||||
ExecutionContext executionContext);
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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.orm.test.query.hql;
|
||||
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
|
||||
|
||||
import org.hibernate.testing.orm.domain.StandardDomainModel;
|
||||
import org.hibernate.testing.orm.domain.gambit.BasicEntity;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
@DomainModel( standardModels = StandardDomainModel.GAMBIT )
|
||||
@ServiceRegistry
|
||||
@SessionFactory( exportSchema = true )
|
||||
public class MutationTests {
|
||||
@Test
|
||||
public void testSimpleDeleteTranslation(SessionFactoryScope scope) {
|
||||
final SqmDeleteStatement sqmDelete = (SqmDeleteStatement) scope.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getHqlTranslator()
|
||||
.translate( "delete BasicEntity" );
|
||||
|
||||
assertThat( sqmDelete, notNullValue() );
|
||||
assertThat( sqmDelete.getTarget().getEntityName(), is( BasicEntity.class.getName() ) );
|
||||
assertThat( sqmDelete.getRestriction(), nullValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleRestrictedDeleteTranslation(SessionFactoryScope scope) {
|
||||
final SqmDeleteStatement sqmDelete = (SqmDeleteStatement) scope.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getHqlTranslator()
|
||||
.translate( "delete BasicEntity where data = 'abc'" );
|
||||
|
||||
assertThat( sqmDelete, notNullValue() );
|
||||
assertThat( sqmDelete.getTarget().getEntityName(), is( BasicEntity.class.getName() ) );
|
||||
assertThat( sqmDelete.getRestriction(), notNullValue() );
|
||||
assertThat( sqmDelete.getRestriction(), instanceOf( SqmComparisonPredicate.class ) );
|
||||
}
|
||||
}
|
|
@ -53,7 +53,7 @@ public abstract class BaseSqmUnitTest
|
|||
}
|
||||
|
||||
public static SqmSelectStatement interpretSelect(String hql, SessionFactoryImplementor sessionFactory) {
|
||||
return (SqmSelectStatement) sessionFactory.getQueryEngine().getHqlTranslator().interpret( hql );
|
||||
return (SqmSelectStatement) sessionFactory.getQueryEngine().getHqlTranslator().translate( hql );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,7 +16,7 @@ import org.hibernate.query.NavigablePath;
|
|||
import org.hibernate.query.hql.spi.HqlQueryImplementor;
|
||||
import org.hibernate.query.spi.QueryImplementor;
|
||||
import org.hibernate.query.sqm.internal.QuerySqmImpl;
|
||||
import org.hibernate.query.sqm.sql.internal.SqmSelectInterpretation;
|
||||
import org.hibernate.query.sqm.sql.SqmSelectInterpretation;
|
||||
import org.hibernate.query.sqm.sql.internal.StandardSqmSelectToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
|
|
Loading…
Reference in New Issue