activerecord 3.1.12 → 3.2.0.rc1

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.

Files changed (99) hide show
  1. data/CHANGELOG.md +6263 -103
  2. data/README.rdoc +2 -2
  3. data/examples/performance.rb +55 -31
  4. data/lib/active_record.rb +28 -2
  5. data/lib/active_record/aggregations.rb +2 -2
  6. data/lib/active_record/associations.rb +82 -69
  7. data/lib/active_record/associations/association.rb +2 -37
  8. data/lib/active_record/associations/association_scope.rb +3 -30
  9. data/lib/active_record/associations/builder/association.rb +6 -4
  10. data/lib/active_record/associations/builder/belongs_to.rb +3 -3
  11. data/lib/active_record/associations/builder/collection_association.rb +2 -2
  12. data/lib/active_record/associations/builder/has_many.rb +4 -4
  13. data/lib/active_record/associations/builder/has_one.rb +5 -6
  14. data/lib/active_record/associations/builder/singular_association.rb +3 -16
  15. data/lib/active_record/associations/collection_association.rb +55 -28
  16. data/lib/active_record/associations/collection_proxy.rb +1 -35
  17. data/lib/active_record/associations/has_many_association.rb +5 -1
  18. data/lib/active_record/associations/has_many_through_association.rb +11 -8
  19. data/lib/active_record/associations/join_dependency.rb +1 -1
  20. data/lib/active_record/associations/preloader/association.rb +3 -1
  21. data/lib/active_record/attribute_assignment.rb +221 -0
  22. data/lib/active_record/attribute_methods.rb +212 -32
  23. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
  24. data/lib/active_record/attribute_methods/dirty.rb +3 -3
  25. data/lib/active_record/attribute_methods/primary_key.rb +62 -25
  26. data/lib/active_record/attribute_methods/read.rb +69 -80
  27. data/lib/active_record/attribute_methods/serialization.rb +89 -0
  28. data/lib/active_record/attribute_methods/time_zone_conversion.rb +9 -14
  29. data/lib/active_record/attribute_methods/write.rb +27 -5
  30. data/lib/active_record/autosave_association.rb +23 -8
  31. data/lib/active_record/base.rb +223 -1712
  32. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +98 -132
  33. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +82 -29
  34. data/lib/active_record/connection_adapters/abstract/database_statements.rb +13 -42
  35. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  36. data/lib/active_record/connection_adapters/abstract/quoting.rb +7 -4
  37. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +36 -25
  38. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +41 -13
  39. data/lib/active_record/connection_adapters/abstract_adapter.rb +78 -43
  40. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +653 -0
  41. data/lib/active_record/connection_adapters/mysql2_adapter.rb +138 -578
  42. data/lib/active_record/connection_adapters/mysql_adapter.rb +86 -658
  43. data/lib/active_record/connection_adapters/postgresql_adapter.rb +144 -94
  44. data/lib/active_record/connection_adapters/schema_cache.rb +50 -0
  45. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -6
  46. data/lib/active_record/connection_adapters/sqlite_adapter.rb +43 -22
  47. data/lib/active_record/counter_cache.rb +1 -1
  48. data/lib/active_record/dynamic_matchers.rb +79 -0
  49. data/lib/active_record/errors.rb +11 -1
  50. data/lib/active_record/explain.rb +83 -0
  51. data/lib/active_record/explain_subscriber.rb +21 -0
  52. data/lib/active_record/fixtures.rb +31 -76
  53. data/lib/active_record/fixtures/file.rb +65 -0
  54. data/lib/active_record/identity_map.rb +1 -7
  55. data/lib/active_record/inheritance.rb +167 -0
  56. data/lib/active_record/integration.rb +49 -0
  57. data/lib/active_record/locking/optimistic.rb +19 -11
  58. data/lib/active_record/locking/pessimistic.rb +1 -1
  59. data/lib/active_record/log_subscriber.rb +3 -3
  60. data/lib/active_record/migration.rb +38 -29
  61. data/lib/active_record/migration/command_recorder.rb +7 -7
  62. data/lib/active_record/model_schema.rb +362 -0
  63. data/lib/active_record/nested_attributes.rb +3 -2
  64. data/lib/active_record/persistence.rb +51 -1
  65. data/lib/active_record/querying.rb +58 -0
  66. data/lib/active_record/railtie.rb +24 -28
  67. data/lib/active_record/railties/controller_runtime.rb +3 -1
  68. data/lib/active_record/railties/databases.rake +133 -77
  69. data/lib/active_record/readonly_attributes.rb +26 -0
  70. data/lib/active_record/reflection.rb +7 -15
  71. data/lib/active_record/relation.rb +78 -35
  72. data/lib/active_record/relation/batches.rb +5 -2
  73. data/lib/active_record/relation/calculations.rb +27 -6
  74. data/lib/active_record/relation/delegation.rb +49 -0
  75. data/lib/active_record/relation/finder_methods.rb +5 -4
  76. data/lib/active_record/relation/predicate_builder.rb +13 -16
  77. data/lib/active_record/relation/query_methods.rb +59 -4
  78. data/lib/active_record/result.rb +1 -1
  79. data/lib/active_record/sanitization.rb +194 -0
  80. data/lib/active_record/schema_dumper.rb +5 -2
  81. data/lib/active_record/scoping.rb +152 -0
  82. data/lib/active_record/scoping/default.rb +140 -0
  83. data/lib/active_record/scoping/named.rb +202 -0
  84. data/lib/active_record/serialization.rb +1 -43
  85. data/lib/active_record/serializers/xml_serializer.rb +2 -44
  86. data/lib/active_record/session_store.rb +11 -11
  87. data/lib/active_record/store.rb +50 -0
  88. data/lib/active_record/test_case.rb +11 -7
  89. data/lib/active_record/timestamp.rb +16 -3
  90. data/lib/active_record/transactions.rb +5 -5
  91. data/lib/active_record/translation.rb +22 -0
  92. data/lib/active_record/validations.rb +1 -1
  93. data/lib/active_record/validations/associated.rb +5 -4
  94. data/lib/active_record/validations/uniqueness.rb +4 -4
  95. data/lib/active_record/version.rb +3 -3
  96. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +1 -5
  97. metadata +48 -38
  98. checksums.yaml +0 -7
  99. data/lib/active_record/named_scope.rb +0 -200
