departure 8.1.0 → 8.2.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 +3 -1
- data/.pryrc +6 -6
- data/.standard.yml +9 -0
- data/AGENTS.md +9 -7
- data/Appraisals +11 -9
- data/CHANGELOG.md +4 -0
- data/Gemfile +8 -9
- data/Gemfile.lock +25 -11
- data/README.md +1 -1
- data/RELEASING.md +5 -4
- data/Rakefile +10 -10
- data/configuration.rb +3 -3
- data/departure.gemspec +22 -24
- data/gemfiles/rails_7_2.gemfile +12 -12
- data/gemfiles/rails_7_2.gemfile.lock +28 -11
- data/gemfiles/rails_8_0.gemfile +12 -12
- data/gemfiles/rails_8_0.gemfile.lock +28 -11
- data/gemfiles/rails_8_1.gemfile +11 -12
- data/gemfiles/rails_8_1.gemfile.lock +25 -11
- data/lib/active_record/connection_adapters/departure_adapter_behavior.rb +88 -0
- data/lib/active_record/connection_adapters/for_alter.rb +4 -4
- data/lib/active_record/connection_adapters/patch_connection_handling.rb +2 -2
- data/lib/active_record/connection_adapters/rails_7_2_departure_adapter.rb +17 -58
- data/lib/active_record/connection_adapters/rails_7_2_trilogy_adapter.rb +53 -0
- data/lib/active_record/connection_adapters/rails_8_0_departure_adapter.rb +26 -66
- data/lib/active_record/connection_adapters/rails_8_0_trilogy_adapter.rb +21 -0
- data/lib/active_record/connection_adapters/rails_8_1_mysql2_adapter.rb +7 -7
- data/lib/active_record/connection_adapters/rails_8_1_trilogy_adapter.rb +7 -7
- data/lib/departure/alter_argument.rb +6 -6
- data/lib/departure/cli_generator.rb +12 -12
- data/lib/departure/command.rb +1 -1
- data/lib/departure/configuration.rb +3 -3
- data/lib/departure/connection_details.rb +7 -7
- data/lib/departure/db_client.rb +5 -5
- data/lib/departure/dsn.rb +2 -2
- data/lib/departure/errors.rb +2 -2
- data/lib/departure/log_sanitizers/password_sanitizer.rb +1 -1
- data/lib/departure/logger.rb +2 -2
- data/lib/departure/option.rb +4 -4
- data/lib/departure/rails_adapter.rb +126 -102
- data/lib/departure/rails_patches/active_record_migrator_with_advisory_lock_patch.rb +2 -2
- data/lib/departure/railtie.rb +5 -5
- data/lib/departure/runner.rb +3 -3
- data/lib/departure/user_options.rb +1 -1
- data/lib/departure/version.rb +1 -1
- data/lib/departure.rb +18 -18
- data/lib/lhm/adapter.rb +12 -12
- data/lib/lhm/column_with_sql.rb +8 -8
- data/lib/lhm.rb +1 -1
- data/test_database.rb +10 -10
- metadata +5 -4
- data/.rubocop.yml +0 -66
- data/.rubocop_todo.yml +0 -238
- data/lib/active_record/connection_adapters/rails_8_1_adapter_behavior.rb +0 -64
data/gemfiles/rails_8_1.gemfile
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
# This file was generated by Appraisal
|
|
2
2
|
|
|
3
|
-
source
|
|
3
|
+
source "https://rubygems.org"
|
|
4
4
|
|
|
5
|
-
gem
|
|
6
|
-
gem
|
|
7
|
-
gem
|
|
8
|
-
gem
|
|
9
|
-
gem
|
|
10
|
-
gem
|
|
11
|
-
gem
|
|
12
|
-
gem
|
|
13
|
-
gem
|
|
14
|
-
gem 'zeitwerk', '< 2.7.0'
|
|
5
|
+
gem "base64"
|
|
6
|
+
gem "codeclimate-test-reporter", "~> 1.0.3", group: :test, require: nil
|
|
7
|
+
gem "lhm"
|
|
8
|
+
gem "logger"
|
|
9
|
+
gem "mutex_m", require: false
|
|
10
|
+
gem "rails", "8.1.1"
|
|
11
|
+
gem "standardrb", require: false
|
|
12
|
+
gem "trilogy"
|
|
13
|
+
gem "zeitwerk", "< 2.7.0"
|
|
15
14
|
|
|
16
|
-
gemspec path:
|
|
15
|
+
gemspec path: "../"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
departure (8.
|
|
4
|
+
departure (8.2.0)
|
|
5
5
|
activerecord (>= 7.2.0)
|
|
6
6
|
mysql2 (>= 0.4.0, < 0.6.0)
|
|
7
7
|
railties (>= 7.2.0)
|
|
@@ -169,7 +169,7 @@ GEM
|
|
|
169
169
|
pp (0.6.3)
|
|
170
170
|
prettyprint
|
|
171
171
|
prettyprint (0.2.0)
|
|
172
|
-
prism (1.
|
|
172
|
+
prism (1.9.0)
|
|
173
173
|
pry (0.15.2)
|
|
174
174
|
coderay (~> 1.1)
|
|
175
175
|
method_source (~> 1.0)
|
|
@@ -243,7 +243,7 @@ GEM
|
|
|
243
243
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
244
244
|
rspec-support (~> 3.13.0)
|
|
245
245
|
rspec-support (3.13.6)
|
|
246
|
-
rubocop (1.
|
|
246
|
+
rubocop (1.84.2)
|
|
247
247
|
json (~> 2.3)
|
|
248
248
|
language_server-protocol (~> 3.17.0.2)
|
|
249
249
|
lint_roller (~> 1.1.0)
|
|
@@ -251,15 +251,16 @@ GEM
|
|
|
251
251
|
parser (>= 3.3.0.2)
|
|
252
252
|
rainbow (>= 2.2.2, < 4.0)
|
|
253
253
|
regexp_parser (>= 2.9.3, < 3.0)
|
|
254
|
-
rubocop-ast (>= 1.
|
|
254
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
255
255
|
ruby-progressbar (~> 1.7)
|
|
256
256
|
unicode-display_width (>= 2.4.0, < 4.0)
|
|
257
|
-
rubocop-ast (1.
|
|
257
|
+
rubocop-ast (1.49.1)
|
|
258
258
|
parser (>= 3.3.7.2)
|
|
259
|
-
prism (~> 1.
|
|
260
|
-
rubocop-performance (1.
|
|
261
|
-
|
|
262
|
-
rubocop
|
|
259
|
+
prism (~> 1.7)
|
|
260
|
+
rubocop-performance (1.26.1)
|
|
261
|
+
lint_roller (~> 1.1)
|
|
262
|
+
rubocop (>= 1.75.0, < 2.0)
|
|
263
|
+
rubocop-ast (>= 1.47.1, < 2.0)
|
|
263
264
|
ruby-progressbar (1.13.0)
|
|
264
265
|
securerandom (0.4.1)
|
|
265
266
|
simplecov (0.13.0)
|
|
@@ -267,6 +268,20 @@ GEM
|
|
|
267
268
|
json (>= 1.8, < 3)
|
|
268
269
|
simplecov-html (~> 0.10.0)
|
|
269
270
|
simplecov-html (0.10.2)
|
|
271
|
+
standard (1.54.0)
|
|
272
|
+
language_server-protocol (~> 3.17.0.2)
|
|
273
|
+
lint_roller (~> 1.0)
|
|
274
|
+
rubocop (~> 1.84.0)
|
|
275
|
+
standard-custom (~> 1.0.0)
|
|
276
|
+
standard-performance (~> 1.8)
|
|
277
|
+
standard-custom (1.0.2)
|
|
278
|
+
lint_roller (~> 1.0)
|
|
279
|
+
rubocop (~> 1.50)
|
|
280
|
+
standard-performance (1.9.0)
|
|
281
|
+
lint_roller (~> 1.1)
|
|
282
|
+
rubocop-performance (~> 1.26.0)
|
|
283
|
+
standardrb (1.0.1)
|
|
284
|
+
standard
|
|
270
285
|
stringio (3.1.7)
|
|
271
286
|
thor (1.4.0)
|
|
272
287
|
timeout (0.4.4)
|
|
@@ -309,8 +324,7 @@ DEPENDENCIES
|
|
|
309
324
|
rake (>= 10.0)
|
|
310
325
|
rspec (~> 3.4, >= 3.4.0)
|
|
311
326
|
rspec-its (~> 1.2)
|
|
312
|
-
|
|
313
|
-
rubocop-performance (~> 1.20.2)
|
|
327
|
+
standardrb
|
|
314
328
|
trilogy
|
|
315
329
|
zeitwerk (< 2.7.0)
|
|
316
330
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
module ActiveRecord
|
|
2
|
+
module ConnectionAdapters
|
|
3
|
+
# Behavior shared between the per-Rails-version Departure adapters.
|
|
4
|
+
# Adapters compose the pieces they need:
|
|
5
|
+
#
|
|
6
|
+
# - SchemaStatements: ALTER TABLE-friendly schema statements, so every DDL
|
|
7
|
+
# change goes through a statement pt-online-schema-change understands.
|
|
8
|
+
# - DbClientConnection: wraps the raw database client in a
|
|
9
|
+
# Departure::DbClient, which routes ALTER TABLE statements to
|
|
10
|
+
# pt-online-schema-change.
|
|
11
|
+
# - PerformQuery: intercepts ALTER TABLE statements through the
|
|
12
|
+
# perform_query hook available on Rails >= 8.0.
|
|
13
|
+
# - Rails8: the composition used by Rails >= 8.0 adapters.
|
|
14
|
+
module DepartureAdapterBehavior
|
|
15
|
+
module SchemaStatements
|
|
16
|
+
class SchemaCreation < ActiveRecord::ConnectionAdapters::MySQL::SchemaCreation
|
|
17
|
+
def visit_DropForeignKey(name) # standard:disable Naming/MethodName
|
|
18
|
+
fk_name =
|
|
19
|
+
if name =~ /^__(.+)/
|
|
20
|
+
Regexp.last_match(1)
|
|
21
|
+
else
|
|
22
|
+
"_#{name}"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
"DROP FOREIGN KEY #{fk_name}"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.included(adapter_class)
|
|
30
|
+
adapter_class.const_set(:SchemaCreation, SchemaCreation)
|
|
31
|
+
adapter_class.include ForAlterStatements unless adapter_class.method_defined?(:change_column_for_alter)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# add_index is modified from the underlying mysql adapter implementation to ensure we add ALTER TABLE to it
|
|
35
|
+
def add_index(table_name, column_name, options = {})
|
|
36
|
+
index_definition, = add_index_options(table_name, column_name, **options)
|
|
37
|
+
execute <<-SQL.squish
|
|
38
|
+
ALTER TABLE #{quote_table_name(index_definition.table)}
|
|
39
|
+
ADD #{schema_creation.accept(index_definition)}
|
|
40
|
+
SQL
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# remove_index is modified from the underlying mysql adapter implementation to ensure we add ALTER TABLE to it
|
|
44
|
+
def remove_index(table_name, column_name = nil, **options)
|
|
45
|
+
return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
|
|
46
|
+
|
|
47
|
+
index_name = index_name_for_remove(table_name, column_name, options)
|
|
48
|
+
|
|
49
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} DROP INDEX #{quote_column_name(index_name)}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def schema_creation
|
|
53
|
+
self.class::SchemaCreation.new(self)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Meant to be used with `extend`, so new_client can call super up to the
|
|
58
|
+
# underlying adapter's implementation.
|
|
59
|
+
module DbClientConnection
|
|
60
|
+
def new_client(config)
|
|
61
|
+
original_client = super
|
|
62
|
+
|
|
63
|
+
Departure::DbClient.new(config, original_client)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
module PerformQuery
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
# rubocop:disable Metrics/ParameterLists
|
|
71
|
+
def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch: false)
|
|
72
|
+
return raw_connection.send_to_pt_online_schema_change(sql) if raw_connection.alter_statement?(sql)
|
|
73
|
+
|
|
74
|
+
super
|
|
75
|
+
end
|
|
76
|
+
# rubocop:enable Metrics/ParameterLists
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
module Rails8
|
|
80
|
+
def self.included(adapter_class)
|
|
81
|
+
adapter_class.include SchemaStatements
|
|
82
|
+
adapter_class.extend DbClientConnection
|
|
83
|
+
adapter_class.include PerformQuery
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "active_record/connection_adapters/mysql/schema_statements"
|
|
2
2
|
|
|
3
3
|
module ForAlterStatements
|
|
4
4
|
def bulk_change_table(table_name, operations) #:nodoc:
|
|
@@ -10,7 +10,7 @@ module ForAlterStatements
|
|
|
10
10
|
|
|
11
11
|
raise "Unknown method called : #{method}(#{arguments.inspect})" unless respond_to?(method, true)
|
|
12
12
|
public_send(method, table, *arguments)
|
|
13
|
-
end.join(
|
|
13
|
+
end.join(", ")
|
|
14
14
|
|
|
15
15
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{sqls}")
|
|
16
16
|
end
|
|
@@ -31,7 +31,7 @@ module ForAlterStatements
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def rename_column_for_alter(table_name, column_name, new_column_name)
|
|
34
|
-
column
|
|
34
|
+
column = column_for(table_name, column_name)
|
|
35
35
|
options = {
|
|
36
36
|
default: column.default,
|
|
37
37
|
null: column.null,
|
|
@@ -39,7 +39,7 @@ module ForAlterStatements
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
columns_sql = "SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}"
|
|
42
|
-
current_type = exec_query(columns_sql,
|
|
42
|
+
current_type = exec_query(columns_sql, "SCHEMA").first["Type"]
|
|
43
43
|
td = create_table_definition(table_name)
|
|
44
44
|
cd = td.new_column_definition(new_column_name, current_type, **options)
|
|
45
45
|
schema_creation.accept(ActiveRecord::ConnectionAdapters::ChangeColumnDefinition.new(cd, column.name))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "active_record/connection_handling"
|
|
4
4
|
|
|
5
5
|
module ActiveRecord
|
|
6
6
|
module ConnectionHandling
|
|
@@ -9,7 +9,7 @@ module ActiveRecord
|
|
|
9
9
|
def percona_connection(config)
|
|
10
10
|
config = config.dup
|
|
11
11
|
original_adapter = config.delete(:departure_original_adapter)
|
|
12
|
-
config[:username] ||=
|
|
12
|
+
config[:username] ||= "root"
|
|
13
13
|
|
|
14
14
|
Departure::RailsAdapter
|
|
15
15
|
.for_current(db_connection_adapter: original_adapter)
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
require
|
|
7
|
-
require
|
|
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/patch_connection_handling"
|
|
5
|
+
require "active_support/core_ext/string/filters"
|
|
6
|
+
require "departure"
|
|
7
|
+
require "forwardable"
|
|
8
|
+
require "active_record/connection_adapters/departure_adapter_behavior"
|
|
8
9
|
|
|
9
10
|
module ActiveRecord
|
|
10
11
|
module ConnectionAdapters
|
|
@@ -17,24 +18,11 @@ module ActiveRecord
|
|
|
17
18
|
end
|
|
18
19
|
end
|
|
19
20
|
|
|
20
|
-
class SchemaCreation < ActiveRecord::ConnectionAdapters::MySQL::SchemaCreation
|
|
21
|
-
def visit_DropForeignKey(name) # rubocop:disable Style/MethodName
|
|
22
|
-
fk_name =
|
|
23
|
-
if name =~ /^__(.+)/
|
|
24
|
-
Regexp.last_match(1)
|
|
25
|
-
else
|
|
26
|
-
"_#{name}"
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
"DROP FOREIGN KEY #{fk_name}"
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
21
|
extend Forwardable
|
|
34
22
|
|
|
35
|
-
include
|
|
23
|
+
include DepartureAdapterBehavior::SchemaStatements
|
|
36
24
|
|
|
37
|
-
ADAPTER_NAME =
|
|
25
|
+
ADAPTER_NAME = "Percona".freeze
|
|
38
26
|
|
|
39
27
|
def self.new_client(config)
|
|
40
28
|
connection_details = Departure::ConnectionDetails.new(config)
|
|
@@ -45,7 +33,7 @@ module ActiveRecord
|
|
|
45
33
|
percona_logger = Departure::LoggerFactory.build(sanitizers: sanitizers, verbose: verbose)
|
|
46
34
|
cli_generator = Departure::CliGenerator.new(connection_details)
|
|
47
35
|
|
|
48
|
-
mysql_adapter = ActiveRecord::ConnectionAdapters::Mysql2Adapter.new(config.merge(adapter:
|
|
36
|
+
mysql_adapter = ActiveRecord::ConnectionAdapters::Mysql2Adapter.new(config.merge(adapter: "mysql2"))
|
|
49
37
|
|
|
50
38
|
Departure::Runner.new(
|
|
51
39
|
percona_logger,
|
|
@@ -60,7 +48,7 @@ module ActiveRecord
|
|
|
60
48
|
@config[:flags] ||= 0
|
|
61
49
|
|
|
62
50
|
if @config[:flags].is_a? Array
|
|
63
|
-
@config[:flags].push
|
|
51
|
+
@config[:flags].push "FOUND_ROWS"
|
|
64
52
|
else
|
|
65
53
|
@config[:flags] |= ::Mysql2::Client::FOUND_ROWS
|
|
66
54
|
end
|
|
@@ -79,18 +67,18 @@ module ActiveRecord
|
|
|
79
67
|
|
|
80
68
|
@raw_connection.affected_rows
|
|
81
69
|
end
|
|
82
|
-
|
|
70
|
+
alias_method :exec_update, :exec_delete
|
|
83
71
|
|
|
84
|
-
def exec_insert(sql, name, binds, pky = nil, sequence_name = nil, returning: nil) #
|
|
72
|
+
def exec_insert(sql, name, binds, pky = nil, sequence_name = nil, returning: nil) # standard:disable Lint/UnusedMethodArgument
|
|
85
73
|
execute(to_sql(sql, binds), name)
|
|
86
74
|
end
|
|
87
75
|
|
|
88
|
-
def internal_exec_query(sql, name =
|
|
76
|
+
def internal_exec_query(sql, name = "SQL", _binds = [], **_kwargs) # :nodoc:
|
|
89
77
|
result = execute(sql, name)
|
|
90
78
|
fields = result.fields if defined?(result.fields)
|
|
91
79
|
ActiveRecord::Result.new(fields || [], result.to_a)
|
|
92
80
|
end
|
|
93
|
-
|
|
81
|
+
alias_method :exec_query, :internal_exec_query
|
|
94
82
|
|
|
95
83
|
# Executes a SELECT query and returns an array of rows. Each row is an
|
|
96
84
|
# array of field values.
|
|
@@ -114,35 +102,6 @@ module ActiveRecord
|
|
|
114
102
|
Column.new(...)
|
|
115
103
|
end
|
|
116
104
|
|
|
117
|
-
# Adds a new index to the table
|
|
118
|
-
#
|
|
119
|
-
# @param table_name [String, Symbol]
|
|
120
|
-
# @param column_name [String, Symbol]
|
|
121
|
-
# @param options [Hash] optional
|
|
122
|
-
def add_index(table_name, column_name, options = {})
|
|
123
|
-
index_definition, = add_index_options(table_name, column_name, **options)
|
|
124
|
-
execute <<-SQL.squish
|
|
125
|
-
ALTER TABLE #{quote_table_name(index_definition.table)}
|
|
126
|
-
ADD #{schema_creation.accept(index_definition)}
|
|
127
|
-
SQL
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
# Remove the given index from the table.
|
|
131
|
-
#
|
|
132
|
-
# @param table_name [String, Symbol]
|
|
133
|
-
# @param options [Hash] optional
|
|
134
|
-
def remove_index(table_name, column_name = nil, **options)
|
|
135
|
-
return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
|
|
136
|
-
|
|
137
|
-
index_name = index_name_for_remove(table_name, column_name, options)
|
|
138
|
-
|
|
139
|
-
execute "ALTER TABLE #{quote_table_name(table_name)} DROP INDEX #{quote_column_name(index_name)}"
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def schema_creation
|
|
143
|
-
SchemaCreation.new(self)
|
|
144
|
-
end
|
|
145
|
-
|
|
146
105
|
def change_table(table_name, _options = {})
|
|
147
106
|
recorder = ActiveRecord::Migration::CommandRecorder.new(self)
|
|
148
107
|
yield update_table_definition(table_name, recorder)
|
|
@@ -153,7 +112,7 @@ module ActiveRecord
|
|
|
153
112
|
get_full_version
|
|
154
113
|
end
|
|
155
114
|
|
|
156
|
-
def get_full_version #
|
|
115
|
+
def get_full_version # standard:disable Naming/AccessorMethodName
|
|
157
116
|
return @get_full_version if defined? @get_full_version
|
|
158
117
|
|
|
159
118
|
with_raw_connection do |conn|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require "active_record/connection_adapters/abstract_mysql_adapter"
|
|
2
|
+
require "active_record/connection_adapters/trilogy_adapter"
|
|
3
|
+
require "active_record/connection_adapters/patch_connection_handling"
|
|
4
|
+
require "departure"
|
|
5
|
+
require "active_record/connection_adapters/departure_adapter_behavior"
|
|
6
|
+
|
|
7
|
+
module ActiveRecord
|
|
8
|
+
module ConnectionAdapters
|
|
9
|
+
class Rails72TrilogyAdapter < ActiveRecord::ConnectionAdapters::TrilogyAdapter
|
|
10
|
+
class Column < ActiveRecord::ConnectionAdapters::MySQL::Column
|
|
11
|
+
def adapter
|
|
12
|
+
Rails72TrilogyAdapter
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
ADAPTER_NAME = "Percona".freeze
|
|
17
|
+
|
|
18
|
+
include DepartureAdapterBehavior::SchemaStatements
|
|
19
|
+
extend DepartureAdapterBehavior::DbClientConnection
|
|
20
|
+
|
|
21
|
+
def new_column(...)
|
|
22
|
+
Column.new(...)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
# Rails 7.2 has no perform_query hook, so the interception happens here:
|
|
28
|
+
# the DbClient wrapper routes ALTER TABLE statements to
|
|
29
|
+
# pt-online-schema-change, which yields a Process::Status instead of a
|
|
30
|
+
# Trilogy::Result.
|
|
31
|
+
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
|
|
32
|
+
log(sql, name, async: async) do |notification_payload|
|
|
33
|
+
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
|
34
|
+
sync_timezone_changes(conn)
|
|
35
|
+
result = conn.query(sql)
|
|
36
|
+
while conn.more_results_exist?
|
|
37
|
+
conn.next_result
|
|
38
|
+
end
|
|
39
|
+
verified!
|
|
40
|
+
handle_warnings(sql)
|
|
41
|
+
if result.is_a?(Process::Status)
|
|
42
|
+
notification_payload[:exit_code] = result.exitstatus
|
|
43
|
+
notification_payload[:exit_pid] = result.pid
|
|
44
|
+
elsif result.respond_to?(:count)
|
|
45
|
+
notification_payload[:row_count] = result.count
|
|
46
|
+
end
|
|
47
|
+
result
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
require
|
|
7
|
-
require
|
|
8
|
-
require
|
|
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
|
+
require "active_record/connection_adapters/departure_adapter_behavior"
|
|
9
10
|
|
|
10
11
|
module ActiveRecord
|
|
11
12
|
module ConnectionAdapters
|
|
12
13
|
class Rails80DepartureAdapter < AbstractMysqlAdapter
|
|
13
14
|
include ActiveRecord::ConnectionAdapters::Mysql2::DatabaseStatements
|
|
15
|
+
|
|
14
16
|
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) } if defined?(initialize_type_map)
|
|
15
17
|
|
|
16
18
|
class Column < ActiveRecord::ConnectionAdapters::MySQL::Column
|
|
@@ -19,24 +21,11 @@ module ActiveRecord
|
|
|
19
21
|
end
|
|
20
22
|
end
|
|
21
23
|
|
|
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
24
|
extend Forwardable
|
|
36
25
|
|
|
37
|
-
include
|
|
26
|
+
include DepartureAdapterBehavior::SchemaStatements
|
|
38
27
|
|
|
39
|
-
ADAPTER_NAME =
|
|
28
|
+
ADAPTER_NAME = "Percona".freeze
|
|
40
29
|
|
|
41
30
|
def self.new_client(config)
|
|
42
31
|
connection_details = Departure::ConnectionDetails.new(config)
|
|
@@ -47,7 +36,7 @@ module ActiveRecord
|
|
|
47
36
|
percona_logger = Departure::LoggerFactory.build(sanitizers: sanitizers, verbose: verbose)
|
|
48
37
|
cli_generator = Departure::CliGenerator.new(connection_details)
|
|
49
38
|
|
|
50
|
-
mysql_adapter = ActiveRecord::ConnectionAdapters::Mysql2Adapter.new(config.merge(adapter:
|
|
39
|
+
mysql_adapter = ActiveRecord::ConnectionAdapters::Mysql2Adapter.new(config.merge(adapter: "mysql2"))
|
|
51
40
|
|
|
52
41
|
Departure::Runner.new(
|
|
53
42
|
percona_logger,
|
|
@@ -62,7 +51,7 @@ module ActiveRecord
|
|
|
62
51
|
@config[:flags] ||= 0
|
|
63
52
|
|
|
64
53
|
if @config[:flags].is_a? Array
|
|
65
|
-
@config[:flags].push
|
|
54
|
+
@config[:flags].push "FOUND_ROWS"
|
|
66
55
|
else
|
|
67
56
|
@config[:flags] |= ::Mysql2::Client::FOUND_ROWS
|
|
68
57
|
end
|
|
@@ -81,18 +70,18 @@ module ActiveRecord
|
|
|
81
70
|
|
|
82
71
|
@raw_connection.affected_rows
|
|
83
72
|
end
|
|
84
|
-
|
|
73
|
+
alias_method :exec_update, :exec_delete
|
|
85
74
|
|
|
86
75
|
def exec_insert(sql, name, binds, pky = nil, sequence_name = nil, returning: nil) # rubocop:disable Lint/UnusedMethodArgument, Metrics/ParameterLists
|
|
87
76
|
execute(to_sql(sql, binds), name)
|
|
88
77
|
end
|
|
89
78
|
|
|
90
|
-
def internal_exec_query(sql, name =
|
|
79
|
+
def internal_exec_query(sql, name = "SQL", _binds = [], **_kwargs) # :nodoc:
|
|
91
80
|
result = execute(sql, name)
|
|
92
81
|
fields = result.fields if defined?(result.fields)
|
|
93
82
|
ActiveRecord::Result.new(fields || [], result.to_a)
|
|
94
83
|
end
|
|
95
|
-
|
|
84
|
+
alias_method :exec_query, :internal_exec_query
|
|
96
85
|
|
|
97
86
|
# Executes a SELECT query and returns an array of rows. Each row is an
|
|
98
87
|
# array of field values.
|
|
@@ -116,35 +105,6 @@ module ActiveRecord
|
|
|
116
105
|
Column.new(...)
|
|
117
106
|
end
|
|
118
107
|
|
|
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
108
|
def change_table(table_name, _options = {})
|
|
149
109
|
recorder = ActiveRecord::Migration::CommandRecorder.new(self)
|
|
150
110
|
yield update_table_definition(table_name, recorder)
|
|
@@ -183,21 +143,21 @@ module ActiveRecord
|
|
|
183
143
|
|
|
184
144
|
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/ParameterLists
|
|
185
145
|
def raw_execute(sql, name = nil, binds = [], prepare: false, async: false, allow_retry: false,
|
|
186
|
-
|
|
146
|
+
materialize_transactions: true, batch: false)
|
|
187
147
|
type_casted_binds = type_casted_binds(binds)
|
|
188
148
|
log(sql, name, binds, type_casted_binds, async: async) do |notification_payload|
|
|
189
149
|
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
|
190
150
|
perform_query(conn, sql, binds, type_casted_binds, prepare: prepare,
|
|
191
|
-
|
|
151
|
+
notification_payload: notification_payload, batch: batch)
|
|
192
152
|
end
|
|
193
153
|
end
|
|
194
154
|
end
|
|
195
155
|
|
|
196
156
|
def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch: false)
|
|
197
157
|
reset_multi_statement = if batch && !multi_statements_enabled?
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
158
|
+
raw_connection.set_server_option(::Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)
|
|
159
|
+
true
|
|
160
|
+
end
|
|
201
161
|
|
|
202
162
|
# Make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
|
203
163
|
# made since we established the connection
|
|
@@ -216,10 +176,10 @@ module ActiveRecord
|
|
|
216
176
|
# THIS IS THE CORE CHANGES 1 related to size
|
|
217
177
|
# We will sometimes have a process exit code instead of a result from executing
|
|
218
178
|
@affected_rows_before_warnings = if result.is_a? Process::Status
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
179
|
+
result.try(:size) || 0
|
|
180
|
+
else
|
|
181
|
+
result.try(:size) || raw_connection.affected_rows
|
|
182
|
+
end
|
|
223
183
|
end
|
|
224
184
|
elsif prepare
|
|
225
185
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require "active_record/connection_adapters/abstract_mysql_adapter"
|
|
2
|
+
require "active_record/connection_adapters/trilogy_adapter"
|
|
3
|
+
require "active_record/connection_adapters/patch_connection_handling"
|
|
4
|
+
require "departure"
|
|
5
|
+
require "active_record/connection_adapters/departure_adapter_behavior"
|
|
6
|
+
|
|
7
|
+
module ActiveRecord
|
|
8
|
+
module ConnectionAdapters
|
|
9
|
+
class Rails80TrilogyAdapter < ActiveRecord::ConnectionAdapters::TrilogyAdapter
|
|
10
|
+
class Column < ActiveRecord::ConnectionAdapters::MySQL::Column
|
|
11
|
+
def adapter
|
|
12
|
+
Rails80TrilogyAdapter
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
ADAPTER_NAME = "Percona".freeze
|
|
17
|
+
|
|
18
|
+
include DepartureAdapterBehavior::Rails8
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
1
|
+
require "active_record/connection_adapters/abstract_mysql_adapter"
|
|
2
|
+
require "active_record/connection_adapters/mysql2_adapter"
|
|
3
|
+
require "active_record/connection_adapters/patch_connection_handling"
|
|
4
|
+
require "departure"
|
|
5
|
+
require "active_record/connection_adapters/departure_adapter_behavior"
|
|
6
6
|
|
|
7
7
|
module ActiveRecord
|
|
8
8
|
module ConnectionAdapters
|
|
@@ -15,9 +15,9 @@ module ActiveRecord
|
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
ADAPTER_NAME =
|
|
18
|
+
ADAPTER_NAME = "Percona".freeze
|
|
19
19
|
|
|
20
|
-
include
|
|
20
|
+
include DepartureAdapterBehavior::Rails8
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
end
|