Skip to content

Commit 017b078

Browse files
committed
HHH-18217 Properly handle empty value bindings for merge operations
1 parent fc00e39 commit 017b078

File tree

13 files changed

+467
-285
lines changed

13 files changed

+467
-285
lines changed

hibernate-core/src/main/java/org/hibernate/StaleStateException.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,15 @@ public class StaleStateException extends HibernateException {
2626
public StaleStateException(String message) {
2727
super( message );
2828
}
29+
30+
/**
31+
* Constructs a {@code StaleStateException} using the supplied message
32+
* and cause.
33+
*
34+
* @param message The message explaining the exception condition
35+
* @param cause An exception to wrap
36+
*/
37+
public StaleStateException(String message, Exception cause) {
38+
super( message, cause );
39+
}
2940
}

hibernate-core/src/main/java/org/hibernate/dialect/SqlAstTranslatorWithMerge.java

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.hibernate.engine.spi.SessionFactoryImplementor;
1212
import org.hibernate.internal.util.StringHelper;
1313
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
14+
import org.hibernate.jdbc.Expectation;
1415
import org.hibernate.sql.ast.tree.Statement;
1516
import org.hibernate.sql.exec.spi.JdbcOperation;
1617
import org.hibernate.sql.model.ast.ColumnValueBinding;
@@ -46,6 +47,10 @@ public MergeOperation createMergeOperation(OptionalTableUpdate optionalTableUpda
4647
optionalTableUpdate.getMutatingTable().getTableMapping(),
4748
optionalTableUpdate.getMutationTarget(),
4849
getSql(),
50+
// Without value bindings, the upsert may have an update count of 0
51+
optionalTableUpdate.getValueBindings().isEmpty()
52+
? new Expectation.OptionalRowCount()
53+
: new Expectation.RowCount(),
4954
getParameterBinders()
5055
);
5156
}
@@ -228,16 +233,18 @@ protected void renderMergeUpdate(OptionalTableUpdate optionalTableUpdate) {
228233
final List<ColumnValueBinding> valueBindings = optionalTableUpdate.getValueBindings();
229234
final List<ColumnValueBinding> optimisticLockBindings = optionalTableUpdate.getOptimisticLockBindings();
230235

231-
renderWhenMatched( optimisticLockBindings );
232-
appendSql( " then update set " );
233-
for ( int i = 0; i < valueBindings.size(); i++ ) {
234-
final ColumnValueBinding binding = valueBindings.get( i );
235-
if ( i > 0 ) {
236-
appendSql( ", " );
236+
if ( !valueBindings.isEmpty() ) {
237+
renderWhenMatched( optimisticLockBindings );
238+
appendSql( " then update set " );
239+
for ( int i = 0; i < valueBindings.size(); i++ ) {
240+
final ColumnValueBinding binding = valueBindings.get( i );
241+
if ( i > 0 ) {
242+
appendSql( ", " );
243+
}
244+
binding.getColumnReference().appendColumnForWrite( this, null );
245+
appendSql( "=" );
246+
binding.getColumnReference().appendColumnForWrite( this, "s" );
237247
}
238-
binding.getColumnReference().appendColumnForWrite( this, null );
239-
appendSql( "=" );
240-
binding.getColumnReference().appendColumnForWrite( this, "s" );
241248
}
242249
}
243250

hibernate-core/src/main/java/org/hibernate/dialect/SqlAstTranslatorWithUpsert.java

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.util.List;
1010

1111
import org.hibernate.engine.spi.SessionFactoryImplementor;
12+
import org.hibernate.jdbc.Expectation;
1213
import org.hibernate.persister.entity.mutation.EntityTableMapping;
1314
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
1415
import org.hibernate.sql.ast.tree.Statement;
@@ -39,6 +40,10 @@ public MutationOperation createMergeOperation(OptionalTableUpdate optionalTableU
3940
optionalTableUpdate.getMutatingTable().getTableMapping(),
4041
optionalTableUpdate.getMutationTarget(),
4142
getSql(),
43+
// Without value bindings, the upsert may have an update count of 0
44+
optionalTableUpdate.getValueBindings().isEmpty()
45+
? new Expectation.OptionalRowCount()
46+
: new Expectation.RowCount(),
4247
getParameterBinders()
4348
);
4449

@@ -193,17 +198,19 @@ protected void renderMergeUpdate(OptionalTableUpdate optionalTableUpdate) {
193198
final List<ColumnValueBinding> valueBindings = optionalTableUpdate.getValueBindings();
194199
final List<ColumnValueBinding> optimisticLockBindings = optionalTableUpdate.getOptimisticLockBindings();
195200

196-
appendSql( " when matched then update set " );
197-
for ( int i = 0; i < valueBindings.size(); i++ ) {
198-
final ColumnValueBinding binding = valueBindings.get( i );
199-
if ( i > 0 ) {
200-
appendSql( ", " );
201+
if ( !valueBindings.isEmpty() ) {
202+
appendSql( " when matched then update set " );
203+
for ( int i = 0; i < valueBindings.size(); i++ ) {
204+
final ColumnValueBinding binding = valueBindings.get( i );
205+
if ( i > 0 ) {
206+
appendSql( ", " );
207+
}
208+
binding.getColumnReference().appendColumnForWrite( this, "t" );
209+
appendSql( "=" );
210+
binding.getColumnReference().appendColumnForWrite( this, "s" );
201211
}
202-
binding.getColumnReference().appendColumnForWrite( this, "t" );
203-
appendSql( "=" );
204-
binding.getColumnReference().appendColumnForWrite( this, "s" );
212+
renderMatchedWhere( optimisticLockBindings );
205213
}
206-
renderMatchedWhere( optimisticLockBindings );
207214
}
208215

209216
private void renderMatchedWhere(List<ColumnValueBinding> optimisticLockBindings) {

0 commit comments

Comments
 (0)