@@ -1,14 +1,10 @@
1
- require 'active_support/core_ext/module/deprecation'
2
-
3
1
  module ActiveRecord
4
2
  module ConnectionAdapters # :nodoc:
5
3
  module DatabaseStatements
6
4
  # Converts an arel AST to SQL
7
- def to_sql(arel, binds = [])
5
+ def to_sql(arel)
8
6
  if arel.respond_to?(:ast)
9
- visitor.accept(arel.ast) do
10
- quote(*binds.shift.reverse)
11
- end
7
+ visitor.accept(arel.ast)
12
8
  else
13
9
  arel
14
10
  end
@@ -17,7 +13,7 @@ module ActiveRecord
17
13
  # Returns an array of record hashes with the column names as keys and
18
14
  # column values as values.
19
15
  def select_all(arel, name = nil, binds = [])
20
- select(to_sql(arel, binds), name, binds)
16
+ select(to_sql(arel), name, binds)
21
17
  end
22
18
 
23
19
  # Returns a record hash with the column names as keys and column values
@@ -37,7 +33,7 @@ module ActiveRecord
37
33
  # Returns an array of the values of the first column in a select:
38
34
  # select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
39
35
  def select_values(arel, name = nil)
40
- result = select_rows(to_sql(arel, []), name)
36
+ result = select_rows(to_sql(arel), name)
41
37
  result.map { |v| v[0] }
42
38
  end
43
39
 
@@ -53,7 +49,7 @@ module ActiveRecord
53
49
  undef_method :execute
54
50
 
55
51
  # Executes +sql+ statement in the context of this connection using
56
- # +binds+ as the bind substitutes. +name+ is logged along with
52
+ # +binds+ as the bind substitutes. +name+ is logged along with
57
53
  # the executed +sql+ statement.
58
54
  def exec_query(sql, name = 'SQL', binds = [])
