8
8
import java .lang .invoke .MethodHandles ;
9
9
import java .util .concurrent .CompletionStage ;
10
10
11
+ import org .hibernate .dialect .CockroachDialect ;
11
12
import org .hibernate .dialect .Dialect ;
12
13
import org .hibernate .dialect .PostgreSQLDialect ;
13
14
import org .hibernate .dialect .SQLServerDialect ;
23
24
import org .hibernate .reactive .logging .impl .LoggerFactory ;
24
25
import org .hibernate .reactive .pool .ReactiveConnection ;
25
26
import org .hibernate .reactive .session .ReactiveConnectionSupplier ;
27
+ import org .hibernate .type .Type ;
26
28
27
- import static java . util . function . Function . identity ;
28
- import static org .hibernate .dialect .DialectDelegateWrapper . extractRealDialect ;
29
+
30
+ import static org .hibernate .reactive . dialect .ReactiveDialectWrapper . instanceOf ;
29
31
30
32
public interface ReactiveAbstractReturningDelegate extends ReactiveInsertGeneratedIdentifierDelegate {
31
33
@@ -48,16 +50,36 @@ default CompletionStage<Object> reactivePerformInsert(PreparedStatementDetails i
48
50
ReactiveConnection reactiveConnection = ( (ReactiveConnectionSupplier ) session ).getReactiveConnection ();
49
51
return reactiveConnection
50
52
.insertAndSelectIdentifier ( insertSql , params , idType , identifierColumnName )
51
- .thenApply ( identity () );
53
+ .thenApply ( this ::validateGeneratedIdentityId );
54
+ }
55
+
56
+ private Object validateGeneratedIdentityId (Object generatedId ) {
57
+ if ( generatedId == null ) {
58
+ throw LOG .noNativelyGeneratedValueReturned ();
59
+ }
60
+
61
+ // CockroachDB might generate an identifier that fits an integer (and maybe a short) from time to time.
62
+ // Users should not rely on it, or they might have random, hard to debug failures.
63
+ Type identifierType = getPersister ().getIdentifierType ();
64
+ if ( ( identifierType .getReturnedClass ().equals ( Short .class ) || identifierType .getReturnedClass ().equals ( Integer .class ) )
65
+ && instanceOf ( getPersister ().getFactory ().getJdbcServices ().getDialect (), CockroachDialect .class ) ) {
66
+ throw LOG .invalidIdentifierTypeForCockroachDB ( identifierType .getReturnedClass (), getPersister ().getEntityName () );
67
+ }
68
+ return generatedId ;
52
69
}
53
70
54
71
private static String createInsert (PreparedStatementDetails insertStatementDetails , String identifierColumnName , Dialect dialect ) {
72
+ final String sqlEnd = " returning " + identifierColumnName ;
55
73
if ( instanceOf ( dialect , PostgreSQLDialect .class ) ) {
56
- return insertStatementDetails .getSqlString () + " returning " + identifierColumnName ;
74
+ return insertStatementDetails .getSqlString () + sqlEnd ;
75
+ }
76
+ if ( instanceOf ( dialect , CockroachDialect .class )
77
+ && !insertStatementDetails .getSqlString ().endsWith ( sqlEnd ) ) {
78
+ return insertStatementDetails .getSqlString () + sqlEnd ;
57
79
}
58
80
if ( instanceOf ( dialect , SQLServerDialect .class ) ) {
59
81
String sql = insertStatementDetails .getSqlString ();
60
- int index = sql .lastIndexOf ( " returning " + identifierColumnName );
82
+ int index = sql .lastIndexOf ( sqlEnd );
61
83
// FIXME: this is a hack for HHH-16365
62
84
if ( index > -1 ) {
63
85
sql = sql .substring ( 0 , index );
@@ -75,10 +97,6 @@ private static String createInsert(PreparedStatementDetails insertStatementDetai
75
97
return insertStatementDetails .getSqlString ();
76
98
}
77
99
78
- private static boolean instanceOf (Dialect dialect , Class <?> dialectClass ) {
79
- return dialectClass .isInstance ( extractRealDialect ( dialect ) );
80
- }
81
-
82
100
@ Override
83
101
default CompletionStage <Object > reactivePerformInsert (String insertSQL , SharedSessionContractImplementor session , Binder binder ) {
84
102
throw LOG .notYetImplemented ();
0 commit comments