@@ -25,9 +25,13 @@ def execute sql, name = nil, binds = []
2525
2626 def internal_exec_query sql , name = "SQL" , binds = [ ] , prepare : false , async : false , allow_retry : false
2727 result = internal_execute sql , name , binds , prepare : prepare , async : async , allow_retry : allow_retry
28- ActiveRecord ::Result . new (
29- result . fields . keys . map ( &:to_s ) , result . rows . map ( &:values )
30- )
28+ if result
29+ ActiveRecord ::Result . new (
30+ result . fields . keys . map ( &:to_s ) , result . rows . map ( &:values )
31+ )
32+ else
33+ ActiveRecord ::Result . new [ ] , [ ]
34+ end
3135 end
3236
3337 def internal_execute sql , name = "SQL" , binds = [ ] ,
@@ -77,14 +81,16 @@ def execute_query_or_dml statement_type, sql, name, binds
7781 @connection . execute_query sql ,
7882 params : params ,
7983 types : types ,
80- request_options : request_options
84+ request_options : request_options ,
85+ statement_type : statement_type
8186 end
8287 else
8388 @connection . execute_query sql ,
8489 params : params ,
8590 types : types ,
8691 single_use_selector : selector ,
87- request_options : request_options
92+ request_options : request_options ,
93+ statement_type : statement_type
8894 end
8995 end
9096 end
@@ -150,9 +156,13 @@ def query sql, name = nil
150156
151157 def exec_query sql , name = "SQL" , binds = [ ] , prepare : false # rubocop:disable Lint/UnusedMethodArgument
152158 result = execute sql , name , binds
153- ActiveRecord ::Result . new (
154- result . fields . keys . map ( &:to_s ) , result . rows . map ( &:values )
155- )
159+ if result . respond_to? :fields
160+ ActiveRecord ::Result . new (
161+ result . fields . keys . map ( &:to_s ) , result . rows . map ( &:values )
162+ )
163+ else
164+ ActiveRecord ::Result . new [ ] , [ ]
165+ end
156166 end
157167
158168 def sql_for_insert sql , pk , binds
@@ -198,6 +208,12 @@ def update arel, name = nil, binds = []
198208 alias delete update
199209
200210 def exec_update sql , name = "SQL" , binds = [ ]
211+ # Check if a DML batch is active on the connection.
212+ if @connection . dml_batch?
213+ # This call buffers the SQL.
214+ execute sql , name , binds
215+ return
216+ end
201217 result = execute sql , name , binds
202218 # Make sure that we consume the entire result stream before trying to get the stats.
203219 # This is required because the ExecuteStreamingSql RPC is also used for (Partitioned) DML,
@@ -237,7 +253,7 @@ def execute_ddl statements
237253
238254 # Transaction
239255
240- def transaction requires_new : nil , isolation : nil , joinable : true , **kwargs , &block # rubocop:disable Metrics/PerceivedComplexity
256+ def transaction requires_new : nil , isolation : nil , joinable : true , **kwargs , &block # rubocop:disable Metrics/PerceivedComplexity,Metrics/CyclomaticComplexity
241257 commit_options = kwargs . delete :commit_options
242258 exclude_from_streams = kwargs . delete :exclude_txn_from_change_streams
243259 @_spanner_begin_transaction_options = {
@@ -270,6 +286,9 @@ def transaction requires_new: nil, isolation: nil, joinable: true, **kwargs, &bl
270286 else
271287 raise
272288 end
289+ rescue Google ::Cloud ::AbortedError => err
290+ sleep ( delay_from_aborted ( err ) || backoff *= 1.3 )
291+ retry
273292 ensure
274293 # Clean up the instance variable to avoid leaking options.
275294 @_spanner_begin_transaction_options = nil
0 commit comments