59
55
  end
@@ -88,19 +84,19 @@ module ActiveRecord
88
84
  # If the next id was calculated in advance (as in Oracle), it should be
89
85
  # passed in as +id_value+.
90
86
  def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
91
- sql, binds = sql_for_insert(to_sql(arel, binds), pk, id_value, sequence_name, binds)
87
+ sql, binds = sql_for_insert(to_sql(arel), pk, id_value, sequence_name, binds)
92
88
  value = exec_insert(sql, name, binds)
93
89
  id_value || last_inserted_id(value)
94
90
  end
95
91
 
96
92
  # Executes the update statement and returns the number of rows affected.
97
93
  def update(arel, name = nil, binds = [])
98
- exec_update(to_sql(arel, binds), name, binds)
94
+ exec_update(to_sql(arel), name, binds)
99
95
  end
100
96
 
101
97
  # Executes the delete statement and returns the number of rows affected.
102
98
  def delete(arel, name = nil, binds = [])
103
- exec_delete(to_sql(arel, binds), name, binds)
99
+ exec_delete(to_sql(arel), name, binds)
104
100
  end
105
101
 
106
102
  # Checks whether there is currently no transaction active. This is done
@@ -256,38 +252,13 @@ module ActiveRecord
256
252
  # done if the transaction block raises an exception or returns false.
257
253
  def rollback_db_transaction() end
258
254
 
259
- # Appends +LIMIT+ and +OFFSET+ options to an SQL statement, or some SQL
260
- # fragment that has the same semantics as LIMIT and OFFSET.
261
- #
262
- # +options+ must be a Hash which contains a +:limit+ option
263
- # and an +:offset+ option.
264
- #
265
- # This method *modifies* the +sql+ parameter.
266
- #
267
- # This method is deprecated!! Stop using it!
268
- #
269
- # ===== Examples
270
- # add_limit_offset!('SELECT * FROM suppliers', {:limit => 10, :offset => 50})
271
- # generates
272
- # SELECT * FROM suppliers LIMIT 10 OFFSET 50
273
- def add_limit_offset!(sql, options)
274
- if limit = options[:limit]
275
- sql << " LIMIT #{sanitize_limit(limit)}"
276
- end
277
- if offset = options[:offset]
278
- sql << " OFFSET #{offset.to_i}"
279
- end
280
- sql
281
- end
282
- deprecate :add_limit_offset!
283
-
284
255
  def default_sequence_name(table, column)
285
256
  nil
286
257
  end
287
258
 
288
259
  # Set the sequence to the max value of the table's column.
289
260
  def reset_sequence!(table, column, sequence = nil)
290
- # Do nothing by default. Implement for PostgreSQL, Oracle, ...
261
+ # Do nothing by default. Implement for PostgreSQL, Oracle, ...
291
262
  end
292
263
 
293
264
  # Inserts the given fixture into the table. Overridden in adapters that require
@@ -319,10 +290,10 @@ module ActiveRecord
319
290
  # Sanitizes the given LIMIT parameter in order to prevent SQL injection.
320
291
  #
321
292
  # The +limit+ may be anything that can evaluate to a string via #to_s. It
322
- # should look like an integer, or a comma-delimited list of integers, or
293
+ # should look like an integer, or a comma-delimited list of integers, or
323
294
  # an Arel SQL literal.
324
295
  #
325
- # Returns Integer and Arel::Nodes::SqlLiteral limits as is.
296
+ # Returns Integer and Arel::Nodes::SqlLiteral limits as is.
326
297
  # Returns the sanitized limit parameter, either as an integer, or as a
327
298
  # string which contains a comma-delimited list of integers.
328
299
  def sanitize_limit(limit)
@@ -370,7 +341,7 @@ module ActiveRecord
370
341
 
371
342
  # Send a rollback message to all records after they have been rolled back. If rollback
372
343
  # is false, only rollback records since the last save point.
373
- def rollback_transaction_records(rollback) #:nodoc
344
+ def rollback_transaction_records(rollback)
374
345
  if rollback
375
346
  records = @_current_transaction_records.flatten
