Skip to content

Commit 611dac6

Browse files
authored
Merge pull request rails#48054 from Shopify/cleanup-execute
Refactor Mysql2Adapter and TrilogyAdapter
2 parents e93bd8f + eb3a174 commit 611dac6

File tree

4 files changed

+132
-95
lines changed

4 files changed

+132
-95
lines changed

activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,18 +225,31 @@ def disable_referential_integrity # :nodoc:
225225
# Setting +allow_retry+ to true causes the db to reconnect and retry
226226
# executing the SQL statement in case of a connection-related exception.
227227
# This option should only be enabled for known idempotent queries.
228-
def execute(sql, name = nil, async: false, allow_retry: false)
228+
def execute(sql, name = nil, allow_retry: false)
229229
sql = transform_query(sql)
230230
check_if_write_query(sql)
231231

232-
raw_execute(sql, name, async: async, allow_retry: allow_retry)
232+
mark_transaction_written_if_write(sql)
233+
234+
log(sql, name) do
235+
with_raw_connection(allow_retry: allow_retry) do |conn|
236+
sync_timezone_changes(conn)
237+
result = conn.query(sql)
238+
handle_warnings(sql)
239+
result
240+
end
241+
end
233242
end
234243

235244
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
236245
# to write stuff in an abstract way without concerning ourselves about whether it
237246
# needs to be explicitly freed or not.
238247
def execute_and_free(sql, name = nil, async: false) # :nodoc:
239-
yield execute(sql, name, async: async)
248+
sql = transform_query(sql)
249+
check_if_write_query(sql)
250+
251+
mark_transaction_written_if_write(sql)
252+
yield raw_execute(sql, name, async: async)
240253
end
241254

242255
def begin_db_transaction # :nodoc:
@@ -769,6 +782,8 @@ def sync_timezone_changes(raw_connection)
769782
end
770783

771784
def internal_execute(sql, name = "SCHEMA", allow_retry: true, uses_transaction: false)
785+
sql = transform_query(sql)
786+
check_if_write_query(sql)
772787
raw_execute(sql, name, allow_retry: allow_retry, uses_transaction: uses_transaction)
773788
end
774789

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# frozen_string_literal: true
2+
3+
module ActiveRecord
4+
module ConnectionAdapters
5+
module Trilogy
6+
module DatabaseStatements
7+
READ_QUERY = AbstractAdapter.build_read_query_regexp(
8+
:desc, :describe, :set, :show, :use
9+
) # :nodoc:
10+
private_constant :READ_QUERY
11+
12+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP(6)").freeze # :nodoc:
13+
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
14+
15+
def select_all(*, **) # :nodoc:
16+
result = nil
17+
with_raw_connection do |conn|
18+
result = super
19+
conn.next_result while conn.more_results_exist?
20+
end
21+
result
22+
end
23+
24+
def write_query?(sql) # :nodoc:
25+
!READ_QUERY.match?(sql)
26+
rescue ArgumentError # Invalid encoding
27+
!READ_QUERY.match?(sql.b)
28+
end
29+
30+
def explain(arel, binds = [], options = [])
31+
sql = build_explain_clause(options) + " " + to_sql(arel, binds)
32+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
33+
result = exec_query(sql, "EXPLAIN", binds)
34+
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
35+
36+
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
37+
end
38+
39+
def exec_query(sql, name = "SQL", binds = [], prepare: false, async: false) # :nodoc:
40+
sql = transform_query(sql)
41+
check_if_write_query(sql)
42+
43+
result = raw_execute(sql, name, async: async)
44+
ActiveRecord::Result.new(result.fields, result.to_a)
45+
end
46+
47+
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil) # :nodoc:
48+
sql = transform_query(sql)
49+
check_if_write_query(sql)
50+
51+
raw_execute(to_sql(sql, binds), name)
52+
end
53+
54+
def exec_delete(sql, name = nil, binds = []) # :nodoc:
55+
sql = transform_query(sql)
56+
check_if_write_query(sql)
57+
58+
result = raw_execute(to_sql(sql, binds), name)
59+
result.affected_rows
60+
end
61+
62+
alias :exec_update :exec_delete # :nodoc:
63+
64+
def high_precision_current_timestamp
65+
HIGH_PRECISION_CURRENT_TIMESTAMP
66+
end
67+
68+
def build_explain_clause(options = [])
69+
return "EXPLAIN" if options.empty?
70+
71+
explain_clause = "EXPLAIN #{options.join(" ").upcase}"
72+
73+
if analyze_without_explain? && explain_clause.include?("ANALYZE")
74+
explain_clause.sub("EXPLAIN ", "")
75+
else
76+
explain_clause
77+
end
78+
end
79+
80+
private
81+
def last_inserted_id(result)
82+
result.last_insert_id
83+
end
84+
end
85+
end
86+
end
87+
end

activerecord/lib/active_record/connection_adapters/trilogy_adapter.rb

Lines changed: 26 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
gem "trilogy", "~> 2.4"
66
require "trilogy"
77

