HHH-17949 Fix upsert handling when optimistic locking is involved
This commit is contained in:
parent
0ce4f3c083
commit
8436326fc5
|
@ -191,6 +191,7 @@ public class SqlAstTranslatorWithUpsert<T extends JdbcOperation> extends Abstrac
|
||||||
|
|
||||||
protected void renderMergeUpdate(OptionalTableUpdate optionalTableUpdate) {
|
protected void renderMergeUpdate(OptionalTableUpdate optionalTableUpdate) {
|
||||||
final List<ColumnValueBinding> valueBindings = optionalTableUpdate.getValueBindings();
|
final List<ColumnValueBinding> valueBindings = optionalTableUpdate.getValueBindings();
|
||||||
|
final List<ColumnValueBinding> optimisticLockBindings = optionalTableUpdate.getOptimisticLockBindings();
|
||||||
|
|
||||||
appendSql( " when matched then update set " );
|
appendSql( " when matched then update set " );
|
||||||
for ( int i = 0; i < valueBindings.size(); i++ ) {
|
for ( int i = 0; i < valueBindings.size(); i++ ) {
|
||||||
|
@ -202,5 +203,21 @@ public class SqlAstTranslatorWithUpsert<T extends JdbcOperation> extends Abstrac
|
||||||
appendSql( "=" );
|
appendSql( "=" );
|
||||||
binding.getColumnReference().appendColumnForWrite( this, "s" );
|
binding.getColumnReference().appendColumnForWrite( this, "s" );
|
||||||
}
|
}
|
||||||
|
renderMatchedWhere( optimisticLockBindings );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderMatchedWhere(List<ColumnValueBinding> optimisticLockBindings) {
|
||||||
|
if ( !optimisticLockBindings.isEmpty() ) {
|
||||||
|
appendSql( " where " );
|
||||||
|
for (int i = 0; i < optimisticLockBindings.size(); i++) {
|
||||||
|
final ColumnValueBinding binding = optimisticLockBindings.get( i );
|
||||||
|
if ( i>0 ) {
|
||||||
|
appendSql(" and ");
|
||||||
|
}
|
||||||
|
binding.getColumnReference().appendColumnForWrite( this, "t" );
|
||||||
|
appendSql("=");
|
||||||
|
binding.getValueExpression().accept( this );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -386,21 +386,24 @@ public class OptionalTableUpdateOperation implements SelfExecutingUpdateOperatio
|
||||||
|
|
||||||
final BindingGroup bindingGroup = jdbcValueBindings.getBindingGroup( tableMapping.getTableName() );
|
final BindingGroup bindingGroup = jdbcValueBindings.getBindingGroup( tableMapping.getTableName() );
|
||||||
if ( bindingGroup != null ) {
|
if ( bindingGroup != null ) {
|
||||||
bindingGroup.forEachBinding( (binding) -> {
|
bindingGroup.forEachBinding( binding -> {
|
||||||
try {
|
// Skip parameter bindings for e.g. optimistic version check
|
||||||
binding.getValueBinder().bind(
|
if ( binding.getPosition() <= jdbcInsert.getParameterBinders().size() ) {
|
||||||
insertStatement,
|
try {
|
||||||
binding.getValue(),
|
binding.getValueBinder().bind(
|
||||||
binding.getPosition(),
|
insertStatement,
|
||||||
session
|
binding.getValue(),
|
||||||
);
|
binding.getPosition(),
|
||||||
}
|
session
|
||||||
catch (SQLException e) {
|
);
|
||||||
throw session.getJdbcServices().getSqlExceptionHelper().convert(
|
}
|
||||||
e,
|
catch (SQLException e) {
|
||||||
"Unable to bind parameter for upsert insert",
|
throw session.getJdbcServices().getSqlExceptionHelper().convert(
|
||||||
jdbcInsert.getSqlString()
|
e,
|
||||||
);
|
"Unable to bind parameter for upsert insert",
|
||||||
|
jdbcInsert.getSqlString()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,7 @@ package org.hibernate.orm.test.stateless;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.Version;
|
import jakarta.persistence.Version;
|
||||||
import org.hibernate.dialect.H2Dialect;
|
|
||||||
import org.hibernate.dialect.PostgreSQLDialect;
|
|
||||||
import org.hibernate.dialect.SQLServerDialect;
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.RequiresDialect;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -17,9 +13,6 @@ import static org.junit.Assert.assertEquals;
|
||||||
@SessionFactory
|
@SessionFactory
|
||||||
@DomainModel(annotatedClasses = UpsertVersionedTest.Record.class)
|
@DomainModel(annotatedClasses = UpsertVersionedTest.Record.class)
|
||||||
public class UpsertVersionedTest {
|
public class UpsertVersionedTest {
|
||||||
@RequiresDialect(H2Dialect.class)
|
|
||||||
@RequiresDialect(SQLServerDialect.class)
|
|
||||||
@RequiresDialect(value = PostgreSQLDialect.class, matchSubTypes = false)
|
|
||||||
@Test void test(SessionFactoryScope scope) {
|
@Test void test(SessionFactoryScope scope) {
|
||||||
scope.inStatelessTransaction(s-> {
|
scope.inStatelessTransaction(s-> {
|
||||||
s.upsert(new Record(123L,null,"hello earth"));
|
s.upsert(new Record(123L,null,"hello earth"));
|
||||||
|
@ -30,21 +23,21 @@ public class UpsertVersionedTest {
|
||||||
assertEquals("hello mars",s.get(Record.class,456L).message);
|
assertEquals("hello mars",s.get(Record.class,456L).message);
|
||||||
});
|
});
|
||||||
scope.inStatelessTransaction(s-> {
|
scope.inStatelessTransaction(s-> {
|
||||||
s.upsert(new Record(123L,1L,"goodbye earth"));
|
s.upsert(new Record(123L,0L,"goodbye earth"));
|
||||||
});
|
});
|
||||||
scope.inStatelessTransaction(s-> {
|
scope.inStatelessTransaction(s-> {
|
||||||
assertEquals("goodbye earth",s.get(Record.class,123L).message);
|
assertEquals("goodbye earth",s.get(Record.class,123L).message);
|
||||||
assertEquals("hello mars",s.get(Record.class,456L).message);
|
assertEquals("hello mars",s.get(Record.class,456L).message);
|
||||||
});
|
});
|
||||||
scope.inStatelessTransaction(s-> {
|
scope.inStatelessTransaction(s-> {
|
||||||
s.upsert(new Record(456L,4L,"goodbye mars"));
|
s.upsert(new Record(456L,3L,"goodbye mars"));
|
||||||
});
|
});
|
||||||
scope.inStatelessTransaction(s-> {
|
scope.inStatelessTransaction(s-> {
|
||||||
assertEquals("goodbye earth",s.get(Record.class,123L).message);
|
assertEquals("goodbye earth",s.get(Record.class,123L).message);
|
||||||
assertEquals("goodbye mars",s.get(Record.class,456L).message);
|
assertEquals("goodbye mars",s.get(Record.class,456L).message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@Entity
|
@Entity(name = "Record")
|
||||||
static class Record {
|
static class Record {
|
||||||
@Id Long id;
|
@Id Long id;
|
||||||
@Version Long version;
|
@Version Long version;
|
||||||
|
|
Loading…
Reference in New Issue