376
347
  @_current_transaction_records.clear
@@ -390,7 +361,7 @@ module ActiveRecord
390
361
  end
391
362
 
392
363
  # Send a commit message to all records after they have been committed.
393
- def commit_transaction_records #:nodoc
364
+ def commit_transaction_records
394
365
  records = @_current_transaction_records.flatten
395
366
  @_current_transaction_records.clear
396
367
  unless records.blank?
@@ -57,7 +57,7 @@ module ActiveRecord
57
57
 
58
58
  def select_all(arel, name = nil, binds = [])
59
59
  if @query_cache_enabled
60
- sql = to_sql(arel, binds)
60
+ sql = to_sql(arel)
61
61
  cache_sql(sql, binds) { super(sql, name, binds) }
62
62
  else
63
63
  super
@@ -102,10 +102,13 @@ module ActiveRecord
102
102
  def quoted_date(value)
103
103
  if value.acts_like?(:time)
104
104
  zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
105
- value.respond_to?(zone_conversion_method) ? value.send(zone_conversion_method) : value
106
- else
107
- value
108
- end.to_s(:db)
105
+
106
+ if value.respond_to?(zone_conversion_method)
107
+ value = value.send(zone_conversion_method)
108
+ end
109
+ end
110
+
111
+ value.to_s(:db)
109
112
  end
110
113
  end
111
114
  end
@@ -6,7 +6,7 @@ require 'bigdecimal/util'
6
6
 
7
7
  module ActiveRecord
8
8
  module ConnectionAdapters #:nodoc:
9
- class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths) #:nodoc:
9
+ class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders) #:nodoc:
10
10
  end
11
11
 
12
12
  # Abstract representation of a column definition. Instances of this type
@@ -66,6 +66,7 @@ module ActiveRecord
66
66
 
67
67
  def initialize(base)
68
68
  @columns = []
69
+ @columns_hash = {}
69
70
  @base = base
70
71
  end
71
72
 
@@ -86,7 +87,7 @@ module ActiveRecord
86
87
 
87
88
  # Returns a ColumnDefinition for the column with name +name+.
88
89
  def [](name)
89
- @columns.find {|column| column.name.to_s == name.to_s}
90
+ @columns_hash[name.to_s]
90
91
  end
91
92
 
92
93
  # Instantiates a new column for the table.
@@ -224,35 +225,38 @@ module ActiveRecord
224
225
  # t.references :taggable, :polymorphic => { :default => 'Photo' }
225
226
  # end
226
227
  def column(name, type, options = {})
227
- column = self[name] || ColumnDefinition.new(@base, name, type)
228
- if options[:limit]
229
- column.limit = options[:limit]
230
- elsif native[type.to_sym].is_a?(Hash)
231
- column.limit = native[type.to_sym][:limit]
228
+ name = name.to_s
229
+ type = type.to_sym
230
+
231
+ column = self[name] || new_column_definition(@base, name, type)
232
+
233
+ limit = options.fetch(:limit) do
234
+ native[type][:limit] if native[type].is_a?(Hash)
232
235
  end
236
+
237
+ column.limit = limit
233
238
  column.precision = options[:precision]
234
- column.scale = options[:scale]
235
- column.default = options[:default]
236
- column.null = options[:null]
237
- @columns << column unless @columns.include? column
239
+ column.scale = options[:scale]
240
+ column.default = options[:default]
241
+ column.null = options[:null]
238
242
  self
239
243
  end
240
244
 
241
245
  %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
242
246
  class_eval <<-EOV, __FILE__, __LINE__ + 1
243
- def #{column_type}(*args) # def string(*args)
244
- options = args.extract_options! # options = args.extract_options!
245
- column_names = args # column_names = args
246
- #
247
- column_names.each { |name| column(name, '#{column_type}', options) } # column_names.each { |name| column(name, 'string', options) }
248
- end # end
247
+ def #{column_type}(*args) # def string(*args)
248
+ options = args.extract_options! # options = args.extract_options!
249
+ column_names = args # column_names = args
250
+ type = :'#{column_type}' # type = :string
251
+ column_names.each { |name| column(name, type, options) } # column_names.each { |name| column(name, type, options) }
252
+ end # end
249
253
  EOV
