mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-03-03 08:19:15 +00:00
HHH-13715 - working support for "multi-table" HQL/Criteria UPDATE and DELETE queries;
basic working support for simple (non-multi-table) SQM UPDATE statements
This commit is contained in:
parent
eddd5b938b
commit
83a1eb5715
@ -1226,7 +1226,13 @@ public TableGroup createRootTableGroup(
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
||||
SqlAstCreationContext creationContext) {
|
||||
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() );
|
||||
final SqlAliasBase sqlAliasBase;
|
||||
if ( aliasBaseGenerator == null ) {
|
||||
sqlAliasBase = null;
|
||||
}
|
||||
else {
|
||||
sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() );
|
||||
}
|
||||
|
||||
final TableGroupBuilder builder = TableGroupBuilder.builder(
|
||||
navigablePath,
|
||||
|
@ -304,25 +304,26 @@ public SqmUpdateStatement visitUpdateStatement(HqlParser.UpdateStatementContext
|
||||
visitIdentificationVariableDef( ctx.identificationVariableDef() ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
|
||||
final SqmUpdateStatement<?> updateStatement = new SqmUpdateStatement<>( root, creationContext.getNodeBuilder() );
|
||||
|
||||
parameterCollector = updateStatement;
|
||||
final SqmDmlCreationProcessingState processingState = new SqmDmlCreationProcessingState(
|
||||
updateStatement,
|
||||
this
|
||||
);
|
||||
processingStateStack.push( processingState );
|
||||
processingState.getPathRegistry().register( root );
|
||||
|
||||
processingStateStack.push( new SqmDmlCreationProcessingState( updateStatement, this ) );
|
||||
try {
|
||||
updateStatement.getWhereClause().setPredicate(
|
||||
(SqmPredicate) ctx.whereClause().predicate().accept( this )
|
||||
);
|
||||
|
||||
for ( HqlParser.AssignmentContext assignmentContext : ctx.setClause().assignment() ) {
|
||||
final SqmPath stateField = consumeDomainPath( assignmentContext.dotIdentifierSequence() );
|
||||
// todo : validate "state field" expression
|
||||
updateStatement.getSetClause().addAssignment(
|
||||
stateField,
|
||||
updateStatement.applyAssignment(
|
||||
consumeDomainPath( assignmentContext.dotIdentifierSequence() ),
|
||||
(SqmExpression) assignmentContext.expression().accept( this )
|
||||
);
|
||||
}
|
||||
|
||||
updateStatement.applyPredicate( visitWhereClause( ctx.whereClause() ) );
|
||||
|
||||
return updateStatement;
|
||||
}
|
||||
finally {
|
||||
@ -1055,7 +1056,12 @@ protected void consumeJpaCollectionJoin(
|
||||
|
||||
@Override
|
||||
public SqmPredicate visitWhereClause(HqlParser.WhereClauseContext ctx) {
|
||||
if ( ctx == null || ctx.predicate() == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (SqmPredicate) ctx.predicate().accept( this );
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -33,6 +33,7 @@
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelection;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameter;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
@ -59,6 +60,7 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
||||
private final RowTransformer<R> rowTransformer;
|
||||
|
||||
private JdbcSelect jdbcSelect;
|
||||
private FromClauseAccess tableGroupAccess;
|
||||
private Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamsXref;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
@ -172,6 +174,8 @@ public List<R> performList(ExecutionContext executionContext) {
|
||||
sessionFactory
|
||||
);
|
||||
|
||||
tableGroupAccess = sqmConverter.getFromClauseAccess();
|
||||
|
||||
final SqmSelectTranslation interpretation = sqmConverter.translate( sqm );
|
||||
|
||||
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
|
||||
@ -192,8 +196,8 @@ public List<R> performList(ExecutionContext executionContext) {
|
||||
executionContext.getQueryParameterBindings(),
|
||||
domainParameterXref,
|
||||
jdbcParamsXref,
|
||||
// todo (6.0) : ugh. this one is important
|
||||
null,
|
||||
session.getFactory().getDomainModel(),
|
||||
tableGroupAccess::findTableGroup,
|
||||
session
|
||||
);
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
*/
|
||||
package org.hibernate.query.sqm.internal;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -21,9 +20,9 @@
|
||||
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.ast.spi.FromClauseAccess;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcDelete;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameter;
|
||||
@ -37,6 +36,7 @@ public class SimpleDeleteQueryPlan implements NonSelectQueryPlan {
|
||||
private final DomainParameterXref domainParameterXref;
|
||||
|
||||
private JdbcDelete jdbcDelete;
|
||||
private FromClauseAccess tableGroupAccess;
|
||||
private Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamsXref;
|
||||
|
||||
public SimpleDeleteQueryPlan(
|
||||
@ -65,6 +65,8 @@ public int executeUpdate(ExecutionContext executionContext) {
|
||||
|
||||
final SimpleSqmDeleteTranslation sqmInterpretation = translator.translate( sqmDelete );
|
||||
|
||||
tableGroupAccess = translator.getFromClauseAccess();
|
||||
|
||||
final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment();
|
||||
final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory();
|
||||
|
||||
@ -83,30 +85,18 @@ public int executeUpdate(ExecutionContext executionContext) {
|
||||
executionContext.getQueryParameterBindings(),
|
||||
domainParameterXref,
|
||||
jdbcParamsXref,
|
||||
// todo (6.0) : ugh. this one is important
|
||||
null,
|
||||
factory.getDomainModel(),
|
||||
tableGroupAccess::findTableGroup,
|
||||
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
|
||||
);
|
||||
}
|
||||
},
|
||||
sql -> executionContext.getSession()
|
||||
.getJdbcCoordinator()
|
||||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
(integer, preparedStatement) -> {},
|
||||
executionContext
|
||||
);
|
||||
|
@ -9,21 +9,23 @@
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
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.SimpleSqmDeleteTranslation;
|
||||
import org.hibernate.query.sqm.sql.SimpleSqmDeleteTranslator;
|
||||
import org.hibernate.query.sqm.sql.SimpleSqmUpdateTranslation;
|
||||
import org.hibernate.query.sqm.sql.SimpleSqmUpdateTranslator;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.SqlAstUpdateTranslator;
|
||||
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameter;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.JdbcUpdate;
|
||||
|
||||
/**
|
||||
@ -34,6 +36,7 @@ public class SimpleUpdateQueryPlan implements NonSelectQueryPlan {
|
||||
private final DomainParameterXref domainParameterXref;
|
||||
|
||||
private JdbcUpdate jdbcUpdate;
|
||||
private FromClauseAccess tableGroupAccess;
|
||||
private Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamsXref;
|
||||
|
||||
public SimpleUpdateQueryPlan(
|
||||
@ -62,9 +65,40 @@ public int executeUpdate(ExecutionContext executionContext) {
|
||||
|
||||
final SimpleSqmUpdateTranslation sqmInterpretation = translator.translate( sqmUpdate );
|
||||
|
||||
tableGroupAccess = translator.getFromClauseAccess();
|
||||
|
||||
this.jdbcParamsXref = SqmUtil.generateJdbcParamsXref(
|
||||
domainParameterXref,
|
||||
sqmInterpretation::getJdbcParamsBySqmParam
|
||||
);
|
||||
|
||||
final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment();
|
||||
final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory();
|
||||
|
||||
final SqlAstUpdateTranslator sqlAstTranslator = sqlAstTranslatorFactory.buildUpdateTranslator( factory );
|
||||
|
||||
jdbcUpdate = sqlAstTranslator.translate( sqmInterpretation.getSqlAst() );
|
||||
}
|
||||
|
||||
throw new NotYetImplementedFor6Exception( );
|
||||
|
||||
final JdbcParameterBindings jdbcParameterBindings = SqmUtil.createJdbcParameterBindings(
|
||||
executionContext.getQueryParameterBindings(),
|
||||
domainParameterXref,
|
||||
jdbcParamsXref,
|
||||
factory.getDomainModel(),
|
||||
tableGroupAccess::findTableGroup,
|
||||
executionContext.getSession()
|
||||
);
|
||||
|
||||
return jdbcServices.getJdbcUpdateExecutor().execute(
|
||||
jdbcUpdate,
|
||||
jdbcParameterBindings,
|
||||
sql -> executionContext.getSession()
|
||||
.getJdbcCoordinator()
|
||||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
(integer, preparedStatement) -> {},
|
||||
executionContext
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
package org.hibernate.query.sqm.internal;
|
||||
|
||||
import java.util.function.Function;
|
||||
import javax.persistence.metamodel.Bindable;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
@ -25,9 +26,9 @@
|
||||
import org.hibernate.metamodel.model.domain.internal.EntitySqmPathSource;
|
||||
import org.hibernate.metamodel.spi.DomainMetamodel;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.sqm.SqmExpressable;
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.tree.SqmTypedNode;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
@ -102,9 +103,10 @@ public static <J> SqmPathSource<J> resolveSqmPathSource(
|
||||
|
||||
public static MappingModelExpressable resolveMappingModelExpressable(
|
||||
SqmTypedNode<?> sqmNode,
|
||||
SqlAstCreationState creationState) {
|
||||
DomainMetamodel domainModel,
|
||||
Function<NavigablePath,TableGroup> tableGroupLocator) {
|
||||
if ( sqmNode instanceof SqmPath ) {
|
||||
return resolveSqmPath( (SqmPath) sqmNode, creationState );
|
||||
return resolveSqmPath( (SqmPath) sqmNode, domainModel, tableGroupLocator );
|
||||
}
|
||||
|
||||
final SqmExpressable<?> nodeType = sqmNode.getNodeType();
|
||||
@ -115,8 +117,10 @@ public static MappingModelExpressable resolveMappingModelExpressable(
|
||||
throw new NotYetImplementedFor6Exception( DomainModelHelper.class );
|
||||
}
|
||||
|
||||
private static ModelPart resolveSqmPath(SqmPath<?> sqmPath, SqlAstCreationState creationState) {
|
||||
final DomainMetamodel domainModel = creationState.getCreationContext().getDomainModel();
|
||||
private static ModelPart resolveSqmPath(
|
||||
SqmPath<?> sqmPath,
|
||||
DomainMetamodel domainModel,
|
||||
Function<NavigablePath,TableGroup> tableGroupLocator) {
|
||||
|
||||
if ( sqmPath instanceof SqmTreatedPath ) {
|
||||
final SqmTreatedPath treatedPath = (SqmTreatedPath) sqmPath;
|
||||
@ -133,7 +137,7 @@ private static ModelPart resolveSqmPath(SqmPath<?> sqmPath, SqlAstCreationState
|
||||
return container.findSubPart( sqmPath.getNavigablePath().getLocalName(), container );
|
||||
}
|
||||
|
||||
final TableGroup lhsTableGroup = creationState.getFromClauseAccess().findTableGroup( sqmPath.getLhs().getNavigablePath() );
|
||||
final TableGroup lhsTableGroup = tableGroupLocator.apply( sqmPath.getLhs().getNavigablePath() );
|
||||
return lhsTableGroup.getModelPart().findSubPart( sqmPath.getReferencedPathSource().getPathName(), null );
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
@ -21,7 +22,9 @@
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.metamodel.model.domain.AllowableParameterType;
|
||||
import org.hibernate.metamodel.spi.DomainMetamodel;
|
||||
import org.hibernate.query.IllegalQueryOperationException;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.spi.QueryParameterBinding;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||
@ -32,6 +35,7 @@
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameter;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBinding;
|
||||
@ -153,7 +157,8 @@ public static JdbcParameterBindings createJdbcParameterBindings(
|
||||
QueryParameterBindings domainParamBindings,
|
||||
DomainParameterXref domainParameterXref,
|
||||
Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamXref,
|
||||
SqlAstCreationState sqlAstCreationState,
|
||||
DomainMetamodel domainModel,
|
||||
Function<NavigablePath, TableGroup> tableGroupLocator,
|
||||
SharedSessionContractImplementor session) {
|
||||
final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl(
|
||||
domainParameterXref.getSqmParameterCount()
|
||||
@ -176,7 +181,11 @@ public static JdbcParameterBindings createJdbcParameterBindings(
|
||||
final List<JdbcParameter> jdbcParams = jdbcParamMap.get( sqmParameter );
|
||||
|
||||
if ( ! domainParamBinding.isBound() ) {
|
||||
final MappingModelExpressable mappingExpressable = SqmMappingModelHelper.resolveMappingModelExpressable( sqmParameter, sqlAstCreationState );
|
||||
final MappingModelExpressable mappingExpressable = SqmMappingModelHelper.resolveMappingModelExpressable(
|
||||
sqmParameter,
|
||||
domainModel,
|
||||
tableGroupLocator
|
||||
);
|
||||
mappingExpressable.visitJdbcTypes(
|
||||
new Consumer<JdbcMapping>() {
|
||||
int position = 0;
|
||||
|
@ -270,8 +270,8 @@ public static List<Object> selectMatchingIds(
|
||||
executionContext.getQueryParameterBindings(),
|
||||
domainParameterXref,
|
||||
jdbcParamsXref,
|
||||
// todo (6.0) : ugh. this one is important
|
||||
null,
|
||||
factory.getDomainModel(),
|
||||
selectConverter.getFromClauseAccess()::findTableGroup,
|
||||
executionContext.getSession()
|
||||
);
|
||||
|
||||
|
@ -256,7 +256,8 @@ protected int saveMatchingIdsIntoIdTable(ExecutionContext executionContext) {
|
||||
domainParameterXref,
|
||||
sqmIdSelectTranslation::getJdbcParamsBySqmParam
|
||||
),
|
||||
sqmTranslator,
|
||||
factory.getDomainModel(),
|
||||
sqmTranslator.getFromClauseAccess()::findTableGroup,
|
||||
executionContext.getSession()
|
||||
);
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.BinaryArithmeticOperator;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.UnaryArithmeticOperator;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBinding;
|
||||
@ -154,7 +155,7 @@
|
||||
*/
|
||||
public abstract class BaseSqmToSqlAstConverter
|
||||
extends BaseSemanticQueryWalker
|
||||
implements SqmToSqlAstConverter, JdbcParameterBySqmParameterAccess {
|
||||
implements SqmToSqlAstConverter, JdbcParameterBySqmParameterAccess, FromClauseAccess {
|
||||
|
||||
private static final Logger log = Logger.getLogger( BaseSqmToSqlAstConverter.class );
|
||||
|
||||
@ -200,6 +201,19 @@ protected Stack<SqlAstProcessingState> getProcessingStateStack() {
|
||||
return processingStateStack;
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// FromClauseAccess
|
||||
|
||||
@Override
|
||||
public TableGroup findTableGroup(NavigablePath navigablePath) {
|
||||
return fromClauseIndex.findTableGroup( navigablePath );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerTableGroup(NavigablePath navigablePath, TableGroup tableGroup) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// SqlAstCreationState
|
||||
@ -748,7 +762,11 @@ public SqmPathInterpretation<?> visitPluralValuedPath(SqmPluralValuedSimplePath
|
||||
public Expression visitLiteral(SqmLiteral literal) {
|
||||
return new QueryLiteral(
|
||||
literal.getLiteralValue(),
|
||||
(BasicValuedMapping) SqmMappingModelHelper.resolveMappingModelExpressable( literal, this ),
|
||||
(BasicValuedMapping) SqmMappingModelHelper.resolveMappingModelExpressable(
|
||||
literal,
|
||||
getCreationContext().getDomainModel(),
|
||||
getFromClauseAccess()::findTableGroup
|
||||
),
|
||||
getCurrentClauseStack().getCurrent()
|
||||
);
|
||||
}
|
||||
@ -796,7 +814,11 @@ protected MappingModelExpressable<?> determineValueMapping(SqmExpression<?> sqmE
|
||||
|
||||
if ( sqmExpression instanceof SqmPath ) {
|
||||
log.debugf( "Determining mapping-model type for SqmPath : %s ", sqmExpression );
|
||||
return SqmMappingModelHelper.resolveMappingModelExpressable( sqmExpression, this );
|
||||
return SqmMappingModelHelper.resolveMappingModelExpressable(
|
||||
sqmExpression,
|
||||
getCreationContext().getDomainModel(),
|
||||
getFromClauseAccess()::findTableGroup
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -856,7 +878,7 @@ protected MappingModelExpressable<?> determineValueMapping(SqmParameter<?> sqmPa
|
||||
throw new ConversionException( "Could not determine ValueMapping for SqmParameter: " + sqmParameter );
|
||||
}
|
||||
|
||||
private final Stack<Supplier<MappingModelExpressable>> inferableTypeAccessStack = new StandardStack<>(
|
||||
protected final Stack<Supplier<MappingModelExpressable>> inferableTypeAccessStack = new StandardStack<>(
|
||||
() -> null
|
||||
);
|
||||
|
||||
|
@ -9,11 +9,12 @@
|
||||
import org.hibernate.query.sqm.spi.JdbcParameterBySqmParameterAccess;
|
||||
import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SqmSelectTranslator extends SqmToSqlAstConverter, JdbcParameterBySqmParameterAccess, SqmTranslator {
|
||||
public interface SqmSelectTranslator extends SqmToSqlAstConverter, FromClauseAccess, JdbcParameterBySqmParameterAccess, SqmTranslator {
|
||||
SqmSelectTranslation translate(SqmSelectStatement sqmStatement);
|
||||
SqmQuerySpecTranslation translate(SqmQuerySpec sqmQuerySpec);
|
||||
}
|
||||
|
@ -36,7 +36,11 @@ public static <T> SqmTupleInterpretation<T> from(
|
||||
return new SqmTupleInterpretation<>(
|
||||
sqmTuple,
|
||||
groupedSqlExpressions,
|
||||
SqmMappingModelHelper.resolveMappingModelExpressable( sqmTuple, sqlAstCreationState )
|
||||
SqmMappingModelHelper.resolveMappingModelExpressable(
|
||||
sqmTuple,
|
||||
sqlAstCreationState.getCreationContext().getDomainModel(),
|
||||
sqlAstCreationState.getFromClauseAccess()::findTableGroup
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -8,9 +8,12 @@
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.metamodel.spi.DomainMetamodel;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
@ -20,22 +23,30 @@
|
||||
import org.hibernate.query.sqm.sql.SimpleSqmUpdateTranslation;
|
||||
import org.hibernate.query.sqm.sql.SimpleSqmUpdateTranslator;
|
||||
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmNamedParameter;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
|
||||
import org.hibernate.query.sqm.tree.update.SqmAssignment;
|
||||
import org.hibernate.query.sqm.tree.update.SqmSetClause;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.JoinType;
|
||||
import org.hibernate.sql.ast.SqlTreeCreationLogger;
|
||||
import org.hibernate.sql.ast.spi.SqlAliasBase;
|
||||
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||
import org.hibernate.sql.ast.spi.SqlAstProcessingState;
|
||||
import org.hibernate.sql.ast.spi.SqlAstTreeHelper;
|
||||
import org.hibernate.sql.ast.tree.cte.CteStatement;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
import org.hibernate.sql.ast.tree.update.Assignment;
|
||||
import org.hibernate.sql.ast.tree.update.UpdateStatement;
|
||||
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameter;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
@ -53,6 +64,11 @@ public StandardSqmUpdateTranslator(
|
||||
super( creationContext, queryOptions, domainParameterXref, domainParameterBindings );
|
||||
}
|
||||
|
||||
@Override
|
||||
public CteStatement translate(SqmCteStatement sqmCte) {
|
||||
return visitCteStatement( sqmCte );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleSqmUpdateTranslation translate(SqmUpdateStatement sqmUpdate) {
|
||||
final UpdateStatement sqlUpdateAst = visitUpdateStatement( sqmUpdate );
|
||||
@ -83,17 +99,20 @@ public UpdateStatement visitUpdateStatement(SqmUpdateStatement sqmStatement) {
|
||||
null,
|
||||
JoinType.LEFT,
|
||||
LockMode.WRITE,
|
||||
stem -> getSqlAliasBaseGenerator().createSqlAliasBase( stem ),
|
||||
getSqlAliasBaseGenerator(),
|
||||
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" );
|
||||
}
|
||||
|
||||
getFromClauseIndex().registerTableGroup( rootPath, rootTableGroup );
|
||||
|
||||
final List<Assignment> assignments = visitSetClause( sqmStatement.getSetClause() );
|
||||
|
||||
Predicate suppliedPredicate = null;
|
||||
final SqmWhereClause whereClause = sqmStatement.getWhereClause();
|
||||
if ( whereClause != null && whereClause.getPredicate() != null ) {
|
||||
@ -108,7 +127,7 @@ public UpdateStatement visitUpdateStatement(SqmUpdateStatement sqmStatement) {
|
||||
|
||||
return new UpdateStatement(
|
||||
rootTableGroup.getPrimaryTableReference(),
|
||||
visitSetClause( sqmStatement.getSetClause() ),
|
||||
assignments,
|
||||
SqlAstTreeHelper.combinePredicates( suppliedPredicate, additionalRestrictions )
|
||||
);
|
||||
}
|
||||
@ -117,35 +136,152 @@ public UpdateStatement visitUpdateStatement(SqmUpdateStatement sqmStatement) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SqlAliasBaseGenerator getSqlAliasBaseGenerator() {
|
||||
return SQL_ALIAS_BASE_GENERATOR;
|
||||
}
|
||||
|
||||
private static final SqlAliasBaseGenerator SQL_ALIAS_BASE_GENERATOR = new SqlAliasBaseGenerator() {
|
||||
private final SqlAliasBase sqlAliasBase = new SqlAliasBase() {
|
||||
@Override
|
||||
public String getAliasStem() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateNewAlias() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public SqlAliasBase createSqlAliasBase(String stem) {
|
||||
return sqlAliasBase;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public List<Assignment> visitSetClause(SqmSetClause setClause) {
|
||||
final List<Assignment> assignments = new ArrayList<>();
|
||||
|
||||
final List<ColumnReference> targetColumnReferences = new ArrayList<>();
|
||||
|
||||
for ( SqmAssignment sqmAssignment : setClause.getAssignments() ) {
|
||||
final SqmPathInterpretation assignedPathInterpretation = (SqmPathInterpretation) sqmAssignment.getTargetPath().accept( this );
|
||||
assignedPathInterpretation.getExpressionType().visitColumns(
|
||||
(columnExpression, containingTableExpression, jdbcMapping) -> {
|
||||
final JdbcParameter jdbcParameter = new JdbcParameterImpl( jdbcMapping );
|
||||
assignments.add(
|
||||
new Assignment(
|
||||
new ColumnReference(
|
||||
containingTableExpression,
|
||||
columnExpression,
|
||||
jdbcMapping,
|
||||
getCreationContext().getSessionFactory()
|
||||
),
|
||||
jdbcParameter
|
||||
)
|
||||
);
|
||||
getProcessingStateStack().push(
|
||||
new SqlAstProcessingStateImpl(
|
||||
getProcessingStateStack().getCurrent(),
|
||||
this,
|
||||
getCurrentClauseStack()::getCurrent
|
||||
) {
|
||||
@Override
|
||||
public Expression resolveSqlExpression(
|
||||
String key,
|
||||
Function<SqlAstProcessingState, Expression> creator) {
|
||||
final Expression expression = getParentState().getSqlExpressionResolver().resolveSqlExpression( key, creator );
|
||||
assert expression instanceof ColumnReference;
|
||||
|
||||
targetColumnReferences.add( (ColumnReference) expression );
|
||||
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
final SqmPathInterpretation assignedPathInterpretation;
|
||||
try {
|
||||
assignedPathInterpretation = (SqmPathInterpretation) sqmAssignment.getTargetPath().accept( this );
|
||||
}
|
||||
finally {
|
||||
getProcessingStateStack().pop();
|
||||
}
|
||||
|
||||
inferableTypeAccessStack.push( assignedPathInterpretation::getExpressionType );
|
||||
|
||||
final List<ColumnReference> valueColumnReferences = new ArrayList<>();
|
||||
getProcessingStateStack().push(
|
||||
new SqlAstProcessingStateImpl(
|
||||
getProcessingStateStack().getCurrent(),
|
||||
this,
|
||||
getCurrentClauseStack()::getCurrent
|
||||
) {
|
||||
@Override
|
||||
public Expression resolveSqlExpression(
|
||||
String key,
|
||||
Function<SqlAstProcessingState, Expression> creator) {
|
||||
final Expression expression = getParentState().getSqlExpressionResolver().resolveSqlExpression( key, creator );
|
||||
assert expression instanceof ColumnReference;
|
||||
|
||||
valueColumnReferences.add( (ColumnReference) expression );
|
||||
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
|
||||
if ( sqmAssignment.getValue() instanceof SqmParameter ) {
|
||||
final SqmParameter sqmParameter = (SqmParameter) sqmAssignment.getValue();
|
||||
final List<JdbcParameter> jdbcParametersForSqm = new ArrayList<>();
|
||||
|
||||
// create one JdbcParameter for each column in the assigned path
|
||||
assignedPathInterpretation.getExpressionType().visitColumns(
|
||||
(columnExpression, containingTableExpression, jdbcMapping) -> {
|
||||
final JdbcParameter jdbcParameter = new JdbcParameterImpl( jdbcMapping );
|
||||
jdbcParametersForSqm.add( jdbcParameter );
|
||||
assignments.add(
|
||||
new Assignment(
|
||||
new ColumnReference(
|
||||
// we do not want a qualifier (table alias) here
|
||||
(String) null,
|
||||
columnExpression,
|
||||
jdbcMapping,
|
||||
getCreationContext().getSessionFactory()
|
||||
),
|
||||
jdbcParameter
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
getJdbcParamsBySqmParam().put( sqmParameter, jdbcParametersForSqm );
|
||||
}
|
||||
else {
|
||||
final DomainMetamodel domainModel = getCreationContext().getDomainModel();
|
||||
final TypeConfiguration typeConfiguration = domainModel.getTypeConfiguration();
|
||||
|
||||
final Expression valueExpression = (Expression) sqmAssignment.getValue().accept( this );
|
||||
|
||||
final int valueExprJdbcCount = valueExpression.getExpressionType().getJdbcTypeCount( typeConfiguration );
|
||||
final int assignedPathJdbcCount = assignedPathInterpretation.getExpressionType().getJdbcTypeCount( typeConfiguration );
|
||||
|
||||
if ( valueExprJdbcCount != assignedPathJdbcCount ) {
|
||||
SqlTreeCreationLogger.LOGGER.debugf(
|
||||
"JDBC type count does not match in UPDATE assignment between the assigned-path and the assigned-value; " +
|
||||
"this will likely lead to problems executing the query"
|
||||
);
|
||||
}
|
||||
|
||||
assert assignedPathJdbcCount == valueExprJdbcCount;
|
||||
|
||||
if ( valueExpression instanceof ColumnReference ) {
|
||||
assert valueExprJdbcCount == 1;
|
||||
|
||||
assignments.add( new Assignment( (ColumnReference) valueExpression, valueExpression ) );
|
||||
}
|
||||
else {
|
||||
throw new NotYetImplementedFor6Exception( "Support for composite valued assignments in an UPDATE query is not yet implemented" );
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
getProcessingStateStack().pop();
|
||||
inferableTypeAccessStack.pop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return assignments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CteStatement translate(SqmCteStatement sqmCte) {
|
||||
return visitCteStatement( sqmCte );
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,8 @@
|
||||
import org.hibernate.query.sqm.tree.AbstractSqmDmlStatement;
|
||||
import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement;
|
||||
import org.hibernate.query.sqm.tree.cte.SqmCteConsumer;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
||||
import org.hibernate.query.sqm.tree.from.SqmRoot;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
|
||||
@ -156,4 +158,11 @@ public JpaPredicate getRestriction() {
|
||||
public <X> X accept(SemanticQueryWalker<X> walker) {
|
||||
return walker.visitUpdateStatement( this );
|
||||
}
|
||||
|
||||
public void applyAssignment(SqmPath targetPath, SqmExpression value) {
|
||||
if ( setClause == null ) {
|
||||
setClause = new SqmSetClause();
|
||||
}
|
||||
setClause.addAssignment( new SqmAssignment( targetPath, value ) );
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
package org.hibernate.sql.ast;
|
||||
|
||||
import org.hibernate.sql.ast.spi.SqlAstToJdbcOperationConverter;
|
||||
import org.hibernate.sql.ast.spi.SqlSelectAstWalker;
|
||||
import org.hibernate.sql.ast.spi.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.tree.cte.CteStatement;
|
||||
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
|
||||
import org.hibernate.sql.exec.spi.JdbcDelete;
|
||||
@ -15,8 +15,9 @@
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SqlAstDeleteTranslator extends SqlSelectAstWalker, SqlAstToJdbcOperationConverter {
|
||||
public interface SqlAstDeleteTranslator extends SqlAstWalker, SqlAstToJdbcOperationConverter {
|
||||
JdbcDelete translate(DeleteStatement sqlAst);
|
||||
|
||||
@Override
|
||||
JdbcDelete translate(CteStatement cteStatement);
|
||||
}
|
||||
|
@ -25,9 +25,11 @@ public interface SqlAstTranslatorFactory {
|
||||
SqlAstDeleteTranslator buildDeleteTranslator(SessionFactoryImplementor sessionFactory);
|
||||
|
||||
/**
|
||||
* Builds a single-use delete translator
|
||||
* Builds a single-use insert-select translator
|
||||
*/
|
||||
SqlAstInsertSelectTranslator buildInsertTranslator(SessionFactoryImplementor sessionFactory);
|
||||
|
||||
// todo (6.0) : update, insert, etc
|
||||
SqlAstUpdateTranslator buildUpdateTranslator(SessionFactoryImplementor sessionFactory);
|
||||
|
||||
// todo (6.0) : CTE
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.tree.cte.CteStatement;
|
||||
import org.hibernate.sql.ast.tree.update.UpdateStatement;
|
||||
import org.hibernate.sql.exec.spi.JdbcUpdate;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SqlAstUpdateTranslator extends SqlAstWalker, SqlAstToJdbcOperationConverter {
|
||||
JdbcUpdate translate(UpdateStatement sqlAst);
|
||||
|
||||
@Override
|
||||
JdbcUpdate translate(CteStatement cteStatement);
|
||||
}
|
@ -397,7 +397,11 @@ public void visitTableReferenceJoin(TableReferenceJoin tableReferenceJoin) {
|
||||
|
||||
@Override
|
||||
public void visitColumnReference(ColumnReference columnReference) {
|
||||
appendSql( columnReference.renderSqlFragment( getSessionFactory() ) );
|
||||
if ( columnReference.getQualifier() != null ) {
|
||||
appendSql( columnReference.getQualifier() );
|
||||
appendSql( "." );
|
||||
}
|
||||
appendSql( columnReference.getColumnExpression() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -6,12 +6,12 @@
|
||||
*/
|
||||
package org.hibernate.sql.ast.spi;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.sql.ast.SqlAstDeleteTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstInsertSelectTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.SqlAstSelectTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.SqlAstUpdateTranslator;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
@ -31,4 +31,9 @@ public SqlAstDeleteTranslator buildDeleteTranslator(SessionFactoryImplementor se
|
||||
public SqlAstInsertSelectTranslator buildInsertTranslator(SessionFactoryImplementor sessionFactory) {
|
||||
return new StandardSqlAstInsertSelectTranslator( sessionFactory );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlAstUpdateTranslator buildUpdateTranslator(SessionFactoryImplementor sessionFactory) {
|
||||
return new StandardSqlAstUpdateTranslator( sessionFactory );
|
||||
}
|
||||
}
|
||||
|
@ -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.ast.spi;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.sql.ast.SqlAstUpdateTranslator;
|
||||
import org.hibernate.sql.ast.tree.cte.CteStatement;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.update.Assignment;
|
||||
import org.hibernate.sql.ast.tree.update.UpdateStatement;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
|
||||
import org.hibernate.sql.exec.spi.JdbcUpdate;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class StandardSqlAstUpdateTranslator
|
||||
extends AbstractSqlAstToJdbcOperationConverter
|
||||
implements SqlAstUpdateTranslator {
|
||||
public StandardSqlAstUpdateTranslator(SessionFactoryImplementor sessionFactory) {
|
||||
super( sessionFactory );
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcUpdate translate(UpdateStatement sqlAst) {
|
||||
appendSql( "update " );
|
||||
appendSql( sqlAst.getTargetTable().getTableExpression() );
|
||||
|
||||
appendSql( " set " );
|
||||
boolean firstPass = true;
|
||||
for ( int i = 0; i < sqlAst.getAssignments().size(); i++ ) {
|
||||
if ( firstPass ) {
|
||||
firstPass = false;
|
||||
}
|
||||
else {
|
||||
appendSql( ", " );
|
||||
}
|
||||
|
||||
final Assignment assignment = sqlAst.getAssignments().get( i );
|
||||
assignment.getColumnReference().accept( this );
|
||||
appendSql( " = " );
|
||||
assignment.getAssignedValue().accept( this );
|
||||
}
|
||||
|
||||
if ( sqlAst.getRestriction() != null ) {
|
||||
appendSql( " where " );
|
||||
sqlAst.getRestriction().accept( this );
|
||||
}
|
||||
|
||||
return new JdbcUpdate() {
|
||||
@Override
|
||||
public String getSql() {
|
||||
return StandardSqlAstUpdateTranslator.this.getSql();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JdbcParameterBinder> getParameterBinders() {
|
||||
return StandardSqlAstUpdateTranslator.this.getParameterBinders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAffectedTableNames() {
|
||||
return StandardSqlAstUpdateTranslator.this.getAffectedTableNames();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitColumnReference(ColumnReference columnReference) {
|
||||
super.visitColumnReference( columnReference );
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcUpdate translate(CteStatement cteStatement) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@
|
||||
import java.util.Objects;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.sql.ast.spi.SqlAstWalker;
|
||||
@ -36,11 +37,11 @@ public ColumnReference(
|
||||
String columnExpression,
|
||||
JdbcMapping jdbcMapping,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
this.qualifier = qualifier;
|
||||
this.qualifier = StringHelper.nullIfEmpty( qualifier );
|
||||
this.columnExpression = columnExpression;
|
||||
this.referenceExpression = qualifier == null
|
||||
this.referenceExpression = this.qualifier == null
|
||||
? columnExpression
|
||||
: qualifier + "." + columnExpression;
|
||||
: this.qualifier + "." + columnExpression;
|
||||
this.jdbcMapping = jdbcMapping;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,303 @@
|
||||
/*
|
||||
* 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.sql.exec;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
|
||||
import org.hibernate.orm.test.metamodel.mapping.SecondaryTableTests;
|
||||
import org.hibernate.orm.test.metamodel.mapping.inheritance.joined.JoinedInheritanceTest;
|
||||
|
||||
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.FailureExpected;
|
||||
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.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
@DomainModel(
|
||||
standardModels = StandardDomainModel.GAMBIT
|
||||
// standardModels = StandardDomainModel.GAMBIT,
|
||||
// annotatedClasses = {
|
||||
// SecondaryTableTests.SimpleEntityWithSecondaryTables.class,
|
||||
// JoinedInheritanceTest.Customer.class,
|
||||
// JoinedInheritanceTest.DomesticCustomer.class,
|
||||
// JoinedInheritanceTest.ForeignCustomer.class
|
||||
// }
|
||||
)
|
||||
@ServiceRegistry
|
||||
@SessionFactory( exportSchema = true )
|
||||
public class HqlUpdateExecutionTests {
|
||||
@Test
|
||||
public void testSimpleUpdate(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> session.createQuery( "update BasicEntity set data = :p" )
|
||||
.setParameter( "p", "xyz" )
|
||||
.executeUpdate()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleUpdateWithData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.save( new BasicEntity( 1, "abc" ) );
|
||||
session.save( new BasicEntity( 2, "def" ) );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final int rows = session.createQuery( "update BasicEntity set data = :p" )
|
||||
.setParameter( "p", "xyz" )
|
||||
.executeUpdate();
|
||||
assertThat( rows, is( 2 ) );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final BasicEntity basicEntity = session.get( BasicEntity.class, 1 );
|
||||
assertThat( basicEntity.getData(), is( "xyz" ) );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final int rows = session.createQuery( "delete BasicEntity" ).executeUpdate();
|
||||
assertThat( rows, is( 2 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleRestrictedUpdate(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> session.createQuery( "update BasicEntity set data = :p where data = :filter" )
|
||||
.setParameter( "p", "xyz" )
|
||||
.setParameter( "filter", "abc" )
|
||||
.executeUpdate()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleRestrictedUpdateWithData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.save( new BasicEntity( 1, "abc" ) );
|
||||
session.save( new BasicEntity( 2, "def" ) );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final int rows = session.createQuery( "update BasicEntity set data = :val where data = :filter" )
|
||||
.setParameter( "val", "xyz" )
|
||||
.setParameter( "filter", "abc" )
|
||||
.executeUpdate();
|
||||
assertThat( rows, is( 1 ) );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final BasicEntity basicEntity = session.get( BasicEntity.class, 1 );
|
||||
assertThat( basicEntity.getData(), is( "xyz" ) );
|
||||
|
||||
final BasicEntity basicEntity2 = session.get( BasicEntity.class, 2 );
|
||||
assertThat( basicEntity2.getData(), is( "def" ) );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final int rows = session.createQuery( "delete BasicEntity" ).executeUpdate();
|
||||
assertThat( rows, is( 2 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void testSimpleMultiTableDelete(SessionFactoryScope scope) {
|
||||
// scope.inTransaction(
|
||||
// session -> session.createQuery( "delete SimpleEntityWithSecondaryTables" )
|
||||
// .executeUpdate()
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testSimpleMultiTableRestrictedDelete(SessionFactoryScope scope) {
|
||||
// scope.inTransaction(
|
||||
// session -> session.createQuery( "delete SimpleEntityWithSecondaryTables where data = :filter" )
|
||||
// .setParameter( "filter", "abc" )
|
||||
// .executeUpdate()
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// @FailureExpected( reason = "Saving of entities with secondary tables is broken atm" )
|
||||
// public void testSimpleMultiTableRestrictedDeleteResults(SessionFactoryScope scope) {
|
||||
// scope.inTransaction(
|
||||
// session -> {
|
||||
// session.save(
|
||||
// new SecondaryTableTests.SimpleEntityWithSecondaryTables(
|
||||
// 1,
|
||||
// "first",
|
||||
// Date.from( Instant.now() ),
|
||||
// "1 - cfdjdjvokfobkofbvovoijjbvoijofjdbiof"
|
||||
// )
|
||||
// );
|
||||
// session.save(
|
||||
// new SecondaryTableTests.SimpleEntityWithSecondaryTables(
|
||||
// 2,
|
||||
// "second",
|
||||
// Date.from( Instant.now() ),
|
||||
// "2 - s3o2rj9 fcojv9j gj9jfv943jv29j9j4"
|
||||
// )
|
||||
// );
|
||||
// session.save(
|
||||
// new SecondaryTableTests.SimpleEntityWithSecondaryTables(
|
||||
// 3,
|
||||
// "third",
|
||||
// Date.from( Instant.now() ),
|
||||
// "abc"
|
||||
// )
|
||||
// );
|
||||
// }
|
||||
// );
|
||||
// scope.inTransaction(
|
||||
// session -> {
|
||||
// final int rows = session.createQuery( "delete SimpleEntityWithSecondaryTables where data = :filter" )
|
||||
// .setParameter( "filter", "abc" )
|
||||
// .executeUpdate();
|
||||
// assertThat( rows, is ( 1 ) );
|
||||
// }
|
||||
// );
|
||||
// scope.inTransaction(
|
||||
// session -> session.createQuery( "delete SimpleEntityWithSecondaryTables" ).executeUpdate()
|
||||
// );
|
||||
// }
|
||||
//
|
||||
//
|
||||
// @Test
|
||||
// public void testJoinedSubclassRootDelete(SessionFactoryScope scope) {
|
||||
// scope.inTransaction(
|
||||
// session -> session.createQuery( "delete Customer" ).executeUpdate()
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testJoinedSubclassRootRestrictedDelete(SessionFactoryScope scope) {
|
||||
// scope.inTransaction(
|
||||
// session -> session.createQuery( "delete Customer where name = 'abc'" ).executeUpdate()
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testJoinedSubclassRootRestrictedDeleteResults(SessionFactoryScope scope) {
|
||||
// scope.inTransaction(
|
||||
// session -> {
|
||||
// session.save(
|
||||
// new JoinedInheritanceTest.ForeignCustomer( 1, "Adventures Abroad", "123" )
|
||||
// );
|
||||
// session.save(
|
||||
// new JoinedInheritanceTest.DomesticCustomer( 2, "Domestic Wonders", "456" )
|
||||
// );
|
||||
// }
|
||||
// );
|
||||
//
|
||||
// scope.inTransaction(
|
||||
// session -> {
|
||||
// final int rows = session.createQuery( "delete Customer where name = 'Adventures Abroad'" ).executeUpdate();
|
||||
// assertThat( rows, is( 1 ) );
|
||||
// }
|
||||
// );
|
||||
//
|
||||
// scope.inTransaction(
|
||||
// session -> {
|
||||
// final int rows = session.createQuery( "delete from Customer" ).executeUpdate();
|
||||
// assertThat( rows, is( 1 ) );
|
||||
// }
|
||||
// );
|
||||
//
|
||||
// scope.inTransaction(
|
||||
// session -> {
|
||||
// final int rows = session.createQuery( "delete from Customer" ).executeUpdate();
|
||||
// assertThat( rows, is( 0 ) );
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
//
|
||||
//
|
||||
// @Test
|
||||
// public void testJoinedSubclassLeafDelete(SessionFactoryScope scope) {
|
||||
// scope.inTransaction(
|
||||
// session -> session.createQuery( "delete ForeignCustomer" ).executeUpdate()
|
||||
// );
|
||||
// scope.inTransaction(
|
||||
// session -> session.createQuery( "delete DomesticCustomer" ).executeUpdate()
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testJoinedSubclassLeafRestrictedDelete(SessionFactoryScope scope) {
|
||||
// scope.inTransaction(
|
||||
// session -> session.createQuery( "delete ForeignCustomer where name = 'abc'" ).executeUpdate()
|
||||
// );
|
||||
// scope.inTransaction(
|
||||
// session -> session.createQuery( "delete DomesticCustomer where name = 'abc'" ).executeUpdate()
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testJoinedSubclassLeafRestrictedDeleteResult(SessionFactoryScope scope) {
|
||||
// scope.inTransaction(
|
||||
// session -> {
|
||||
// session.save(
|
||||
// new JoinedInheritanceTest.ForeignCustomer( 1, "Adventures Abroad", "123" )
|
||||
// );
|
||||
// session.save(
|
||||
// new JoinedInheritanceTest.DomesticCustomer( 2, "Domestic Wonders", "456" )
|
||||
// );
|
||||
// }
|
||||
// );
|
||||
//
|
||||
// scope.inTransaction(
|
||||
// session -> {
|
||||
// final int rows = session.createQuery( "delete ForeignCustomer where name = 'Adventures Abroad'" )
|
||||
// .executeUpdate();
|
||||
// assertThat( rows, is( 1 ) );
|
||||
// }
|
||||
// );
|
||||
//
|
||||
// scope.inTransaction(
|
||||
// session -> {
|
||||
// final int rows = session.createQuery( "delete DomesticCustomer where name = 'Domestic Wonders'" )
|
||||
// .executeUpdate();
|
||||
// assertThat( rows, is( 1 ) );
|
||||
// }
|
||||
// );
|
||||
//
|
||||
// scope.inTransaction(
|
||||
// session -> {
|
||||
// final int rows = session.createQuery( "delete Customer" )
|
||||
// .executeUpdate();
|
||||
// assertThat( rows, is( 0 ) );
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user