8+
require "active_record/connection_adapters/trilogy/database_statements"
89
require "active_record/connection_adapters/trilogy/lost_connection_exception_translator"
910
require "active_record/connection_adapters/trilogy/errors"
1011

@@ -37,86 +38,13 @@ def trilogy_connection(config)
3738
end
3839
module ConnectionAdapters
3940
class TrilogyAdapter < AbstractMysqlAdapter
40-
module DatabaseStatements
41-
READ_QUERY = AbstractAdapter.build_read_query_regexp(
42-
:desc, :describe, :set, :show, :use
43-
) # :nodoc:
44-
private_constant :READ_QUERY
45-
46-
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP(6)").freeze # :nodoc:
47-
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
48-
49-
def select_all(*, **) # :nodoc:
50-
result = nil
51-
with_raw_connection do |conn|
52-
result = super
53-
conn.next_result while conn.more_results_exist?
54-
end
55-
result
56-
end
57-
58-
def write_query?(sql) # :nodoc:
59-
!READ_QUERY.match?(sql)
60-
rescue ArgumentError # Invalid encoding
61-
!READ_QUERY.match?(sql.b)
62-
end
63-
64-
def explain(arel, binds = [], options = [])
65-
sql = build_explain_clause(options) + " " + to_sql(arel, binds)
66-
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
67-
result = exec_query(sql, "EXPLAIN", binds)
68-
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
69-
70-
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
71-
end
72-
73-
def exec_query(sql, name = "SQL", binds = [], prepare: false, async: false)
74-
result = execute(sql, name, async: async)
75-
ActiveRecord::Result.new(result.fields, result.to_a)
76-
end
77-
78-
alias exec_without_stmt exec_query
79-
80-
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
81-
execute(to_sql(sql, binds), name)
82-
end
83-
84-
def exec_delete(sql, name = nil, binds = [])
85-
result = execute(to_sql(sql, binds), name)
86-
result.affected_rows
87-
end
88-
89-
alias :exec_update :exec_delete
90-
91-
def high_precision_current_timestamp
92-
HIGH_PRECISION_CURRENT_TIMESTAMP
93-
end
94-
95-
def build_explain_clause(options = [])
96-
return "EXPLAIN" if options.empty?
97-
98-
explain_clause = "EXPLAIN #{options.join(" ").upcase}"
99-
100-
if analyze_without_explain? && explain_clause.include?("ANALYZE")
101-
explain_clause.sub("EXPLAIN ", "")
102-
else
103-
explain_clause
104-
end
105-
end
106-
107-
private
108-
def last_inserted_id(result)
109-
result.last_insert_id
110-
end
111-
end
112-
11341
ER_BAD_DB_ERROR = 1049
11442
ER_DBACCESS_DENIED_ERROR = 1044
11543
ER_ACCESS_DENIED_ERROR = 1045
11644

11745
ADAPTER_NAME = "Trilogy"
11846

119-
include DatabaseStatements
47+
include Trilogy::DatabaseStatements
12048

12149
SSL_MODES = {
12250
SSL_MODE_DISABLED: ::Trilogy::SSL_DISABLED,
@@ -214,28 +142,35 @@ def discard!
214142
end
215143
end
216144

217-
def each_hash(result)
218-
return to_enum(:each_hash, result) unless block_given?
145+
def execute(sql, name = nil, allow_retry: false)
146+
sql = transform_query(sql)
147+
check_if_write_query(sql)
219148

220-
keys = result.fields.map(&:to_sym)
221-
result.rows.each do |row|
222-
hash = {}
223-
idx = 0
224-
row.each do |value|
225-
hash[keys[idx]] = value
226-
idx += 1
149+
raw_execute(sql, name, allow_retry: allow_retry)
150+
end
151+
152+
private
153+
def each_hash(result)
154+
return to_enum(:each_hash, result) unless block_given?
155+
156+
keys = result.fields.map(&:to_sym)
157+
result.rows.each do |row|
158+
hash = {}
159+
idx = 0
160+
row.each do |value|
161+
hash[keys[idx]] = value
162+
idx += 1
163+
end
164+
yield hash
227165
end
228-
yield hash
229-
end
230166

231-
nil
232-
end
167+
nil
168+
end
233169

234-
def error_number(exception)
235-
exception.error_code if exception.respond_to?(:error_code)
236-
end
170+
def error_number(exception)
171+
exception.error_code if exception.respond_to?(:error_code)
172+
end
237173

238-
private
239174
def connection
240175
@raw_connection
241176
end

activerecord/test/cases/adapters/trilogy/trilogy_adapter_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ class TrilogyAdapterTest < ActiveRecord::TrilogyTestCase
319319
exception = Minitest::Mock.new
320320
exception.expect :error_code, 123
321321

322-
assert_equal 123, @conn.error_number(exception)
322+
assert_equal 123, @conn.send(:error_number, exception)
323323
end
324324

325325
def assert_raises_with_message(exception, message, &block)

0 commit comments

Comments
 (0)