250
254
  end
251
255
 
252
256
  # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
253
257
  # <tt>:updated_at</tt> to the table.
254
258
  def timestamps(*args)
255
- options = args.extract_options!
259
+ options = { :null => false }.merge(args.extract_options!)
256
260
  column(:created_at, :datetime, options)
257
261
  column(:updated_at, :datetime, options)
258
262
  end
@@ -275,9 +279,16 @@ module ActiveRecord
275
279
  end
276
280
 
277
281
  private
278
- def native
279
- @base.native_database_types
280
- end
282
+ def new_column_definition(base, name, type)
283
+ definition = ColumnDefinition.new base, name, type
284
+ @columns << definition
285
+ @columns_hash[name] = definition
286
+ definition
287
+ end
288
+
289
+ def native
290
+ @base.native_database_types
291
+ end
281
292
  end
282
293
 
283
294
  # Represents an SQL table in an abstract way for updating a table.
@@ -453,13 +464,13 @@ module ActiveRecord
453
464
  def #{column_type}(*args) # def string(*args)
454
465
  options = args.extract_options! # options = args.extract_options!
455
466
  column_names = args # column_names = args
456
- #
467
+ type = :'#{column_type}' # type = :string
457
468
  column_names.each do |name| # column_names.each do |name|
458
- column = ColumnDefinition.new(@base, name, '#{column_type}') # column = ColumnDefinition.new(@base, name, 'string')
469
+ column = ColumnDefinition.new(@base, name.to_s, type) # column = ColumnDefinition.new(@base, name, type)
459
470
  if options[:limit] # if options[:limit]
460
471
  column.limit = options[:limit] # column.limit = options[:limit]
461
- elsif native['#{column_type}'.to_sym].is_a?(Hash) # elsif native['string'.to_sym].is_a?(Hash)
462
- column.limit = native['#{column_type}'.to_sym][:limit] # column.limit = native['string'.to_sym][:limit]
472
+ elsif native[type].is_a?(Hash) # elsif native[type].is_a?(Hash)
473
+ column.limit = native[type][:limit] # column.limit = native[type][:limit]
463
474
  end # end
464
475
  column.precision = options[:precision] # column.precision = options[:precision]
465
476
  column.scale = options[:scale] # column.scale = options[:scale]
@@ -1,10 +1,11 @@
1
1
  require 'active_support/core_ext/array/wrap'
2
+ require 'active_support/deprecation/reporting'
2
3
 
3
4
  module ActiveRecord
4
5
  module ConnectionAdapters # :nodoc:
5
6
  module SchemaStatements
6
7
  # Returns a Hash of mappings from the abstract data types to the native
7
- # database types. See TableDefinition#column for details on the recognized
8
+ # database types. See TableDefinition#column for details on the recognized
8
9
  # abstract data types.
9
10
  def native_database_types
10
11
  {}
@@ -15,8 +16,6 @@ module ActiveRecord
15
16
  table_name[0...table_alias_length].gsub(/\./, '_')
16
17
  end
17
18
 
18
- # def tables(name = nil) end
19
-
20
19
  # Checks to see if the table +table_name+ exists on the database.
21
20
  #
22
21
  # === Example
@@ -78,7 +77,7 @@ module ActiveRecord
78
77
  # Creates a new table with the name +table_name+. +table_name+ may either
79
78
  # be a String or a Symbol.
80
79
  #
81
- # There are two ways to work with +create_table+. You can use the block
80
+ # There are two ways to work with +create_table+. You can use the block
82
81
  # form or the regular form, like this:
83
82
  #
84
83
  # === Block form
@@ -113,7 +112,7 @@ module ActiveRecord
113
112
  # Defaults to +id+. If <tt>:id</tt> is false this option is ignored.
114
113
  #
115
114
  # Also note that this just sets the primary key in the table. You additionally
116
- # need to configure the primary key in the model via the +set_primary_key+ macro.
115
+ # need to configure the primary key in the model via +self.primary_key=+.
117
116
  # Models do NOT auto-detect the primary key from their table definition.
