activerecord 4.0.0 → 4.0.1

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +326 -3
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/association_relation.rb +18 -0
  5. data/lib/active_record/associations/association.rb +11 -3
  6. data/lib/active_record/associations/builder/belongs_to.rb +4 -2
  7. data/lib/active_record/associations/collection_association.rb +8 -8
  8. data/lib/active_record/associations/collection_proxy.rb +2 -4
  9. data/lib/active_record/associations/has_many_association.rb +2 -2
  10. data/lib/active_record/associations/has_one_association.rb +3 -1
  11. data/lib/active_record/associations/join_dependency/join_association.rb +2 -0
  12. data/lib/active_record/associations/join_dependency/join_part.rb +14 -1
  13. data/lib/active_record/associations/preloader.rb +3 -2
  14. data/lib/active_record/attribute_methods/read.rb +15 -9
  15. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
  16. data/lib/active_record/attribute_methods/write.rb +2 -0
  17. data/lib/active_record/attribute_methods.rb +26 -2
  18. data/lib/active_record/autosave_association.rb +8 -8
  19. data/lib/active_record/callbacks.rb +4 -1
  20. data/lib/active_record/connection_adapters/abstract/database_statements.rb +7 -7
  21. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +12 -3
  22. data/lib/active_record/connection_adapters/abstract_adapter.rb +16 -2
  23. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +3 -1
  24. data/lib/active_record/connection_adapters/column.rb +12 -11
  25. data/lib/active_record/connection_adapters/mysql2_adapter.rb +9 -3
  26. data/lib/active_record/connection_adapters/mysql_adapter.rb +19 -9
  27. data/lib/active_record/connection_adapters/postgresql/cast.rb +1 -1
  28. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +7 -6
  29. data/lib/active_record/connection_adapters/postgresql/oid.rb +5 -0
  30. data/lib/active_record/connection_adapters/postgresql/quoting.rb +2 -0
  31. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +7 -10
  32. data/lib/active_record/connection_adapters/postgresql_adapter.rb +19 -13
  33. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +8 -5
  34. data/lib/active_record/core.rb +18 -18
  35. data/lib/active_record/dynamic_matchers.rb +1 -1
  36. data/lib/active_record/fixtures.rb +2 -2
  37. data/lib/active_record/locking/optimistic.rb +1 -1
  38. data/lib/active_record/migration/command_recorder.rb +4 -1
  39. data/lib/active_record/migration.rb +1 -1
  40. data/lib/active_record/model_schema.rb +27 -17
  41. data/lib/active_record/null_relation.rb +1 -5
  42. data/lib/active_record/persistence.rb +16 -5
  43. data/lib/active_record/railtie.rb +1 -0
  44. data/lib/active_record/railties/databases.rake +4 -1
  45. data/lib/active_record/reflection.rb +1 -1
  46. data/lib/active_record/relation/batches.rb +2 -2
  47. data/lib/active_record/relation/calculations.rb +1 -0
  48. data/lib/active_record/relation/finder_methods.rb +10 -10
  49. data/lib/active_record/relation/merger.rb +31 -28
  50. data/lib/active_record/relation/query_methods.rb +20 -11
  51. data/lib/active_record/relation.rb +1 -1
  52. data/lib/active_record/result.rb +15 -1
  53. data/lib/active_record/sanitization.rb +13 -3
  54. data/lib/active_record/schema_dumper.rb +5 -1
  55. data/lib/active_record/tasks/database_tasks.rb +2 -1
  56. data/lib/active_record/tasks/sqlite_database_tasks.rb +1 -1
  57. data/lib/active_record/transactions.rb +5 -5
  58. data/lib/active_record/validations/uniqueness.rb +2 -2
  59. data/lib/active_record/version.rb +1 -1
  60. data/lib/active_record.rb +1 -0
  61. metadata +8 -7
@@ -1,4 +1,5 @@
1
1
  require 'active_support/core_ext/enumerable'
2
+ require 'mutex_m'
2
3
 
3
4
  module ActiveRecord
4
5
  # = Active Record Attribute Methods
@@ -7,6 +8,7 @@ module ActiveRecord
7
8
  include ActiveModel::AttributeMethods
8
9
 
9
10
  included do
