Skip to content

Commit baf9fd4

Browse files
committed
Rails 8 support.
- Add `write_query?` implementation (mimicking postgres) to support the ability to prevent writes to a database - rails/rails@f39d72d - Replace the local implementation of execute, exec_query and its alias internal_exec_query with the new interface defined here rails/rails@fd24e5b#diff-e6fd03cad5e3437c76b6c5db106359124dc9feab8341ade39b9ae54af001fac9 of `raw_execute`, `cast_result`, and `affected_rows`. To support the affected_rows count this also had to add a `row_count` method to the coi and jdbc cursors. - without_prepared_statement? was removed rails/rails@2306c10
1 parent 9f2c1fe commit baf9fd4

File tree

3 files changed

+73
-35
lines changed

3 files changed

+73
-35
lines changed

lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb

Lines changed: 65 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,58 +8,79 @@ module DatabaseStatements
88
#
99
# see: abstract/database_statements.rb
1010

11-
# Executes a SQL statement
12-
def execute(sql, name = nil, async: false, allow_retry: false)
13-
sql = preprocess_query(sql)
11+
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
12+
:close, :declare, :fetch, :move, :set, :show
13+
) # :nodoc:
14+
private_constant :READ_QUERY
15+
16+
def write_query?(sql) # :nodoc:
17+
!READ_QUERY.match?(sql)
18+
rescue ArgumentError # Invalid encoding
19+
!READ_QUERY.match?(sql.b)
20+
end
1421

15-
log(sql, name, async: async) { _connection.exec(sql, allow_retry: allow_retry) }
22+
# Executes a SQL statement
23+
def execute(...)
24+
super
1625
end
1726

18-
def exec_query(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false)
27+
# Low level execution of a SQL statement on the connection returning adapter specific result object.
28+
def raw_execute(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false, materialize_transactions: false)
1929
sql = preprocess_query(sql)
2030

2131
type_casted_binds = type_casted_binds(binds)
32+
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
33+
log(sql, name, binds, type_casted_binds, async: async) do
34+
cursor = nil
35+
cached = false
36+
with_retry do
37+
if binds.nil? || binds.empty?
38+
cursor = conn.prepare(sql)
39+
else
40+
unless @statements.key? sql
41+
@statements[sql] = conn.prepare(sql)
42+
end
2243

23-
log(sql, name, binds, type_casted_binds, async: async) do
24-
cursor = nil
25-
cached = false
26-
with_retry do
27-
if without_prepared_statement?(binds)
28-
cursor = _connection.prepare(sql)
29-
else
30-
unless @statements.key? sql
31-
@statements[sql] = _connection.prepare(sql)
32-
end
33-
34-
cursor = @statements[sql]
35-
36-
cursor.bind_params(type_casted_binds)
44+
cursor = @statements[sql]
45+
cursor.bind_params(type_casted_binds)
3746

38-
cached = true
47+
cached = true
48+
end
49+
cursor.exec
3950
end
4051

41-
cursor.exec
42-
end
43-
44-
if (name == "EXPLAIN") && sql.start_with?("EXPLAIN")
45-
res = true
46-
else
4752
columns = cursor.get_col_names.map do |col_name|
4853
oracle_downcase(col_name)
4954
end
55+
5056
rows = []
51-
fetch_options = { get_lob_value: (name != "Writable Large Object") }
52-
while row = cursor.fetch(fetch_options)
53-
rows << row
57+
if sql =~ /\A\s*SELECT/i # This seems a naive way to detect queries that will have row results.
58+
fetch_options = { get_lob_value: (name != "Writable Large Object") }
59+
while row = cursor.fetch(fetch_options)
60+
rows << row
61+
end
5462
end
55-
res = build_result(columns: columns, rows: rows)
63+
64+
affected_rows_count = cursor.row_count
65+
66+
cursor.close unless cached
67+
68+
{ columns: columns, rows: rows, affected_rows_count: affected_rows_count }
5669
end
70+
end
71+
end
5772

58-
cursor.close unless cached
59-
res
73+
def cast_result(result)
74+
if result.nil?
75+
ActiveRecord::Result.empty
76+
else
77+
ActiveRecord::Result.new(result[:columns], result[:rows])
6078
end
6179
end
62-
alias_method :internal_exec_query, :exec_query
80+
81+
def affected_rows(result)
82+
result[:affected_rows_count]
83+
end
6384

6485
def supports_explain?
6586
true
@@ -106,7 +127,7 @@ def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, retu
106127
cursor = nil
107128
returning_id_col = returning_id_index = nil
108129
with_retry do
109-
if without_prepared_statement?(binds)
130+
if binds.nil? || binds.empty?
110131
cursor = _connection.prepare(sql)
111132
else
112133
unless @statements.key?(sql)
@@ -146,7 +167,7 @@ def exec_update(sql, name = nil, binds = [])
146167
log(sql, name, binds, type_casted_binds) do
147168
with_retry do
148169
cached = false
149-
if without_prepared_statement?(binds)
170+
if binds.nil? || binds.empty?
150171
cursor = _connection.prepare(sql)
151172
else
152173
if @statements.key?(sql)
@@ -289,6 +310,15 @@ def with_retry
289310
raise
290311
end
291312
end
313+
314+
def handle_warnings(sql)
315+
@notice_receiver_sql_warnings.each do |warning|
316+
next if warning_ignored?(warning)
317+
318+
warning.sql = sql
319+
ActiveRecord.db_warnings_action.call(warning)
320+
end
321+
end
292322
end
293323
end
294324
end

lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,10 @@ def column_names
385385
end
386386
alias :get_col_names :column_names
387387

388+
def row_count
389+
@raw_statement.getUpdateCount
390+
end
391+
388392
def fetch(options = {})
389393
if @raw_result_set.next
390394
get_lob_value = options[:get_lob_value]

lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ def get_col_names
158158
@raw_cursor.get_col_names
159159
end
160160

161+
def row_count
162+
@raw_cursor.row_count
163+
end
164+
161165
def fetch(options = {})
162166
if row = @raw_cursor.fetch
163167
get_lob_value = options[:get_lob_value]

0 commit comments

Comments
 (0)