HHH-16103 - MERGE for optional table updates on SQL Server
This commit is contained in:
parent
5525b8d9b7
commit
e27dc5bc47
|
@ -4705,9 +4705,9 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
|
|||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MutationOperation} for an "upsert".
|
||||
* Create a {@link MutationOperation} for a updating an optional table
|
||||
*/
|
||||
public MutationOperation createUpsertOperation(
|
||||
public MutationOperation createOptionalTableUpdateOperation(
|
||||
EntityMutationTarget mutationTarget,
|
||||
OptionalTableUpdate optionalTableUpdate,
|
||||
SessionFactoryImplementor factory) {
|
||||
|
|
|
@ -872,11 +872,11 @@ public class H2Dialect extends Dialect {
|
|||
}
|
||||
|
||||
@Override
|
||||
public MutationOperation createUpsertOperation(
|
||||
public MutationOperation createOptionalTableUpdateOperation(
|
||||
EntityMutationTarget mutationTarget,
|
||||
OptionalTableUpdate optionalTableUpdate,
|
||||
SessionFactoryImplementor factory) {
|
||||
final H2SqlAstTranslator<?> translator = new H2SqlAstTranslator<>( factory, optionalTableUpdate );
|
||||
return translator.visitUpsert( optionalTableUpdate );
|
||||
return translator.createMergeOperation( optionalTableUpdate );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
import org.hibernate.query.sqm.ComparisonOperator;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.cte.CteContainer;
|
||||
|
@ -35,11 +34,7 @@ import org.hibernate.sql.ast.tree.predicate.LikePredicate;
|
|||
import org.hibernate.sql.ast.tree.select.QueryPart;
|
||||
import org.hibernate.sql.ast.tree.select.SelectClause;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperation;
|
||||
import org.hibernate.sql.model.MutationOperation;
|
||||
import org.hibernate.sql.model.ast.ColumnValueBinding;
|
||||
import org.hibernate.sql.model.internal.OptionalTableUpdate;
|
||||
import org.hibernate.sql.model.internal.TableInsertStandard;
|
||||
import org.hibernate.sql.model.jdbc.UpsertOperation;
|
||||
|
||||
import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpty;
|
||||
|
||||
|
@ -48,7 +43,7 @@ import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpt
|
|||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class H2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstTranslator<T> {
|
||||
public class H2SqlAstTranslator<T extends JdbcOperation> extends SqlAstTranslatorWithMerge<T> {
|
||||
|
||||
private boolean renderAsArray;
|
||||
|
||||
|
@ -311,148 +306,4 @@ public class H2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstT
|
|||
// Introduction of PERCENT support https://github.com/h2database/h2database/commit/f45913302e5f6ad149155a73763c0c59d8205849
|
||||
return getDialect().getVersion().isSameOrAfter( 1, 4, 198 );
|
||||
}
|
||||
|
||||
public MutationOperation visitUpsert(OptionalTableUpdate optionalTableUpdate) {
|
||||
// template:
|
||||
//
|
||||
// merge into [table] as t
|
||||
// using values([bindings]) as s ([column-names])
|
||||
// on t.[key] = s.[key]
|
||||
// when not matched
|
||||
// then insert ...
|
||||
// when matched
|
||||
// and s.[columns] is null
|
||||
// then delete
|
||||
// when matched
|
||||
// then update set ...
|
||||
|
||||
renderMergeInto( optionalTableUpdate );
|
||||
appendSql( " " );
|
||||
renderMergeUsing( optionalTableUpdate );
|
||||
appendSql( " " );
|
||||
renderMergeOn( optionalTableUpdate );
|
||||
appendSql( " " );
|
||||
renderMergeInsert( optionalTableUpdate );
|
||||
appendSql( " " );
|
||||
renderMergeDelete( optionalTableUpdate );
|
||||
appendSql( " " );
|
||||
renderMergeUpdate( optionalTableUpdate );
|
||||
|
||||
return new UpsertOperation(
|
||||
optionalTableUpdate.getMutatingTable().getTableMapping(),
|
||||
optionalTableUpdate.getMutationTarget(),
|
||||
getSql(),
|
||||
getParameterBinders()
|
||||
);
|
||||
}
|
||||
|
||||
private void renderMergeInto(OptionalTableUpdate optionalTableUpdate) {
|
||||
appendSql( "merge into " );
|
||||
appendSql( optionalTableUpdate.getMutatingTable().getTableName() );
|
||||
appendSql( " as t" );
|
||||
}
|
||||
|
||||
private void renderMergeUsing(OptionalTableUpdate optionalTableUpdate) {
|
||||
final List<ColumnValueBinding> valueBindings = optionalTableUpdate.getValueBindings();
|
||||
final List<ColumnValueBinding> keyBindings = optionalTableUpdate.getKeyBindings();
|
||||
|
||||
final StringBuilder columnList = new StringBuilder();
|
||||
|
||||
appendSql( "using values (" );
|
||||
|
||||
for ( int i = 0; i < keyBindings.size(); i++ ) {
|
||||
final ColumnValueBinding keyBinding = keyBindings.get( i );
|
||||
if ( i > 0 ) {
|
||||
appendSql( ", " );
|
||||
columnList.append( ", " );
|
||||
}
|
||||
columnList.append( keyBinding.getColumnReference().getColumnExpression() );
|
||||
renderCasted( keyBinding.getValueExpression() );
|
||||
}
|
||||
for ( int i = 0; i < valueBindings.size(); i++ ) {
|
||||
appendSql( ", " );
|
||||
columnList.append( ", " );
|
||||
final ColumnValueBinding valueBinding = valueBindings.get( i );
|
||||
columnList.append( valueBinding.getColumnReference().getColumnExpression() );
|
||||
renderCasted( valueBinding.getValueExpression() );
|
||||
}
|
||||
|
||||
appendSql( ") as s(" );
|
||||
appendSql( columnList.toString() );
|
||||
appendSql( ")" );
|
||||
}
|
||||
|
||||
private void renderMergeOn(OptionalTableUpdate optionalTableUpdate) {
|
||||
appendSql( "on " );
|
||||
|
||||
// todo : optimistic locks?
|
||||
|
||||
final List<ColumnValueBinding> keyBindings = optionalTableUpdate.getKeyBindings();
|
||||
for ( int i = 0; i < keyBindings.size(); i++ ) {
|
||||
final ColumnValueBinding keyBinding = keyBindings.get( i );
|
||||
if ( i > 0 ) {
|
||||
appendSql( " and " );
|
||||
}
|
||||
keyBinding.getColumnReference().appendReadExpression( this, "t" );
|
||||
appendSql( "=" );
|
||||
keyBinding.getColumnReference().appendReadExpression( this, "s" );
|
||||
}
|
||||
}
|
||||
|
||||
private void renderMergeInsert(OptionalTableUpdate optionalTableUpdate) {
|
||||
final List<ColumnValueBinding> valueBindings = optionalTableUpdate.getValueBindings();
|
||||
final List<ColumnValueBinding> keyBindings = optionalTableUpdate.getKeyBindings();
|
||||
|
||||
final StringBuilder valuesList = new StringBuilder();
|
||||
|
||||
appendSql( "when not matched then insert (" );
|
||||
for ( int i = 0; i < keyBindings.size(); i++ ) {
|
||||
if ( i > 0 ) {
|
||||
appendSql( ", " );
|
||||
valuesList.append( ", " );
|
||||
}
|
||||
final ColumnValueBinding keyBinding = keyBindings.get( i );
|
||||
appendSql( keyBinding.getColumnReference().getColumnExpression() );
|
||||
keyBinding.getColumnReference().appendReadExpression( "s", valuesList::append );
|
||||
}
|
||||
for ( int i = 0; i < valueBindings.size(); i++ ) {
|
||||
appendSql( ", " );
|
||||
valuesList.append( ", " );
|
||||
final ColumnValueBinding valueBinding = valueBindings.get( i );
|
||||
appendSql( valueBinding.getColumnReference().getColumnExpression() );
|
||||
valueBinding.getColumnReference().appendReadExpression( "s", valuesList::append );
|
||||
}
|
||||
|
||||
appendSql( ") values (" );
|
||||
appendSql( valuesList.toString() );
|
||||
appendSql( ")" );
|
||||
}
|
||||
|
||||
private void renderMergeDelete(OptionalTableUpdate optionalTableUpdate) {
|
||||
final List<ColumnValueBinding> valueBindings = optionalTableUpdate.getValueBindings();
|
||||
|
||||
appendSql( " when matched " );
|
||||
for ( int i = 0; i < valueBindings.size(); i++ ) {
|
||||
final ColumnValueBinding binding = valueBindings.get( i );
|
||||
appendSql( " and " );
|
||||
binding.getColumnReference().appendReadExpression( this, "s" );
|
||||
appendSql( " is null" );
|
||||
}
|
||||
appendSql( " then delete" );
|
||||
}
|
||||
|
||||
private void renderMergeUpdate(OptionalTableUpdate optionalTableUpdate) {
|
||||
final List<ColumnValueBinding> valueBindings = optionalTableUpdate.getValueBindings();
|
||||
|
||||
appendSql( " when matched then update set " );
|
||||
for ( int i = 0; i < valueBindings.size(); i++ ) {
|
||||
final ColumnValueBinding binding = valueBindings.get( i );
|
||||
if ( i > 0 ) {
|
||||
appendSql( ", " );
|
||||
}
|
||||
binding.getColumnReference().appendColumnForWrite( this, "t" );
|
||||
appendSql( "=" );
|
||||
binding.getColumnReference().appendColumnForWrite( this, "s" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.time.temporal.ChronoField;
|
|||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
|
@ -48,6 +49,7 @@ import org.hibernate.exception.LockTimeoutException;
|
|||
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
|
||||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.persister.entity.mutation.EntityMutationTarget;
|
||||
import org.hibernate.query.sqm.CastType;
|
||||
import org.hibernate.query.sqm.FetchClauseType;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
|
@ -61,6 +63,8 @@ import org.hibernate.sql.ast.spi.SqlAppender;
|
|||
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperation;
|
||||
import org.hibernate.sql.model.MutationOperation;
|
||||
import org.hibernate.sql.model.internal.OptionalTableUpdate;
|
||||
import org.hibernate.tool.schema.internal.StandardSequenceExporter;
|
||||
import org.hibernate.tool.schema.spi.Exporter;
|
||||
import org.hibernate.type.BasicType;
|
||||
|
@ -75,8 +79,6 @@ import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
|||
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
|
||||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.query.sqm.TemporalUnit.NANOSECOND;
|
||||
|
@ -1076,4 +1078,14 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
|||
// public String getEnableConstraintStatement(String tableName, String name) {
|
||||
// return "alter table " + tableName + " with check check constraint " + name;
|
||||
// }
|
||||
|
||||
|
||||
@Override
|
||||
public MutationOperation createOptionalTableUpdateOperation(
|
||||
EntityMutationTarget mutationTarget,
|
||||
OptionalTableUpdate optionalTableUpdate,
|
||||
SessionFactoryImplementor factory) {
|
||||
final SQLServerSqlAstTranslator<JdbcOperation> translator = new SQLServerSqlAstTranslator<>( factory, optionalTableUpdate );
|
||||
return translator.createMergeOperation( optionalTableUpdate );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ import org.hibernate.query.sqm.ComparisonOperator;
|
|||
import org.hibernate.query.sqm.FetchClauseType;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
|
||||
|
@ -36,6 +35,7 @@ import org.hibernate.sql.ast.tree.select.QuerySpec;
|
|||
import org.hibernate.sql.ast.tree.select.SelectClause;
|
||||
import org.hibernate.sql.ast.tree.select.SortSpecification;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperation;
|
||||
import org.hibernate.sql.model.internal.OptionalTableUpdate;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
|
||||
/**
|
||||
|
@ -43,7 +43,7 @@ import org.hibernate.type.SqlTypes;
|
|||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstTranslator<T> {
|
||||
public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends SqlAstTranslatorWithMerge<T> {
|
||||
|
||||
private static final String UNION_ALL = " union all ";
|
||||
|
||||
|
@ -440,4 +440,9 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends Abstract
|
|||
TOP_ONLY,
|
||||
EMULATED;
|
||||
}
|
||||
|
||||
protected void renderMergeStatement(OptionalTableUpdate optionalTableUpdate) {
|
||||
super.renderMergeStatement( optionalTableUpdate );
|
||||
appendSql( ";" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperation;
|
||||
import org.hibernate.sql.model.MutationOperation;
|
||||
import org.hibernate.sql.model.ast.ColumnValueBinding;
|
||||
import org.hibernate.sql.model.internal.OptionalTableUpdate;
|
||||
import org.hibernate.sql.model.jdbc.MergeOperation;
|
||||
|
||||
/**
|
||||
* Base SqlAstTranslator for translators which support a full insert/update/delete MERGE statement
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class SqlAstTranslatorWithMerge<T extends JdbcOperation> extends AbstractSqlAstTranslator<T> {
|
||||
public SqlAstTranslatorWithMerge(SessionFactoryImplementor sessionFactory, Statement statement) {
|
||||
super( sessionFactory, statement );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the MutationOperation for performing a MERGE
|
||||
*/
|
||||
public MutationOperation createMergeOperation(OptionalTableUpdate optionalTableUpdate) {
|
||||
renderMergeStatement( optionalTableUpdate );
|
||||
|
||||
return new MergeOperation(
|
||||
optionalTableUpdate.getMutatingTable().getTableMapping(),
|
||||
optionalTableUpdate.getMutationTarget(),
|
||||
getSql(),
|
||||
getParameterBinders()
|
||||
);
|
||||
}
|
||||
|
||||
protected void renderMergeStatement(OptionalTableUpdate optionalTableUpdate) {
|
||||
// template:
|
||||
//
|
||||
// merge into [table] as t
|
||||
// using values([bindings]) as s ([column-names])
|
||||
// on t.[key] = s.[key]
|
||||
// when not matched
|
||||
// then insert ...
|
||||
// when matched
|
||||
// and s.[columns] is null
|
||||
// then delete
|
||||
// when matched
|
||||
// then update set ...
|
||||
|
||||
renderMergeInto( optionalTableUpdate );
|
||||
appendSql( " " );
|
||||
renderMergeUsing( optionalTableUpdate );
|
||||
appendSql( " " );
|
||||
renderMergeOn( optionalTableUpdate );
|
||||
appendSql( " " );
|
||||
renderMergeInsert( optionalTableUpdate );
|
||||
appendSql( " " );
|
||||
renderMergeDelete( optionalTableUpdate );
|
||||
appendSql( " " );
|
||||
renderMergeUpdate( optionalTableUpdate );
|
||||
}
|
||||
|
||||
protected void renderMergeInto(OptionalTableUpdate optionalTableUpdate) {
|
||||
appendSql( "merge into " );
|
||||
appendSql( optionalTableUpdate.getMutatingTable().getTableName() );
|
||||
renderMergeTargetAlias();
|
||||
}
|
||||
|
||||
protected void renderMergeTargetAlias() {
|
||||
appendSql( " as t" );
|
||||
}
|
||||
|
||||
protected void renderMergeUsing(OptionalTableUpdate optionalTableUpdate) {
|
||||
appendSql( "using " );
|
||||
|
||||
renderMergeSource( optionalTableUpdate );
|
||||
}
|
||||
|
||||
protected boolean wrapMergeSourceExpression() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void renderMergeSource(OptionalTableUpdate optionalTableUpdate) {
|
||||
if ( wrapMergeSourceExpression() ) {
|
||||
appendSql( " (" );
|
||||
}
|
||||
|
||||
final List<ColumnValueBinding> valueBindings = optionalTableUpdate.getValueBindings();
|
||||
final List<ColumnValueBinding> keyBindings = optionalTableUpdate.getKeyBindings();
|
||||
|
||||
final StringBuilder columnList = new StringBuilder();
|
||||
|
||||
appendSql( " values (" );
|
||||
|
||||
for ( int i = 0; i < keyBindings.size(); i++ ) {
|
||||
final ColumnValueBinding keyBinding = keyBindings.get( i );
|
||||
if ( i > 0 ) {
|
||||
appendSql( ", " );
|
||||
columnList.append( ", " );
|
||||
}
|
||||
columnList.append( keyBinding.getColumnReference().getColumnExpression() );
|
||||
renderCasted( keyBinding.getValueExpression() );
|
||||
}
|
||||
for ( int i = 0; i < valueBindings.size(); i++ ) {
|
||||
appendSql( ", " );
|
||||
columnList.append( ", " );
|
||||
final ColumnValueBinding valueBinding = valueBindings.get( i );
|
||||
columnList.append( valueBinding.getColumnReference().getColumnExpression() );
|
||||
renderCasted( valueBinding.getValueExpression() );
|
||||
}
|
||||
|
||||
appendSql( ") " );
|
||||
|
||||
if ( wrapMergeSourceExpression() ) {
|
||||
appendSql( ") " );
|
||||
}
|
||||
|
||||
renderMergeSourceAlias();
|
||||
|
||||
appendSql( "(" );
|
||||
appendSql( columnList.toString() );
|
||||
appendSql( ")" );
|
||||
}
|
||||
|
||||
protected void renderMergeSourceAlias() {
|
||||
appendSql( " as s" );
|
||||
}
|
||||
|
||||
protected void renderMergeOn(OptionalTableUpdate optionalTableUpdate) {
|
||||
appendSql( "on (" );
|
||||
|
||||
final List<ColumnValueBinding> keyBindings = optionalTableUpdate.getKeyBindings();
|
||||
for ( int i = 0; i < keyBindings.size(); i++ ) {
|
||||
final ColumnValueBinding keyBinding = keyBindings.get( i );
|
||||
if ( i > 0 ) {
|
||||
appendSql( " and " );
|
||||
}
|
||||
keyBinding.getColumnReference().appendReadExpression( this, "t" );
|
||||
appendSql( "=" );
|
||||
keyBinding.getColumnReference().appendReadExpression( this, "s" );
|
||||
}
|
||||
// todo : optimistic locks?
|
||||
|
||||
appendSql( ")" );
|
||||
}
|
||||
|
||||
protected void renderMergeInsert(OptionalTableUpdate optionalTableUpdate) {
|
||||
final List<ColumnValueBinding> valueBindings = optionalTableUpdate.getValueBindings();
|
||||
final List<ColumnValueBinding> keyBindings = optionalTableUpdate.getKeyBindings();
|
||||
|
||||
final StringBuilder valuesList = new StringBuilder();
|
||||
|
||||
appendSql( "when not matched then insert (" );
|
||||
for ( int i = 0; i < keyBindings.size(); i++ ) {
|
||||
if ( i > 0 ) {
|
||||
appendSql( ", " );
|
||||
valuesList.append( ", " );
|
||||
}
|
||||
final ColumnValueBinding keyBinding = keyBindings.get( i );
|
||||
appendSql( keyBinding.getColumnReference().getColumnExpression() );
|
||||
keyBinding.getColumnReference().appendReadExpression( "s", valuesList::append );
|
||||
}
|
||||
for ( int i = 0; i < valueBindings.size(); i++ ) {
|
||||
appendSql( ", " );
|
||||
valuesList.append( ", " );
|
||||
final ColumnValueBinding valueBinding = valueBindings.get( i );
|
||||
appendSql( valueBinding.getColumnReference().getColumnExpression() );
|
||||
valueBinding.getColumnReference().appendReadExpression( "s", valuesList::append );
|
||||
}
|
||||
|
||||
appendSql( ") values (" );
|
||||
appendSql( valuesList.toString() );
|
||||
appendSql( ")" );
|
||||
}
|
||||
|
||||
protected void renderMergeDelete(OptionalTableUpdate optionalTableUpdate) {
|
||||
final List<ColumnValueBinding> valueBindings = optionalTableUpdate.getValueBindings();
|
||||
|
||||
appendSql( " when matched " );
|
||||
for ( int i = 0; i < valueBindings.size(); i++ ) {
|
||||
final ColumnValueBinding binding = valueBindings.get( i );
|
||||
appendSql( " and " );
|
||||
binding.getColumnReference().appendReadExpression( this, "s" );
|
||||
appendSql( " is null" );
|
||||
}
|
||||
appendSql( " then delete" );
|
||||
}
|
||||
|
||||
protected void renderMergeUpdate(OptionalTableUpdate optionalTableUpdate) {
|
||||
final List<ColumnValueBinding> valueBindings = optionalTableUpdate.getValueBindings();
|
||||
|
||||
appendSql( " when matched then update set " );
|
||||
for ( int i = 0; i < valueBindings.size(); i++ ) {
|
||||
final ColumnValueBinding binding = valueBindings.get( i );
|
||||
if ( i > 0 ) {
|
||||
appendSql( ", " );
|
||||
}
|
||||
binding.getColumnReference().appendColumnForWrite( this, "t" );
|
||||
appendSql( "=" );
|
||||
binding.getColumnReference().appendColumnForWrite( this, "s" );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -131,7 +131,7 @@ public class OptionalTableUpdate
|
|||
// Fallback to the optional table mutation operation because we have to execute user specified SQL
|
||||
return new OptionalTableUpdateOperation( getMutationTarget(), this, factory );
|
||||
}
|
||||
return factory.getJdbcServices().getDialect().createUpsertOperation(
|
||||
return factory.getJdbcServices().getDialect().createOptionalTableUpdateOperation(
|
||||
getMutationTarget(),
|
||||
this,
|
||||
factory
|
||||
|
|
|
@ -15,12 +15,12 @@ import org.hibernate.sql.model.MutationType;
|
|||
import org.hibernate.sql.model.TableMapping;
|
||||
|
||||
/**
|
||||
* JdbcMutation implementation for MERGE/UPSERT handling
|
||||
* JdbcMutation implementation for MERGE handling
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class UpsertOperation extends AbstractJdbcMutation {
|
||||
public UpsertOperation(
|
||||
public class MergeOperation extends AbstractJdbcMutation {
|
||||
public MergeOperation(
|
||||
TableMapping tableDetails,
|
||||
MutationTarget<?> mutationTarget,
|
||||
String sql,
|
|
@ -24,9 +24,9 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@DomainModel(annotatedClasses = UpsertTests.TheEntity.class)
|
||||
@DomainModel(annotatedClasses = OptionalTableUpdateTests.TheEntity.class)
|
||||
@SessionFactory
|
||||
public class UpsertTests {
|
||||
public class OptionalTableUpdateTests {
|
||||
@Test
|
||||
void testUpsertInsert(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (session) -> {
|
Loading…
Reference in New Issue