11
+ initialize_generated_modules
10
12
  include Read
11
13
  include Write
12
14
  include BeforeTypeCast
@@ -18,12 +20,34 @@ module ActiveRecord
18
20
  end
19
21
 
20
22
  module ClassMethods
23
+ def inherited(child_class) #:nodoc:
24
+ child_class.initialize_generated_modules
25
+ super
26
+ end
27
+
28
+ def initialize_generated_modules # :nodoc:
29
+ @generated_attribute_methods = Module.new {
30
+ extend Mutex_m
31
+
32
+ const_set :AttrNames, Module.new {
33
+ def self.set_name_cache(name, value)
34
+ const_name = "ATTR_#{name}"
35
+ unless const_defined? const_name
36
+ const_set const_name, value.dup.freeze
37
+ end
38
+ end
39
+ }
40
+ }
41
+ @attribute_methods_generated = false
42
+ include @generated_attribute_methods
43
+ end
44
+
21
45
  # Generates all the attribute related methods for columns in the database
22
46
  # accessors, mutators and query methods.
23
47
  def define_attribute_methods # :nodoc:
24
48
  # Use a mutex; we don't want two thread simultaneously trying to define
25
49
  # attribute methods.
26
- @attribute_methods_mutex.synchronize do
50
+ generated_attribute_methods.synchronize do
27
51
  return if attribute_methods_generated?
28
52
  superclass.define_attribute_methods unless self == base_class
29
53
  super(column_names)
@@ -32,7 +56,7 @@ module ActiveRecord
32
56
  end
33
57
 
34
58
  def attribute_methods_generated? # :nodoc:
35
- @attribute_methods_generated ||= false
59
+ @attribute_methods_generated
36
60
  end
37
61
 
38
62
  def undefine_attribute_methods # :nodoc:
@@ -335,15 +335,19 @@ module ActiveRecord
335
335
  autosave = reflection.options[:autosave]
336
336
 
337
337
  if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
338
- records_to_destroy = []
338
+
339
+ if autosave
340
+ records_to_destroy = records.select(&:marked_for_destruction?)
341
+ records_to_destroy.each { |record| association.destroy(record) }
342
+ records -= records_to_destroy
343
+ end
344
+
339
345
  records.each do |record|
340
346
  next if record.destroyed?
341
347
 
342
348
  saved = true
343
349
 
344
- if autosave && record.marked_for_destruction?
345
- records_to_destroy << record
346
- elsif autosave != false && (@new_record_before_save || record.new_record?)
350
+ if autosave != false && (@new_record_before_save || record.new_record?)
347
351
  if autosave
348
352
  saved = association.insert_record(record, false)
349
353
  else
@@ -355,10 +359,6 @@ module ActiveRecord
355
359
 
356
360
  raise ActiveRecord::Rollback unless saved
357
361
  end
358
-
359
- records_to_destroy.each do |record|
360
- association.destroy(record)
361
- end
362
362
  end
363
363
 
364
364
  # reconstruct the scope now that we know the owner's id
@@ -23,11 +23,14 @@ module ActiveRecord
23
23
  # Check out <tt>ActiveRecord::Transactions</tt> for more details about <tt>after_commit</tt> and
24
24
  # <tt>after_rollback</tt>.
25
25
  #
26
+ # Additionally, an <tt>after_touch</tt> callback is triggered whenever an
27
+ # object is touched.
28
+ #
26
29
  # Lastly an <tt>after_find</tt> and <tt>after_initialize</tt> callback is triggered for each object that
27
30
  # is found and instantiated by a finder, with <tt>after_initialize</tt> being triggered after new objects
28
31
  # are instantiated as well.
29
32
  #
30
- # That's a total of twelve callbacks, which gives you immense power to react and prepare for each state in the
33
+ # There are nineteen callbacks in total, which give you immense power to react and prepare for each state in the
31
34
  # Active Record life cycle. The sequence for calling <tt>Base#save</tt> for an existing record is similar,
32
35
  # except that each <tt>_create</tt> callback is replaced by the corresponding <tt>_update</tt> callback.
33
36
  #
@@ -377,14 +377,14 @@ module ActiveRecord
377
377
  update_sql(sql, name)
