Skip to content

Commit 63c0d6b

Browse files
committed
Active Record: clear query cache automatically when calling #execute
Also refactor #execute to be defined in AbstractAdapter.
1 parent af97f7e commit 63c0d6b

File tree

12 files changed

+81
-95
lines changed

12 files changed

+81
-95
lines changed

activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def write_query?(sql)
124124
# method may be manually memory managed. Consider using the exec_query
125125
# wrapper instead.
126126
def execute(sql, name = nil, allow_retry: false)
127-
raise NotImplementedError
127+
internal_execute(sql, name, allow_retry: allow_retry)
128128
end
129129

130130
# Executes +sql+ statement in the context of this connection using
@@ -491,16 +491,25 @@ def high_precision_current_timestamp
491491
end
492492

493493
private
494-
def internal_execute(sql, name = "SCHEMA")
495-
execute(sql, name)
494+
def internal_execute(sql, name = "SCHEMA", allow_retry: false, uses_transaction: true)
495+
sql = transform_query(sql)
496+
check_if_write_query(sql)
497+
498+
mark_transaction_written_if_write(sql)
499+
500+
raw_execute(sql, name, allow_retry: allow_retry, uses_transaction: uses_transaction)
496501
end
497502

498503
def execute_batch(statements, name = nil)
499504
statements.each do |statement|
500-
execute(statement, name)
505+
internal_execute(statement, name)
501506
end
502507
end
503508

509+
def raw_execute(sql, name, async: false, allow_retry: false, uses_transaction: true)
510+
raise NotImplementedError
511+
end
512+
504513
DEFAULT_INSERT_VALUE = Arel.sql("DEFAULT").freeze
505514
private_constant :DEFAULT_INSERT_VALUE
506515

activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module ConnectionAdapters # :nodoc:
77
module QueryCache
88
class << self
99
def included(base) # :nodoc:
10-
dirties_query_cache base, :create, :insert, :update, :delete, :truncate, :truncate_tables,
10+
dirties_query_cache base, :execute, :create, :insert, :update, :delete, :truncate, :truncate_tables,
1111
:rollback_to_savepoint, :rollback_db_transaction, :restart_db_transaction, :exec_insert_all
1212

1313
base.set_callback :checkout, :after, :configure_query_cache!
@@ -17,7 +17,7 @@ def included(base) # :nodoc:
1717
def dirties_query_cache(base, *method_names)
1818
method_names.each do |method_name|
1919
base.class_eval <<-end_code, __FILE__, __LINE__ + 1
20-
def #{method_name}(*)
20+
def #{method_name}(...)
2121
ActiveRecord::Base.clear_query_caches_for_current_thread
2222
super
2323
end

activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb

Lines changed: 2 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -220,27 +220,6 @@ def disable_referential_integrity # :nodoc:
220220
# DATABASE STATEMENTS ======================================
221221
#++
222222

223-
# Executes the SQL statement in the context of this connection.
224-
#
225-
# Setting +allow_retry+ to true causes the db to reconnect and retry
226-
# executing the SQL statement in case of a connection-related exception.
227-
# This option should only be enabled for known idempotent queries.
228-
def execute(sql, name = nil, allow_retry: false)
229-
sql = transform_query(sql)
230-
check_if_write_query(sql)
231-
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
242-
end
243-
244223
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
245224
# to write stuff in an abstract way without concerning ourselves about whether it
246225
# needs to be explicitly freed or not.
@@ -253,11 +232,11 @@ def execute_and_free(sql, name = nil, async: false) # :nodoc:
253232
end
254233

255234
def begin_db_transaction # :nodoc:
256-
internal_execute("BEGIN", "TRANSACTION")
235+
internal_execute("BEGIN", "TRANSACTION", allow_retry: true, uses_transaction: false)
257236
end
258237

259238
def begin_isolated_db_transaction(isolation) # :nodoc:
260-
internal_execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}", "TRANSACTION"
239+
internal_execute("SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}", "TRANSACTION", allow_retry: true, uses_transaction: false)
261240
begin_db_transaction
262241
end
263242

@@ -746,19 +725,6 @@ def extended_type_map_key
746725
end
747726
end
748727

