@@ -104,3 +104,125 @@ async fn concurrent_serializable_transactions_behave_correctly() {
104
104
res. unwrap_err( )
105
105
) ;
106
106
}
107
+
108
+ #[ cfg( feature = "postgres" ) ]
109
+ #[ tokio:: test]
110
+ async fn commit_with_serialization_failure_already_ends_transaction ( ) {
111
+ use diesel:: prelude:: * ;
112
+ use diesel_async:: { AsyncConnection , RunQueryDsl } ;
113
+ use std:: sync:: Arc ;
114
+ use tokio:: sync:: Barrier ;
115
+
116
+ table ! {
117
+ users4 {
118
+ id -> Integer ,
119
+ }
120
+ }
121
+
122
+ // create an async connection
123
+ let mut conn = super :: connection_without_transaction ( ) . await ;
124
+
125
+ struct A ( Vec < & ' static str > ) ;
126
+ impl diesel:: connection:: Instrumentation for A {
127
+ fn on_connection_event ( & mut self , event : diesel:: connection:: InstrumentationEvent < ' _ > ) {
128
+ if let diesel:: connection:: InstrumentationEvent :: StartQuery { query, .. } = event {
129
+ let q = query. to_string ( ) ;
130
+ let q = q. split_once ( ' ' ) . map ( |( a, _) | a) . unwrap_or ( & q) ;
131
+
132
+ if matches ! ( q, "BEGIN" | "COMMIT" | "ROLLBACK" ) {
133
+ assert_eq ! ( q, self . 0 . pop( ) . unwrap( ) ) ;
134
+ }
135
+ }
136
+ }
137
+ }
138
+ conn. set_instrumentation ( A ( vec ! [ "COMMIT" , "BEGIN" , "COMMIT" , "BEGIN" ] ) ) ;
139
+
140
+ let mut conn1 = super :: connection_without_transaction ( ) . await ;
141
+
142
+ diesel:: sql_query ( "CREATE TABLE IF NOT EXISTS users4 (id int);" )
143
+ . execute ( & mut conn)
144
+ . await
145
+ . unwrap ( ) ;
146
+
147
+ let barrier_1 = Arc :: new ( Barrier :: new ( 2 ) ) ;
148
+ let barrier_2 = Arc :: new ( Barrier :: new ( 2 ) ) ;
149
+ let barrier_1_for_tx1 = barrier_1. clone ( ) ;
150
+ let barrier_1_for_tx2 = barrier_1. clone ( ) ;
151
+ let barrier_2_for_tx1 = barrier_2. clone ( ) ;
152
+ let barrier_2_for_tx2 = barrier_2. clone ( ) ;
153
+
154
+ let mut tx = conn. build_transaction ( ) . serializable ( ) . read_write ( ) ;
155
+
156
+ let res = tx. run ( |conn| {
157
+ Box :: pin ( async {
158
+ users4:: table. select ( users4:: id) . load :: < i32 > ( conn) . await ?;
159
+
160
+ barrier_1_for_tx1. wait ( ) . await ;
161
+ diesel:: insert_into ( users4:: table)
162
+ . values ( users4:: id. eq ( 1 ) )
163
+ . execute ( conn)
164
+ . await ?;
165
+ barrier_2_for_tx1. wait ( ) . await ;
166
+
167
+ Ok :: < _ , diesel:: result:: Error > ( ( ) )
168
+ } )
169
+ } ) ;
170
+
171
+ let mut tx1 = conn1. build_transaction ( ) . serializable ( ) . read_write ( ) ;
172
+
173
+ let res1 = async {
174
+ let res = tx1
175
+ . run ( |conn| {
176
+ Box :: pin ( async {
177
+ users4:: table. select ( users4:: id) . load :: < i32 > ( conn) . await ?;
178
+
179
+ barrier_1_for_tx2. wait ( ) . await ;
180
+ diesel:: insert_into ( users4:: table)
181
+ . values ( users4:: id. eq ( 1 ) )
182
+ . execute ( conn)
183
+ . await ?;
184
+
185
+ Ok :: < _ , diesel:: result:: Error > ( ( ) )
186
+ } )
187
+ } )
188
+ . await ;
189
+ barrier_2_for_tx2. wait ( ) . await ;
190
+ res
191
+ } ;
192
+
193
+ let ( res, res1) = tokio:: join!( res, res1) ;
194
+ let _ = diesel:: sql_query ( "DROP TABLE users4" )
195
+ . execute ( & mut conn1)
196
+ . await ;
197
+
198
+ assert ! (
199
+ res1. is_ok( ) ,
200
+ "Expected the second transaction to be succussfull, but got an error: {:?}" ,
201
+ res1. unwrap_err( )
202
+ ) ;
203
+
204
+ assert ! ( res. is_err( ) , "Expected the first transaction to fail" ) ;
205
+ let err = res. unwrap_err ( ) ;
206
+ assert ! (
207
+ matches!(
208
+ & err,
209
+ diesel:: result:: Error :: DatabaseError (
210
+ diesel:: result:: DatabaseErrorKind :: SerializationFailure ,
211
+ _
212
+ )
213
+ ) ,
214
+ "Expected an serialization failure but got another error: {err:?}"
215
+ ) ;
216
+
217
+ let mut tx = conn. build_transaction ( ) ;
218
+
219
+ let res = tx
220
+ . run ( |_| Box :: pin ( async { Ok :: < _ , diesel:: result:: Error > ( ( ) ) } ) )
221
+ . await ;
222
+
223
+ assert ! (
224
+ res. is_ok( ) ,
225
+ "Expect transaction to run fine but got an error: {:?}" ,
226
+ res. unwrap_err( )
227
+ ) ;
228
+ }
0 commit comments