118
117
  #
119
118
  # [<tt>:options</tt>]
@@ -161,7 +160,7 @@ module ActiveRecord
161
160
  yield td if block_given?
162
161
 
163
162
  if options[:force] && table_exists?(table_name)
164
- drop_table(table_name, options)
163
+ drop_table(table_name)
165
164
  end
166
165
 
167
166
  create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
@@ -253,7 +252,7 @@ module ActiveRecord
253
252
  end
254
253
 
255
254
  # Drops a table from the database.
256
- def drop_table(table_name, options = {})
255
+ def drop_table(table_name)
257
256
  execute "DROP TABLE #{quote_table_name(table_name)}"
258
257
  end
259
258
 
@@ -299,7 +298,7 @@ module ActiveRecord
299
298
  raise NotImplementedError, "rename_column is not implemented"
300
299
  end
301
300
 
302
- # Adds a new index to the table. +column_name+ can be a single Symbol, or
301
+ # Adds a new index to the table. +column_name+ can be a single Symbol, or
303
302
  # an Array of Symbols.
304
303
  #
305
304
  # The index will be named after the table and the first column name,
@@ -339,6 +338,14 @@ module ActiveRecord
339
338
  # CREATE INDEX by_name_surname ON accounts(name(10), surname(15))
340
339
  #
341
340
  # Note: SQLite doesn't support index length
341
+ #
342
+ # ====== Creating an index with a sort order (desc or asc, asc is the default)
343
+ # add_index(:accounts, [:branch_id, :party_id, :surname], :order => {:branch_id => :desc, :part_id => :asc})
344
+ # generates
345
+ # CREATE INDEX by_branch_desc_party ON accounts(branch_id DESC, party_id ASC, surname)
346
+ #
347
+ # Note: mysql doesn't yet support index order (it accepts the syntax but ignores it)
348
+ #
342
349
  def add_index(table_name, column_name, options = {})
343
350
  index_name, index_type, index_columns = add_index_options(table_name, column_name, options)
344
351
  execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns})"
@@ -405,7 +412,7 @@ module ActiveRecord
405
412
 
406
413
  def dump_schema_information #:nodoc:
407
414
  sm_table = ActiveRecord::Migrator.schema_migrations_table_name
408
- migrated = select_values("SELECT version FROM #{sm_table}")
415
+ migrated = select_values("SELECT version FROM #{sm_table} ORDER BY version")
409
416
  migrated.map { |v| "INSERT INTO #{sm_table} (version) VALUES ('#{v}');" }.join("\n\n")
410
417
  end
411
418
 
@@ -426,6 +433,7 @@ module ActiveRecord
426
433
  si_table = Base.table_name_prefix + 'schema_info' + Base.table_name_suffix
427
434
 
428
435
  if table_exists?(si_table)
436
+ ActiveRecord::Deprecation.warn "Usage of the schema table `#{si_table}` is deprecated. Please switch to using `schema_migrations` table"
429
437
 
430
438
  old_version = select_value("SELECT version FROM #{quote_table_name(si_table)}").to_i
431
439
  assume_migrated_upto_version(old_version)
@@ -507,8 +515,8 @@ module ActiveRecord
507
515
  # ===== Examples
508
516
  # add_timestamps(:suppliers)
509
517
  def add_timestamps(table_name)
510
- add_column table_name, :created_at, :datetime
511
- add_column table_name, :updated_at, :datetime
518
+ add_column table_name, :created_at, :datetime, :null => false
519
+ add_column table_name, :updated_at, :datetime, :null => false
512
520
  end
513
521
 
514
522
  # Removes the timestamp columns (created_at and updated_at) from the table definition.
@@ -520,9 +528,29 @@ module ActiveRecord
520
528
  end
521
529
 
522
530
  protected
531
+ def add_index_sort_order(option_strings, column_names, options = {})
532
+ if options.is_a?(Hash) && order = options[:order]
533
+ case order
534
+ when Hash
535
+ column_names.each {|name| option_strings[name] += " #{order[name].to_s.upcase}" if order.has_key?(name)}
536
+ when String
537
+ column_names.each {|name| option_strings[name] += " #{order.upcase}"}
538
+ end
539
+ end
540
+
541
+ return option_strings
542
+ end
543
+
523
544
  # Overridden by the mysql adapter for supporting index lengths
