activerecord 5.0.0 → 5.0.7.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +431 -2
- data/README.rdoc +1 -1
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/association_relation.rb +4 -1
- data/lib/active_record/associations/association.rb +11 -1
- data/lib/active_record/associations/association_scope.rb +1 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +4 -2
- data/lib/active_record/associations/builder/singular_association.rb +10 -1
- data/lib/active_record/associations/collection_association.rb +56 -48
- data/lib/active_record/associations/collection_proxy.rb +38 -20
- data/lib/active_record/associations/has_many_association.rb +1 -7
- data/lib/active_record/associations/has_many_through_association.rb +2 -4
- data/lib/active_record/associations/join_dependency/join_association.rb +6 -11
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/join_dependency.rb +10 -4
- data/lib/active_record/associations/preloader/association.rb +24 -37
- data/lib/active_record/associations/preloader/collection_association.rb +0 -1
- data/lib/active_record/associations/preloader/singular_association.rb +0 -1
- data/lib/active_record/associations/preloader/through_association.rb +10 -4
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +38 -17
- data/lib/active_record/attribute.rb +3 -3
- data/lib/active_record/attribute_methods/primary_key.rb +14 -1
- data/lib/active_record/attribute_methods/read.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +2 -2
- data/lib/active_record/attribute_methods.rb +3 -7
- data/lib/active_record/attribute_set/builder.rb +37 -13
- data/lib/active_record/attribute_set.rb +2 -0
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +15 -11
- data/lib/active_record/base.rb +1 -1
- data/lib/active_record/collection_cache_key.rb +16 -6
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +41 -33
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +37 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +11 -14
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +68 -56
- data/lib/active_record/connection_adapters/abstract_adapter.rb +36 -12
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +63 -60
- data/lib/active_record/connection_adapters/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +8 -25
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +2 -6
- data/lib/active_record/connection_adapters/postgresql/column.rb +28 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +12 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +32 -3
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +18 -8
- data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +25 -19
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +4 -4
- data/lib/active_record/core.rb +6 -4
- data/lib/active_record/enum.rb +8 -5
- data/lib/active_record/explain.rb +20 -9
- data/lib/active_record/fixtures.rb +5 -5
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/integration.rb +13 -10
- data/lib/active_record/log_subscriber.rb +19 -17
- data/lib/active_record/migration.rb +35 -14
- data/lib/active_record/model_schema.rb +161 -52
- data/lib/active_record/no_touching.rb +4 -0
- data/lib/active_record/persistence.rb +41 -20
- data/lib/active_record/query_cache.rb +15 -17
- data/lib/active_record/querying.rb +3 -3
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +9 -21
- data/lib/active_record/reflection.rb +20 -0
- data/lib/active_record/relation/batches.rb +10 -10
- data/lib/active_record/relation/calculations.rb +16 -12
- data/lib/active_record/relation/delegation.rb +2 -1
- data/lib/active_record/relation/finder_methods.rb +13 -11
- data/lib/active_record/relation/query_methods.rb +3 -3
- data/lib/active_record/relation.rb +12 -5
- data/lib/active_record/result.rb +7 -1
- data/lib/active_record/sanitization.rb +11 -1
- data/lib/active_record/schema_dumper.rb +10 -17
- data/lib/active_record/scoping/default.rb +5 -1
- data/lib/active_record/scoping/named.rb +18 -6
- data/lib/active_record/scoping.rb +4 -3
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/table_metadata.rb +4 -3
- data/lib/active_record/tasks/database_tasks.rb +14 -11
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/touch_later.rb +6 -1
- data/lib/active_record/transactions.rb +1 -1
- data/lib/active_record/type/internal/abstract_json.rb +5 -1
- data/lib/active_record/validations/uniqueness.rb +3 -4
- data/lib/active_record.rb +3 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
- data/lib/rails/generators/active_record/migration.rb +8 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- metadata +7 -8
@@ -4,6 +4,9 @@ module ActiveRecord
|
|
4
4
|
class << self
|
5
5
|
def included(base) #:nodoc:
|
6
6
|
dirties_query_cache base, :insert, :update, :delete, :rollback_to_savepoint, :rollback_db_transaction
|
7
|
+
|
8
|
+
base.set_callback :checkout, :after, :configure_query_cache!
|
9
|
+
base.set_callback :checkin, :after, :disable_query_cache!
|
7
10
|
end
|
8
11
|
|
9
12
|
def dirties_query_cache(base, *method_names)
|
@@ -18,6 +21,27 @@ module ActiveRecord
|
|
18
21
|
end
|
19
22
|
end
|
20
23
|
|
24
|
+
module ConnectionPoolConfiguration
|
25
|
+
def initialize(*)
|
26
|
+
super
|
27
|
+
@query_cache_enabled = Concurrent::Map.new { false }
|
28
|
+
end
|
29
|
+
|
30
|
+
def enable_query_cache!
|
31
|
+
@query_cache_enabled[connection_cache_key(Thread.current)] = true
|
32
|
+
connection.enable_query_cache! if active_connection?
|
33
|
+
end
|
34
|
+
|
35
|
+
def disable_query_cache!
|
36
|
+
@query_cache_enabled.delete connection_cache_key(Thread.current)
|
37
|
+
connection.disable_query_cache! if active_connection?
|
38
|
+
end
|
39
|
+
|
40
|
+
def query_cache_enabled
|
41
|
+
@query_cache_enabled[connection_cache_key(Thread.current)]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
21
45
|
attr_reader :query_cache, :query_cache_enabled
|
22
46
|
|
23
47
|
def initialize(*)
|
@@ -41,6 +65,7 @@ module ActiveRecord
|
|
41
65
|
|
42
66
|
def disable_query_cache!
|
43
67
|
@query_cache_enabled = false
|
68
|
+
clear_query_cache
|
44
69
|
end
|
45
70
|
|
46
71
|
# Disable the query cache within the block.
|
@@ -76,8 +101,14 @@ module ActiveRecord
|
|
76
101
|
def cache_sql(sql, binds)
|
77
102
|
result =
|
78
103
|
if @query_cache[sql].key?(binds)
|
79
|
-
ActiveSupport::Notifications.instrument(
|
80
|
-
|
104
|
+
ActiveSupport::Notifications.instrument(
|
105
|
+
"sql.active_record",
|
106
|
+
sql: sql,
|
107
|
+
binds: binds,
|
108
|
+
type_casted_binds: -> { type_casted_binds(binds) },
|
109
|
+
name: "CACHE",
|
110
|
+
connection_id: object_id,
|
111
|
+
)
|
81
112
|
@query_cache[sql][binds]
|
82
113
|
else
|
83
114
|
@query_cache[sql][binds] = yield
|
@@ -90,6 +121,10 @@ module ActiveRecord
|
|
90
121
|
def locked?(arel)
|
91
122
|
arel.respond_to?(:locked) && arel.locked
|
92
123
|
end
|
124
|
+
|
125
|
+
def configure_query_cache!
|
126
|
+
enable_query_cache! if pool.query_cache_enabled
|
127
|
+
end
|
93
128
|
end
|
94
129
|
end
|
95
130
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'active_support/core_ext/big_decimal/conversions'
|
2
|
+
require "active_support/multibyte/chars"
|
2
3
|
|
3
4
|
module ActiveRecord
|
4
5
|
module ConnectionAdapters # :nodoc:
|
@@ -112,19 +113,19 @@ module ActiveRecord
|
|
112
113
|
end
|
113
114
|
|
114
115
|
def quoted_true
|
115
|
-
"'t'"
|
116
|
+
"'t'".freeze
|
116
117
|
end
|
117
118
|
|
118
119
|
def unquoted_true
|
119
|
-
't'
|
120
|
+
't'.freeze
|
120
121
|
end
|
121
122
|
|
122
123
|
def quoted_false
|
123
|
-
"'f'"
|
124
|
+
"'f'".freeze
|
124
125
|
end
|
125
126
|
|
126
127
|
def unquoted_false
|
127
|
-
'f'
|
128
|
+
'f'.freeze
|
128
129
|
end
|
129
130
|
|
130
131
|
# Quote date/time values for use in SQL input. Includes microseconds
|
@@ -147,13 +148,21 @@ module ActiveRecord
|
|
147
148
|
end
|
148
149
|
|
149
150
|
def quoted_time(value) # :nodoc:
|
150
|
-
quoted_date(value).sub(/\
|
151
|
+
quoted_date(value).sub(/\A\d\d\d\d-\d\d-\d\d /, '')
|
151
152
|
end
|
152
153
|
|
153
154
|
def prepare_binds_for_database(binds) # :nodoc:
|
154
155
|
binds.map(&:value_for_database)
|
155
156
|
end
|
156
157
|
|
158
|
+
def type_casted_binds(binds) # :nodoc:
|
159
|
+
if binds.first.is_a?(Array)
|
160
|
+
binds.map { |column, value| type_cast(value, column) }
|
161
|
+
else
|
162
|
+
binds.map { |attr| type_cast(attr.value_for_database) }
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
157
166
|
private
|
158
167
|
|
159
168
|
def types_which_need_no_typecasting
|
@@ -51,11 +51,12 @@ module ActiveRecord
|
|
51
51
|
options[:primary_key] != default_primary_key
|
52
52
|
end
|
53
53
|
|
54
|
-
def defined_for?(
|
55
|
-
if
|
56
|
-
|
54
|
+
def defined_for?(to_table_ord = nil, to_table: nil, **options)
|
55
|
+
if to_table_ord
|
56
|
+
self.to_table == to_table_ord.to_s
|
57
57
|
else
|
58
|
-
to_table ==
|
58
|
+
(to_table.nil? || to_table.to_s == self.to_table) &&
|
59
|
+
options.all? { |k, v| self.options[k].to_s == v.to_s }
|
59
60
|
end
|
60
61
|
end
|
61
62
|
|
@@ -106,16 +107,12 @@ module ActiveRecord
|
|
106
107
|
|
107
108
|
private
|
108
109
|
|
109
|
-
def as_options(value
|
110
|
-
|
111
|
-
value
|
112
|
-
else
|
113
|
-
default
|
114
|
-
end
|
110
|
+
def as_options(value)
|
111
|
+
value.is_a?(Hash) ? value : {}
|
115
112
|
end
|
116
113
|
|
117
114
|
def polymorphic_options
|
118
|
-
as_options(polymorphic
|
115
|
+
as_options(polymorphic).merge(null: options[:null])
|
119
116
|
end
|
120
117
|
|
121
118
|
def index_options
|
@@ -211,7 +208,7 @@ module ActiveRecord
|
|
211
208
|
|
212
209
|
def initialize(name, temporary = false, options = nil, as = nil, comment: nil)
|
213
210
|
@columns_hash = {}
|
214
|
-
@indexes =
|
211
|
+
@indexes = []
|
215
212
|
@foreign_keys = []
|
216
213
|
@primary_keys = nil
|
217
214
|
@temporary = temporary
|
@@ -303,7 +300,7 @@ module ActiveRecord
|
|
303
300
|
# end
|
304
301
|
def column(name, type, options = {})
|
305
302
|
name = name.to_s
|
306
|
-
type = type.to_sym
|
303
|
+
type = type.to_sym if type
|
307
304
|
options = options.dup
|
308
305
|
|
309
306
|
if @columns_hash[name] && @columns_hash[name].primary_key?
|
@@ -327,7 +324,7 @@ module ActiveRecord
|
|
327
324
|
#
|
328
325
|
# index(:account_id, name: 'index_projects_on_account_id')
|
329
326
|
def index(column_name, options = {})
|
330
|
-
indexes[column_name
|
327
|
+
indexes << [column_name, options]
|
331
328
|
end
|
332
329
|
|
333
330
|
def foreign_key(table_name, options = {}) # :nodoc:
|
@@ -129,14 +129,9 @@ module ActiveRecord
|
|
129
129
|
|
130
130
|
# Returns just a table's primary key
|
131
131
|
def primary_key(table_name)
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
#{table_name} has composite primary key. Composite primary key is ignored.
|
137
|
-
WARNING
|
138
|
-
|
139
|
-
pks.first if pks.one?
|
132
|
+
pk = primary_keys(table_name)
|
133
|
+
pk = pk.first unless pk.size > 1
|
134
|
+
pk
|
140
135
|
end
|
141
136
|
|
142
137
|
# Creates a new table with the name +table_name+. +table_name+ may either
|
@@ -283,16 +278,16 @@ module ActiveRecord
|
|
283
278
|
result = execute schema_creation.accept td
|
284
279
|
|
285
280
|
unless supports_indexes_in_create?
|
286
|
-
td.indexes.
|
281
|
+
td.indexes.each do |column_name, index_options|
|
287
282
|
add_index(table_name, column_name, index_options)
|
288
283
|
end
|
289
284
|
end
|
290
285
|
|
291
286
|
if supports_comments? && !supports_comments_in_create?
|
292
|
-
change_table_comment(table_name, comment) if comment
|
287
|
+
change_table_comment(table_name, comment) if comment.present?
|
293
288
|
|
294
289
|
td.columns.each do |column|
|
295
|
-
change_column_comment(table_name, column.name, column.comment) if column.comment
|
290
|
+
change_column_comment(table_name, column.name, column.comment) if column.comment.present?
|
296
291
|
end
|
297
292
|
end
|
298
293
|
|
@@ -767,7 +762,7 @@ module ActiveRecord
|
|
767
762
|
raise ArgumentError, "You must specify the index name"
|
768
763
|
end
|
769
764
|
else
|
770
|
-
index_name(table_name,
|
765
|
+
index_name(table_name, index_name_options(options))
|
771
766
|
end
|
772
767
|
end
|
773
768
|
|
@@ -790,7 +785,7 @@ module ActiveRecord
|
|
790
785
|
# [<tt>:type</tt>]
|
791
786
|
# The reference column type. Defaults to +:integer+.
|
792
787
|
# [<tt>:index</tt>]
|
793
|
-
# Add an appropriate index. Defaults to
|
788
|
+
# Add an appropriate index. Defaults to true.
|
794
789
|
# See #add_index for usage of this option.
|
795
790
|
# [<tt>:foreign_key</tt>]
|
796
791
|
# Add an appropriate foreign key constraint. Defaults to false.
|
@@ -847,14 +842,19 @@ module ActiveRecord
|
|
847
842
|
#
|
848
843
|
# remove_reference(:products, :user, index: true, foreign_key: true)
|
849
844
|
#
|
850
|
-
def remove_reference(table_name, ref_name,
|
851
|
-
if
|
845
|
+
def remove_reference(table_name, ref_name, foreign_key: false, polymorphic: false, **options)
|
846
|
+
if foreign_key
|
852
847
|
reference_name = Base.pluralize_table_names ? ref_name.to_s.pluralize : ref_name
|
853
|
-
|
848
|
+
if foreign_key.is_a?(Hash)
|
849
|
+
foreign_key_options = foreign_key
|
850
|
+
else
|
851
|
+
foreign_key_options = { to_table: reference_name }
|
852
|
+
end
|
853
|
+
remove_foreign_key(table_name, **foreign_key_options)
|
854
854
|
end
|
855
855
|
|
856
856
|
remove_column(table_name, "#{ref_name}_id")
|
857
|
-
remove_column(table_name, "#{ref_name}_type") if
|
857
|
+
remove_column(table_name, "#{ref_name}_type") if polymorphic
|
858
858
|
end
|
859
859
|
alias :remove_belongs_to :remove_reference
|
860
860
|
|
@@ -986,21 +986,19 @@ module ActiveRecord
|
|
986
986
|
|
987
987
|
def dump_schema_information #:nodoc:
|
988
988
|
versions = ActiveRecord::SchemaMigration.order('version').pluck(:version)
|
989
|
-
insert_versions_sql(versions)
|
989
|
+
insert_versions_sql(versions) if versions.any?
|
990
990
|
end
|
991
991
|
|
992
992
|
def insert_versions_sql(versions) # :nodoc:
|
993
|
-
sm_table = ActiveRecord::Migrator.schema_migrations_table_name
|
993
|
+
sm_table = quote_table_name(ActiveRecord::Migrator.schema_migrations_table_name)
|
994
994
|
|
995
|
-
if
|
996
|
-
sql = "INSERT INTO #{sm_table} (version) VALUES
|
997
|
-
sql << versions.map {|v| "(
|
995
|
+
if versions.is_a?(Array)
|
996
|
+
sql = "INSERT INTO #{sm_table} (version) VALUES\n"
|
997
|
+
sql << versions.map { |v| "(#{quote(v)})" }.join(",\n")
|
998
998
|
sql << ";\n\n"
|
999
999
|
sql
|
1000
1000
|
else
|
1001
|
-
|
1002
|
-
"INSERT INTO #{sm_table} (version) VALUES ('#{version}');"
|
1003
|
-
}.join "\n\n"
|
1001
|
+
"INSERT INTO #{sm_table} (version) VALUES (#{quote(versions)});"
|
1004
1002
|
end
|
1005
1003
|
end
|
1006
1004
|
|
@@ -1024,13 +1022,12 @@ module ActiveRecord
|
|
1024
1022
|
sm_table = quote_table_name(ActiveRecord::Migrator.schema_migrations_table_name)
|
1025
1023
|
|
1026
1024
|
migrated = select_values("SELECT version FROM #{sm_table}").map(&:to_i)
|
1027
|
-
|
1028
|
-
|
1029
|
-
filename.split('/').last.split('_').first.to_i
|
1025
|
+
versions = ActiveRecord::Migrator.migration_files(migrations_paths).map do |file|
|
1026
|
+
ActiveRecord::Migrator.parse_migration_filename(file).first.to_i
|
1030
1027
|
end
|
1031
1028
|
|
1032
1029
|
unless migrated.include?(version)
|
1033
|
-
execute "INSERT INTO #{sm_table} (version) VALUES (
|
1030
|
+
execute "INSERT INTO #{sm_table} (version) VALUES (#{quote(version)})"
|
1034
1031
|
end
|
1035
1032
|
|
1036
1033
|
inserting = (versions - migrated).select {|v| v < version}
|
@@ -1038,12 +1035,19 @@ module ActiveRecord
|
|
1038
1035
|
if (duplicate = inserting.detect {|v| inserting.count(v) > 1})
|
1039
1036
|
raise "Duplicate migration #{duplicate}. Please renumber your migrations to resolve the conflict."
|
1040
1037
|
end
|
1041
|
-
|
1038
|
+
if supports_multi_insert?
|
1039
|
+
execute insert_versions_sql(inserting)
|
1040
|
+
else
|
1041
|
+
inserting.each do |v|
|
1042
|
+
execute insert_versions_sql(v)
|
1043
|
+
end
|
1044
|
+
end
|
1042
1045
|
end
|
1043
1046
|
end
|
1044
1047
|
|
1045
1048
|
def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
|
1046
|
-
|
1049
|
+
type = type.to_sym if type
|
1050
|
+
if native = native_database_types[type]
|
1047
1051
|
column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup
|
1048
1052
|
|
1049
1053
|
if type == :decimal # ignore limit, use precision and scale
|
@@ -1111,18 +1115,14 @@ module ActiveRecord
|
|
1111
1115
|
end
|
1112
1116
|
|
1113
1117
|
def add_index_options(table_name, column_name, comment: nil, **options) # :nodoc:
|
1114
|
-
|
1115
|
-
column_names = column_name
|
1116
|
-
else
|
1117
|
-
column_names = Array(column_name)
|
1118
|
-
end
|
1118
|
+
column_names = index_column_names(column_name)
|
1119
1119
|
|
1120
1120
|
options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type)
|
1121
1121
|
|
1122
1122
|
index_type = options[:type].to_s if options.key?(:type)
|
1123
1123
|
index_type ||= options[:unique] ? "UNIQUE" : ""
|
1124
1124
|
index_name = options[:name].to_s if options.key?(:name)
|
1125
|
-
index_name ||= index_name(table_name,
|
1125
|
+
index_name ||= index_name(table_name, column_names)
|
1126
1126
|
max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length
|
1127
1127
|
|
1128
1128
|
if options.key?(:algorithm)
|
@@ -1163,31 +1163,35 @@ module ActiveRecord
|
|
1163
1163
|
end
|
1164
1164
|
|
1165
1165
|
protected
|
1166
|
-
|
1167
|
-
|
1166
|
+
|
1167
|
+
def add_index_sort_order(quoted_columns, **options)
|
1168
|
+
if order = options[:order]
|
1168
1169
|
case order
|
1169
1170
|
when Hash
|
1170
|
-
|
1171
|
+
order = order.symbolize_keys
|
1172
|
+
quoted_columns.each { |name, column| column << " #{order[name].upcase}" if order[name].present? }
|
1171
1173
|
when String
|
1172
|
-
|
1174
|
+
quoted_columns.each { |name, column| column << " #{order.upcase}" if order.present? }
|
1173
1175
|
end
|
1174
1176
|
end
|
1175
1177
|
|
1176
|
-
|
1178
|
+
quoted_columns
|
1177
1179
|
end
|
1178
1180
|
|
1179
1181
|
# Overridden by the MySQL adapter for supporting index lengths
|
1180
|
-
def
|
1181
|
-
return [column_names] if column_names.is_a?(String)
|
1182
|
-
|
1183
|
-
option_strings = Hash[column_names.map {|name| [name, '']}]
|
1184
|
-
|
1185
|
-
# add index sort order if supported
|
1182
|
+
def add_options_for_index_columns(quoted_columns, **options)
|
1186
1183
|
if supports_index_sort_order?
|
1187
|
-
|
1184
|
+
quoted_columns = add_index_sort_order(quoted_columns, options)
|
1188
1185
|
end
|
1189
1186
|
|
1190
|
-
|
1187
|
+
quoted_columns
|
1188
|
+
end
|
1189
|
+
|
1190
|
+
def quoted_columns_for_index(column_names, **options)
|
1191
|
+
return [column_names] if column_names.is_a?(String)
|
1192
|
+
|
1193
|
+
quoted_columns = Hash[column_names.map { |name| [name.to_sym, quote_column_name(name).dup] }]
|
1194
|
+
add_options_for_index_columns(quoted_columns, options).values
|
1191
1195
|
end
|
1192
1196
|
|
1193
1197
|
def index_name_for_remove(table_name, options = {})
|
@@ -1201,16 +1205,16 @@ module ActiveRecord
|
|
1201
1205
|
|
1202
1206
|
if options.is_a?(Hash)
|
1203
1207
|
checks << lambda { |i| i.name == options[:name].to_s } if options.key?(:name)
|
1204
|
-
column_names =
|
1208
|
+
column_names = index_column_names(options[:column])
|
1205
1209
|
else
|
1206
|
-
column_names =
|
1210
|
+
column_names = index_column_names(options)
|
1207
1211
|
end
|
1208
1212
|
|
1209
|
-
if column_names.
|
1210
|
-
checks << lambda { |i| i.columns
|
1213
|
+
if column_names.present?
|
1214
|
+
checks << lambda { |i| index_name(table_name, i.columns) == index_name(table_name, column_names) }
|
1211
1215
|
end
|
1212
1216
|
|
1213
|
-
raise ArgumentError "No name or columns specified" if checks.none?
|
1217
|
+
raise ArgumentError, "No name or columns specified" if checks.none?
|
1214
1218
|
|
1215
1219
|
matching_indexes = indexes(table_name).select { |i| checks.all? { |check| check[i] } }
|
1216
1220
|
|
@@ -1255,8 +1259,16 @@ module ActiveRecord
|
|
1255
1259
|
AlterTable.new create_table_definition(name)
|
1256
1260
|
end
|
1257
1261
|
|
1262
|
+
def index_column_names(column_names)
|
1263
|
+
if column_names.is_a?(String) && /\W/ === column_names
|
1264
|
+
column_names
|
1265
|
+
else
|
1266
|
+
Array(column_names)
|
1267
|
+
end
|
1268
|
+
end
|
1269
|
+
|
1258
1270
|
def index_name_options(column_names) # :nodoc:
|
1259
|
-
if column_names.is_a?(String)
|
1271
|
+
if column_names.is_a?(String) && /\W/ === column_names
|
1260
1272
|
column_names = column_names.scan(/\w+/).join('_')
|
1261
1273
|
end
|
1262
1274
|
|
@@ -61,18 +61,18 @@ module ActiveRecord
|
|
61
61
|
# Most of the methods in the adapter are useful during migrations. Most
|
62
62
|
# notably, the instance methods provided by SchemaStatements are very useful.
|
63
63
|
class AbstractAdapter
|
64
|
-
ADAPTER_NAME =
|
64
|
+
ADAPTER_NAME = "Abstract".freeze
|
65
|
+
include ActiveSupport::Callbacks
|
66
|
+
define_callbacks :checkout, :checkin
|
67
|
+
|
65
68
|
include Quoting, DatabaseStatements, SchemaStatements
|
66
69
|
include DatabaseLimits
|
67
70
|
include QueryCache
|
68
|
-
include ActiveSupport::Callbacks
|
69
71
|
include ColumnDumper
|
70
72
|
include Savepoints
|
71
73
|
|
72
74
|
SIMPLE_INT = /\A\d+\z/
|
73
75
|
|
74
|
-
define_callbacks :checkout, :checkin
|
75
|
-
|
76
76
|
attr_accessor :visitor, :pool
|
77
77
|
attr_reader :schema_cache, :owner, :logger
|
78
78
|
alias :in_use? :owner
|
@@ -184,7 +184,30 @@ module ActiveRecord
|
|
184
184
|
|
185
185
|
# this method must only be called while holding connection pool's mutex
|
186
186
|
def expire
|
187
|
-
|
187
|
+
if in_use?
|
188
|
+
if @owner != Thread.current
|
189
|
+
raise ActiveRecordError, "Cannot expire connection, " <<
|
190
|
+
"it is owned by a different thread: #{@owner}. " <<
|
191
|
+
"Current thread: #{Thread.current}."
|
192
|
+
end
|
193
|
+
|
194
|
+
@owner = nil
|
195
|
+
else
|
196
|
+
raise ActiveRecordError, 'Cannot expire connection, it is not currently leased.'
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# this method must only be called while holding connection pool's mutex (and a desire for segfaults)
|
201
|
+
def steal! # :nodoc:
|
202
|
+
if in_use?
|
203
|
+
if @owner != Thread.current
|
204
|
+
pool.send :remove_connection_from_thread_cache, self, @owner
|
205
|
+
|
206
|
+
@owner = Thread.current
|
207
|
+
end
|
208
|
+
else
|
209
|
+
raise ActiveRecordError, 'Cannot steal connection, it is not currently leased.'
|
210
|
+
end
|
188
211
|
end
|
189
212
|
|
190
213
|
def unprepared_statement
|
@@ -402,7 +425,7 @@ module ActiveRecord
|
|
402
425
|
|
403
426
|
# Provides access to the underlying database driver for this adapter. For
|
404
427
|
# example, this method returns a Mysql2::Client object in case of Mysql2Adapter,
|
405
|
-
# and a
|
428
|
+
# and a PG::Connection object in case of PostgreSQLAdapter.
|
406
429
|
#
|
407
430
|
# This is useful for when you need to call a proprietary method such as
|
408
431
|
# PostgreSQL's lo_* methods.
|
@@ -556,14 +579,15 @@ module ActiveRecord
|
|
556
579
|
exception
|
557
580
|
end
|
558
581
|
|
559
|
-
def log(sql, name = "SQL", binds = [], statement_name = nil)
|
582
|
+
def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil)
|
560
583
|
@instrumenter.instrument(
|
561
584
|
"sql.active_record",
|
562
|
-
:sql
|
563
|
-
:name
|
564
|
-
:
|
565
|
-
:
|
566
|
-
:
|
585
|
+
sql: sql,
|
586
|
+
name: name,
|
587
|
+
binds: binds,
|
588
|
+
type_casted_binds: type_casted_binds,
|
589
|
+
statement_name: statement_name,
|
590
|
+
connection_id: object_id) { yield }
|
567
591
|
rescue => e
|
568
592
|
raise translate_exception_class(e, sql)
|
569
593
|
end
|