Skip to content

Commit e6a05b2

Browse files
committed
Refactor adapter interface to match abstract adapter
1 parent edddc2b commit e6a05b2

File tree

1 file changed

+109
-53
lines changed

1 file changed

+109
-53
lines changed

lib/active_record/connection_adapters/sqlserver/database_statements.rb

Lines changed: 109 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,55 +7,110 @@ module DatabaseStatements
77
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(:begin, :commit, :dbcc, :explain, :save, :select, :set, :rollback, :waitfor, :use) # :nodoc:
88
private_constant :READ_QUERY
99

10-
def write_query?(sql) # :nodoc:
11-
!READ_QUERY.match?(sql)
12-
rescue ArgumentError # Invalid encoding
13-
!READ_QUERY.match?(sql.b)
14-
end
10+
# TODO: replace `internal_exec_query` by `perform_query`.
1511

16-
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
17-
log(sql, name, async: async) do |notification_payload|
18-
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
19-
result = if id_insert_table_name = query_requires_identity_insert?(sql)
20-
with_identity_insert_enabled(id_insert_table_name, conn) { internal_raw_execute(sql, conn, perform_do: true) }
21-
else
22-
internal_raw_execute(sql, conn, perform_do: true)
23-
end
24-
verified!
25-
notification_payload[:row_count] = result
26-
result
27-
end
28-
end
29-
end
12+
def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch:)
13+
unless binds.nil? || binds.empty?
14+
types, params = sp_executesql_types_and_parameters(binds)
3015

31-
def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false)
32-
sql = transform_query(sql)
16+
# TODO: `name` parameter does not exist.
17+
sql = sp_executesql_sql(sql, types, params)
18+
end
3319

34-
check_if_write_query(sql)
35-
mark_transaction_written_if_write(sql)
3620

37-
unless without_prepared_statement?(binds)
38-
types, params = sp_executesql_types_and_parameters(binds)
39-
sql = sp_executesql_sql(sql, types, params, name)
21+
result = if id_insert_table_name = query_requires_identity_insert?(sql)
22+
with_identity_insert_enabled(id_insert_table_name, raw_connection) do
23+
internal_exec_sql_query(sql, raw_connection)
24+
end
25+
else
26+
internal_exec_sql_query(sql, raw_connection)
27+
end
28+
29+
verified!
30+
notification_payload[:row_count] = result.count
31+
result
32+
end
33+
34+
#
35+
# def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false)
36+
# sql = transform_query(sql)
37+
#
38+
# check_if_write_query(sql)
39+
# mark_transaction_written_if_write(sql)
40+
#
41+
# unless without_prepared_statement?(binds)
42+
# types, params = sp_executesql_types_and_parameters(binds)
43+
# sql = sp_executesql_sql(sql, types, params, name)
44+
# end
45+
#
46+
# log(sql, name, binds, async: async) do |notification_payload|
47+
# with_raw_connection do |conn|
48+
# result = if id_insert_table_name = query_requires_identity_insert?(sql)
49+
# with_identity_insert_enabled(id_insert_table_name, conn) do
50+
# internal_exec_sql_query(sql, conn)
51+
# end
52+
# else
53+
# internal_exec_sql_query(sql, conn)
54+
# end
55+
#
56+
# verified!
57+
# notification_payload[:row_count] = result.count
58+
# result
59+
# end
60+
# end
61+
# end
62+
63+
64+
# Receive a native adapter result object and returns an ActiveRecord::Result object.
65+
def cast_result(raw_result)
66+
if raw_result.columns.empty?
67+
ActiveRecord::Result.empty
68+
else
69+
ActiveRecord::Result.new(raw_result.columns, raw_result.rows)
4070
end
4171

42-
log(sql, name, binds, async: async) do |notification_payload|
43-
with_raw_connection do |conn|
44-
result = if id_insert_table_name = query_requires_identity_insert?(sql)
45-
with_identity_insert_enabled(id_insert_table_name, conn) do
46-
internal_exec_sql_query(sql, conn)
47-
end
48-
else
49-
internal_exec_sql_query(sql, conn)
50-
end
72+
# rescue => e
73+
# binding.pry
74+
end
5175