378
378
  end
379
379
 
380
- def sql_for_insert(sql, pk, id_value, sequence_name, binds)
381
- [sql, binds]
382
- end
380
+ def sql_for_insert(sql, pk, id_value, sequence_name, binds)
381
+ [sql, binds]
382
+ end
383
383
 
384
- def last_inserted_id(result)
385
- row = result.rows.first
386
- row && row.first
387
- end
384
+ def last_inserted_id(result)
385
+ row = result.rows.first
386
+ row && row.first
387
+ end
388
388
  end
389
389
  end
390
390
  end
@@ -706,12 +706,21 @@ module ActiveRecord
706
706
  end
707
707
 
708
708
  # SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
709
- # Both PostgreSQL and Oracle overrides this for custom DISTINCT syntax.
710
709
  #
711
- # distinct("posts.id", "posts.created_at desc")
710
+ # distinct("posts.id", ["posts.created_at desc"])
712
711
  #
713
712
  def distinct(columns, order_by)
714
- "DISTINCT #{columns}"
713
+ ActiveSupport::Deprecation.warn("#distinct is deprecated and shall be removed from future releases.")
714
+ "DISTINCT #{columns_for_distinct(columns, order_by)}"
715
+ end
716
+
717
+ # Given a set of columns and an ORDER BY clause, returns the columns for a SELECT DISTINCT.
718
+ # Both PostgreSQL and Oracle overrides this for custom DISTINCT syntax - they
719
+ # require the order columns appear in the SELECT.
720
+ #
721
+ # columns_for_distinct("posts.id", ["posts.created_at desc"])
722
+ def columns_for_distinct(columns, orders) # :nodoc:
723
+ columns
715
724
  end
716
725
 
717
726
  # Adds timestamps (+created_at+ and +updated_at+) columns to the named table.
@@ -99,6 +99,7 @@ module ActiveRecord
99
99
  @query_cache_enabled = false
100
100
  @schema_cache = SchemaCache.new self
101
101
  @visitor = nil
102
+ @prepared_statements = false
102
103
  end
103
104
 
104
105
  def valid_type?(type)
@@ -197,10 +198,11 @@ module ActiveRecord
197
198
  end
198
199
 
199
200
  def unprepared_statement
200
- old, @visitor = @visitor, unprepared_visitor
201
+ old_prepared_statements, @prepared_statements = @prepared_statements, false
202
+ old_visitor, @visitor = @visitor, unprepared_visitor
201
203
  yield
202
204
  ensure
203
- @visitor = old
205
+ @visitor, @prepared_statements = old_visitor, old_prepared_statements
204
206
  end
205
207
 
206
208
  # Returns the human-readable name of the adapter. Use mixed case - one
@@ -280,6 +282,14 @@ module ActiveRecord
280
282
  false
281
283
  end
282
284
 
285
+ # This is meant to be implemented by the adapters that support extensions
286
+ def disable_extension(name)
287
+ end
288
+
289
+ # This is meant to be implemented by the adapters that support extensions
290
+ def enable_extension(name)
291
+ end
292
+
283
293
  # A list of extensions, to be filled in by adapters that support them. At
284
294
  # the moment only postgresql does.
285
295
  def extensions
@@ -435,6 +445,10 @@ module ActiveRecord
435
445
  # override in derived class
436
446
  ActiveRecord::StatementInvalid.new(message, exception)
437
447
  end
448
+
449
+ def without_prepared_statement?(binds)
450
+ !@prepared_statements || binds.empty?
451
+ end
438
452
  end
439
453
  end
440
454
  end
@@ -165,6 +165,7 @@ module ActiveRecord
165
165
  @quoted_column_names, @quoted_table_names = {}, {}
166
166
 
167
167
  if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
168
+ @prepared_statements = true
168
169
  @visitor = Arel::Visitors::MySQL.new self
169
170
  else
170
171
  @visitor = unprepared_visitor
@@ -460,7 +461,8 @@ module ActiveRecord
460
461
  sql = "SHOW FULL FIELDS FROM #{quote_table_name(table_name)}"
461
462
  execute_and_free(sql, 'SCHEMA') do |result|
462
463
  each_hash(result).map do |field|
