departure 6.8.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +2 -2
- data/.rubocop.yml +1 -1
- data/Appraisals +4 -4
- data/CHANGELOG.md +5 -1
- data/Gemfile +1 -0
- data/Gemfile.lock +86 -73
- data/Rakefile +1 -0
- data/departure.gemspec +3 -3
- data/gemfiles/rails_7_0.gemfile +8 -2
- data/gemfiles/rails_7_0.gemfile.lock +178 -129
- data/gemfiles/rails_7_1.gemfile +6 -1
- data/gemfiles/rails_7_1.gemfile.lock +136 -120
- data/gemfiles/rails_7_2.gemfile +5 -0
- data/gemfiles/rails_7_2.gemfile.lock +33 -21
- data/gemfiles/{rails_6_1.gemfile → rails_8_0.gemfile} +6 -2
- data/gemfiles/rails_8_0.gemfile.lock +285 -0
- data/lib/active_record/connection_adapters/for_alter.rb +4 -17
- data/lib/active_record/connection_adapters/percona_adapter.rb +8 -21
- data/lib/active_record/connection_adapters/rails_8_0_departure_adapter.rb +293 -0
- data/lib/departure/migration.rb +1 -5
- data/lib/departure/rails_adapter.rb +42 -2
- data/lib/departure/rails_patches/active_record_migrator_with_advisory_lock_patch.rb +2 -2
- data/lib/departure/runner.rb +8 -0
- data/lib/departure/version.rb +1 -1
- metadata +11 -37
- data/gemfiles/rails_6_1.gemfile.lock +0 -243
@@ -0,0 +1,285 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ..
|
3
|
+
specs:
|
4
|
+
departure (6.8.0)
|
5
|
+
activerecord (>= 7.0.1)
|
6
|
+
mysql2 (>= 0.4.0, < 0.6.0)
|
7
|
+
railties (>= 7.0.1)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
actioncable (8.0.2.1)
|
13
|
+
actionpack (= 8.0.2.1)
|
14
|
+
activesupport (= 8.0.2.1)
|
15
|
+
nio4r (~> 2.0)
|
16
|
+
websocket-driver (>= 0.6.1)
|
17
|
+
zeitwerk (~> 2.6)
|
18
|
+
actionmailbox (8.0.2.1)
|
19
|
+
actionpack (= 8.0.2.1)
|
20
|
+
activejob (= 8.0.2.1)
|
21
|
+
activerecord (= 8.0.2.1)
|
22
|
+
activestorage (= 8.0.2.1)
|
23
|
+
activesupport (= 8.0.2.1)
|
24
|
+
mail (>= 2.8.0)
|
25
|
+
actionmailer (8.0.2.1)
|
26
|
+
actionpack (= 8.0.2.1)
|
27
|
+
actionview (= 8.0.2.1)
|
28
|
+
activejob (= 8.0.2.1)
|
29
|
+
activesupport (= 8.0.2.1)
|
30
|
+
mail (>= 2.8.0)
|
31
|
+
rails-dom-testing (~> 2.2)
|
32
|
+
actionpack (8.0.2.1)
|
33
|
+
actionview (= 8.0.2.1)
|
34
|
+
activesupport (= 8.0.2.1)
|
35
|
+
nokogiri (>= 1.8.5)
|
36
|
+
rack (>= 2.2.4)
|
37
|
+
rack-session (>= 1.0.1)
|
38
|
+
rack-test (>= 0.6.3)
|
39
|
+
rails-dom-testing (~> 2.2)
|
40
|
+
rails-html-sanitizer (~> 1.6)
|
41
|
+
useragent (~> 0.16)
|
42
|
+
actiontext (8.0.2.1)
|
43
|
+
actionpack (= 8.0.2.1)
|
44
|
+
activerecord (= 8.0.2.1)
|
45
|
+
activestorage (= 8.0.2.1)
|
46
|
+
activesupport (= 8.0.2.1)
|
47
|
+
globalid (>= 0.6.0)
|
48
|
+
nokogiri (>= 1.8.5)
|
49
|
+
actionview (8.0.2.1)
|
50
|
+
activesupport (= 8.0.2.1)
|
51
|
+
builder (~> 3.1)
|
52
|
+
erubi (~> 1.11)
|
53
|
+
rails-dom-testing (~> 2.2)
|
54
|
+
rails-html-sanitizer (~> 1.6)
|
55
|
+
activejob (8.0.2.1)
|
56
|
+
activesupport (= 8.0.2.1)
|
57
|
+
globalid (>= 0.3.6)
|
58
|
+
activemodel (8.0.2.1)
|
59
|
+
activesupport (= 8.0.2.1)
|
60
|
+
activerecord (8.0.2.1)
|
61
|
+
activemodel (= 8.0.2.1)
|
62
|
+
activesupport (= 8.0.2.1)
|
63
|
+
timeout (>= 0.4.0)
|
64
|
+
activestorage (8.0.2.1)
|
65
|
+
actionpack (= 8.0.2.1)
|
66
|
+
activejob (= 8.0.2.1)
|
67
|
+
activerecord (= 8.0.2.1)
|
68
|
+
activesupport (= 8.0.2.1)
|
69
|
+
marcel (~> 1.0)
|
70
|
+
activesupport (8.0.2.1)
|
71
|
+
base64
|
72
|
+
benchmark (>= 0.3)
|
73
|
+
bigdecimal
|
74
|
+
concurrent-ruby (~> 1.0, >= 1.3.1)
|
75
|
+
connection_pool (>= 2.2.5)
|
76
|
+
drb
|
77
|
+
i18n (>= 1.6, < 2)
|
78
|
+
logger (>= 1.4.2)
|
79
|
+
minitest (>= 5.1)
|
80
|
+
securerandom (>= 0.3)
|
81
|
+
tzinfo (~> 2.0, >= 2.0.5)
|
82
|
+
uri (>= 0.13.1)
|
83
|
+
appraisal (2.4.1)
|
84
|
+
bundler
|
85
|
+
rake
|
86
|
+
thor (>= 0.14.0)
|
87
|
+
ast (2.4.3)
|
88
|
+
base64 (0.2.0)
|
89
|
+
benchmark (0.4.0)
|
90
|
+
bigdecimal (3.1.9)
|
91
|
+
builder (3.3.0)
|
92
|
+
byebug (12.0.0)
|
93
|
+
climate_control (0.0.4)
|
94
|
+
activesupport (>= 3.0)
|
95
|
+
codeclimate-test-reporter (1.0.9)
|
96
|
+
simplecov (<= 0.13)
|
97
|
+
coderay (1.1.3)
|
98
|
+
concurrent-ruby (1.3.5)
|
99
|
+
connection_pool (2.5.0)
|
100
|
+
crass (1.0.6)
|
101
|
+
date (3.4.1)
|
102
|
+
diff-lcs (1.6.1)
|
103
|
+
docile (1.1.5)
|
104
|
+
drb (2.2.1)
|
105
|
+
erubi (1.13.1)
|
106
|
+
globalid (1.2.1)
|
107
|
+
activesupport (>= 6.1)
|
108
|
+
i18n (1.14.7)
|
109
|
+
concurrent-ruby (~> 1.0)
|
110
|
+
io-console (0.8.0)
|
111
|
+
irb (1.15.2)
|
112
|
+
pp (>= 0.6.0)
|
113
|
+
rdoc (>= 4.0.0)
|
114
|
+
reline (>= 0.4.2)
|
115
|
+
json (2.10.2)
|
116
|
+
language_server-protocol (3.17.0.4)
|
117
|
+
lhm (2.2.0)
|
118
|
+
lint_roller (1.1.0)
|
119
|
+
logger (1.7.0)
|
120
|
+
loofah (2.24.0)
|
121
|
+
crass (~> 1.0.2)
|
122
|
+
nokogiri (>= 1.12.0)
|
123
|
+
mail (2.8.1)
|
124
|
+
mini_mime (>= 0.1.1)
|
125
|
+
net-imap
|
126
|
+
net-pop
|
127
|
+
net-smtp
|
128
|
+
marcel (1.0.4)
|
129
|
+
method_source (1.1.0)
|
130
|
+
mini_mime (1.1.5)
|
131
|
+
minitest (5.25.5)
|
132
|
+
mutex_m (0.3.0)
|
133
|
+
mysql2 (0.5.6)
|
134
|
+
net-imap (0.5.6)
|
135
|
+
date
|
136
|
+
net-protocol
|
137
|
+
net-pop (0.1.2)
|
138
|
+
net-protocol
|
139
|
+
net-protocol (0.2.2)
|
140
|
+
timeout
|
141
|
+
net-smtp (0.5.1)
|
142
|
+
net-protocol
|
143
|
+
nio4r (2.7.4)
|
144
|
+
nokogiri (1.18.7-x86_64-linux-gnu)
|
145
|
+
racc (~> 1.4)
|
146
|
+
parallel (1.26.3)
|
147
|
+
parser (3.3.7.4)
|
148
|
+
ast (~> 2.4.1)
|
149
|
+
racc
|
150
|
+
pp (0.6.2)
|
151
|
+
prettyprint
|
152
|
+
prettyprint (0.2.0)
|
153
|
+
prism (1.4.0)
|
154
|
+
pry (0.15.2)
|
155
|
+
coderay (~> 1.1)
|
156
|
+
method_source (~> 1.0)
|
157
|
+
pry-byebug (3.11.0)
|
158
|
+
byebug (~> 12.0)
|
159
|
+
pry (>= 0.13, < 0.16)
|
160
|
+
psych (5.2.3)
|
161
|
+
date
|
162
|
+
stringio
|
163
|
+
racc (1.8.1)
|
164
|
+
rack (3.1.12)
|
165
|
+
rack-session (2.1.0)
|
166
|
+
base64 (>= 0.1.0)
|
167
|
+
rack (>= 3.0.0)
|
168
|
+
rack-test (2.2.0)
|
169
|
+
rack (>= 1.3)
|
170
|
+
rackup (2.2.1)
|
171
|
+
rack (>= 3)
|
172
|
+
rails (8.0.2.1)
|
173
|
+
actioncable (= 8.0.2.1)
|
174
|
+
actionmailbox (= 8.0.2.1)
|
175
|
+
actionmailer (= 8.0.2.1)
|
176
|
+
actionpack (= 8.0.2.1)
|
177
|
+
actiontext (= 8.0.2.1)
|
178
|
+
actionview (= 8.0.2.1)
|
179
|
+
activejob (= 8.0.2.1)
|
180
|
+
activemodel (= 8.0.2.1)
|
181
|
+
activerecord (= 8.0.2.1)
|
182
|
+
activestorage (= 8.0.2.1)
|
183
|
+
activesupport (= 8.0.2.1)
|
184
|
+
bundler (>= 1.15.0)
|
185
|
+
railties (= 8.0.2.1)
|
186
|
+
rails-dom-testing (2.2.0)
|
187
|
+
activesupport (>= 5.0.0)
|
188
|
+
minitest
|
189
|
+
nokogiri (>= 1.6)
|
190
|
+
rails-html-sanitizer (1.6.2)
|
191
|
+
loofah (~> 2.21)
|
192
|
+
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
193
|
+
railties (8.0.2.1)
|
194
|
+
actionpack (= 8.0.2.1)
|
195
|
+
activesupport (= 8.0.2.1)
|
196
|
+
irb (~> 1.13)
|
197
|
+
rackup (>= 1.0.0)
|
198
|
+
rake (>= 12.2)
|
199
|
+
thor (~> 1.0, >= 1.2.2)
|
200
|
+
zeitwerk (~> 2.6)
|
201
|
+
rainbow (3.1.1)
|
202
|
+
rake (13.2.1)
|
203
|
+
rdoc (6.13.1)
|
204
|
+
psych (>= 4.0.0)
|
205
|
+
regexp_parser (2.10.0)
|
206
|
+
reline (0.6.0)
|
207
|
+
io-console (~> 0.5)
|
208
|
+
rspec (3.13.0)
|
209
|
+
rspec-core (~> 3.13.0)
|
210
|
+
rspec-expectations (~> 3.13.0)
|
211
|
+
rspec-mocks (~> 3.13.0)
|
212
|
+
rspec-core (3.13.3)
|
213
|
+
rspec-support (~> 3.13.0)
|
214
|
+
rspec-expectations (3.13.3)
|
215
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
216
|
+
rspec-support (~> 3.13.0)
|
217
|
+
rspec-its (1.3.1)
|
218
|
+
rspec-core (>= 3.0.0)
|
219
|
+
rspec-expectations (>= 3.0.0)
|
220
|
+
rspec-mocks (3.13.2)
|
221
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
222
|
+
rspec-support (~> 3.13.0)
|
223
|
+
rspec-support (3.13.2)
|
224
|
+
rubocop (1.74.0)
|
225
|
+
json (~> 2.3)
|
226
|
+
language_server-protocol (~> 3.17.0.2)
|
227
|
+
lint_roller (~> 1.1.0)
|
228
|
+
parallel (~> 1.10)
|
229
|
+
parser (>= 3.3.0.2)
|
230
|
+
rainbow (>= 2.2.2, < 4.0)
|
231
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
232
|
+
rubocop-ast (>= 1.38.0, < 2.0)
|
233
|
+
ruby-progressbar (~> 1.7)
|
234
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
235
|
+
rubocop-ast (1.44.0)
|
236
|
+
parser (>= 3.3.7.2)
|
237
|
+
prism (~> 1.4)
|
238
|
+
rubocop-performance (1.20.2)
|
239
|
+
rubocop (>= 1.48.1, < 2.0)
|
240
|
+
rubocop-ast (>= 1.30.0, < 2.0)
|
241
|
+
ruby-progressbar (1.13.0)
|
242
|
+
securerandom (0.4.1)
|
243
|
+
simplecov (0.13.0)
|
244
|
+
docile (~> 1.1.0)
|
245
|
+
json (>= 1.8, < 3)
|
246
|
+
simplecov-html (~> 0.10.0)
|
247
|
+
simplecov-html (0.10.2)
|
248
|
+
stringio (3.1.6)
|
249
|
+
thor (1.3.2)
|
250
|
+
timeout (0.4.3)
|
251
|
+
tzinfo (2.0.6)
|
252
|
+
concurrent-ruby (~> 1.0)
|
253
|
+
unicode-display_width (3.1.4)
|
254
|
+
unicode-emoji (~> 4.0, >= 4.0.4)
|
255
|
+
unicode-emoji (4.0.4)
|
256
|
+
uri (1.0.3)
|
257
|
+
useragent (0.16.11)
|
258
|
+
websocket-driver (0.7.7)
|
259
|
+
base64
|
260
|
+
websocket-extensions (>= 0.1.0)
|
261
|
+
websocket-extensions (0.1.5)
|
262
|
+
zeitwerk (2.7.2)
|
263
|
+
|
264
|
+
PLATFORMS
|
265
|
+
x86_64-linux
|
266
|
+
|
267
|
+
DEPENDENCIES
|
268
|
+
appraisal (~> 2.4.1)
|
269
|
+
base64
|
270
|
+
climate_control (~> 0.0.3)
|
271
|
+
codeclimate-test-reporter (~> 1.0.3)
|
272
|
+
departure!
|
273
|
+
lhm
|
274
|
+
logger
|
275
|
+
mutex_m
|
276
|
+
pry-byebug
|
277
|
+
rails (= 8.0.2.1)
|
278
|
+
rake (>= 10.0)
|
279
|
+
rspec (~> 3.4, >= 3.4.0)
|
280
|
+
rspec-its (~> 1.2)
|
281
|
+
rubocop (~> 1.74.0)
|
282
|
+
rubocop-performance (~> 1.20.2)
|
283
|
+
|
284
|
+
BUNDLED WITH
|
285
|
+
2.6.6
|
@@ -52,27 +52,14 @@ module ForAlterStatements
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def add_index_for_alter(table_name, column_name, options = {})
|
55
|
-
|
56
|
-
index_definition, = add_index_options(table_name, column_name, **options)
|
55
|
+
index_definition, = add_index_options(table_name, column_name, **options)
|
57
56
|
|
58
|
-
|
59
|
-
else
|
60
|
-
index_name, index_type, index_columns, _,
|
61
|
-
index_algorithm, index_using = add_index_options(table_name, column_name, **options)
|
62
|
-
index_algorithm[0, 0] = ', ' if index_algorithm.present?
|
63
|
-
|
64
|
-
"ADD #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_algorithm}"
|
65
|
-
end
|
57
|
+
"ADD #{schema_creation.accept(index_definition)}"
|
66
58
|
end
|
67
59
|
|
68
60
|
def remove_index_for_alter(table_name, column_name = nil, **options)
|
69
|
-
index_name =
|
70
|
-
|
71
|
-
index_name_for_remove(table_name, column_name, options)
|
72
|
-
else
|
73
|
-
options = [column_name, options] if column_name
|
74
|
-
index_name_for_remove(table_name, options)
|
75
|
-
end
|
61
|
+
index_name = index_name_for_remove(table_name, column_name, options)
|
62
|
+
|
76
63
|
"DROP INDEX #{quote_column_name(index_name)}"
|
77
64
|
end
|
78
65
|
|
@@ -99,20 +99,11 @@ module ActiveRecord
|
|
99
99
|
# @param column_name [String, Symbol]
|
100
100
|
# @param options [Hash] optional
|
101
101
|
def add_index(table_name, column_name, options = {})
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
SQL
|
108
|
-
else
|
109
|
-
index_name, index_type, index_columns, index_options = add_index_options(table_name, column_name, **options)
|
110
|
-
execute <<-SQL.squish
|
111
|
-
ALTER TABLE #{quote_table_name(table_name)}
|
112
|
-
ADD #{index_type} INDEX
|
113
|
-
#{quote_column_name(index_name)} (#{index_columns})#{index_options}
|
114
|
-
SQL
|
115
|
-
end
|
102
|
+
index_definition, = add_index_options(table_name, column_name, **options)
|
103
|
+
execute <<-SQL.squish
|
104
|
+
ALTER TABLE #{quote_table_name(index_definition.table)}
|
105
|
+
ADD #{schema_creation.accept(index_definition)}
|
106
|
+
SQL
|
116
107
|
end
|
117
108
|
|
118
109
|
# Remove the given index from the table.
|
@@ -120,12 +111,8 @@ module ActiveRecord
|
|
120
111
|
# @param table_name [String, Symbol]
|
121
112
|
# @param options [Hash] optional
|
122
113
|
def remove_index(table_name, column_name = nil, **options)
|
123
|
-
if
|
124
|
-
|
125
|
-
index_name = index_name_for_remove(table_name, column_name, options)
|
126
|
-
else
|
127
|
-
index_name = index_name_for_remove(table_name, options)
|
128
|
-
end
|
114
|
+
return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
|
115
|
+
index_name = index_name_for_remove(table_name, column_name, options)
|
129
116
|
|
130
117
|
execute "ALTER TABLE #{quote_table_name(table_name)} DROP INDEX #{quote_column_name(index_name)}"
|
131
118
|
end
|
@@ -166,7 +153,7 @@ module ActiveRecord
|
|
166
153
|
|
167
154
|
attr_reader :mysql_adapter
|
168
155
|
|
169
|
-
if ActiveRecord.version
|
156
|
+
if Departure::RailsAdapter.version_matches?(ActiveRecord.version, '~> 7.1.0')
|
170
157
|
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
|
171
158
|
log(sql, name, async: async) do
|
172
159
|
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
@@ -0,0 +1,293 @@
|
|
1
|
+
require 'active_record/connection_adapters/abstract_mysql_adapter'
|
2
|
+
require 'active_record/connection_adapters/statement_pool'
|
3
|
+
require 'active_record/connection_adapters/mysql2_adapter'
|
4
|
+
require 'active_record/connection_adapters/mysql2/database_statements'
|
5
|
+
require 'active_record/connection_adapters/patch_connection_handling'
|
6
|
+
require 'active_support/core_ext/string/filters'
|
7
|
+
require 'departure'
|
8
|
+
require 'forwardable'
|
9
|
+
|
10
|
+
module ActiveRecord
|
11
|
+
module ConnectionAdapters
|
12
|
+
class Rails80DepartureAdapter < AbstractMysqlAdapter
|
13
|
+
include ActiveRecord::ConnectionAdapters::Mysql2::DatabaseStatements
|
14
|
+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) } if defined?(initialize_type_map)
|
15
|
+
|
16
|
+
class Column < ActiveRecord::ConnectionAdapters::MySQL::Column
|
17
|
+
def adapter
|
18
|
+
Rails80DepartureAdapter
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class SchemaCreation < ActiveRecord::ConnectionAdapters::MySQL::SchemaCreation
|
23
|
+
def visit_DropForeignKey(name) # rubocop:disable Naming/MethodName
|
24
|
+
fk_name =
|
25
|
+
if name =~ /^__(.+)/
|
26
|
+
Regexp.last_match(1)
|
27
|
+
else
|
28
|
+
"_#{name}"
|
29
|
+
end
|
30
|
+
|
31
|
+
"DROP FOREIGN KEY #{fk_name}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
extend Forwardable
|
36
|
+
|
37
|
+
include ForAlterStatements unless method_defined?(:change_column_for_alter)
|
38
|
+
|
39
|
+
ADAPTER_NAME = 'Percona'.freeze
|
40
|
+
|
41
|
+
def self.new_client(config)
|
42
|
+
connection_details = Departure::ConnectionDetails.new(config)
|
43
|
+
verbose = ActiveRecord::Migration.verbose
|
44
|
+
sanitizers = [
|
45
|
+
Departure::LogSanitizers::PasswordSanitizer.new(connection_details)
|
46
|
+
]
|
47
|
+
percona_logger = Departure::LoggerFactory.build(sanitizers: sanitizers, verbose: verbose)
|
48
|
+
cli_generator = Departure::CliGenerator.new(connection_details)
|
49
|
+
|
50
|
+
mysql_adapter = ActiveRecord::ConnectionAdapters::Mysql2Adapter.new(config.merge(adapter: 'mysql2'))
|
51
|
+
|
52
|
+
Departure::Runner.new(
|
53
|
+
percona_logger,
|
54
|
+
cli_generator,
|
55
|
+
mysql_adapter
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
def initialize(config)
|
60
|
+
super
|
61
|
+
|
62
|
+
@config[:flags] ||= 0
|
63
|
+
|
64
|
+
if @config[:flags].is_a? Array
|
65
|
+
@config[:flags].push 'FOUND_ROWS'
|
66
|
+
else
|
67
|
+
@config[:flags] |= ::Mysql2::Client::FOUND_ROWS
|
68
|
+
end
|
69
|
+
|
70
|
+
@prepared_statements = false
|
71
|
+
end
|
72
|
+
|
73
|
+
def write_query?(sql) # :nodoc:
|
74
|
+
!ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
75
|
+
:desc, :describe, :set, :show, :use
|
76
|
+
).match?(sql)
|
77
|
+
end
|
78
|
+
|
79
|
+
def exec_delete(sql, name, binds)
|
80
|
+
execute(to_sql(sql, binds), name)
|
81
|
+
|
82
|
+
@raw_connection.affected_rows
|
83
|
+
end
|
84
|
+
alias exec_update exec_delete
|
85
|
+
|
86
|
+
def exec_insert(sql, name, binds, pky = nil, sequence_name = nil, returning: nil) # rubocop:disable Lint/UnusedMethodArgument, Metrics/ParameterLists
|
87
|
+
execute(to_sql(sql, binds), name)
|
88
|
+
end
|
89
|
+
|
90
|
+
def internal_exec_query(sql, name = 'SQL', _binds = [], **_kwargs) # :nodoc:
|
91
|
+
result = execute(sql, name)
|
92
|
+
fields = result.fields if defined?(result.fields)
|
93
|
+
ActiveRecord::Result.new(fields || [], result.to_a)
|
94
|
+
end
|
95
|
+
alias exec_query internal_exec_query
|
96
|
+
|
97
|
+
# Executes a SELECT query and returns an array of rows. Each row is an
|
98
|
+
# array of field values.
|
99
|
+
|
100
|
+
def select_rows(arel, name = nil, binds = [])
|
101
|
+
select_all(arel, name, binds).rows
|
102
|
+
end
|
103
|
+
|
104
|
+
# Executes a SELECT query and returns an array of record hashes with the
|
105
|
+
# column names as keys and column values as values.
|
106
|
+
def select(sql, name = nil, binds = [], **kwargs)
|
107
|
+
exec_query(sql, name, binds, **kwargs)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns true, as this adapter supports migrations
|
111
|
+
def supports_migrations?
|
112
|
+
true
|
113
|
+
end
|
114
|
+
|
115
|
+
def new_column(...)
|
116
|
+
Column.new(...)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Adds a new index to the table
|
120
|
+
#
|
121
|
+
# @param table_name [String, Symbol]
|
122
|
+
# @param column_name [String, Symbol]
|
123
|
+
# @param options [Hash] optional
|
124
|
+
def add_index(table_name, column_name, options = {})
|
125
|
+
index_definition, = add_index_options(table_name, column_name, **options)
|
126
|
+
execute <<-SQL.squish
|
127
|
+
ALTER TABLE #{quote_table_name(index_definition.table)}
|
128
|
+
ADD #{schema_creation.accept(index_definition)}
|
129
|
+
SQL
|
130
|
+
end
|
131
|
+
|
132
|
+
# Remove the given index from the table.
|
133
|
+
#
|
134
|
+
# @param table_name [String, Symbol]
|
135
|
+
# @param options [Hash] optional
|
136
|
+
def remove_index(table_name, column_name = nil, **options)
|
137
|
+
return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
|
138
|
+
|
139
|
+
index_name = index_name_for_remove(table_name, column_name, options)
|
140
|
+
|
141
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} DROP INDEX #{quote_column_name(index_name)}"
|
142
|
+
end
|
143
|
+
|
144
|
+
def schema_creation
|
145
|
+
SchemaCreation.new(self)
|
146
|
+
end
|
147
|
+
|
148
|
+
def change_table(table_name, _options = {})
|
149
|
+
recorder = ActiveRecord::Migration::CommandRecorder.new(self)
|
150
|
+
yield update_table_definition(table_name, recorder)
|
151
|
+
bulk_change_table(table_name, recorder.commands)
|
152
|
+
end
|
153
|
+
|
154
|
+
def full_version
|
155
|
+
get_full_version
|
156
|
+
end
|
157
|
+
|
158
|
+
def get_full_version # rubocop:disable Naming/AccessorMethodName
|
159
|
+
return @get_full_version if defined? @get_full_version
|
160
|
+
|
161
|
+
with_raw_connection do |conn|
|
162
|
+
@get_full_version = conn.database_adapter.get_database_version.full_version_string
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def last_inserted_id(result)
|
167
|
+
@raw_connection.database_adapter.send(:last_inserted_id, result)
|
168
|
+
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
attr_reader :mysql_adapter
|
173
|
+
|
174
|
+
def each_hash(result, &block) # :nodoc:
|
175
|
+
@raw_connection.database_adapter.each_hash(result, &block)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Must return the MySQL error number from the exception, if the exception has an
|
179
|
+
# error number.
|
180
|
+
def error_number(exception)
|
181
|
+
@raw_connection.database_adapter.error_number(exception)
|
182
|
+
end
|
183
|
+
|
184
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/ParameterLists
|
185
|
+
def raw_execute(sql, name = nil, binds = [], prepare: false, async: false, allow_retry: false,
|
186
|
+
materialize_transactions: true, batch: false)
|
187
|
+
type_casted_binds = type_casted_binds(binds)
|
188
|
+
log(sql, name, binds, type_casted_binds, async: async) do |notification_payload|
|
189
|
+
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
190
|
+
perform_query(conn, sql, binds, type_casted_binds, prepare: prepare,
|
191
|
+
notification_payload: notification_payload, batch: batch)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch: false)
|
197
|
+
reset_multi_statement = if batch && !multi_statements_enabled?
|
198
|
+
raw_connection.set_server_option(::Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)
|
199
|
+
true
|
200
|
+
end
|
201
|
+
|
202
|
+
# Make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
203
|
+
# made since we established the connection
|
204
|
+
raw_connection.query_options[:database_timezone] = default_timezone
|
205
|
+
|
206
|
+
result = nil
|
207
|
+
if binds.nil? || binds.empty?
|
208
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
209
|
+
result = raw_connection.query(sql)
|
210
|
+
# Ref: https://github.com/brianmario/mysql2/pull/1383
|
211
|
+
# As of mysql2 0.5.6 `#affected_rows` might raise Mysql2::Error if a prepared statement
|
212
|
+
# from that same connection was GCed while `#query` released the GVL.
|
213
|
+
# By avoiding to call `#affected_rows` when we have a result, we reduce the likeliness
|
214
|
+
# of hitting the bug.
|
215
|
+
|
216
|
+
# THIS IS THE CORE CHANGES 1 related to size
|
217
|
+
# We will sometimes have a process exit code instead of a result from executing
|
218
|
+
@affected_rows_before_warnings = result.try(:size) || raw_connection.affected_rows
|
219
|
+
end
|
220
|
+
elsif prepare
|
221
|
+
|
222
|
+
stmt = @statements[sql] ||= raw_connection.prepare(sql)
|
223
|
+
begin
|
224
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
225
|
+
result = stmt.execute(*type_casted_binds)
|
226
|
+
@affected_rows_before_warnings = stmt.affected_rows
|
227
|
+
end
|
228
|
+
rescue ::Mysql2::Error
|
229
|
+
@statements.delete(sql)
|
230
|
+
raise
|
231
|
+
end
|
232
|
+
else
|
233
|
+
stmt = raw_connection.prepare(sql)
|
234
|
+
|
235
|
+
begin
|
236
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
237
|
+
result = stmt.execute(*type_casted_binds)
|
238
|
+
@affected_rows_before_warnings = stmt.affected_rows
|
239
|
+
end
|
240
|
+
|
241
|
+
# Ref: https://github.com/brianmario/mysql2/pull/1383
|
242
|
+
# by eagerly closing uncached prepared statements, we also reduce the chances of
|
243
|
+
# that bug happening. It can still happen if `#execute` is used as we have no callback
|
244
|
+
# to eagerly close the statement.
|
245
|
+
if result
|
246
|
+
result.instance_variable_set(:@_ar_stmt_to_close, stmt)
|
247
|
+
else
|
248
|
+
stmt.close
|
249
|
+
end
|
250
|
+
rescue ::Mysql2::Error
|
251
|
+
stmt.close
|
252
|
+
raise
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
notification_payload[:affected_rows] = @affected_rows_before_warnings
|
257
|
+
|
258
|
+
# THIS IS THE CORE CHANGES 2 related to size
|
259
|
+
notification_payload[:row_count] = result.try(:size) || 0
|
260
|
+
|
261
|
+
if result.is_a? Process::Status
|
262
|
+
notification_payload[:exit_code] = result.exitstatus
|
263
|
+
notification_payload[:exit_pid] = result.pid
|
264
|
+
end
|
265
|
+
|
266
|
+
raw_connection.abandon_results!
|
267
|
+
|
268
|
+
verified!
|
269
|
+
handle_warnings(sql)
|
270
|
+
result
|
271
|
+
ensure
|
272
|
+
if reset_multi_statement && active?
|
273
|
+
raw_connection.set_server_option(::Mysql2::Client::OPTION_MULTI_STATEMENTS_OFF)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/ParameterLists
|
277
|
+
|
278
|
+
def connect
|
279
|
+
@raw_connection = self.class.new_client(@config)
|
280
|
+
rescue ConnectionNotEstablished => e
|
281
|
+
raise e.set_pool(@pool)
|
282
|
+
end
|
283
|
+
|
284
|
+
def reconnect
|
285
|
+
@lock.synchronize do
|
286
|
+
@raw_connection&.close
|
287
|
+
@raw_connection = nil
|
288
|
+
connect
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
data/lib/departure/migration.rb
CHANGED
@@ -94,11 +94,7 @@ module Departure
|
|
94
94
|
end
|
95
95
|
|
96
96
|
private def configuration_hash
|
97
|
-
|
98
|
-
ActiveRecord::Base.connection_db_config.configuration_hash
|
99
|
-
else
|
100
|
-
ActiveRecord::Base.connection_config
|
101
|
-
end
|
97
|
+
ActiveRecord::Base.connection_db_config.configuration_hash
|
102
98
|
end
|
103
99
|
end
|
104
100
|
end
|