activerecord 3.0.0.beta3 → 3.0.0.beta4
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.
- data/CHANGELOG +27 -0
- data/lib/active_record.rb +5 -1
- data/lib/active_record/aggregations.rb +1 -0
- data/lib/active_record/association_preload.rb +1 -1
- data/lib/active_record/associations.rb +88 -33
- data/lib/active_record/associations/association_collection.rb +12 -11
- data/lib/active_record/associations/association_proxy.rb +1 -1
- data/lib/active_record/attribute_methods.rb +10 -1
- data/lib/active_record/attribute_methods/dirty.rb +50 -50
- data/lib/active_record/attribute_methods/primary_key.rb +1 -1
- data/lib/active_record/autosave_association.rb +20 -5
- data/lib/active_record/base.rb +28 -343
- data/lib/active_record/callbacks.rb +23 -34
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +57 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +56 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +11 -18
- data/lib/active_record/connection_adapters/abstract/quoting.rb +3 -7
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +61 -7
- data/lib/active_record/connection_adapters/abstract_adapter.rb +3 -1
- data/lib/active_record/connection_adapters/mysql_adapter.rb +22 -50
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +31 -143
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +6 -2
- data/lib/active_record/counter_cache.rb +105 -0
- data/lib/active_record/fixtures.rb +16 -15
- data/lib/active_record/locale/en.yml +2 -2
- data/lib/active_record/locking/optimistic.rb +37 -16
- data/lib/active_record/migration.rb +7 -3
- data/lib/active_record/named_scope.rb +1 -5
- data/lib/active_record/nested_attributes.rb +13 -2
- data/lib/active_record/observer.rb +19 -7
- data/lib/active_record/persistence.rb +230 -0
- data/lib/active_record/railtie.rb +17 -23
- data/lib/active_record/railties/databases.rake +3 -2
- data/lib/active_record/relation.rb +5 -2
- data/lib/active_record/relation/batches.rb +6 -1
- data/lib/active_record/relation/calculations.rb +12 -9
- data/lib/active_record/relation/finder_methods.rb +14 -10
- data/lib/active_record/relation/query_methods.rb +62 -44
- data/lib/active_record/relation/spawn_methods.rb +6 -1
- data/lib/active_record/schema_dumper.rb +3 -0
- data/lib/active_record/serializers/xml_serializer.rb +30 -56
- data/lib/active_record/session_store.rb +1 -1
- data/lib/active_record/timestamp.rb +22 -26
- data/lib/active_record/transactions.rb +168 -50
- data/lib/active_record/validations.rb +33 -49
- data/lib/active_record/version.rb +1 -1
- data/lib/rails/generators/active_record.rb +6 -9
- metadata +27 -10
@@ -17,8 +17,13 @@ module ActiveRecord
|
|
17
17
|
# * (-) <tt>create</tt>
|
18
18
|
# * (5) <tt>after_create</tt>
|
19
19
|
# * (6) <tt>after_save</tt>
|
20
|
+
# * (7) <tt>after_commit</tt>
|
20
21
|
#
|
21
|
-
#
|
22
|
+
# Also, an <tt>after_rollback</tt> callback can be configured to be triggered whenever a rollback is issued.
|
23
|
+
# Check out <tt>ActiveRecord::Transactions</tt> for more details about <tt>after_commit</tt> and
|
24
|
+
# <tt>after_rollback</tt>.
|
25
|
+
#
|
26
|
+
# That's a total of ten callbacks, which gives you immense power to react and prepare for each state in the
|
22
27
|
# Active Record lifecycle. The sequence for calling <tt>Base#save</tt> for an existing record is similar, except that each
|
23
28
|
# <tt>_on_create</tt> callback is replaced by the corresponding <tt>_on_update</tt> callback.
|
24
29
|
#
|
@@ -26,7 +31,7 @@ module ActiveRecord
|
|
26
31
|
# class CreditCard < ActiveRecord::Base
|
27
32
|
# # Strip everything but digits, so the user can specify "555 234 34" or
|
28
33
|
# # "5552-3434" or both will mean "55523434"
|
29
|
-
#
|
34
|
+
# before_validation(:on => :create) do
|
30
35
|
# self.number = number.gsub(/[^0-9]/, "") if attribute_present?("number")
|
31
36
|
# end
|
32
37
|
# end
|
@@ -228,10 +233,6 @@ module ActiveRecord
|
|
228
233
|
]
|
229
234
|
|
230
235
|
included do
|
231
|
-
[:create_or_update, :valid?, :create, :update, :destroy].each do |method|
|
232
|
-
alias_method_chain method, :callbacks
|
233
|
-
end
|
234
|
-
|
235
236
|
extend ActiveModel::Callbacks
|
236
237
|
|
237
238
|
define_callbacks :validation, :terminator => "result == false", :scope => [:kind, :name]
|
@@ -268,45 +269,33 @@ module ActiveRecord
|
|
268
269
|
end
|
269
270
|
end
|
270
271
|
|
271
|
-
def
|
272
|
-
|
273
|
-
|
274
|
-
end
|
272
|
+
def valid?(*) #:nodoc:
|
273
|
+
@_on_validate = new_record? ? :create : :update
|
274
|
+
_run_validation_callbacks { super }
|
275
275
|
end
|
276
|
-
private :create_or_update_with_callbacks
|
277
276
|
|
278
|
-
def
|
279
|
-
|
280
|
-
create_without_callbacks
|
281
|
-
end
|
277
|
+
def destroy #:nodoc:
|
278
|
+
_run_destroy_callbacks { super }
|
282
279
|
end
|
283
|
-
private :create_with_callbacks
|
284
280
|
|
285
|
-
def
|
286
|
-
|
287
|
-
|
281
|
+
def deprecated_callback_method(symbol) #:nodoc:
|
282
|
+
if respond_to?(symbol, true)
|
283
|
+
ActiveSupport::Deprecation.warn("Overwriting #{symbol} in your models has been deprecated, please use Base##{symbol} :method_name instead")
|
284
|
+
send(symbol)
|
288
285
|
end
|
289
286
|
end
|
290
|
-
private :update_with_callbacks
|
291
287
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
valid_without_callbacks?
|
296
|
-
end
|
288
|
+
private
|
289
|
+
def create_or_update #:nodoc:
|
290
|
+
_run_save_callbacks { super }
|
297
291
|
end
|
298
292
|
|
299
|
-
def
|
300
|
-
|
301
|
-
destroy_without_callbacks
|
302
|
-
end
|
293
|
+
def create #:nodoc:
|
294
|
+
_run_create_callbacks { super }
|
303
295
|
end
|
304
296
|
|
305
|
-
def
|
306
|
-
|
307
|
-
ActiveSupport::Deprecation.warn("Overwriting #{symbol} in your models has been deprecated, please use Base##{symbol} :method_name instead")
|
308
|
-
send(symbol)
|
309
|
-
end
|
297
|
+
def update(*) #:nodoc:
|
298
|
+
_run_update_callbacks { super }
|
310
299
|
end
|
311
300
|
end
|
312
301
|
end
|
@@ -10,8 +10,8 @@ module ActiveRecord
|
|
10
10
|
##
|
11
11
|
# :singleton-method:
|
12
12
|
# The connection handler
|
13
|
-
|
14
|
-
|
13
|
+
class_attribute :connection_handler, :instance_writer => false
|
14
|
+
self.connection_handler = ConnectionAdapters::ConnectionHandler.new
|
15
15
|
|
16
16
|
# Returns the connection currently associated with the class. This can
|
17
17
|
# also be used to "borrow" the connection to do database work that isn't
|
@@ -54,7 +54,7 @@ module ActiveRecord
|
|
54
54
|
raise AdapterNotSpecified unless defined?(Rails.env)
|
55
55
|
establish_connection(Rails.env)
|
56
56
|
when ConnectionSpecification
|
57
|
-
|
57
|
+
self.connection_handler.establish_connection(name, spec)
|
58
58
|
when Symbol, String
|
59
59
|
if configuration = configurations[spec.to_s]
|
60
60
|
establish_connection(configuration)
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters # :nodoc:
|
3
|
+
module DatabaseLimits
|
4
|
+
|
5
|
+
# the maximum length of a table alias
|
6
|
+
def table_alias_length
|
7
|
+
255
|
8
|
+
end
|
9
|
+
|
10
|
+
# the maximum length of a column name
|
11
|
+
def column_name_length
|
12
|
+
64
|
13
|
+
end
|
14
|
+
|
15
|
+
# the maximum length of a table name
|
16
|
+
def table_name_length
|
17
|
+
64
|
18
|
+
end
|
19
|
+
|
20
|
+
# the maximum length of an index name
|
21
|
+
def index_name_length
|
22
|
+
64
|
23
|
+
end
|
24
|
+
|
25
|
+
# the maximum number of columns per table
|
26
|
+
def columns_per_table
|
27
|
+
1024
|
28
|
+
end
|
29
|
+
|
30
|
+
# the maximum number of indexes per table
|
31
|
+
def indexes_per_table
|
32
|
+
16
|
33
|
+
end
|
34
|
+
|
35
|
+
# the maximum number of columns in a multicolumn index
|
36
|
+
def columns_per_multicolumn_index
|
37
|
+
16
|
38
|
+
end
|
39
|
+
|
40
|
+
# the maximum number of elements in an IN (x,y,z) clause
|
41
|
+
def in_clause_length
|
42
|
+
65535
|
43
|
+
end
|
44
|
+
|
45
|
+
# the maximum length of a SQL query
|
46
|
+
def sql_query_length
|
47
|
+
1048575
|
48
|
+
end
|
49
|
+
|
50
|
+
# maximum number of joins in a single query
|
51
|
+
def joins_per_query
|
52
|
+
256
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -122,6 +122,8 @@ module ActiveRecord
|
|
122
122
|
requires_new = options[:requires_new] || !last_transaction_joinable
|
123
123
|
|
124
124
|
transaction_open = false
|
125
|
+
@_current_transaction_records ||= []
|
126
|
+
|
125
127
|
begin
|
126
128
|
if block_given?
|
127
129
|
if requires_new || open_transactions == 0
|
@@ -132,6 +134,7 @@ module ActiveRecord
|
|
132
134
|
end
|
133
135
|
increment_open_transactions
|
134
136
|
transaction_open = true
|
137
|
+
@_current_transaction_records.push([])
|
135
138
|
end
|
136
139
|
yield
|
137
140
|
end
|
@@ -141,8 +144,10 @@ module ActiveRecord
|
|
141
144
|
decrement_open_transactions
|
142
145
|
if open_transactions == 0
|
143
146
|
rollback_db_transaction
|
147
|
+
rollback_transaction_records(true)
|
144
148
|
else
|
145
149
|
rollback_to_savepoint
|
150
|
+
rollback_transaction_records(false)
|
146
151
|
end
|
147
152
|
end
|
148
153
|
raise unless database_transaction_rollback.is_a?(ActiveRecord::Rollback)
|
@@ -157,20 +162,35 @@ module ActiveRecord
|
|
157
162
|
begin
|
158
163
|
if open_transactions == 0
|
159
164
|
commit_db_transaction
|
165
|
+
commit_transaction_records
|
160
166
|
else
|
161
167
|
release_savepoint
|
168
|
+
save_point_records = @_current_transaction_records.pop
|
169
|
+
unless save_point_records.blank?
|
170
|
+
@_current_transaction_records.push([]) if @_current_transaction_records.empty?
|
171
|
+
@_current_transaction_records.last.concat(save_point_records)
|
172
|
+
end
|
162
173
|
end
|
163
174
|
rescue Exception => database_transaction_rollback
|
164
175
|
if open_transactions == 0
|
165
176
|
rollback_db_transaction
|
177
|
+
rollback_transaction_records(true)
|
166
178
|
else
|
167
179
|
rollback_to_savepoint
|
180
|
+
rollback_transaction_records(false)
|
168
181
|
end
|
169
182
|
raise
|
170
183
|
end
|
171
184
|
end
|
172
185
|
end
|
173
186
|
|
187
|
+
# Register a record with the current transaction so that its after_commit and after_rollback callbacks
|
188
|
+
# can be called.
|
189
|
+
def add_transaction_record(record)
|
190
|
+
last_batch = @_current_transaction_records.last
|
191
|
+
last_batch << record if last_batch
|
192
|
+
end
|
193
|
+
|
174
194
|
# Begins the transaction (and turns off auto-committing).
|
175
195
|
def begin_db_transaction() end
|
176
196
|
|
@@ -268,6 +288,42 @@ module ActiveRecord
|
|
268
288
|
limit.to_i
|
269
289
|
end
|
270
290
|
end
|
291
|
+
|
292
|
+
# Send a rollback message to all records after they have been rolled back. If rollback
|
293
|
+
# is false, only rollback records since the last save point.
|
294
|
+
def rollback_transaction_records(rollback) #:nodoc
|
295
|
+
if rollback
|
296
|
+
records = @_current_transaction_records.flatten
|
297
|
+
@_current_transaction_records.clear
|
298
|
+
else
|
299
|
+
records = @_current_transaction_records.pop
|
300
|
+
end
|
301
|
+
|
302
|
+
unless records.blank?
|
303
|
+
records.uniq.each do |record|
|
304
|
+
begin
|
305
|
+
record.rolledback!(rollback)
|
306
|
+
rescue Exception => e
|
307
|
+
record.logger.error(e) if record.respond_to?(:logger)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# Send a commit message to all records after they have been committed.
|
314
|
+
def commit_transaction_records #:nodoc
|
315
|
+
records = @_current_transaction_records.flatten
|
316
|
+
@_current_transaction_records.clear
|
317
|
+
unless records.blank?
|
318
|
+
records.uniq.each do |record|
|
319
|
+
begin
|
320
|
+
record.committed!
|
321
|
+
rescue Exception => e
|
322
|
+
record.logger.error(e) if record.respond_to?(:logger)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
271
327
|
end
|
272
328
|
end
|
273
329
|
end
|
@@ -5,23 +5,16 @@ module ActiveRecord
|
|
5
5
|
module QueryCache
|
6
6
|
class << self
|
7
7
|
def included(base)
|
8
|
-
base.class_eval do
|
9
|
-
alias_method_chain :columns, :query_cache
|
10
|
-
alias_method_chain :select_all, :query_cache
|
11
|
-
end
|
12
|
-
|
13
8
|
dirties_query_cache base, :insert, :update, :delete
|
14
9
|
end
|
15
10
|
|
16
11
|
def dirties_query_cache(base, *method_names)
|
17
12
|
method_names.each do |method_name|
|
18
13
|
base.class_eval <<-end_code, __FILE__, __LINE__ + 1
|
19
|
-
def #{method_name}
|
20
|
-
clear_query_cache if @query_cache_enabled
|
21
|
-
#
|
22
|
-
end
|
23
|
-
#
|
24
|
-
alias_method_chain :#{method_name}, :query_dirty # alias_method_chain :update, :query_dirty
|
14
|
+
def #{method_name}(*) # def update_with_query_dirty(*args)
|
15
|
+
clear_query_cache if @query_cache_enabled # clear_query_cache if @query_cache_enabled
|
16
|
+
super # update_without_query_dirty(*args)
|
17
|
+
end # end
|
25
18
|
end_code
|
26
19
|
end
|
27
20
|
end
|
@@ -56,19 +49,19 @@ module ActiveRecord
|
|
56
49
|
@query_cache.clear
|
57
50
|
end
|
58
51
|
|
59
|
-
def
|
52
|
+
def select_all(*args)
|
60
53
|
if @query_cache_enabled
|
61
|
-
cache_sql(args.first) {
|
54
|
+
cache_sql(args.first) { super }
|
62
55
|
else
|
63
|
-
|
56
|
+
super
|
64
57
|
end
|
65
58
|
end
|
66
59
|
|
67
|
-
def
|
60
|
+
def columns(*)
|
68
61
|
if @query_cache_enabled
|
69
|
-
@query_cache["SHOW FIELDS FROM #{args.first}"] ||=
|
62
|
+
@query_cache["SHOW FIELDS FROM #{args.first}"] ||= super
|
70
63
|
else
|
71
|
-
|
64
|
+
super
|
72
65
|
end
|
73
66
|
end
|
74
67
|
|
@@ -76,7 +69,7 @@ module ActiveRecord
|
|
76
69
|
def cache_sql(sql)
|
77
70
|
result =
|
78
71
|
if @query_cache.has_key?(sql)
|
79
|
-
ActiveSupport::Notifications.instrument("active_record
|
72
|
+
ActiveSupport::Notifications.instrument("sql.active_record",
|
80
73
|
:sql => sql, :name => "CACHE", :connection_id => self.object_id)
|
81
74
|
@query_cache[sql]
|
82
75
|
else
|
@@ -13,12 +13,12 @@ module ActiveRecord
|
|
13
13
|
when String, ActiveSupport::Multibyte::Chars
|
14
14
|
value = value.to_s
|
15
15
|
if column && column.type == :binary && column.class.respond_to?(:string_to_binary)
|
16
|
-
"
|
16
|
+
"'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
|
17
17
|
elsif column && [:integer, :float].include?(column.type)
|
18
18
|
value = column.type == :integer ? value.to_i : value.to_f
|
19
19
|
value.to_s
|
20
20
|
else
|
21
|
-
"
|
21
|
+
"'#{quote_string(value)}'" # ' (for ruby-mode)
|
22
22
|
end
|
23
23
|
when NilClass then "NULL"
|
24
24
|
when TrueClass then (column && column.type == :integer ? '1' : quoted_true)
|
@@ -30,7 +30,7 @@ module ActiveRecord
|
|
30
30
|
if value.acts_like?(:date) || value.acts_like?(:time)
|
31
31
|
"'#{quoted_date(value)}'"
|
32
32
|
else
|
33
|
-
"
|
33
|
+
"'#{quote_string(value.to_yaml)}'"
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
@@ -67,10 +67,6 @@ module ActiveRecord
|
|
67
67
|
value
|
68
68
|
end.to_s(:db)
|
69
69
|
end
|
70
|
-
|
71
|
-
def quoted_string_prefix
|
72
|
-
''
|
73
|
-
end
|
74
70
|
end
|
75
71
|
end
|
76
72
|
end
|
@@ -258,7 +258,7 @@ module ActiveRecord
|
|
258
258
|
end
|
259
259
|
end
|
260
260
|
|
261
|
-
class IndexDefinition < Struct.new(:table, :name, :unique, :columns) #:nodoc:
|
261
|
+
class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths) #:nodoc:
|
262
262
|
end
|
263
263
|
|
264
264
|
# Abstract representation of a column definition. Instances of this type
|
@@ -494,7 +494,7 @@ module ActiveRecord
|
|
494
494
|
end
|
495
495
|
|
496
496
|
%w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
|
497
|
-
class_eval <<-EOV
|
497
|
+
class_eval <<-EOV, __FILE__, __LINE__ + 1
|
498
498
|
def #{column_type}(*args) # def string(*args)
|
499
499
|
options = args.extract_options! # options = args.extract_options!
|
500
500
|
column_names = args # column_names = args
|
@@ -694,7 +694,7 @@ module ActiveRecord
|
|
694
694
|
# t.string(:goat)
|
695
695
|
# t.string(:goat, :sheep)
|
696
696
|
%w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
|
697
|
-
class_eval <<-EOV
|
697
|
+
class_eval <<-EOV, __FILE__, __LINE__ + 1
|
698
698
|
def #{column_type}(*args) # def string(*args)
|
699
699
|
options = args.extract_options! # options = args.extract_options!
|
700
700
|
column_names = args # column_names = args
|
@@ -10,11 +10,6 @@ module ActiveRecord
|
|
10
10
|
{}
|
11
11
|
end
|
12
12
|
|
13
|
-
# This is the maximum length a table alias can be
|
14
|
-
def table_alias_length
|
15
|
-
255
|
16
|
-
end
|
17
|
-
|
18
13
|
# Truncates a table alias according to the limits of the current adapter.
|
19
14
|
def table_alias_for(table_name)
|
20
15
|
table_name[0..table_alias_length-1].gsub(/\./, '_')
|
@@ -256,18 +251,32 @@ module ActiveRecord
|
|
256
251
|
# name.
|
257
252
|
#
|
258
253
|
# ===== Examples
|
254
|
+
#
|
259
255
|
# ====== Creating a simple index
|
260
256
|
# add_index(:suppliers, :name)
|
261
257
|
# generates
|
262
258
|
# CREATE INDEX suppliers_name_index ON suppliers(name)
|
259
|
+
#
|
263
260
|
# ====== Creating a unique index
|
264
261
|
# add_index(:accounts, [:branch_id, :party_id], :unique => true)
|
265
262
|
# generates
|
266
263
|
# CREATE UNIQUE INDEX accounts_branch_id_party_id_index ON accounts(branch_id, party_id)
|
264
|
+
#
|
267
265
|
# ====== Creating a named index
|
268
266
|
# add_index(:accounts, [:branch_id, :party_id], :unique => true, :name => 'by_branch_party')
|
269
267
|
# generates
|
270
268
|
# CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)
|
269
|
+
#
|
270
|
+
# ====== Creating an index with specific key length
|
271
|
+
# add_index(:accounts, :name, :name => 'by_name', :length => 10)
|
272
|
+
# generates
|
273
|
+
# CREATE INDEX by_name ON accounts(name(10))
|
274
|
+
#
|
275
|
+
# add_index(:accounts, [:name, :surname], :name => 'by_name_surname', :length => {:name => 10, :surname => 15})
|
276
|
+
# generates
|
277
|
+
# CREATE INDEX by_name_surname ON accounts(name(10), surname(15))
|
278
|
+
#
|
279
|
+
# Note: SQLite doesn't support index length
|
271
280
|
def add_index(table_name, column_name, options = {})
|
272
281
|
column_names = Array.wrap(column_name)
|
273
282
|
index_name = index_name(table_name, :column => column_names)
|
@@ -278,7 +287,17 @@ module ActiveRecord
|
|
278
287
|
else
|
279
288
|
index_type = options
|
280
289
|
end
|
281
|
-
|
290
|
+
|
291
|
+
if index_name.length > index_name_length
|
292
|
+
@logger.warn("Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{index_name_length} characters. Skipping.")
|
293
|
+
return
|
294
|
+
end
|
295
|
+
if index_exists?(table_name, index_name, false)
|
296
|
+
@logger.warn("Index name '#{index_name}' on table '#{table_name}' already exists. Skipping.")
|
297
|
+
return
|
298
|
+
end
|
299
|
+
quoted_column_names = quoted_columns_for_index(column_names, options).join(", ")
|
300
|
+
|
282
301
|
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})"
|
283
302
|
end
|
284
303
|
|
@@ -293,7 +312,28 @@ module ActiveRecord
|
|
293
312
|
# Remove the index named by_branch_party in the accounts table.
|
294
313
|
# remove_index :accounts, :name => :by_branch_party
|
295
314
|
def remove_index(table_name, options = {})
|
296
|
-
|
315
|
+
index_name = index_name(table_name, options)
|
316
|
+
unless index_exists?(table_name, index_name, true)
|
317
|
+
@logger.warn("Index name '#{index_name}' on table '#{table_name}' does not exist. Skipping.")
|
318
|
+
return
|
319
|
+
end
|
320
|
+
remove_index!(table_name, index_name)
|
321
|
+
end
|
322
|
+
|
323
|
+
def remove_index!(table_name, index_name) #:nodoc:
|
324
|
+
execute "DROP INDEX #{quote_column_name(index_name)} ON #{table_name}"
|
325
|
+
end
|
326
|
+
|
327
|
+
# Rename an index.
|
328
|
+
#
|
329
|
+
# Rename the index_people_on_last_name index to index_users_on_last_name
|
330
|
+
# rename_index :people, 'index_people_on_last_name', 'index_users_on_last_name'
|
331
|
+
def rename_index(table_name, old_name, new_name)
|
332
|
+
# this is a naive implementation; some DBs may support this more efficiently (Postgres, for instance)
|
333
|
+
old_index_def = indexes(table_name).detect { |i| i.name == old_name }
|
334
|
+
return unless old_index_def
|
335
|
+
remove_index(table_name, :name => old_name)
|
336
|
+
add_index(table_name, old_index_def.columns, :name => new_name, :unique => old_index_def.unique)
|
297
337
|
end
|
298
338
|
|
299
339
|
def index_name(table_name, options) #:nodoc:
|
@@ -310,6 +350,15 @@ module ActiveRecord
|
|
310
350
|
end
|
311
351
|
end
|
312
352
|
|
353
|
+
# Verify the existence of an index.
|
354
|
+
#
|
355
|
+
# The default argument is returned if the underlying implementation does not define the indexes method,
|
356
|
+
# as there's no way to determine the correct answer in that case.
|
357
|
+
def index_exists?(table_name, index_name, default)
|
358
|
+
return default unless respond_to?(:indexes)
|
359
|
+
indexes(table_name).detect { |i| i.name == index_name }
|
360
|
+
end
|
361
|
+
|
313
362
|
# Returns a string of <tt>CREATE TABLE</tt> SQL statement(s) for recreating the
|
314
363
|
# entire structure of the database.
|
315
364
|
def structure_dump
|
@@ -430,6 +479,11 @@ module ActiveRecord
|
|
430
479
|
end
|
431
480
|
|
432
481
|
protected
|
482
|
+
# Overridden by the mysql adapter for supporting index lengths
|
483
|
+
def quoted_columns_for_index(column_names, options = {})
|
484
|
+
column_names.map {|name| quote_column_name(name) }
|
485
|
+
end
|
486
|
+
|
433
487
|
def options_include_default?(options)
|
434
488
|
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
|
435
489
|
end
|