463
- new_column(field[:Field], field[:Default], field[:Type], field[:Null] == "YES", field[:Collation], field[:Extra])
464
+ field_name = set_field_encoding(field[:Field])
465
+ new_column(field_name, field[:Default], field[:Type], field[:Null] == "YES", field[:Collation], field[:Extra])
464
466
  end
465
467
  end
466
468
  end
@@ -13,7 +13,7 @@ module ActiveRecord
13
13
  ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/
14
14
  end
15
15
 
16
- attr_reader :name, :default, :type, :limit, :null, :sql_type, :precision, :scale
16
+ attr_reader :name, :default, :type, :limit, :null, :sql_type, :precision, :scale, :default_function
17
17
  attr_accessor :primary, :coder
18
18
 
19
19
  alias :encoded? :coder
@@ -27,16 +27,17 @@ module ActiveRecord
27
27
  # It will be mapped to one of the standard Rails SQL types in the <tt>type</tt> attribute.
28
28
  # +null+ determines if this column allows +NULL+ values.
29
29
  def initialize(name, default, sql_type = nil, null = true)
30
- @name = name
31
- @sql_type = sql_type
32
- @null = null
33
- @limit = extract_limit(sql_type)
34
- @precision = extract_precision(sql_type)
35
- @scale = extract_scale(sql_type)
36
- @type = simplified_type(sql_type)
37
- @default = extract_default(default)
38
- @primary = nil
39
- @coder = nil
30
+ @name = name
31
+ @sql_type = sql_type
32
+ @null = null
33
+ @limit = extract_limit(sql_type)
34
+ @precision = extract_precision(sql_type)
35
+ @scale = extract_scale(sql_type)
36
+ @type = simplified_type(sql_type)
37
+ @default = extract_default(default)
38
+ @default_function = nil
39
+ @primary = nil
40
+ @coder = nil
40
41
  end
41
42
 
42
43
  # Returns +true+ if the column is either of type string or text.
@@ -213,9 +213,11 @@ module ActiveRecord
213
213
 
214
214
  # Executes the SQL statement in the context of this connection.
215
215
  def execute(sql, name = nil)
216
- # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
217
- # made since we established the connection
218
- @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
216
+ if @connection
217
+ # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
218
+ # made since we established the connection
219
+ @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
220
+ end
219
221
 
220
222
  super
221
223
  end
@@ -268,6 +270,10 @@ module ActiveRecord
268
270
  def version
269
271
  @version ||= @connection.info[:version].scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i }
270
272
  end
273
+
274
+ def set_field_encoding field_name
275
+ field_name
276
+ end
271
277
  end
272
278
  end
273
279
  end
@@ -279,11 +279,7 @@ module ActiveRecord
279
279
  end
280
280
 
281
281
  def exec_query(sql, name = 'SQL', binds = [])
282
- # If the configuration sets prepared_statements:false, binds will
283
- # always be empty, since the bind variables will have been already
284
- # substituted and removed from binds by BindVisitor, so this will
285
- # effectively disable prepared statement usage completely.
286
- if binds.empty?
282
+ if without_prepared_statement?(binds)
287
283
  result_set, affected_rows = exec_without_stmt(sql, name)
288
284
  else
289
285
  result_set, affected_rows = exec_stmt(sql, name, binds)
@@ -393,6 +389,14 @@ module ActiveRecord
393
389
  TYPES[new] = TYPES[old]
394
390
  end
395
391
 
392
+ def self.find_type(field)
393
+ if field.type == Mysql::Field::TYPE_TINY && field.length > 1
394
+ TYPES[Mysql::Field::TYPE_LONG]
395
+ else
396
+ TYPES.fetch(field.type) { Fields::Identity.new }
397
+ end
398
+ end
399
+
396
400
  register_type Mysql::Field::TYPE_TINY, Fields::Boolean.new
397
401
  register_type Mysql::Field::TYPE_LONG, Fields::Integer.new
398
402
  alias_type Mysql::Field::TYPE_LONGLONG, Mysql::Field::TYPE_LONG
@@ -425,9 +429,7 @@ module ActiveRecord
425
429
  if field.decimals > 0
426
430
  types[field.name] = Fields::Decimal.new
427
431
  else
