activerecord 4.1.15 → 4.2.0.beta1
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 +4 -4
- data/CHANGELOG.md +634 -2176
- data/README.rdoc +15 -10
- data/lib/active_record/aggregations.rb +12 -8
- data/lib/active_record/associations/association.rb +1 -1
- data/lib/active_record/associations/association_scope.rb +53 -21
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/builder/association.rb +16 -5
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -11
- data/lib/active_record/associations/builder/has_one.rb +2 -2
- data/lib/active_record/associations/builder/singular_association.rb +8 -1
- data/lib/active_record/associations/collection_association.rb +32 -44
- data/lib/active_record/associations/collection_proxy.rb +1 -10
- data/lib/active_record/associations/has_many_association.rb +60 -14
- data/lib/active_record/associations/has_many_through_association.rb +34 -23
- data/lib/active_record/associations/has_one_association.rb +0 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +18 -14
- data/lib/active_record/associations/join_dependency.rb +7 -9
- data/lib/active_record/associations/preloader/association.rb +9 -5
- data/lib/active_record/associations/preloader/through_association.rb +3 -3
- data/lib/active_record/associations/preloader.rb +2 -2
- data/lib/active_record/associations/singular_association.rb +16 -1
- data/lib/active_record/associations/through_association.rb +6 -22
- data/lib/active_record/associations.rb +58 -33
- data/lib/active_record/attribute.rb +131 -0
- data/lib/active_record/attribute_assignment.rb +19 -11
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
- data/lib/active_record/attribute_methods/dirty.rb +85 -42
- data/lib/active_record/attribute_methods/primary_key.rb +6 -8
- data/lib/active_record/attribute_methods/read.rb +14 -57
- data/lib/active_record/attribute_methods/serialization.rb +12 -146
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +32 -40
- data/lib/active_record/attribute_methods/write.rb +8 -23
- data/lib/active_record/attribute_methods.rb +53 -90
- data/lib/active_record/attribute_set/builder.rb +32 -0
- data/lib/active_record/attribute_set.rb +77 -0
- data/lib/active_record/attributes.rb +122 -0
- data/lib/active_record/autosave_association.rb +11 -21
- data/lib/active_record/base.rb +9 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +69 -45
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -42
- data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -60
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +37 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +102 -21
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +9 -33
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +178 -55
- data/lib/active_record/connection_adapters/abstract/transaction.rb +120 -115
- data/lib/active_record/connection_adapters/abstract_adapter.rb +143 -57
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +156 -107
- data/lib/active_record/connection_adapters/column.rb +13 -244
- data/lib/active_record/connection_adapters/connection_specification.rb +6 -20
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -15
- data/lib/active_record/connection_adapters/mysql_adapter.rb +55 -143
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -20
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +96 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +85 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +42 -122
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +154 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +86 -34
- data/lib/active_record/connection_adapters/postgresql/utils.rb +66 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +188 -452
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +54 -47
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +119 -22
- data/lib/active_record/counter_cache.rb +60 -6
- data/lib/active_record/enum.rb +9 -10
- data/lib/active_record/errors.rb +27 -26
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixtures.rb +52 -45
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +33 -8
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/locking/optimistic.rb +34 -16
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +22 -32
- data/lib/active_record/model_schema.rb +39 -48
- data/lib/active_record/nested_attributes.rb +8 -18
- data/lib/active_record/persistence.rb +39 -22
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +1 -8
- data/lib/active_record/railtie.rb +17 -10
- data/lib/active_record/railties/databases.rake +47 -42
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +225 -92
- data/lib/active_record/relation/batches.rb +0 -2
- data/lib/active_record/relation/calculations.rb +28 -32
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +42 -20
- data/lib/active_record/relation/merger.rb +0 -1
- data/lib/active_record/relation/predicate_builder/array_handler.rb +16 -11
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +0 -4
- data/lib/active_record/relation/predicate_builder.rb +1 -22
- data/lib/active_record/relation/query_methods.rb +98 -62
- data/lib/active_record/relation/spawn_methods.rb +6 -7
- data/lib/active_record/relation.rb +35 -11
- data/lib/active_record/result.rb +16 -9
- data/lib/active_record/sanitization.rb +8 -1
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +51 -9
- data/lib/active_record/schema_migration.rb +4 -0
- data/lib/active_record/scoping/default.rb +5 -4
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +79 -5
- data/lib/active_record/store.rb +5 -5
- data/lib/active_record/tasks/database_tasks.rb +37 -5
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +2 -2
- data/lib/active_record/timestamp.rb +9 -7
- data/lib/active_record/transactions.rb +35 -21
- data/lib/active_record/type/binary.rb +40 -0
- data/lib/active_record/type/boolean.rb +19 -0
- data/lib/active_record/type/date.rb +46 -0
- data/lib/active_record/type/date_time.rb +43 -0
- data/lib/active_record/type/decimal.rb +40 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +19 -0
- data/lib/active_record/type/integer.rb +23 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +51 -0
- data/lib/active_record/type/string.rb +36 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +48 -0
- data/lib/active_record/type/value.rb +101 -0
- data/lib/active_record/type.rb +20 -0
- data/lib/active_record/validations/uniqueness.rb +9 -23
- data/lib/active_record/validations.rb +21 -16
- data/lib/active_record.rb +2 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +71 -14
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -6,12 +6,29 @@ module ActiveRecord
|
|
6
6
|
include Savepoints
|
7
7
|
|
8
8
|
class SchemaCreation < AbstractAdapter::SchemaCreation
|
9
|
-
|
10
9
|
def visit_AddColumn(o)
|
11
10
|
add_column_position!(super, column_options(o))
|
12
11
|
end
|
13
12
|
|
14
13
|
private
|
14
|
+
|
15
|
+
def visit_DropForeignKey(name)
|
16
|
+
"DROP FOREIGN KEY #{name}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def visit_TableDefinition(o)
|
20
|
+
name = o.name
|
21
|
+
create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE #{quote_table_name(name)} "
|
22
|
+
|
23
|
+
statements = o.columns.map { |c| accept c }
|
24
|
+
statements.concat(o.indexes.map { |column_name, options| index_in_create(name, column_name, options) })
|
25
|
+
|
26
|
+
create_sql << "(#{statements.join(', ')}) " if statements.present?
|
27
|
+
create_sql << "#{o.options}"
|
28
|
+
create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
|
29
|
+
create_sql
|
30
|
+
end
|
31
|
+
|
15
32
|
def visit_ChangeColumnDefinition(o)
|
16
33
|
column = o.column
|
17
34
|
options = o.options
|
@@ -29,6 +46,11 @@ module ActiveRecord
|
|
29
46
|
end
|
30
47
|
sql
|
31
48
|
end
|
49
|
+
|
50
|
+
def index_in_create(table_name, column_name, options)
|
51
|
+
index_name, index_type, index_columns, index_options, index_algorithm, index_using = @conn.add_index_options(table_name, column_name, options)
|
52
|
+
"#{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_options} #{index_algorithm}"
|
53
|
+
end
|
32
54
|
end
|
33
55
|
|
34
56
|
def schema_creation
|
@@ -38,29 +60,25 @@ module ActiveRecord
|
|
38
60
|
class Column < ConnectionAdapters::Column # :nodoc:
|
39
61
|
attr_reader :collation, :strict, :extra
|
40
62
|
|
41
|
-
def initialize(name, default, sql_type = nil, null = true, collation = nil, strict = false, extra = "")
|
63
|
+
def initialize(name, default, cast_type, sql_type = nil, null = true, collation = nil, strict = false, extra = "")
|
42
64
|
@strict = strict
|
43
65
|
@collation = collation
|
44
66
|
@extra = extra
|
45
|
-
super(name, default, sql_type, null)
|
67
|
+
super(name, default, cast_type, sql_type, null)
|
68
|
+
assert_valid_default(default)
|
69
|
+
extract_default
|
46
70
|
end
|
47
71
|
|
48
|
-
def extract_default
|
72
|
+
def extract_default
|
49
73
|
if blob_or_text_column?
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}"
|
54
|
-
end
|
55
|
-
elsif missing_default_forged_as_empty_string?(default)
|
56
|
-
nil
|
57
|
-
else
|
58
|
-
super
|
74
|
+
@default = null || strict ? nil : ''
|
75
|
+
elsif missing_default_forged_as_empty_string?(@default)
|
76
|
+
@default = nil
|
59
77
|
end
|
60
78
|
end
|
61
79
|
|
62
80
|
def has_default?
|
63
|
-
return false if blob_or_text_column? #
|
81
|
+
return false if blob_or_text_column? # MySQL forbids defaults on blob and text columns
|
64
82
|
super
|
65
83
|
end
|
66
84
|
|
@@ -68,56 +86,12 @@ module ActiveRecord
|
|
68
86
|
sql_type =~ /blob/i || type == :text
|
69
87
|
end
|
70
88
|
|
71
|
-
# Must return the relevant concrete adapter
|
72
|
-
def adapter
|
73
|
-
raise NotImplementedError
|
74
|
-
end
|
75
|
-
|
76
89
|
def case_sensitive?
|
77
90
|
collation && !collation.match(/_ci$/)
|
78
91
|
end
|
79
92
|
|
80
93
|
private
|
81
94
|
|
82
|
-
def simplified_type(field_type)
|
83
|
-
return :boolean if adapter.emulate_booleans && field_type.downcase.index("tinyint(1)")
|
84
|
-
|
85
|
-
case field_type
|
86
|
-
when /enum/i, /set/i then :string
|
87
|
-
when /year/i then :integer
|
88
|
-
when /bit/i then :binary
|
89
|
-
else
|
90
|
-
super
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def extract_limit(sql_type)
|
95
|
-
case sql_type
|
96
|
-
when /^enum\((.+)\)/i
|
97
|
-
$1.split(',').map{|enum| enum.strip.length - 2}.max
|
98
|
-
when /blob|text/i
|
99
|
-
case sql_type
|
100
|
-
when /tiny/i
|
101
|
-
255
|
102
|
-
when /medium/i
|
103
|
-
16777215
|
104
|
-
when /long/i
|
105
|
-
2147483647 # mysql only allows 2^31-1, not 2^32-1, somewhat inconsistently with the tiny/medium/normal cases
|
106
|
-
else
|
107
|
-
super # we could return 65535 here, but we leave it undecorated by default
|
108
|
-
end
|
109
|
-
when /^bigint/i; 8
|
110
|
-
when /^int/i; 4
|
111
|
-
when /^mediumint/i; 3
|
112
|
-
when /^smallint/i; 2
|
113
|
-
when /^tinyint/i; 1
|
114
|
-
when /^float/i; 24
|
115
|
-
when /^double/i; 53
|
116
|
-
else
|
117
|
-
super
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
95
|
# MySQL misreports NOT NULL column default when none is given.
|
122
96
|
# We can't detect this for columns which may have a legitimate ''
|
123
97
|
# default (string) but we can for others (integer, datetime, boolean,
|
@@ -128,6 +102,12 @@ module ActiveRecord
|
|
128
102
|
def missing_default_forged_as_empty_string?(default)
|
129
103
|
type != :string && !null && default == ''
|
130
104
|
end
|
105
|
+
|
106
|
+
def assert_valid_default(default)
|
107
|
+
if blob_or_text_column? && default.present?
|
108
|
+
raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}"
|
109
|
+
end
|
110
|
+
end
|
131
111
|
end
|
132
112
|
|
133
113
|
##
|
@@ -157,7 +137,6 @@ module ActiveRecord
|
|
157
137
|
:float => { :name => "float" },
|
158
138
|
:decimal => { :name => "decimal" },
|
159
139
|
:datetime => { :name => "datetime" },
|
160
|
-
:timestamp => { :name => "datetime" },
|
161
140
|
:time => { :name => "time" },
|
162
141
|
:date => { :name => "date" },
|
163
142
|
:binary => { :name => "blob" },
|
@@ -167,21 +146,18 @@ module ActiveRecord
|
|
167
146
|
INDEX_TYPES = [:fulltext, :spatial]
|
168
147
|
INDEX_USINGS = [:btree, :hash]
|
169
148
|
|
170
|
-
class BindSubstitution < Arel::Visitors::MySQL # :nodoc:
|
171
|
-
include Arel::Visitors::BindVisitor
|
172
|
-
end
|
173
|
-
|
174
149
|
# FIXME: Make the first parameter more similar for the two adapters
|
175
150
|
def initialize(connection, logger, connection_options, config)
|
176
151
|
super(connection, logger)
|
177
152
|
@connection_options, @config = connection_options, config
|
178
153
|
@quoted_column_names, @quoted_table_names = {}, {}
|
179
154
|
|
155
|
+
@visitor = Arel::Visitors::MySQL.new self
|
156
|
+
|
180
157
|
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
181
158
|
@prepared_statements = true
|
182
|
-
@visitor = Arel::Visitors::MySQL.new self
|
183
159
|
else
|
184
|
-
@
|
160
|
+
@prepared_statements = false
|
185
161
|
end
|
186
162
|
end
|
187
163
|
|
@@ -208,17 +184,6 @@ module ActiveRecord
|
|
208
184
|
true
|
209
185
|
end
|
210
186
|
|
211
|
-
def type_cast(value, column)
|
212
|
-
case value
|
213
|
-
when TrueClass
|
214
|
-
1
|
215
|
-
when FalseClass
|
216
|
-
0
|
217
|
-
else
|
218
|
-
super
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
187
|
# MySQL 4 technically support transaction isolation, but it is affected by a bug
|
223
188
|
# where the transaction level gets persisted for the whole session:
|
224
189
|
#
|
@@ -227,6 +192,14 @@ module ActiveRecord
|
|
227
192
|
version[0] >= 5
|
228
193
|
end
|
229
194
|
|
195
|
+
def supports_indexes_in_create?
|
196
|
+
true
|
197
|
+
end
|
198
|
+
|
199
|
+
def supports_foreign_keys?
|
200
|
+
true
|
201
|
+
end
|
202
|
+
|
230
203
|
def native_database_types
|
231
204
|
NATIVE_DATABASE_TYPES
|
232
205
|
end
|
@@ -243,12 +216,11 @@ module ActiveRecord
|
|
243
216
|
raise NotImplementedError
|
244
217
|
end
|
245
218
|
|
246
|
-
|
247
|
-
|
248
|
-
Column.new(field, default, type, null, collation, extra)
|
219
|
+
def new_column(field, default, cast_type, sql_type = nil, null = true, collation = "", extra = "") # :nodoc:
|
220
|
+
Column.new(field, default, cast_type, sql_type, null, collation, strict_mode?, extra)
|
249
221
|
end
|
250
222
|
|
251
|
-
# Must return the
|
223
|
+
# Must return the MySQL error number from the exception, if the exception has an
|
252
224
|
# error number.
|
253
225
|
def error_number(exception) # :nodoc:
|
254
226
|
raise NotImplementedError
|
@@ -256,12 +228,9 @@ module ActiveRecord
|
|
256
228
|
|
257
229
|
# QUOTING ==================================================
|
258
230
|
|
259
|
-
def
|
260
|
-
if value.
|
261
|
-
|
262
|
-
"x'#{s}'"
|
263
|
-
elsif value.kind_of?(BigDecimal)
|
264
|
-
value.to_s("F")
|
231
|
+
def _quote(value) # :nodoc:
|
232
|
+
if value.is_a?(Type::Binary::Data)
|
233
|
+
"x'#{value.hex}'"
|
265
234
|
else
|
266
235
|
super
|
267
236
|
end
|
@@ -279,10 +248,18 @@ module ActiveRecord
|
|
279
248
|
QUOTED_TRUE
|
280
249
|
end
|
281
250
|
|
251
|
+
def unquoted_true
|
252
|
+
1
|
253
|
+
end
|
254
|
+
|
282
255
|
def quoted_false
|
283
256
|
QUOTED_FALSE
|
284
257
|
end
|
285
258
|
|
259
|
+
def unquoted_false
|
260
|
+
0
|
261
|
+
end
|
262
|
+
|
286
263
|
# REFERENTIAL INTEGRITY ====================================
|
287
264
|
|
288
265
|
def disable_referential_integrity #:nodoc:
|
@@ -298,6 +275,11 @@ module ActiveRecord
|
|
298
275
|
|
299
276
|
# DATABASE STATEMENTS ======================================
|
300
277
|
|
278
|
+
def clear_cache!
|
279
|
+
super
|
280
|
+
reload_type_map
|
281
|
+
end
|
282
|
+
|
301
283
|
# Executes the SQL statement in the context of this connection.
|
302
284
|
def execute(sql, name = nil)
|
303
285
|
log(sql, name) { @connection.query(sql) }
|
@@ -407,7 +389,7 @@ module ActiveRecord
|
|
407
389
|
end
|
408
390
|
|
409
391
|
def table_exists?(name)
|
410
|
-
return false unless name
|
392
|
+
return false unless name.present?
|
411
393
|
return true if tables(nil, nil, name).any?
|
412
394
|
|
413
395
|
name = name.to_s
|
@@ -451,7 +433,9 @@ module ActiveRecord
|
|
451
433
|
execute_and_free(sql, 'SCHEMA') do |result|
|
452
434
|
each_hash(result).map do |field|
|
453
435
|
field_name = set_field_encoding(field[:Field])
|
454
|
-
|
436
|
+
sql_type = field[:Type]
|
437
|
+
cast_type = lookup_cast_type(sql_type)
|
438
|
+
new_column(field_name, field[:Default], cast_type, sql_type, field[:Null] == "YES", field[:Collation], field[:Extra])
|
455
439
|
end
|
456
440
|
end
|
457
441
|
end
|
@@ -461,7 +445,7 @@ module ActiveRecord
|
|
461
445
|
end
|
462
446
|
|
463
447
|
def bulk_change_table(table_name, operations) #:nodoc:
|
464
|
-
sqls = operations.
|
448
|
+
sqls = operations.flat_map do |command, args|
|
465
449
|
table, arguments = args.shift, args
|
466
450
|
method = :"#{command}_sql"
|
467
451
|
|
@@ -470,7 +454,7 @@ module ActiveRecord
|
|
470
454
|
else
|
471
455
|
raise "Unknown method called : #{method}(#{arguments.inspect})"
|
472
456
|
end
|
473
|
-
end.
|
457
|
+
end.join(", ")
|
474
458
|
|
475
459
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{sqls}")
|
476
460
|
end
|
@@ -525,6 +509,34 @@ module ActiveRecord
|
|
525
509
|
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} ON #{quote_table_name(table_name)} (#{index_columns})#{index_options} #{index_algorithm}"
|
526
510
|
end
|
527
511
|
|
512
|
+
def foreign_keys(table_name)
|
513
|
+
fk_info = select_all <<-SQL.strip_heredoc
|
514
|
+
SELECT fk.referenced_table_name as 'to_table'
|
515
|
+
,fk.referenced_column_name as 'primary_key'
|
516
|
+
,fk.column_name as 'column'
|
517
|
+
,fk.constraint_name as 'name'
|
518
|
+
FROM information_schema.key_column_usage fk
|
519
|
+
WHERE fk.referenced_column_name is not null
|
520
|
+
AND fk.table_schema = '#{@config[:database]}'
|
521
|
+
AND fk.table_name = '#{table_name}'
|
522
|
+
SQL
|
523
|
+
|
524
|
+
create_table_info = select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")["Create Table"]
|
525
|
+
|
526
|
+
fk_info.map do |row|
|
527
|
+
options = {
|
528
|
+
column: row['column'],
|
529
|
+
name: row['name'],
|
530
|
+
primary_key: row['primary_key']
|
531
|
+
}
|
532
|
+
|
533
|
+
options[:on_update] = extract_foreign_key_action(create_table_info, row['name'], "UPDATE")
|
534
|
+
options[:on_delete] = extract_foreign_key_action(create_table_info, row['name'], "DELETE")
|
535
|
+
|
536
|
+
ForeignKeyDefinition.new(table_name, row['to_table'], options)
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
528
540
|
# Maps logical Rails types to MySQL-specific data types.
|
529
541
|
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
|
530
542
|
case type.to_s
|
@@ -590,10 +602,19 @@ module ActiveRecord
|
|
590
602
|
pk_and_sequence && pk_and_sequence.first
|
591
603
|
end
|
592
604
|
|
593
|
-
def case_sensitive_modifier(node)
|
605
|
+
def case_sensitive_modifier(node, table_attribute)
|
606
|
+
node = Arel::Nodes.build_quoted node, table_attribute
|
594
607
|
Arel::Nodes::Bin.new(node)
|
595
608
|
end
|
596
609
|
|
610
|
+
def case_sensitive_comparison(table, attribute, column, value)
|
611
|
+
if column.case_sensitive?
|
612
|
+
table[attribute].eq(value)
|
613
|
+
else
|
614
|
+
super
|
615
|
+
end
|
616
|
+
end
|
617
|
+
|
597
618
|
def case_insensitive_comparison(table, attribute, column, value)
|
598
619
|
if column.case_sensitive?
|
599
620
|
super
|
@@ -616,6 +637,34 @@ module ActiveRecord
|
|
616
637
|
|
617
638
|
protected
|
618
639
|
|
640
|
+
def initialize_type_map(m) # :nodoc:
|
641
|
+
super
|
642
|
+
m.register_type(%r(enum)i) do |sql_type|
|
643
|
+
limit = sql_type[/^enum\((.+)\)/i, 1]
|
644
|
+
.split(',').map{|enum| enum.strip.length - 2}.max
|
645
|
+
Type::String.new(limit: limit)
|
646
|
+
end
|
647
|
+
|
648
|
+
m.register_type %r(tinytext)i, Type::Text.new(limit: 255)
|
649
|
+
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 255)
|
650
|
+
m.register_type %r(mediumtext)i, Type::Text.new(limit: 16777215)
|
651
|
+
m.register_type %r(mediumblob)i, Type::Binary.new(limit: 16777215)
|
652
|
+
m.register_type %r(longtext)i, Type::Text.new(limit: 2147483647)
|
653
|
+
m.register_type %r(longblob)i, Type::Binary.new(limit: 2147483647)
|
654
|
+
m.register_type %r(^bigint)i, Type::Integer.new(limit: 8)
|
655
|
+
m.register_type %r(^int)i, Type::Integer.new(limit: 4)
|
656
|
+
m.register_type %r(^mediumint)i, Type::Integer.new(limit: 3)
|
657
|
+
m.register_type %r(^smallint)i, Type::Integer.new(limit: 2)
|
658
|
+
m.register_type %r(^tinyint)i, Type::Integer.new(limit: 1)
|
659
|
+
m.register_type %r(^float)i, Type::Float.new(limit: 24)
|
660
|
+
m.register_type %r(^double)i, Type::Float.new(limit: 53)
|
661
|
+
|
662
|
+
m.alias_type %r(tinyint\(1\))i, 'boolean' if emulate_booleans
|
663
|
+
m.alias_type %r(set)i, 'varchar'
|
664
|
+
m.alias_type %r(year)i, 'integer'
|
665
|
+
m.alias_type %r(bit)i, 'binary'
|
666
|
+
end
|
667
|
+
|
619
668
|
# MySQL is too stupid to create a temporary table for use subquery, so we have
|
620
669
|
# to give it some prompting in the form of a subsubquery. Ugh!
|
621
670
|
def subquery_for(key, select)
|
@@ -685,15 +734,13 @@ module ActiveRecord
|
|
685
734
|
end
|
686
735
|
|
687
736
|
def rename_column_sql(table_name, column_name, new_column_name)
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
raise ActiveRecordError, "No such column: #{table_name}.#{column_name}"
|
696
|
-
end
|
737
|
+
column = column_for(table_name, column_name)
|
738
|
+
options = {
|
739
|
+
name: new_column_name,
|
740
|
+
default: column.default,
|
741
|
+
null: column.null,
|
742
|
+
auto_increment: column.extra == "auto_increment"
|
743
|
+
}
|
697
744
|
|
698
745
|
current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'", 'SCHEMA')["Type"]
|
699
746
|
schema_creation.accept ChangeColumnDefinition.new column, current_type, options
|
@@ -743,13 +790,6 @@ module ActiveRecord
|
|
743
790
|
mariadb? ? false : (version[0] == 5 && version[1] >= 7) || version[0] >= 6
|
744
791
|
end
|
745
792
|
|
746
|
-
def column_for(table_name, column_name)
|
747
|
-
unless column = columns(table_name).find { |c| c.name == column_name.to_s }
|
748
|
-
raise "No such column: #{table_name}.#{column_name}"
|
749
|
-
end
|
750
|
-
column
|
751
|
-
end
|
752
|
-
|
753
793
|
def configure_connection
|
754
794
|
variables = @config.fetch(:variables, {}).stringify_keys
|
755
795
|
|
@@ -787,6 +827,15 @@ module ActiveRecord
|
|
787
827
|
# ...and send them all in one query
|
788
828
|
@connection.query "SET #{encoding} #{variable_assignments}"
|
789
829
|
end
|
830
|
+
|
831
|
+
def extract_foreign_key_action(structure, name, action) # :nodoc:
|
832
|
+
if structure =~ /CONSTRAINT #{quote_column_name(name)} FOREIGN KEY .* REFERENCES .* ON #{action} (CASCADE|SET NULL|RESTRICT)/
|
833
|
+
case $1
|
834
|
+
when 'CASCADE'; :cascade
|
835
|
+
when 'SET NULL'; :nullify
|
836
|
+
end
|
837
|
+
end
|
838
|
+
end
|
790
839
|
end
|
791
840
|
end
|
792
841
|
end
|