HHH-16103 - MERGE for optional table updates on SQL Server

This commit is contained in:
Steve Ebersole 2023-01-25 17:07:03 -06:00
parent 375f6b5f14
commit 5525b8d9b7
6 changed files with 40 additions and 41 deletions

View File

@ -40,7 +40,6 @@ import java.util.TimeZone;
import java.util.UUID;
import java.util.regex.Pattern;
import jakarta.persistence.GenerationType;
import org.hibernate.AssertionFailure;
import org.hibernate.Incubating;
import org.hibernate.Length;
@ -147,7 +146,7 @@ import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StringBuilderSqlAppender;
import org.hibernate.sql.model.MutationOperation;
import org.hibernate.sql.model.internal.TableUpsert;
import org.hibernate.sql.model.internal.OptionalTableUpdate;
import org.hibernate.sql.model.jdbc.OptionalTableUpdateOperation;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
@ -192,6 +191,7 @@ import org.hibernate.type.spi.TypeConfiguration;
import org.jboss.logging.Logger;
import jakarta.persistence.GenerationType;
import jakarta.persistence.TemporalType;
import static java.lang.Math.ceil;
@ -4709,9 +4709,9 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
*/
public MutationOperation createUpsertOperation(
EntityMutationTarget mutationTarget,
TableUpsert tableUpsert,
OptionalTableUpdate optionalTableUpdate,
SessionFactoryImplementor factory) {
return new OptionalTableUpdateOperation( mutationTarget, tableUpsert, factory );
return new OptionalTableUpdateOperation( mutationTarget, optionalTableUpdate, factory );
}
/**

View File

@ -62,7 +62,7 @@ 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.TableUpsert;
import org.hibernate.sql.model.internal.OptionalTableUpdate;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorH2DatabaseImpl;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
@ -874,9 +874,9 @@ public class H2Dialect extends Dialect {
@Override
public MutationOperation createUpsertOperation(
EntityMutationTarget mutationTarget,
TableUpsert tableUpsert,
OptionalTableUpdate optionalTableUpdate,
SessionFactoryImplementor factory) {
final H2SqlAstTranslator<?> translator = new H2SqlAstTranslator<>( factory, tableUpsert );
return translator.visitUpsert( tableUpsert );
final H2SqlAstTranslator<?> translator = new H2SqlAstTranslator<>( factory, optionalTableUpdate );
return translator.visitUpsert( optionalTableUpdate );
}
}

View File

@ -37,8 +37,8 @@ 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.internal.TableUpsert;
import org.hibernate.sql.model.jdbc.UpsertOperation;
import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpty;
@ -312,7 +312,7 @@ public class H2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstT
return getDialect().getVersion().isSameOrAfter( 1, 4, 198 );
}
public MutationOperation visitUpsert(TableUpsert tableUpsert) {
public MutationOperation visitUpsert(OptionalTableUpdate optionalTableUpdate) {
// template:
//
// merge into [table] as t
@ -326,35 +326,35 @@ public class H2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstT
// when matched
// then update set ...
renderMergeInto( tableUpsert );
renderMergeInto( optionalTableUpdate );
appendSql( " " );
renderMergeUsing( tableUpsert );
renderMergeUsing( optionalTableUpdate );
appendSql( " " );
renderMergeOn( tableUpsert );
renderMergeOn( optionalTableUpdate );
appendSql( " " );
renderMergeInsert( tableUpsert );
renderMergeInsert( optionalTableUpdate );
appendSql( " " );
renderMergeDelete( tableUpsert );
renderMergeDelete( optionalTableUpdate );
appendSql( " " );
renderMergeUpdate( tableUpsert );
renderMergeUpdate( optionalTableUpdate );
return new UpsertOperation(
tableUpsert.getMutatingTable().getTableMapping(),
tableUpsert.getMutationTarget(),
optionalTableUpdate.getMutatingTable().getTableMapping(),
optionalTableUpdate.getMutationTarget(),
getSql(),
getParameterBinders()
);
}
private void renderMergeInto(TableUpsert tableUpsert) {
private void renderMergeInto(OptionalTableUpdate optionalTableUpdate) {
appendSql( "merge into " );
appendSql( tableUpsert.getMutatingTable().getTableName() );
appendSql( optionalTableUpdate.getMutatingTable().getTableName() );
appendSql( " as t" );
}
private void renderMergeUsing(TableUpsert tableUpsert) {
final List<ColumnValueBinding> valueBindings = tableUpsert.getValueBindings();
final List<ColumnValueBinding> keyBindings = tableUpsert.getKeyBindings();
private void renderMergeUsing(OptionalTableUpdate optionalTableUpdate) {
final List<ColumnValueBinding> valueBindings = optionalTableUpdate.getValueBindings();
final List<ColumnValueBinding> keyBindings = optionalTableUpdate.getKeyBindings();
final StringBuilder columnList = new StringBuilder();
@ -382,12 +382,12 @@ public class H2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstT
appendSql( ")" );
}
private void renderMergeOn(TableUpsert tableUpsert) {
private void renderMergeOn(OptionalTableUpdate optionalTableUpdate) {
appendSql( "on " );
// todo : optimistic locks?
final List<ColumnValueBinding> keyBindings = tableUpsert.getKeyBindings();
final List<ColumnValueBinding> keyBindings = optionalTableUpdate.getKeyBindings();
for ( int i = 0; i < keyBindings.size(); i++ ) {
final ColumnValueBinding keyBinding = keyBindings.get( i );
if ( i > 0 ) {
@ -399,9 +399,9 @@ public class H2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstT
}
}
private void renderMergeInsert(TableUpsert tableUpsert) {
final List<ColumnValueBinding> valueBindings = tableUpsert.getValueBindings();
final List<ColumnValueBinding> keyBindings = tableUpsert.getKeyBindings();
private void renderMergeInsert(OptionalTableUpdate optionalTableUpdate) {
final List<ColumnValueBinding> valueBindings = optionalTableUpdate.getValueBindings();
final List<ColumnValueBinding> keyBindings = optionalTableUpdate.getKeyBindings();
final StringBuilder valuesList = new StringBuilder();
@ -428,8 +428,8 @@ public class H2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstT
appendSql( ")" );
}
private void renderMergeDelete(TableUpsert tableUpsert) {
final List<ColumnValueBinding> valueBindings = tableUpsert.getValueBindings();
private void renderMergeDelete(OptionalTableUpdate optionalTableUpdate) {
final List<ColumnValueBinding> valueBindings = optionalTableUpdate.getValueBindings();
appendSql( " when matched " );
for ( int i = 0; i < valueBindings.size(); i++ ) {
@ -441,8 +441,8 @@ public class H2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstT
appendSql( " then delete" );
}
private void renderMergeUpdate(TableUpsert tableUpsert) {
final List<ColumnValueBinding> valueBindings = tableUpsert.getValueBindings();
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++ ) {

View File

@ -13,13 +13,12 @@ import org.hibernate.sql.model.MutationOperation;
import org.hibernate.sql.model.MutationTarget;
import org.hibernate.sql.model.TableMapping;
import org.hibernate.sql.model.ast.ColumnValueBinding;
import org.hibernate.sql.model.ast.ColumnValueParameter;
import org.hibernate.sql.model.ast.MutatingTableReference;
import org.hibernate.sql.model.ast.RestrictedTableMutation;
import org.hibernate.sql.model.internal.OptionalTableUpdate;
import org.hibernate.sql.model.internal.TableUpdateCustomSql;
import org.hibernate.sql.model.internal.TableUpdateNoSet;
import org.hibernate.sql.model.internal.TableUpdateStandard;
import org.hibernate.sql.model.internal.TableUpsert;
/**
* Standard TableUpdateBuilder implementation
@ -62,7 +61,7 @@ public class TableUpdateBuilderStandard<O extends MutationOperation> extends Abs
}
if ( getMutatingTable().getTableMapping().isOptional() ) {
return (RestrictedTableMutation<O>) new TableUpsert(
return (RestrictedTableMutation<O>) new OptionalTableUpdate(
getMutatingTable(),
getMutationTarget(),
valueBindings,

View File

@ -34,12 +34,12 @@ import static org.hibernate.sql.model.ast.AbstractTableUpdate.collectParameters;
*
* @author Steve Ebersole
*/
public class TableUpsert
public class OptionalTableUpdate
extends AbstractRestrictedTableMutation<MutationOperation>
implements RestrictedTableMutation<MutationOperation> {
private final List<ColumnValueBinding> valueBindings;
public TableUpsert(
public OptionalTableUpdate(
MutatingTableReference mutatingTable,
MutationTarget<?> mutationTarget,
List<ColumnValueBinding> valueBindings,
@ -55,7 +55,7 @@ public class TableUpsert
);
}
public TableUpsert(
public OptionalTableUpdate(
MutatingTableReference mutatingTable,
MutationTarget<?> mutationTarget,
String comment,
@ -75,7 +75,7 @@ public class TableUpsert
@Override
protected String getLoggableName() {
return "TableUpsert";
return "OptionalTableUpdate";
}
@Override

View File

@ -46,13 +46,13 @@ import org.hibernate.sql.model.ast.MutatingTableReference;
import org.hibernate.sql.model.ast.TableDelete;
import org.hibernate.sql.model.ast.TableInsert;
import org.hibernate.sql.model.ast.TableUpdate;
import org.hibernate.sql.model.internal.OptionalTableUpdate;
import org.hibernate.sql.model.internal.TableDeleteCustomSql;
import org.hibernate.sql.model.internal.TableDeleteStandard;
import org.hibernate.sql.model.internal.TableInsertCustomSql;
import org.hibernate.sql.model.internal.TableInsertStandard;
import org.hibernate.sql.model.internal.TableUpdateCustomSql;
import org.hibernate.sql.model.internal.TableUpdateStandard;
import org.hibernate.sql.model.internal.TableUpsert;
import static org.hibernate.sql.model.ModelMutationLogging.MODEL_MUTATION_LOGGER;
@ -76,7 +76,7 @@ public class OptionalTableUpdateOperation implements SelfExecutingUpdateOperatio
public OptionalTableUpdateOperation(
MutationTarget<?> mutationTarget,
TableUpsert upsert,
OptionalTableUpdate upsert,
@SuppressWarnings("unused") SessionFactoryImplementor factory) {
this.mutationTarget = (EntityMutationTarget) mutationTarget;
this.tableMapping = (EntityTableMapping) upsert.getMutatingTable().getTableMapping();