428
- types[field.name] = Fields::TYPES.fetch(field.type) {
429
- Fields::Identity.new
430
- }
432
+ types[field.name] = Fields.find_type field
431
433
  end
432
434
  }
433
435
  result_set = ActiveRecord::Result.new(types.keys, result.to_a, types)
@@ -501,12 +503,12 @@ module ActiveRecord
501
503
  cols = cache[:cols] ||= metadata.fetch_fields.map { |field|
502
504
  field.name
503
505
  }
506
+ metadata.free
504
507
  end
505
508
 
506
509
  result_set = ActiveRecord::Result.new(cols, stmt.to_a) if cols
507
510
  affected_rows = stmt.affected_rows
508
511
 
509
- stmt.result_metadata.free if cols
510
512
  stmt.free_result
511
513
  stmt.close if binds.empty?
512
514
 
@@ -553,6 +555,14 @@ module ActiveRecord
553
555
  def version
554
556
  @version ||= @connection.server_info.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i }
555
557
  end
558
+
559
+ def set_field_encoding field_name
560
+ field_name.force_encoding(client_encoding)
561
+ if internal_enc = Encoding.default_internal
562
+ field_name = field_name.encode!(internal_enc)
563
+ end
564
+ field_name
565
+ end
556
566
  end
557
567
  end
558
568
  end
@@ -60,7 +60,7 @@ module ActiveRecord
60
60
  end
61
61
 
62
62
  def json_to_string(object)
63
- if Hash === object
63
+ if Hash === object || Array === object
64
64
  ActiveSupport::JSON.encode(object)
65
65
  else
66
66
  object
@@ -135,11 +135,12 @@ module ActiveRecord
135
135
 
136
136
  def exec_query(sql, name = 'SQL', binds = [])
137
137
  log(sql, name, binds) do
138
- result = binds.empty? ? exec_no_cache(sql, binds) :
139
- exec_cache(sql, binds)
138
+ result = without_prepared_statement?(binds) ? exec_no_cache(sql, binds) :
139
+ exec_cache(sql, binds)
140
140
 
141
141
  types = {}
142
- result.fields.each_with_index do |fname, i|
142
+ fields = result.fields
143
+ fields.each_with_index do |fname, i|
143
144
  ftype = result.ftype i
144
145
  fmod = result.fmod i
145
146
  types[fname] = OID::TYPE_MAP.fetch(ftype, fmod) { |oid, mod|
@@ -148,7 +149,7 @@ module ActiveRecord
148
149
  }
149
150
  end
150
151
 
151
- ret = ActiveRecord::Result.new(result.fields, result.values, types)
152
+ ret = ActiveRecord::Result.new(fields, result.values, types)
152
153
  result.clear
153
154
  return ret
154
155
  end
@@ -156,8 +157,8 @@ module ActiveRecord
156
157
 
157
158
  def exec_delete(sql, name = 'SQL', binds = [])
158
159
  log(sql, name, binds) do
159
- result = binds.empty? ? exec_no_cache(sql, binds) :
160
- exec_cache(sql, binds)
160
+ result = without_prepared_statement?(binds) ? exec_no_cache(sql, binds) :
161
+ exec_cache(sql, binds)
161
162
  affected = result.cmd_tuples
162
163
  result.clear
163
164
  affected
@@ -38,12 +38,17 @@ module ActiveRecord
38
38
  class Money < Type
39
39
  def type_cast(value)
40
40
  return if value.nil?
41
+ return value unless String === value
41
42
 
42
43
  # Because money output is formatted according to the locale, there are two
43
44
  # cases to consider (note the decimal separators):
44
45
  # (1) $12,345,678.12
45
46
  # (2) $12.345.678,12
47
+ # Negative values are represented as follows:
48
+ # (3) -$2.55
49
+ # (4) ($2.55)
46
50
 
51
+ value.sub!(/^\((.+)\)$/, '-\1') # (4)
47
52
  case value
48
53
  when /^-?\D+[\d,]+\.\d{2}$/ # (1)
49
54
  value.gsub!(/[^-\d.]/, '')
@@ -30,6 +30,7 @@ module ActiveRecord
30
30
  when Array
31
31
  case sql_type