749-
def raw_execute(sql, name, async: false, allow_retry: false, uses_transaction: true)
750-
mark_transaction_written_if_write(sql)
751-
752-
log(sql, name, async: async) do
753-
with_raw_connection(allow_retry: allow_retry, uses_transaction: uses_transaction) do |conn|
754-
sync_timezone_changes(conn)
755-
result = conn.query(sql)
756-
handle_warnings(sql)
757-
result
758-
end
759-
end
760-
end
761-
762728
def handle_warnings(sql)
763729
return if ActiveRecord.db_warnings_action.nil? || @raw_connection.warning_count == 0
764730

@@ -781,12 +747,6 @@ def warning_ignored?(warning)
781747
def sync_timezone_changes(raw_connection)
782748
end
783749

784-
def internal_execute(sql, name = "SCHEMA", allow_retry: true, uses_transaction: false)
785-
sql = transform_query(sql)
786-
check_if_write_query(sql)
787-
raw_execute(sql, name, allow_retry: allow_retry, uses_transaction: uses_transaction)
788-
end
789-
790750
# See https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html
791751
ER_DB_CREATE_EXISTS = 1007
792752
ER_FILSORT_ABORT = 1028

activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def select_all(*, **) # :nodoc:
1919
end
2020

2121
def query(sql, name = nil) # :nodoc:
22-
execute(sql, name).to_a
22+
raw_execute(sql, name).to_a
2323
end
2424

2525
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
@@ -169,6 +169,17 @@ def max_allowed_packet
169169
@max_allowed_packet ||= show_variable("max_allowed_packet")
170170
end
171171

172+
def raw_execute(sql, name, async: false, allow_retry: false, uses_transaction: true)
173+
log(sql, name, async: async) do
174+
with_raw_connection(allow_retry: allow_retry, uses_transaction: uses_transaction) do |conn|
175+
sync_timezone_changes(conn)
176+
result = conn.query(sql)
177+
handle_warnings(sql)
178+
result
179+
end
180+
end
181+
end
182+
172183
def exec_stmt_and_free(sql, name, binds, cache_stmt: false, async: false)
173184
sql = transform_query(sql)
174185
check_if_write_query(sql)

activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,30 +41,18 @@ def write_query?(sql) # :nodoc:
4141
#
4242
# Note: the PG::Result object is manually memory managed; if you don't
4343
# need it specifically, you may want consider the <tt>exec_query</tt> wrapper.
44-
def execute(sql, name = nil, allow_retry: false)
45-
sql = transform_query(sql)
46-
check_if_write_query(sql)
47-
48-
mark_transaction_written_if_write(sql)
49-
50-
with_raw_connection(allow_retry: allow_retry) do |conn|
51-
log(sql, name) do
52-
result = conn.async_exec(sql)
53-
handle_warnings(sql)
54-
result
55-
end
56-
end
44+
def execute(...) # :nodoc:
45+
super
5746
ensure
5847
@notice_receiver_sql_warnings = []
5948
end
6049

61-
def internal_execute(sql, name = "SCHEMA", allow_retry: true, uses_transaction: false)
62-
sql = transform_query(sql)
63-
check_if_write_query(sql)
64-
65-
with_raw_connection(allow_retry: allow_retry, uses_transaction: uses_transaction) do |conn|
66-
log(sql, name) do
67-
conn.async_exec(sql)
50+
def raw_execute(sql, name, async: false, allow_retry: false, uses_transaction: true)
51+
log(sql, name, async: async) do
52+
with_raw_connection(allow_retry: allow_retry, uses_transaction: uses_transaction) do |conn|
53+
result = conn.async_exec(sql)
54+
handle_warnings(result)
55+
result
6856
end
6957
end
7058
end
@@ -122,11 +110,11 @@ def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil) # :n
122110

123111
# Begins a transaction.
124112
def begin_db_transaction # :nodoc:
125-
internal_execute("BEGIN", "TRANSACTION")
113+
internal_execute("BEGIN", "TRANSACTION", allow_retry: true, uses_transaction: false)
126114
end
127115

128116
def begin_isolated_db_transaction(isolation) # :nodoc:
129-
internal_execute("BEGIN ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}", "TRANSACTION")
117+
internal_execute("BEGIN ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}", "TRANSACTION", allow_retry: true, uses_transaction: false)
130118
end
131119

132120
# Commits a transaction.

activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -864,8 +864,8 @@ def exec_cache(sql, name, binds, async:, allow_retry:, uses_transaction:)
864864
stmt_key = prepare_statement(sql, binds)
865865
type_casted_binds = type_casted_binds(binds)
866866