524
545
  def quoted_columns_for_index(column_names, options = {})
525
- column_names.map {|name| quote_column_name(name) }
546
+ option_strings = Hash[column_names.map {|name| [name, '']}]
547
+
548
+ # add index sort order if supported
549
+ if supports_index_sort_order?
550
+ option_strings = add_index_sort_order(option_strings, column_names, options)
551
+ end
552
+
553
+ column_names.map {|name| quote_column_name(name) + option_strings[name]}
526
554
  end
527
555
 
528
556
  def options_include_default?(options)
@@ -564,7 +592,7 @@ module ActiveRecord
564
592
  def columns_for_remove(table_name, *column_names)
565
593
  column_names = column_names.flatten
566
594
 
567
- raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.blank?
595
+ raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.blank?
568
596
  column_names.map {|column_name| quote_column_name(column_name) }
569
597
  end
570
598
 
@@ -3,21 +3,34 @@ require 'bigdecimal'
3
3
  require 'bigdecimal/util'
4
4
  require 'active_support/core_ext/benchmark'
5
5
  require 'active_support/deprecation'
6
-
7
- # TODO: Autoload these files
8
- require 'active_record/connection_adapters/column'
9
- require 'active_record/connection_adapters/abstract/schema_definitions'
10
- require 'active_record/connection_adapters/abstract/schema_statements'
11
- require 'active_record/connection_adapters/abstract/database_statements'
12
- require 'active_record/connection_adapters/abstract/quoting'
13
- require 'active_record/connection_adapters/abstract/connection_pool'
14
- require 'active_record/connection_adapters/abstract/connection_specification'
15
- require 'active_record/connection_adapters/abstract/query_cache'
16
- require 'active_record/connection_adapters/abstract/database_limits'
17
- require 'active_record/result'
6
+ require 'active_record/connection_adapters/schema_cache'
7
+ require 'monitor'
18
8
 
19
9
  module ActiveRecord
20
10
  module ConnectionAdapters # :nodoc:
11
+ extend ActiveSupport::Autoload
12
+
13
+ autoload :Column
14
+
15
+ autoload_under 'abstract' do
16
+ autoload :IndexDefinition, 'active_record/connection_adapters/abstract/schema_definitions'
17
+ autoload :ColumnDefinition, 'active_record/connection_adapters/abstract/schema_definitions'
18
+ autoload :TableDefinition, 'active_record/connection_adapters/abstract/schema_definitions'
19
+ autoload :Table, 'active_record/connection_adapters/abstract/schema_definitions'
20
+
21
+ autoload :SchemaStatements
22
+ autoload :DatabaseStatements
23
+ autoload :DatabaseLimits
24
+ autoload :Quoting
25
+
26
+ autoload :ConnectionPool
27
+ autoload :ConnectionHandler, 'active_record/connection_adapters/abstract/connection_pool'
28
+ autoload :ConnectionManagement, 'active_record/connection_adapters/abstract/connection_pool'
29
+ autoload :ConnectionSpecification
30
+
31
+ autoload :QueryCache
32
+ end
33
+
21
34
  # Active Record supports multiple database systems. AbstractAdapter and
22
35
  # related classes form the abstraction layer which makes this possible.
23
36
  # An AbstractAdapter represents a connection to a database, and provides an
@@ -36,39 +49,44 @@ module ActiveRecord
36
49
  include DatabaseLimits
37
50
  include QueryCache
38
51
  include ActiveSupport::Callbacks
52
+ include MonitorMixin
39
53
 
40
54
  define_callbacks :checkout, :checkin
41
55
 