32
32
  when 'point' then super(PostgreSQLColumn.point_to_string(value))
33
+ when 'json' then super(PostgreSQLColumn.json_to_string(value))
33
34
  else
34
35
  if column.array
35
36
  "'#{PostgreSQLColumn.array_to_string(value, column, self).gsub(/'/, "''")}'"
@@ -98,6 +99,7 @@ module ActiveRecord
98
99
  when Array
99
100
  case column.sql_type
100
101
  when 'point' then PostgreSQLColumn.point_to_string(value)
102
+ when 'json' then PostgreSQLColumn.json_to_string(value)
101
103
  else
102
104
  return super(value, column) unless column.array
103
105
  PostgreSQLColumn.array_to_string(value, column, self)
@@ -321,6 +321,7 @@ module ActiveRecord
321
321
  result = query(<<-end_sql, 'SCHEMA')[0]
322
322
  SELECT attr.attname,
323
323
  CASE
324
+ WHEN pg_get_expr(def.adbin, def.adrelid) !~* 'nextval' THEN NULL
324
325
  WHEN split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2) ~ '.' THEN
325
326
  substr(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2),
326
327
  strpos(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2), '.')+1)
@@ -332,7 +333,7 @@ module ActiveRecord
332
333
  JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
333
334
  WHERE t.oid = '#{quote_table_name(table)}'::regclass
334
335
  AND cons.contype = 'p'
335
- AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval'
336
+ AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval|uuid_generate'
336
337
  end_sql
337
338
  end
338
339
 
@@ -383,8 +384,9 @@ module ActiveRecord
383
384
  def change_column(table_name, column_name, type, options = {})
384
385
  clear_cache!
385
386
  quoted_table_name = quote_table_name(table_name)
386
-
387
- execute "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(column_name)} TYPE #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
387
+ sql_type = type_to_sql(type, options[:limit], options[:precision], options[:scale])
388
+ sql_type << "[]" if options[:array]
389
+ execute "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(column_name)} TYPE #{sql_type}"
388
390
 
389
391
  change_column_default(table_name, column_name, options[:default]) if options_include_default?(options)
390
392
  change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
@@ -466,14 +468,9 @@ module ActiveRecord
466
468
  end
467
469
  end
468
470
 
469
- # Returns a SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
470
- #
471
471
  # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
472
472
  # requires that the ORDER BY include the distinct column.
473
- #
474
- # distinct("posts.id", ["posts.created_at desc"])
475
- # # => "DISTINCT posts.id, posts.created_at AS alias_0"
476
- def distinct(columns, orders) #:nodoc:
473
+ def columns_for_distinct(columns, orders) #:nodoc:
477
474
  order_columns = orders.map{ |s|
478
475
  # Convert Arel node to string
479
476
  s = s.to_sql unless s.is_a?(String)
@@ -481,7 +478,7 @@ module ActiveRecord
481
478
  s.gsub(/\s+(ASC|DESC)\s*(NULLS\s+(FIRST|LAST)\s*)?/i, '')
482
479
  }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
483
480
 
484
- [super].concat(order_columns).join(', ')
481
+ [super, *order_columns].join(', ')
485
482
  end
486
483
  end
487
484
  end
@@ -49,13 +49,17 @@ module ActiveRecord
49
49
  # Instantiates a new PostgreSQL column definition in a table.
50
50
  def initialize(name, default, oid_type, sql_type = nil, null = true)
51
51
  @oid_type = oid_type
52
+ default_value = self.class.extract_value_from_default(default)
53
+
52
54
  if sql_type =~ /\[\]$/
53
55
  @array = true
54
- super(name, self.class.extract_value_from_default(default), sql_type[0..sql_type.length - 3], null)
56
+ super(name, default_value, sql_type[0..sql_type.length - 3], null)
55
57
  else
56
58
  @array = false
57
- super(name, self.class.extract_value_from_default(default), sql_type, null)
59
+ super(name, default_value, sql_type, null)
58
60
  end
61
+
62
+ @default_function = default if has_default_function?(default_value, default)
59
63
  end
60
64
 
61
65
  # :stopdoc:
@@ -138,6 +142,10 @@ module ActiveRecord
138
142
 
139
143
  private
140
144
 