867-
log(sql, name, binds, type_casted_binds, stmt_key, async: async) do
868-
with_raw_connection do |conn|
867+
with_raw_connection do |conn|
868+
log(sql, name, binds, type_casted_binds, stmt_key, async: async) do
869869
conn.exec_prepared(stmt_key, type_casted_binds)
870870
end
871871
end

activerecord/lib/active_record/connection_adapters/sqlite3/database_statements.rb

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,6 @@ def explain(arel, binds = [], _options = [])
2121
SQLite3::ExplainPrettyPrinter.new.pp(result)
2222
end
2323

24-
def execute(sql, name = nil, allow_retry: false) # :nodoc:
25-
sql = transform_query(sql)
26-
check_if_write_query(sql)
27-
28-
mark_transaction_written_if_write(sql)
29-
30-
log(sql, name) do
31-
with_raw_connection(allow_retry: allow_retry) do |conn|
32-
conn.execute(sql)
33-
end
34-
end
35-
end
36-
3724
def exec_query(sql, name = nil, binds = [], prepare: false, async: false) # :nodoc:
3825
sql = transform_query(sql)
3926
check_if_write_query(sql)
@@ -122,6 +109,14 @@ def high_precision_current_timestamp
122109
end
123110

124111
private
112+
def raw_execute(sql, name, async: false, allow_retry: false, uses_transaction: false)
113+
log(sql, name, async: async) do
114+
with_raw_connection(allow_retry: allow_retry, uses_transaction: uses_transaction) do |conn|
115+
conn.execute(sql)
116+
end
117+
end
118+
end
119+
125120
def reset_read_uncommitted
126121
read_uncommitted = ActiveSupport::IsolatedExecutionState[:active_record_read_uncommitted]
127122
return unless read_uncommitted

activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,7 @@ def reconnect
691691
def configure_connection
692692
@raw_connection.busy_timeout(self.class.type_cast_config_to_integer(@config[:timeout])) if @config[:timeout]
693693

694-
execute("PRAGMA foreign_keys = ON", "SCHEMA")
694+
raw_execute("PRAGMA foreign_keys = ON", "SCHEMA")
695695
end
696696
end
697697
ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)

activerecord/lib/active_record/connection_adapters/trilogy/database_statements.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ def explain(arel, binds = [], options = [])
3939
def exec_query(sql, name = "SQL", binds = [], prepare: false, async: false) # :nodoc:
4040
sql = transform_query(sql)
4141
check_if_write_query(sql)
42+
mark_transaction_written_if_write(sql)
4243

4344
result = raw_execute(sql, name, async: async)
4445
ActiveRecord::Result.new(result.fields, result.to_a)
@@ -47,13 +48,15 @@ def exec_query(sql, name = "SQL", binds = [], prepare: false, async: false) # :n
4748
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil) # :nodoc:
4849
sql = transform_query(sql)
4950
check_if_write_query(sql)
51+
mark_transaction_written_if_write(sql)
5052

5153
raw_execute(to_sql(sql, binds), name)
5254
end
5355

5456
def exec_delete(sql, name = nil, binds = []) # :nodoc:
5557
sql = transform_query(sql)
5658
check_if_write_query(sql)
59+
mark_transaction_written_if_write(sql)
5760

5861
result = raw_execute(to_sql(sql, binds), name)
5962
result.affected_rows
@@ -78,6 +81,17 @@ def build_explain_clause(options = [])
7881
end
7982

8083
private
84+
def raw_execute(sql, name, async: false, allow_retry: false, uses_transaction: true)
85+
log(sql, name, async: async) do
86+
with_raw_connection(allow_retry: allow_retry, uses_transaction: uses_transaction) do |conn|
87+
sync_timezone_changes(conn)
88+
result = conn.query(sql)
89+
handle_warnings(sql)
90+
result
91+
end
92+
end
93+
end
94+
8195
def last_inserted_id(result)
8296
result.last_insert_id
8397
end

activerecord/lib/active_record/connection_adapters/trilogy_adapter.rb

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,6 @@ def discard!
142142
end
143143
end
144144

145-
def execute(sql, name = nil, allow_retry: false)
146-
sql = transform_query(sql)
147-
check_if_write_query(sql)
148-
149-
raw_execute(sql, name, allow_retry: allow_retry)
150-
end
151-
152145
private
153146
def each_hash(result)
154147
return to_enum(:each_hash, result) unless block_given?

0 commit comments

Comments
 (0)