42
- attr_accessor :visitor
43
- attr_reader :logger
44
-
45
- def initialize(connection, logger = nil) #:nodoc:
46
- @active = nil
47
- @connection, @logger = connection, logger
56
+ attr_accessor :visitor, :pool
57
+ attr_reader :schema_cache, :last_use, :in_use
58
+ alias :in_use? :in_use
59
+
60
+ def initialize(connection, logger = nil, pool = nil) #:nodoc:
61
+ super()
62
+
63
+ @active = nil
64
+ @connection = connection
65
+ @in_use = false
66
+ @instrumenter = ActiveSupport::Notifications.instrumenter
67
+ @last_use = false
68
+ @logger = logger
69
+ @open_transactions = 0
70
+ @pool = pool
71
+ @query_cache = Hash.new { |h,sql| h[sql] = {} }
48
72
  @query_cache_enabled = false
49
- @query_cache = Hash.new { |h,sql| h[sql] = {} }
50
- @instrumenter = ActiveSupport::Notifications.instrumenter
51
- @visitor = nil
52
- end
53
-
54
- # Returns a visitor instance for this adaptor, which conforms to the Arel::ToSql interface
55
- def self.visitor_for(pool) # :nodoc:
56
- adapter = pool.spec.config[:adapter]
57
-
58
- if Arel::Visitors::VISITORS[adapter]
59
- ActiveSupport::Deprecation.warn(
60
- "Arel::Visitors::VISITORS is deprecated and will be removed. Database adapters " \
61
- "should define a visitor_for method which returns the appropriate visitor for " \
62
- "the database. For example, MysqlAdapter.visitor_for(pool) returns " \
63
- "Arel::Visitors::MySQL.new(pool)."
64
- )
65
-
66
- Arel::Visitors::VISITORS[adapter].new(pool)
67
- else
68
- Arel::Visitors::ToSql.new(pool)
73
+ @schema_cache = SchemaCache.new self
74
+ @visitor = nil
75
+ end
76
+
77
+ def lease
78
+ synchronize do
79
+ unless in_use
80
+ @in_use = true
81
+ @last_use = Time.now
82
+ end
69
83
  end
70
84
  end
71
85
 
86
+ def expire
87
+ @in_use = false
88
+ end
89
+
72
90
  # Returns the human-readable name of the adapter. Use mixed case - one
73
91
  # can always use downcase if needed.
74
92
  def adapter_name
@@ -119,6 +137,17 @@ module ActiveRecord
119
137
  false
120
138
  end
121
139
 
140
+ # Does this adapter support index sort order?
141
+ def supports_index_sort_order?
142
+ false
143
+ end
144
+
145
+ # Does this adapter support explain? As of this writing sqlite3,
146
+ # mysql2, and postgresql are the only ones that do.
147
+ def supports_explain?
148
+ false
149
+ end
150
+
122
151
  # QUOTING ==================================================
123
152
 
124
153
  # Override to return the quoted table name. Defaults to column quoting.
@@ -129,7 +158,7 @@ module ActiveRecord
129
158
  # Returns a bind substitution value given a +column+ and list of current
130
159
  # +binds+
131
160
  def substitute_at(column, index)
132
- Arel::Nodes::BindParam.new '?'
161
+ Arel.sql '?'
133
162
  end
134
163
 
135
164
  # REFERENTIAL INTEGRITY ====================================
@@ -200,12 +229,9 @@ module ActiveRecord
200
229
  @connection
201
230
  end
202
231
 
203
- def open_transactions
204
- @open_transactions ||= 0
205
- end
232
+ attr_reader :open_transactions
206
233
 
207
234
  def increment_open_transactions
208
- @open_transactions ||= 0
209
235
  @open_transactions += 1
210
236
  end
211
237
 
@@ -230,10 +256,19 @@ module ActiveRecord
230
256
  node
231
257
  end
232
258
 
259
+ def case_insensitive_comparison(table, attribute, column, value)
260
+ table[attribute].lower.eq(table.lower(value))
261
+ end
262
+
233
263
  def current_savepoint_name
234
264
  "active_record_#{open_transactions}"
235
265
  end
236
266
 
267
+ # Check the connection back in to the connection pool
268
+ def close
269
+ pool.checkin self
270
+ end
271
+
237
272
  protected
238
273
 
239
274
  def log(sql, name = "SQL", binds = [])