145
+ def has_default_function?(default_value, default)
146
+ !default_value && (%r{\w+\(.*\)} === default)
147
+ end
148
+
141
149
  def extract_limit(sql_type)
142
150
  case sql_type
143
151
  when /^bigint/i; 8
@@ -374,15 +382,11 @@ module ActiveRecord
374
382
  self
375
383
  end
376
384
 
377
- def xml(options = {})
378
- column(args[0], :text, options)
379
- end
380
-
381
385
  private
382
386
 
383
- def create_column_definition(name, type)
384
- ColumnDefinition.new name, type
385
- end
387
+ def create_column_definition(name, type)
388
+ ColumnDefinition.new name, type
389
+ end
386
390
  end
387
391
 
388
392
  class Table < ActiveRecord::ConnectionAdapters::Table
@@ -436,6 +440,7 @@ module ActiveRecord
436
440
  def prepare_column_options(column, types)
437
441
  spec = super
438
442
  spec[:array] = 'true' if column.respond_to?(:array) && column.array
443
+ spec[:default] = "\"#{column.default_function}\"" if column.default_function
439
444
  spec
440
445
  end
441
446
 
@@ -528,6 +533,7 @@ module ActiveRecord
528
533
  super(connection, logger)
529
534
 
530
535
  if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
536
+ @prepared_statements = true
531
537
  @visitor = Arel::Visitors::PostgreSQL.new self
532
538
  else
533
539
  @visitor = unprepared_visitor
@@ -623,9 +629,9 @@ module ActiveRecord
623
629
  true
624
630
  end
625
631
 
626
- # Returns true if pg > 9.2
632
+ # Returns true if pg > 9.1
627
633
  def supports_extensions?
628
- postgresql_version >= 90200
634
+ postgresql_version >= 90100
629
635
  end
630
636
 
631
637
  # Range datatypes weren't introduced until PostgreSQL 9.2
@@ -647,9 +653,9 @@ module ActiveRecord
647
653
 
648
654
  def extension_enabled?(name)
649
655
  if supports_extensions?
650
- res = exec_query "SELECT EXISTS(SELECT * FROM pg_available_extensions WHERE name = '#{name}' AND installed_version IS NOT NULL)",
656
+ res = exec_query "SELECT EXISTS(SELECT * FROM pg_available_extensions WHERE name = '#{name}' AND installed_version IS NOT NULL) as enabled",
651
657
  'SCHEMA'
652
- res.column_types['exists'].type_cast res.rows.first.first
658
+ res.column_types['enabled'].type_cast res.rows.first.first
653
659
  end
654
660
  end
655
661
 
@@ -17,12 +17,14 @@ module ActiveRecord
17
17
  # Allow database path relative to Rails.root, but only if
18
18
  # the database path is not the special path that tells
19
19
  # Sqlite to build a database only in memory.
20
- if defined?(Rails.root) && ':memory:' != config[:database]
21
- config[:database] = File.expand_path(config[:database], Rails.root)
20
+ if ':memory:' != config[:database]
21
+ config[:database] = File.expand_path(config[:database], Rails.root) if defined?(Rails.root)
22
+ dirname = File.dirname(config[:database])
23
+ Dir.mkdir(dirname) unless File.directory?(dirname)
22
24
  end
23
25
 
24
26
  db = SQLite3::Database.new(
25
- config[:database],
27
+ config[:database].to_s,
26
28
  :results_as_hash => true
27
29
  )
28
30
 
@@ -111,6 +113,7 @@ module ActiveRecord
111
113
  @config = config
112
114
 
113
115
  if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
116
+ @prepared_statements = true
114
117
  @visitor = Arel::Visitors::SQLite.new self
115
118
  else
116
119
  @visitor = unprepared_visitor
@@ -291,8 +294,8 @@ module ActiveRecord
291
294
  def exec_query(sql, name = nil, binds = [])
292
295
  log(sql, name, binds) do
293
296
 
294
- # Don't cache statements without bind values
295
- if binds.empty?
297
+ # Don't cache statements if they are not prepared
298
+ if without_prepared_statement?(binds)
296
299
  stmt = @connection.prepare(sql)
297
300
  cols = stmt.columns
298
301
  records = stmt.to_a