52-
verified!
53-
notification_payload[:row_count] = result.count
54-
result
55-
end
76+
def affected_rows(raw_result)
77+
78+
if raw_result.count == 1 && raw_result.first.key?('AffectedRows')
79+
raw_result.first['AffectedRows']
80+
else
81+
raw_result.count
5682
end
83+
84+
rescue => e
85+
binding.pry
5786
end
5887

88+
89+
90+
def write_query?(sql) # :nodoc:
91+
!READ_QUERY.match?(sql)
92+
rescue ArgumentError # Invalid encoding
93+
!READ_QUERY.match?(sql.b)
94+
end
95+
96+
# TODO: This method implemented in Rails.
97+
# def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
98+
# log(sql, name, async: async) do |notification_payload|
99+
# with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
100+
# result = if id_insert_table_name = query_requires_identity_insert?(sql)
101+
# with_identity_insert_enabled(id_insert_table_name, conn) { internal_raw_execute(sql, conn, perform_do: true) }
102+
# else
103+
# internal_raw_execute(sql, conn, perform_do: true)
104+
# end
105+
# verified!
106+
# notification_payload[:row_count] = result
107+
# result
108+
# end
109+
# end
110+
# end
111+
112+
113+
59114
def internal_exec_sql_query(sql, conn)
60115
handle = internal_raw_execute(sql, conn)
61116
handle_to_names_and_values(handle, ar_result: true)
@@ -65,12 +120,12 @@ def internal_exec_sql_query(sql, conn)
65120

66121
def exec_delete(sql, name, binds)
67122
sql = sql.dup << "; SELECT @@ROWCOUNT AS AffectedRows"
68-
super(sql, name, binds).rows.first.first
123+
super(sql, name, binds)
69124
end
70125

71126
def exec_update(sql, name, binds)
72127
sql = sql.dup << "; SELECT @@ROWCOUNT AS AffectedRows"
73-
super(sql, name, binds).rows.first.first
128+
super(sql, name, binds)
74129
end
75130

76131
def begin_db_transaction
@@ -366,18 +421,19 @@ def basic_attribute_type?(type)
366421
type.is_a?(NilClass)
367422
end
368423

369-
def sp_executesql_sql(sql, types, params, name)
370-
if name == "EXPLAIN"
371-
params.each.with_index do |param, index|
372-
substitute_at_finder = /(@#{index})(?=(?:[^']|'[^']*')*$)/ # Finds unquoted @n values.
373-
sql = sql.sub substitute_at_finder, param.to_s
374-
end
375-
else
424+
# TODO: `name` was removed from the method signature.
425+
def sp_executesql_sql(sql, types, params)
426+
# if name == "EXPLAIN"
427+
# params.each.with_index do |param, index|
428+
# substitute_at_finder = /(@#{index})(?=(?:[^']|'[^']*')*$)/ # Finds unquoted @n values.
429+
# sql = sql.sub substitute_at_finder, param.to_s
430+
# end
431+
# else
376432
types = quote(types.join(", "))
377433
params = params.map.with_index { |p, i| "@#{i} = #{p}" }.join(", ") # Only p is needed, but with @i helps explain regexp.
378434
sql = "EXEC sp_executesql #{quote(sql)}"
379435
sql += ", #{types}, #{params}" unless params.empty?
380-
end
436+
# end
381437
sql.freeze
382438
end
383439

@@ -455,10 +511,10 @@ def finish_statement_handle(handle)
455511
# TinyTDS returns false instead of raising an exception if connection fails.
456512
# Getting around this by raising an exception ourselves while PR
457513
# https://github.com/rails-sqlserver/tiny_tds/pull/469 is not released.
458-
def internal_raw_execute(sql, conn, perform_do: false)
459-
result = conn.execute(sql).tap do |_result|
460-
raise TinyTds::Error, "failed to execute statement" if _result.is_a?(FalseClass)
461-
end
514+
# TODO: Check if `perform_do` is needed.
515+
def internal_raw_execute(sql, raw_connection, perform_do: false)
516+
result = raw_connection.execute(sql)
517+
raise TinyTds::Error, "failed to execute statement" if result.is_a?(FalseClass)
462518

463519
perform_do ? result.do : result
464520
end

0 commit comments

Comments
 (0)