switchman 2.0.7 → 3.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/Rakefile +10 -2
- data/app/models/switchman/shard.rb +234 -270
- data/app/models/switchman/unsharded_record.rb +7 -0
- data/db/migrate/20130328212039_create_switchman_shards.rb +1 -1
- data/db/migrate/20130328224244_create_default_shard.rb +5 -5
- data/db/migrate/20161206323434_add_back_default_string_limits_switchman.rb +1 -0
- data/db/migrate/20180828183945_add_default_shard_index.rb +1 -1
- data/db/migrate/20180828192111_add_timestamps_to_shards.rb +7 -5
- data/db/migrate/20190114212900_add_unique_name_indexes.rb +5 -3
- data/lib/switchman.rb +3 -3
- data/lib/switchman/action_controller/caching.rb +2 -2
- data/lib/switchman/active_record/abstract_adapter.rb +1 -0
- data/lib/switchman/active_record/association.rb +78 -89
- data/lib/switchman/active_record/attribute_methods.rb +58 -52
- data/lib/switchman/active_record/base.rb +58 -59
- data/lib/switchman/active_record/calculations.rb +73 -66
- data/lib/switchman/active_record/connection_pool.rb +14 -41
- data/lib/switchman/active_record/database_configurations.rb +34 -0
- data/lib/switchman/active_record/database_configurations/database_config.rb +13 -0
- data/lib/switchman/active_record/finder_methods.rb +11 -16
- data/lib/switchman/active_record/log_subscriber.rb +4 -8
- data/lib/switchman/active_record/migration.rb +5 -14
- data/lib/switchman/active_record/model_schema.rb +1 -1
- data/lib/switchman/active_record/persistence.rb +4 -6
- data/lib/switchman/active_record/postgresql_adapter.rb +42 -53
- data/lib/switchman/active_record/predicate_builder.rb +1 -1
- data/lib/switchman/active_record/query_cache.rb +18 -19
- data/lib/switchman/active_record/query_methods.rb +172 -181
- data/lib/switchman/active_record/reflection.rb +6 -10
- data/lib/switchman/active_record/relation.rb +27 -21
- data/lib/switchman/active_record/spawn_methods.rb +27 -29
- data/lib/switchman/active_record/statement_cache.rb +18 -35
- data/lib/switchman/active_record/tasks/database_tasks.rb +16 -0
- data/lib/switchman/active_support/cache.rb +3 -5
- data/lib/switchman/arel.rb +13 -8
- data/lib/switchman/database_server.rb +121 -142
- data/lib/switchman/default_shard.rb +52 -16
- data/lib/switchman/engine.rb +61 -57
- data/lib/switchman/environment.rb +4 -8
- data/lib/switchman/errors.rb +1 -0
- data/lib/switchman/guard_rail.rb +6 -19
- data/lib/switchman/guard_rail/relation.rb +5 -7
- data/lib/switchman/r_spec_helper.rb +29 -37
- data/lib/switchman/rails.rb +14 -12
- data/lib/switchman/schema_cache.rb +1 -1
- data/lib/switchman/sharded_instrumenter.rb +1 -1
- data/lib/switchman/standard_error.rb +15 -3
- data/lib/switchman/test_helper.rb +6 -10
- data/lib/switchman/version.rb +1 -1
- data/lib/tasks/switchman.rake +54 -69
- metadata +90 -48
- data/lib/switchman/active_record/batches.rb +0 -11
- data/lib/switchman/active_record/connection_handler.rb +0 -172
- data/lib/switchman/active_record/where_clause_factory.rb +0 -36
- data/lib/switchman/connection_pool_proxy.rb +0 -169
|
@@ -6,15 +6,18 @@ module Switchman
|
|
|
6
6
|
module ActiveRecord
|
|
7
7
|
module ConnectionPool
|
|
8
8
|
def shard
|
|
9
|
-
|
|
9
|
+
shard_stack.last || Shard.default
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
def
|
|
13
|
-
Thread.current
|
|
12
|
+
def shard_stack
|
|
13
|
+
unless (shard_stack = Thread.current.thread_variable_get(tls_key))
|
|
14
|
+
shard_stack = Concurrent::Array.new
|
|
15
|
+
Thread.current.thread_variable_set(tls_key, shard_stack)
|
|
16
|
+
end
|
|
17
|
+
shard_stack
|
|
14
18
|
end
|
|
15
19
|
|
|
16
20
|
def default_schema
|
|
17
|
-
raise "Not postgres!" unless self.spec.config[:adapter] == 'postgresql'
|
|
18
21
|
connection unless @schemas
|
|
19
22
|
# default shard will not switch databases immediately, so it won't be set yet
|
|
20
23
|
@schemas ||= connection.current_schemas
|
|
@@ -22,39 +25,29 @@ module Switchman
|
|
|
22
25
|
end
|
|
23
26
|
|
|
24
27
|
def checkout_new_connection
|
|
25
|
-
conn =
|
|
26
|
-
|
|
27
|
-
# without locking anything, but if spec returns not-the-object passed
|
|
28
|
-
# to initialize this pool, things break
|
|
29
|
-
spec.config[:shard_name] = self.shard.name
|
|
30
|
-
|
|
31
|
-
super
|
|
32
|
-
end
|
|
33
|
-
conn.shard = self.shard
|
|
28
|
+
conn = super
|
|
29
|
+
conn.shard = shard
|
|
34
30
|
conn
|
|
35
31
|
end
|
|
36
32
|
|
|
37
33
|
def connection(switch_shard: true)
|
|
38
34
|
conn = super()
|
|
39
35
|
raise NonExistentShardError if shard.new_record?
|
|
40
|
-
|
|
36
|
+
|
|
37
|
+
switch_database(conn) if conn.shard != shard && switch_shard
|
|
41
38
|
conn
|
|
42
39
|
end
|
|
43
40
|
|
|
44
41
|
def release_connection(with_id = Thread.current)
|
|
45
42
|
super(with_id)
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
clear_idle_connections!(Time.now - spec.config[:idle_timeout].to_i)
|
|
49
|
-
end
|
|
44
|
+
flush
|
|
50
45
|
end
|
|
51
46
|
|
|
52
47
|
def remove_shard!(shard)
|
|
53
48
|
synchronize do
|
|
54
49
|
# The shard might be currently active, so we need to update our own shard
|
|
55
|
-
if self.shard == shard
|
|
56
|
-
self.shard = Shard.default
|
|
57
|
-
end
|
|
50
|
+
self.shard = Shard.default if self.shard == shard
|
|
58
51
|
# Update out any connections that may be using this shard
|
|
59
52
|
@connections.each do |conn|
|
|
60
53
|
# This will also update the connection's shard to the default shard
|
|
@@ -63,29 +56,9 @@ module Switchman
|
|
|
63
56
|
end
|
|
64
57
|
end
|
|
65
58
|
|
|
66
|
-
def clear_idle_connections!(since_when)
|
|
67
|
-
synchronize do
|
|
68
|
-
@connections.reject! do |conn|
|
|
69
|
-
if conn.last_query_at < since_when && !conn.in_use?
|
|
70
|
-
conn.disconnect!
|
|
71
|
-
true
|
|
72
|
-
else
|
|
73
|
-
false
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
@available.clear
|
|
77
|
-
@connections.each do |conn|
|
|
78
|
-
@available.add conn
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
59
|
def switch_database(conn)
|
|
84
|
-
if !@schemas && conn.adapter_name == 'PostgreSQL' && !
|
|
85
|
-
@schemas = conn.current_schemas
|
|
86
|
-
end
|
|
60
|
+
@schemas = conn.current_schemas if !@schemas && conn.adapter_name == 'PostgreSQL' && !shard.database_server.config[:shard_name]
|
|
87
61
|
|
|
88
|
-
spec.config[:shard_name] = self.shard.name
|
|
89
62
|
conn.shard = shard
|
|
90
63
|
end
|
|
91
64
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Switchman
|
|
4
|
+
module ActiveRecord
|
|
5
|
+
module DatabaseConfigurations
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
# key difference: assumes a hybrid two-tier structure; each third tier
|
|
9
|
+
# is implicitly named, and their config is constructing by merging into
|
|
10
|
+
# its parent
|
|
11
|
+
def build_configs(configs)
|
|
12
|
+
return configs.configurations if configs.is_a?(DatabaseConfigurations)
|
|
13
|
+
return configs if configs.is_a?(Array)
|
|
14
|
+
|
|
15
|
+
db_configs = configs.flat_map do |env_name, config|
|
|
16
|
+
roles = config.keys.select { |k| config[k].is_a?(Hash) }
|
|
17
|
+
base_config = config.except(*roles)
|
|
18
|
+
|
|
19
|
+
name = "#{env_name}/primary"
|
|
20
|
+
name = 'primary' if env_name == default_env
|
|
21
|
+
base_db = build_db_config_from_raw_config(env_name, name, base_config)
|
|
22
|
+
[base_db] + roles.map do |role|
|
|
23
|
+
build_db_config_from_raw_config(env_name, "#{env_name}/#{role}",
|
|
24
|
+
base_config.merge(config[role]).merge(replica: true))
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
db_configs << environment_url_config(default_env, 'primary', {}) unless db_configs.find(&:for_current_env?)
|
|
29
|
+
|
|
30
|
+
merge_db_environment_variables(default_env, db_configs.compact)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -7,19 +7,18 @@ module Switchman
|
|
|
7
7
|
return super(id) unless klass.integral_id?
|
|
8
8
|
|
|
9
9
|
if shard_source_value != :implicit
|
|
10
|
-
current_shard = Shard.current(klass.
|
|
11
|
-
result =
|
|
10
|
+
current_shard = Shard.current(klass.connection_classes)
|
|
11
|
+
result = activate do |relation, shard|
|
|
12
12
|
current_id = Shard.relative_id_for(id, current_shard, shard)
|
|
13
13
|
# current_id will be nil for non-integral id
|
|
14
14
|
next unless current_id
|
|
15
15
|
# skip the shard if the object can't be on it. unless we're only looking at one shard;
|
|
16
16
|
# we might be expecting a shadow object
|
|
17
|
-
next if current_id > Shard::IDS_PER_SHARD &&
|
|
17
|
+
next if current_id > Shard::IDS_PER_SHARD && all_shards.length > 1
|
|
18
|
+
|
|
18
19
|
relation.call_super(:find_one, FinderMethods, current_id)
|
|
19
20
|
end
|
|
20
|
-
if result.is_a?(Array)
|
|
21
|
-
result = result.first
|
|
22
|
-
end
|
|
21
|
+
result = result.first if result.is_a?(Array)
|
|
23
22
|
# we may have skipped all shards
|
|
24
23
|
raise_record_not_found_exception!(id, 0, 1) unless result
|
|
25
24
|
return result
|
|
@@ -34,8 +33,8 @@ module Switchman
|
|
|
34
33
|
end
|
|
35
34
|
|
|
36
35
|
def find_some_ordered(ids)
|
|
37
|
-
current_shard = Shard.current(klass.
|
|
38
|
-
ids = ids.map{|id| Shard.relative_id_for(id, current_shard, current_shard)}
|
|
36
|
+
current_shard = Shard.current(klass.connection_classes)
|
|
37
|
+
ids = ids.map { |id| Shard.relative_id_for(id, current_shard, current_shard) }
|
|
39
38
|
super(ids)
|
|
40
39
|
end
|
|
41
40
|
|
|
@@ -45,14 +44,12 @@ module Switchman
|
|
|
45
44
|
|
|
46
45
|
def exists?(conditions = :none)
|
|
47
46
|
conditions = conditions.id if ::ActiveRecord::Base === conditions
|
|
48
|
-
return false
|
|
47
|
+
return false unless conditions
|
|
49
48
|
|
|
50
|
-
relation =
|
|
51
|
-
apply_join_dependency(eager_loading: false) :
|
|
52
|
-
apply_join_dependency(self, construct_join_dependency)
|
|
49
|
+
relation = apply_join_dependency(eager_loading: false)
|
|
53
50
|
return false if ::ActiveRecord::NullRelation === relation
|
|
54
51
|
|
|
55
|
-
relation = relation.except(:select, :order).select(
|
|
52
|
+
relation = relation.except(:select, :order).select('1 AS one').limit(1)
|
|
56
53
|
|
|
57
54
|
case conditions
|
|
58
55
|
when Array, Hash
|
|
@@ -62,9 +59,7 @@ module Switchman
|
|
|
62
59
|
end
|
|
63
60
|
|
|
64
61
|
relation.activate do |shard_rel|
|
|
65
|
-
return true if
|
|
66
|
-
connection.select_value(shard_rel.arel, "#{name} Exists") :
|
|
67
|
-
connection.select_value(shard_rel, "#{name} Exists", shard_rel.bound_attributes)
|
|
62
|
+
return true if connection.select_value(shard_rel.arel, "#{name} Exists")
|
|
68
63
|
end
|
|
69
64
|
false
|
|
70
65
|
end
|
|
@@ -14,20 +14,16 @@ module Switchman
|
|
|
14
14
|
|
|
15
15
|
name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
|
|
16
16
|
name = "CACHE #{name}" if payload[:cached]
|
|
17
|
-
sql = payload[:sql].squeeze(' '
|
|
17
|
+
sql = payload[:sql].squeeze(' ')
|
|
18
18
|
binds = nil
|
|
19
19
|
shard = payload[:shard]
|
|
20
20
|
shard = " [#{shard[:database_server_id]}:#{shard[:id]} #{shard[:env]}]" if shard
|
|
21
21
|
|
|
22
22
|
unless (payload[:binds] || []).empty?
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
[payload[:binds], payload[:type_casted_binds]] :
|
|
26
|
-
[payload[:type_casted_binds]]
|
|
27
|
-
casted_params = type_casted_binds(*args)
|
|
28
|
-
binds = " " + payload[:binds].zip(casted_params).map { |attr, value|
|
|
23
|
+
casted_params = type_casted_binds(payload[:type_casted_binds])
|
|
24
|
+
binds = ' ' + payload[:binds].zip(casted_params).map do |attr, value|
|
|
29
25
|
render_bind(attr, value)
|
|
30
|
-
|
|
26
|
+
end.inspect
|
|
31
27
|
end
|
|
32
28
|
|
|
33
29
|
name = colorize_payload_name(name, payload[:name])
|
|
@@ -4,27 +4,17 @@ module Switchman
|
|
|
4
4
|
module ActiveRecord
|
|
5
5
|
module Migration
|
|
6
6
|
module Compatibility
|
|
7
|
-
module V5_0
|
|
7
|
+
module V5_0 # rubocop:disable Naming/ClassAndModuleCamelCase
|
|
8
8
|
def create_table(*args, **options)
|
|
9
|
-
unless options.key?(:id)
|
|
10
|
-
|
|
11
|
-
end
|
|
12
|
-
if block_given?
|
|
13
|
-
super do |td|
|
|
14
|
-
yield td
|
|
15
|
-
end
|
|
16
|
-
else
|
|
17
|
-
super
|
|
18
|
-
end
|
|
9
|
+
options[:id] = :bigserial unless options.key?(:id)
|
|
10
|
+
super
|
|
19
11
|
end
|
|
20
12
|
end
|
|
21
13
|
end
|
|
22
14
|
|
|
23
15
|
def connection
|
|
24
16
|
conn = super
|
|
25
|
-
if conn.shard != ::ActiveRecord::Base.connection_pool.
|
|
26
|
-
::ActiveRecord::Base.connection_pool.current_pool.switch_database(conn)
|
|
27
|
-
end
|
|
17
|
+
::ActiveRecord::Base.connection_pool.switch_database(conn) if conn.shard != ::ActiveRecord::Base.connection_pool.shard
|
|
28
18
|
conn
|
|
29
19
|
end
|
|
30
20
|
end
|
|
@@ -39,6 +29,7 @@ module Switchman
|
|
|
39
29
|
module MigrationContext
|
|
40
30
|
def migrations
|
|
41
31
|
return @migrations if instance_variable_defined?(:@migrations)
|
|
32
|
+
|
|
42
33
|
migrations_cache = Thread.current[:migrations_cache] ||= {}
|
|
43
34
|
key = Digest::MD5.hexdigest(migration_files.sort.join(','))
|
|
44
35
|
@migrations = migrations_cache[key] ||= super
|
|
@@ -6,7 +6,7 @@ module Switchman
|
|
|
6
6
|
module ClassMethods
|
|
7
7
|
def quoted_table_name
|
|
8
8
|
@quoted_table_name ||= {}
|
|
9
|
-
@quoted_table_name[Shard.current(
|
|
9
|
+
@quoted_table_name[Shard.current(connection_classes).id] ||= connection.quote_table_name(table_name)
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
end
|
|
@@ -5,14 +5,12 @@ module Switchman
|
|
|
5
5
|
module Persistence
|
|
6
6
|
# touch reads the id attribute directly, so it's not relative to the current shard
|
|
7
7
|
def touch(*, **)
|
|
8
|
-
shard.activate(self.class.
|
|
8
|
+
shard.activate(self.class.connection_classes) { super }
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
shard.activate(self.class.shard_category) { super }
|
|
14
|
-
end
|
|
11
|
+
def update_columns(*)
|
|
12
|
+
shard.activate(self.class.connection_classes) { super }
|
|
15
13
|
end
|
|
16
14
|
end
|
|
17
15
|
end
|
|
18
|
-
end
|
|
16
|
+
end
|
|
@@ -9,22 +9,22 @@ module Switchman
|
|
|
9
9
|
|
|
10
10
|
option_string = options.sum do |key, value|
|
|
11
11
|
case key
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
12
|
+
when :owner
|
|
13
|
+
" OWNER = \"#{value}\""
|
|
14
|
+
when :template
|
|
15
|
+
" TEMPLATE = \"#{value}\""
|
|
16
|
+
when :encoding
|
|
17
|
+
" ENCODING = '#{value}'"
|
|
18
|
+
when :collation
|
|
19
|
+
" LC_COLLATE = '#{value}'"
|
|
20
|
+
when :ctype
|
|
21
|
+
" LC_CTYPE = '#{value}'"
|
|
22
|
+
when :tablespace
|
|
23
|
+
" TABLESPACE = \"#{value}\""
|
|
24
|
+
when :connection_limit
|
|
25
|
+
" CONNECTION LIMIT = #{value}"
|
|
26
|
+
else
|
|
27
|
+
''
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
@@ -37,10 +37,10 @@ module Switchman
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def current_schemas
|
|
40
|
-
select_values(
|
|
40
|
+
select_values('SELECT * FROM unnest(current_schemas(false))')
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
def tables(
|
|
43
|
+
def tables(_name = nil)
|
|
44
44
|
query(<<-SQL, 'SCHEMA').map { |row| row[0] }
|
|
45
45
|
SELECT tablename
|
|
46
46
|
FROM pg_tables
|
|
@@ -50,18 +50,15 @@ module Switchman
|
|
|
50
50
|
|
|
51
51
|
def extract_schema_qualified_name(string)
|
|
52
52
|
name = ::ActiveRecord::ConnectionAdapters::PostgreSQL::Utils.extract_schema_qualified_name(string.to_s)
|
|
53
|
-
if string && !name.schema
|
|
54
|
-
name.instance_variable_set(:@schema, shard.name)
|
|
55
|
-
end
|
|
53
|
+
name.instance_variable_set(:@schema, shard.name) if string && !name.schema
|
|
56
54
|
[name.schema, name.identifier]
|
|
57
55
|
end
|
|
58
56
|
|
|
59
57
|
def view_exists?(name)
|
|
60
58
|
name = ::ActiveRecord::ConnectionAdapters::PostgreSQL::Utils.extract_schema_qualified_name(name.to_s)
|
|
61
59
|
return false unless name.identifier
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
end
|
|
60
|
+
|
|
61
|
+
name.instance_variable_set(:@schema, shard.name) unless name.schema
|
|
65
62
|
|
|
66
63
|
select_values(<<-SQL, 'SCHEMA').any?
|
|
67
64
|
SELECT c.relname
|
|
@@ -86,41 +83,37 @@ module Switchman
|
|
|
86
83
|
ORDER BY i.relname
|
|
87
84
|
SQL
|
|
88
85
|
|
|
89
|
-
|
|
90
86
|
result.map do |row|
|
|
91
87
|
index_name = row[0]
|
|
92
88
|
unique = row[1] == true || row[1] == 't'
|
|
93
|
-
indkey = row[2].split
|
|
89
|
+
indkey = row[2].split
|
|
94
90
|
inddef = row[3]
|
|
95
91
|
oid = row[4]
|
|
96
92
|
|
|
97
|
-
columns = Hash[query(<<-SQL,
|
|
93
|
+
columns = Hash[query(<<-SQL, 'SCHEMA')] # rubocop:disable Style/HashConversion
|
|
98
94
|
SELECT a.attnum, a.attname
|
|
99
95
|
FROM pg_attribute a
|
|
100
96
|
WHERE a.attrelid = #{oid}
|
|
101
|
-
AND a.attnum IN (#{indkey.join(
|
|
97
|
+
AND a.attnum IN (#{indkey.join(',')})
|
|
102
98
|
SQL
|
|
103
99
|
|
|
104
100
|
column_names = columns.stringify_keys.values_at(*indkey).compact
|
|
105
101
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
::ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, index_name, unique, column_names, [], orders, where, nil, using)
|
|
117
|
-
end
|
|
118
|
-
end
|
|
102
|
+
next if column_names.empty?
|
|
103
|
+
|
|
104
|
+
# add info on sort order for columns (only desc order is explicitly specified, asc is the default)
|
|
105
|
+
desc_order_columns = inddef.scan(/(\w+) DESC/).flatten
|
|
106
|
+
orders = desc_order_columns.any? ? Hash[desc_order_columns.map { |order_column| [order_column, :desc] }] : {} # rubocop:disable Style/HashConversion
|
|
107
|
+
where = inddef.scan(/WHERE (.+)$/).flatten[0]
|
|
108
|
+
using = inddef.scan(/USING (.+?) /).flatten[0].to_sym
|
|
109
|
+
|
|
110
|
+
::ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, index_name, unique, column_names,
|
|
111
|
+
orders: orders, where: where, using: using)
|
|
119
112
|
end.compact
|
|
120
113
|
end
|
|
121
114
|
|
|
122
115
|
def index_name_exists?(table_name, index_name, _default = nil)
|
|
123
|
-
exec_query(<<-SQL, 'SCHEMA').rows.first[0].to_i
|
|
116
|
+
exec_query(<<-SQL, 'SCHEMA').rows.first[0].to_i.positive?
|
|
124
117
|
SELECT COUNT(*)
|
|
125
118
|
FROM pg_class t
|
|
126
119
|
INNER JOIN pg_index d ON t.oid = d.indrelid
|
|
@@ -141,14 +134,13 @@ module Switchman
|
|
|
141
134
|
|
|
142
135
|
def quote_table_name(name)
|
|
143
136
|
return quote_local_table_name(name) if @use_local_table_name
|
|
137
|
+
|
|
144
138
|
name = ::ActiveRecord::ConnectionAdapters::PostgreSQL::Utils.extract_schema_qualified_name(name.to_s)
|
|
145
|
-
|
|
146
|
-
name.instance_variable_set(:@schema, shard.name)
|
|
147
|
-
end
|
|
139
|
+
name.instance_variable_set(:@schema, shard.name) unless name.schema
|
|
148
140
|
name.quoted
|
|
149
141
|
end
|
|
150
142
|
|
|
151
|
-
def with_local_table_name(enable = true)
|
|
143
|
+
def with_local_table_name(enable = true) # rubocop:disable Style/OptionalBooleanParameter
|
|
152
144
|
old_value = @use_local_table_name
|
|
153
145
|
@use_local_table_name = enable
|
|
154
146
|
yield
|
|
@@ -157,7 +149,6 @@ module Switchman
|
|
|
157
149
|
end
|
|
158
150
|
|
|
159
151
|
def foreign_keys(table_name)
|
|
160
|
-
|
|
161
152
|
# mostly copy-pasted from AR - only change is to the nspname condition for qualified names support
|
|
162
153
|
fk_info = select_all <<-SQL.strip_heredoc
|
|
163
154
|
SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
|
|
@@ -186,18 +177,16 @@ module Switchman
|
|
|
186
177
|
# strip the schema name from to_table if it matches
|
|
187
178
|
to_table = row['to_table']
|
|
188
179
|
to_table_qualified_name = ::ActiveRecord::ConnectionAdapters::PostgreSQL::Utils.extract_schema_qualified_name(to_table)
|
|
189
|
-
if to_table_qualified_name.schema == shard.name
|
|
190
|
-
to_table = to_table_qualified_name.identifier
|
|
191
|
-
end
|
|
180
|
+
to_table = to_table_qualified_name.identifier if to_table_qualified_name.schema == shard.name
|
|
192
181
|
|
|
193
182
|
::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(table_name, to_table, options)
|
|
194
183
|
end
|
|
195
184
|
end
|
|
196
185
|
|
|
197
186
|
def add_index_options(_table_name, _column_name, **)
|
|
198
|
-
|
|
199
|
-
algorithm = nil if DatabaseServer.creating_new_shard && algorithm ==
|
|
200
|
-
[
|
|
187
|
+
index, algorithm, if_not_exists = super
|
|
188
|
+
algorithm = nil if DatabaseServer.creating_new_shard && algorithm == 'CONCURRENTLY'
|
|
189
|
+
[index, algorithm, if_not_exists]
|
|
201
190
|
end
|
|
202
191
|
|
|
203
192
|
def rename_table(table_name, new_name)
|