activerecord 4.0.13 → 4.1.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.

Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +745 -2700
  3. data/README.rdoc +2 -2
  4. data/examples/performance.rb +30 -18
  5. data/examples/simple.rb +4 -4
  6. data/lib/active_record.rb +2 -6
  7. data/lib/active_record/aggregations.rb +2 -1
  8. data/lib/active_record/association_relation.rb +0 -4
  9. data/lib/active_record/associations.rb +87 -43
  10. data/lib/active_record/associations/alias_tracker.rb +1 -3
  11. data/lib/active_record/associations/association.rb +8 -16
  12. data/lib/active_record/associations/association_scope.rb +5 -16
  13. data/lib/active_record/associations/belongs_to_association.rb +34 -25
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  15. data/lib/active_record/associations/builder/association.rb +78 -54
  16. data/lib/active_record/associations/builder/belongs_to.rb +91 -58
  17. data/lib/active_record/associations/builder/collection_association.rb +47 -45
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +107 -25
  19. data/lib/active_record/associations/builder/has_many.rb +2 -2
  20. data/lib/active_record/associations/builder/has_one.rb +5 -7
  21. data/lib/active_record/associations/builder/singular_association.rb +6 -7
  22. data/lib/active_record/associations/collection_association.rb +68 -105
  23. data/lib/active_record/associations/collection_proxy.rb +12 -15
  24. data/lib/active_record/associations/has_many_association.rb +11 -9
  25. data/lib/active_record/associations/has_many_through_association.rb +16 -12
  26. data/lib/active_record/associations/has_one_association.rb +1 -1
  27. data/lib/active_record/associations/join_dependency.rb +204 -165
  28. data/lib/active_record/associations/join_dependency/join_association.rb +43 -101
  29. data/lib/active_record/associations/join_dependency/join_base.rb +6 -8
  30. data/lib/active_record/associations/join_dependency/join_part.rb +18 -37
  31. data/lib/active_record/associations/join_helper.rb +2 -11
  32. data/lib/active_record/associations/preloader.rb +89 -34
  33. data/lib/active_record/associations/preloader/association.rb +43 -25
  34. data/lib/active_record/associations/preloader/collection_association.rb +2 -2
  35. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +58 -26
  38. data/lib/active_record/associations/singular_association.rb +6 -5
  39. data/lib/active_record/associations/through_association.rb +2 -2
  40. data/lib/active_record/attribute_assignment.rb +5 -2
  41. data/lib/active_record/attribute_methods.rb +45 -40
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
  43. data/lib/active_record/attribute_methods/dirty.rb +8 -22
  44. data/lib/active_record/attribute_methods/primary_key.rb +1 -7
  45. data/lib/active_record/attribute_methods/read.rb +55 -28
  46. data/lib/active_record/attribute_methods/serialization.rb +12 -33
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -13
  48. data/lib/active_record/attribute_methods/write.rb +37 -12
  49. data/lib/active_record/autosave_association.rb +207 -207
  50. data/lib/active_record/base.rb +5 -1
  51. data/lib/active_record/callbacks.rb +2 -2
  52. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +2 -7
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +11 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +12 -14
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -5
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +84 -0
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -8
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +52 -83
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +0 -5
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +14 -97
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +58 -60
  63. data/lib/active_record/connection_adapters/column.rb +1 -35
  64. data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
  65. data/lib/active_record/connection_adapters/mysql2_adapter.rb +3 -4
  66. data/lib/active_record/connection_adapters/mysql_adapter.rb +16 -15
  67. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +24 -18
  68. data/lib/active_record/connection_adapters/postgresql/cast.rb +20 -16
  69. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +23 -43
  70. data/lib/active_record/connection_adapters/postgresql/oid.rb +19 -12
  71. data/lib/active_record/connection_adapters/postgresql/quoting.rb +28 -23
  72. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +8 -30
  73. data/lib/active_record/connection_adapters/postgresql_adapter.rb +92 -75
  74. data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
  75. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +31 -64
  76. data/lib/active_record/connection_handling.rb +2 -2
  77. data/lib/active_record/core.rb +22 -43
  78. data/lib/active_record/counter_cache.rb +7 -7
  79. data/lib/active_record/enum.rb +100 -0
  80. data/lib/active_record/errors.rb +10 -5
  81. data/lib/active_record/fixture_set/file.rb +2 -1
  82. data/lib/active_record/fixtures.rb +171 -74
  83. data/lib/active_record/inheritance.rb +16 -22
  84. data/lib/active_record/integration.rb +52 -1
  85. data/lib/active_record/locking/optimistic.rb +7 -2
  86. data/lib/active_record/locking/pessimistic.rb +1 -1
  87. data/lib/active_record/log_subscriber.rb +5 -12
  88. data/lib/active_record/migration.rb +62 -46
  89. data/lib/active_record/migration/command_recorder.rb +7 -13
  90. data/lib/active_record/model_schema.rb +7 -14
  91. data/lib/active_record/nested_attributes.rb +10 -8
  92. data/lib/active_record/no_touching.rb +52 -0
  93. data/lib/active_record/null_relation.rb +3 -3
  94. data/lib/active_record/persistence.rb +16 -34
  95. data/lib/active_record/querying.rb +14 -12
  96. data/lib/active_record/railtie.rb +0 -50
  97. data/lib/active_record/railties/databases.rake +12 -15
  98. data/lib/active_record/readonly_attributes.rb +0 -6
  99. data/lib/active_record/reflection.rb +189 -75
  100. data/lib/active_record/relation.rb +69 -94
  101. data/lib/active_record/relation/batches.rb +57 -23
  102. data/lib/active_record/relation/calculations.rb +36 -43
  103. data/lib/active_record/relation/delegation.rb +54 -39
  104. data/lib/active_record/relation/finder_methods.rb +107 -62
  105. data/lib/active_record/relation/merger.rb +7 -20
  106. data/lib/active_record/relation/predicate_builder.rb +57 -38
  107. data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
  108. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  109. data/lib/active_record/relation/query_methods.rb +110 -98
  110. data/lib/active_record/relation/spawn_methods.rb +1 -2
  111. data/lib/active_record/result.rb +45 -6
  112. data/lib/active_record/runtime_registry.rb +5 -0
  113. data/lib/active_record/sanitization.rb +6 -8
  114. data/lib/active_record/schema_dumper.rb +16 -5
  115. data/lib/active_record/schema_migration.rb +24 -25
  116. data/lib/active_record/scoping/default.rb +5 -18
  117. data/lib/active_record/scoping/named.rb +8 -29
  118. data/lib/active_record/store.rb +56 -28
  119. data/lib/active_record/tasks/database_tasks.rb +8 -4
  120. data/lib/active_record/timestamp.rb +4 -4
  121. data/lib/active_record/transactions.rb +8 -10
  122. data/lib/active_record/validations/presence.rb +1 -1
  123. data/lib/active_record/validations/uniqueness.rb +1 -6
  124. data/lib/active_record/version.rb +1 -1
  125. data/lib/rails/generators/active_record.rb +2 -8
  126. data/lib/rails/generators/active_record/migration.rb +18 -0
  127. data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
  128. data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
  129. metadata +32 -45
  130. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
  131. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  132. data/lib/active_record/tasks/firebird_database_tasks.rb +0 -56
  133. data/lib/active_record/tasks/oracle_database_tasks.rb +0 -45
  134. data/lib/active_record/tasks/sqlserver_database_tasks.rb +0 -48
  135. data/lib/active_record/test_case.rb +0 -102
@@ -16,15 +16,14 @@ module ActiveRecord
16
16
 
17
17
  # Quotes PostgreSQL-specific data types for SQL input.
18
18
  def quote(value, column = nil) #:nodoc:
19
- return super unless column && column.type
19
+ return super unless column
20
20
 
21
21
  sql_type = type_to_sql(column.type, column.limit, column.precision, column.scale)
22
22
 
23
23
  case value
24
24
  when Range
25
25
  if /range$/ =~ sql_type
26
- escaped = quote_string(PostgreSQLColumn.range_to_string(value))
27
- "'#{escaped}'::#{sql_type}"
26
+ "'#{PostgreSQLColumn.range_to_string(value)}'::#{sql_type}"
28
27
  else
29
28
  super
30
29
  end
@@ -71,8 +70,8 @@ module ActiveRecord
71
70
  when 'xml' then "xml '#{quote_string(value)}'"
72
71
  when /^bit/
73
72
  case value
74
- when /\A[01]*\Z/ then "B'#{value}'" # Bit-string notation
75
- when /\A[0-9A-F]*\Z/i then "X'#{value}'" # Hexadecimal notation
73
+ when /^[01]*$/ then "B'#{value}'" # Bit-string notation
74
+ when /^[0-9A-F]*$/i then "X'#{value}'" # Hexadecimal notation
76
75
  end
77
76
  else
78
77
  super
@@ -87,8 +86,11 @@ module ActiveRecord
87
86
 
88
87
  case value
89
88
  when Range
90
- return super(value, column) unless /range$/ =~ column.sql_type
91
- PostgreSQLColumn.range_to_string(value)
89
+ if /range$/ =~ column.sql_type
90
+ PostgreSQLColumn.range_to_string(value)
91
+ else
92
+ super(value, column)
93
+ end
92
94
  when NilClass
93
95
  if column.array && array_member
94
96
  'NULL'
@@ -102,21 +104,33 @@ module ActiveRecord
102
104
  when 'point' then PostgreSQLColumn.point_to_string(value)
103
105
  when 'json' then PostgreSQLColumn.json_to_string(value)
104
106
  else
105
- return super(value, column) unless column.array
106
- PostgreSQLColumn.array_to_string(value, column, self)
107
+ if column.array
108
+ PostgreSQLColumn.array_to_string(value, column, self)
109
+ else
110
+ super(value, column)
111
+ end
107
112
  end
108
113
  when String
109
- return super(value, column) unless 'bytea' == column.sql_type
110
- { :value => value, :format => 1 }
114
+ if 'bytea' == column.sql_type
115
+ # Return a bind param hash with format as binary.
116
+ # See http://deveiate.org/code/pg/PGconn.html#method-i-exec_prepared-doc
117
+ # for more information
118
+ { value: value, format: 1 }
119
+ else
120
+ super(value, column)
121
+ end
111
122
  when Hash
112
123
  case column.sql_type
113
- when 'hstore' then PostgreSQLColumn.hstore_to_string(value, array_member)
124
+ when 'hstore' then PostgreSQLColumn.hstore_to_string(value)
114
125
  when 'json' then PostgreSQLColumn.json_to_string(value)
115
126
  else super(value, column)
116
127
  end
117
128
  when IPAddr
118
- return super(value, column) unless ['inet','cidr'].include? column.sql_type
119
- PostgreSQLColumn.cidr_to_string(value)
129
+ if %w(inet cidr).include? column.sql_type
130
+ PostgreSQLColumn.cidr_to_string(value)
131
+ else
132
+ super(value, column)
133
+ end
120
134
  else
121
135
  super(value, column)
122
136
  end
@@ -168,15 +182,6 @@ module ActiveRecord
168
182
  end
169
183
  result
170
184
  end
171
-
172
- # Does not quote function default values for UUID columns
173
- def quote_default_value(value, column) #:nodoc:
174
- if column.type == :uuid && value =~ /\(\)/
175
- value
176
- else
177
- quote(value, column)
178
- end
179
- end
180
185
  end
181
186
  end
182
187
  end
@@ -46,7 +46,7 @@ module ActiveRecord
46
46
  end
47
47
 
48
48
  # Create a new PostgreSQL database. Options include <tt>:owner</tt>, <tt>:template</tt>,
49
- # <tt>:encoding</tt>, <tt>:collation</tt>, <tt>:ctype</tt>,
49
+ # <tt>:encoding</tt> (defaults to utf8), <tt>:collation</tt>, <tt>:ctype</tt>,
50
50
  # <tt>:tablespace</tt>, and <tt>:connection_limit</tt> (note that MySQL uses
51
51
  # <tt>:charset</tt> while PostgreSQL uses <tt>:encoding</tt>).
52
52
  #
@@ -126,19 +126,6 @@ module ActiveRecord
126
126
  SQL
127
127
  end
128
128
 
129
- def index_name_exists?(table_name, index_name, default)
130
- exec_query(<<-SQL, 'SCHEMA').rows.first[0].to_i > 0
131
- SELECT COUNT(*)
132
- FROM pg_class t
133
- INNER JOIN pg_index d ON t.oid = d.indrelid
134
- INNER JOIN pg_class i ON d.indexrelid = i.oid
135
- WHERE i.relkind = 'i'
136
- AND i.relname = '#{index_name}'
137
- AND t.relname = '#{table_name}'
138
- AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
139
- SQL
140
- end
141
-
142
129
  # Returns an array of indexes for the given table.
143
130
  def indexes(table_name, name = nil)
144
131
  result = query(<<-SQL, 'SCHEMA')
@@ -185,15 +172,13 @@ module ActiveRecord
185
172
  def columns(table_name)
186
173
  # Limit, precision, and scale are all handled by the superclass.
187
174
  column_definitions(table_name).map do |column_name, type, default, notnull, oid, fmod|
188
- oid = get_oid_type(oid.to_i, fmod.to_i, column_name)
175
+ oid = type_map.fetch(oid.to_i, fmod.to_i) {
176
+ OID::Identity.new
177
+ }
189
178
  PostgreSQLColumn.new(column_name, default, oid, type, notnull == 'f')
190
179
  end
191
180
  end
192
181
 
193
- def column_for(table_name, column_name) #:nodoc:
194
- columns(table_name).detect { |c| c.name == column_name.to_s }
195
- end
196
-
197
182
  # Returns the current database name.
198
183
  def current_database
199
184
  query('select current_database()', 'SCHEMA')[0][0]
@@ -382,10 +367,7 @@ module ActiveRecord
382
367
  pk, seq = pk_and_sequence_for(new_name)
383
368
  if seq == "#{table_name}_#{pk}_seq"
384
369
  new_seq = "#{new_name}_#{pk}_seq"
385
- idx = "#{table_name}_pkey"
386
- new_idx = "#{new_name}_pkey"
387
370
  execute "ALTER TABLE #{quote_table_name(seq)} RENAME TO #{quote_table_name(new_seq)}"
388
- execute "ALTER INDEX #{quote_table_name(idx)} RENAME TO #{quote_table_name(new_idx)}"
389
371
  end
390
372
 
391
373
  rename_table_indexes(table_name, new_name)
@@ -413,16 +395,13 @@ module ActiveRecord
413
395
  # Changes the default value of a table column.
414
396
  def change_column_default(table_name, column_name, default)
415
397
  clear_cache!
416
- column = column_for(table_name, column_name)
417
-
418
- execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT #{quote_default_value(default, column)}" if column
398
+ execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT #{quote(default)}"
419
399
  end
420
400
 
421
401
  def change_column_null(table_name, column_name, null, default = nil)
422
402
  clear_cache!
423
403
  unless null || default.nil?
424
- column = column_for(table_name, column_name)
425
- execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote_default_value(default, column)} WHERE #{quote_column_name(column_name)} IS NULL") if column
404
+ execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
426
405
  end
427
406
  execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
428
407
  end
@@ -492,12 +471,11 @@ module ActiveRecord
492
471
  # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
493
472
  # requires that the ORDER BY include the distinct column.
494
473
  def columns_for_distinct(columns, orders) #:nodoc:
495
- order_columns = orders.map{ |s|
474
+ order_columns = orders.reject(&:blank?).map{ |s|
496
475
  # Convert Arel node to string
497
476
  s = s.to_sql unless s.is_a?(String)
498
477
  # Remove any ASC/DESC modifiers
499
- s.gsub(/\s+(?:ASC|DESC)\b/i, '')
500
- .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, '')
478
+ s.gsub(/\s+(ASC|DESC)\s*(NULLS\s+(FIRST|LAST)\s*)?/i, '')
501
479
  }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
502
480
 
503
481
  [super, *order_columns].join(', ')
@@ -20,8 +20,8 @@ module ActiveRecord
20
20
  VALID_CONN_PARAMS = [:host, :hostaddr, :port, :dbname, :user, :password, :connect_timeout,
21
21
  :client_encoding, :options, :application_name, :fallback_application_name,
22
22
  :keepalives, :keepalives_idle, :keepalives_interval, :keepalives_count,
23
- :tty, :sslmode, :requiressl, :sslcert, :sslkey, :sslrootcert, :sslcrl,
24
- :requirepeer, :krbsrvname, :gsslib, :service]
23
+ :tty, :sslmode, :requiressl, :sslcompression, :sslcert, :sslkey,
24
+ :sslrootcert, :sslcrl, :requirepeer, :krbsrvname, :gsslib, :service]
25
25
 
26
26
  # Establishes a connection to the database that's used by all Active Record objects
27
27
  def postgresql_connection(config)
@@ -46,7 +46,7 @@ module ActiveRecord
46
46
  # PostgreSQL-specific extensions to column definitions in a table.
47
47
  class PostgreSQLColumn < Column #:nodoc:
48
48
  attr_accessor :array
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
52
  default_value = self.class.extract_value_from_default(default)
@@ -62,14 +62,6 @@ module ActiveRecord
62
62
  @default_function = default if has_default_function?(default_value, default)
63
63
  end
64
64
 
65
- def number?
66
- !array && super
67
- end
68
-
69
- def text?
70
- !array && super
71
- end
72
-
73
65
  # :stopdoc:
74
66
  class << self
75
67
  include ConnectionAdapters::PostgreSQLColumn::Cast
@@ -96,7 +88,7 @@ module ActiveRecord
96
88
  $1
97
89
  # Character types
98
90
  when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m
99
- $1
91
+ $1.gsub(/''/, "'")
100
92
  # Binary data types
101
93
  when /\A'(.*)'::bytea\z/m
102
94
  $1
@@ -141,6 +133,14 @@ module ActiveRecord
141
133
  end
142
134
  end
143
135
 
136
+ def type_cast_for_write(value)
137
+ if @oid_type.respond_to?(:type_cast_for_write)
138
+ @oid_type.type_cast_for_write(value)
139
+ else
140
+ super
141
+ end
142
+ end
143
+
144
144
  def type_cast(value)
145
145
  return if value.nil?
146
146
  return super if encoded?
@@ -148,6 +148,10 @@ module ActiveRecord
148
148
  @oid_type.type_cast value
149
149
  end
150
150
 
151
+ def accessor
152
+ @oid_type.accessor
153
+ end
154
+
151
155
  private
152
156
 
153
157
  def has_default_function?(default_value, default)
@@ -356,10 +360,10 @@ module ActiveRecord
356
360
  # end
357
361
  #
358
362
  # By default, this will use the +uuid_generate_v4()+ function from the
359
- # +uuid-ossp+ extension, which MUST be enabled on your databse. To enable
363
+ # +uuid-ossp+ extension, which MUST be enabled on your database. To enable
360
364
  # the +uuid-ossp+ extension, you can use the +enable_extension+ method in your
361
- # migrations To use a UUID primary key without +uuid-ossp+ enabled, you can
362
- # set the +:default+ option to nil:
365
+ # migrations. To use a UUID primary key without +uuid-ossp+ enabled, you can
366
+ # set the +:default+ option to +nil+:
363
367
  #
364
368
  # create_table :stuffs, id: false do |t|
365
369
  # t.primary_key :id, :uuid, default: nil
@@ -370,11 +374,10 @@ module ActiveRecord
370
374
  # You may also pass a different UUID generation function from +uuid-ossp+
371
375
  # or another library.
372
376
  #
373
- # Note that setting the UUID primary key default value to +nil+
374
- # will require you to assure that you always provide a UUID value
375
- # before saving a record (as primary keys cannot be nil). This might be
376
- # done via the SecureRandom.uuid method and a +before_save+ callback,
377
- # for instance.
377
+ # Note that setting the UUID primary key default value to +nil+ will
378
+ # require you to assure that you always provide a UUID value before saving
379
+ # a record (as primary keys cannot be +nil+). This might be done via the
380
+ # +SecureRandom.uuid+ method and a +before_save+ callback, for instance.
378
381
  def primary_key(name, type = :primary_key, options = {})
379
382
  return super unless type == :uuid
380
383
  options[:default] = options.fetch(:default, 'uuid_generate_v4()')
@@ -437,6 +440,7 @@ module ActiveRecord
437
440
  include ReferentialIntegrity
438
441
  include SchemaStatements
439
442
  include DatabaseStatements
443
+ include Savepoints
440
444
 
441
445
  # Returns 'PostgreSQL' as adapter name for identification purposes.
442
446
  def adapter_name
@@ -561,7 +565,8 @@ module ActiveRecord
561
565
  raise "Your version of PostgreSQL (#{postgresql_version}) is too old, please upgrade!"
562
566
  end
563
567
 
564
- initialize_type_map
568
+ @type_map = OID::TypeMap.new
569
+ initialize_type_map(type_map)
565
570
  @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
566
571
  @use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true
567
572
  end
@@ -573,16 +578,11 @@ module ActiveRecord
573
578
 
574
579
  # Is this connection alive and ready for queries?
575
580
  def active?
576
- @connection.query 'SELECT 1'
577
- true
581
+ @connection.connect_poll != PG::PGRES_POLLING_FAILED
578
582
  rescue PGError
579
583
  false
580
584
  end
581
585
 
582
- def active_threadsafe?
583
- @connection.connect_poll != PG::PGRES_POLLING_FAILED
584
- end
585
-
586
586
  # Close then reopen the connection.
587
587
  def reconnect!
588
588
  super
@@ -632,12 +632,6 @@ module ActiveRecord
632
632
  true
633
633
  end
634
634
 
635
- # Returns true, since this connection adapter supports savepoints.
636
- def supports_savepoints?
637
- true
638
- end
639
-
640
- # Returns true.
641
635
  def supports_explain?
642
636
  true
643
637
  end
@@ -719,10 +713,6 @@ module ActiveRecord
719
713
  !native_database_types[type].nil?
720
714
  end
721
715
 
722
- def update_table_definition(table_name, base) #:nodoc:
723
- Table.new(table_name, base)
724
- end
725
-
726
716
  protected
727
717
 
728
718
  # Returns the version of the connected PostgreSQL server.
@@ -749,72 +739,85 @@ module ActiveRecord
749
739
 
750
740
  private
751
741
 
752
- def get_oid_type(oid, fmod, column_name)
753
- OID::TYPE_MAP.fetch(oid, fmod) {
754
- warn "unknown OID #{oid}: failed to recognize type of '#{column_name}'. It will be treated as String."
755
- OID::TYPE_MAP[oid] = OID::Identity.new
756
- }
742
+ def type_map
743
+ @type_map
757
744
  end
758
745
 
759
746
  def reload_type_map
760
- OID::TYPE_MAP.clear
761
- initialize_type_map
747
+ type_map.clear
748
+ initialize_type_map(type_map)
749
+ end
750
+
751
+ def add_oid(row, records_by_oid, type_map)
752
+ return type_map if type_map.key? row['type_elem'].to_i
753
+
754
+ if OID.registered_type? row['typname']
755
+ # this composite type is explicitly registered
756
+ vector = OID::NAMES[row['typname']]
757
+ else
758
+ # use the default for composite types
759
+ unless type_map.key? row['typelem'].to_i
760
+ add_oid records_by_oid[row['typelem']], records_by_oid, type_map
761
+ end
762
+
763
+ vector = OID::Vector.new row['typdelim'], type_map[row['typelem'].to_i]
764
+ end
765
+
766
+ type_map[row['oid'].to_i] = vector
767
+ type_map
762
768
  end
763
769
 
764
- def initialize_type_map
770
+ def initialize_type_map(type_map)
765
771
  result = execute('SELECT oid, typname, typelem, typdelim, typinput FROM pg_type', 'SCHEMA')
766
772
  leaves, nodes = result.partition { |row| row['typelem'] == '0' }
767
773
 
768
774
  # populate the leaf nodes
769
775
  leaves.find_all { |row| OID.registered_type? row['typname'] }.each do |row|
770
- OID::TYPE_MAP[row['oid'].to_i] = OID::NAMES[row['typname']]
776
+ type_map[row['oid'].to_i] = OID::NAMES[row['typname']]
771
777
  end
772
778
 
779
+ records_by_oid = result.group_by { |row| row['oid'] }
780
+
773
781
  arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in' }
774
782
 
775
783
  # populate composite types
776
- nodes.find_all { |row| OID::TYPE_MAP.key? row['typelem'].to_i }.each do |row|
777
- if OID.registered_type? row['typname']
778
- # this composite type is explicitly registered
779
- vector = OID::NAMES[row['typname']]
780
- else
781
- # use the default for composite types
782
- vector = OID::Vector.new row['typdelim'], OID::TYPE_MAP[row['typelem'].to_i]
783
- end
784
-
785
- OID::TYPE_MAP[row['oid'].to_i] = vector
784
+ nodes.each do |row|
785
+ add_oid row, records_by_oid, type_map
786
786
  end
787
787
 
788
788
  # populate array types
789
- arrays.find_all { |row| OID::TYPE_MAP.key? row['typelem'].to_i }.each do |row|
790
- array = OID::Array.new OID::TYPE_MAP[row['typelem'].to_i]
791
- OID::TYPE_MAP[row['oid'].to_i] = array
789
+ arrays.find_all { |row| type_map.key? row['typelem'].to_i }.each do |row|
790
+ array = OID::Array.new type_map[row['typelem'].to_i]
791
+ type_map[row['oid'].to_i] = array
792
792
  end
793
793
  end
794
794
 
795
- FEATURE_NOT_SUPPORTED = "0A000" #:nodoc:
795
+ FEATURE_NOT_SUPPORTED = "0A000" # :nodoc:
796
796
 
797
- def exec_no_cache(sql, binds)
798
- @connection.async_exec(sql, [])
797
+ def exec_no_cache(sql, name, binds)
798
+ log(sql, name, binds) { @connection.async_exec(sql) }
799
799
  end
800
800
 
801
- def exec_cache(sql, binds)
802
- stmt_key = prepare_statement sql
801
+ def exec_cache(sql, name, binds)
802
+ stmt_key = prepare_statement(sql)
803
+ type_casted_binds = binds.map { |col, val|
804
+ [col, type_cast(val, col)]
805
+ }
806
+
807
+ log(sql, name, type_casted_binds, stmt_key) do
808
+ @connection.send_query_prepared(stmt_key, type_casted_binds.map { |_, val| val })
809
+ @connection.block
810
+ @connection.get_last_result
811
+ end
812
+ rescue ActiveRecord::StatementInvalid => e
813
+ pgerror = e.original_exception
803
814
 
804
- # Clear the queue
805
- @connection.get_last_result
806
- @connection.send_query_prepared(stmt_key, binds.map { |col, val|
807
- type_cast(val, col)
808
- })
809
- @connection.block
810
- @connection.get_last_result
811
- rescue PGError => e
812
815
  # Get the PG code for the failure. Annoyingly, the code for
813
816
  # prepared statements whose return value may have changed is
814
817
  # FEATURE_NOT_SUPPORTED. Check here for more details:
815
818
  # http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
816
819
  begin
817
- code = e.result.result_error_field(PGresult::PG_DIAG_SQLSTATE)
820
+ code = pgerror.result.result_error_field(PGresult::PG_DIAG_SQLSTATE)
818
821
  rescue
819
822
  raise e
820
823
  end
@@ -839,6 +842,8 @@ module ActiveRecord
839
842
  unless @statements.key? sql_key
840
843
  nextkey = @statements.next_key
841
844
  @connection.prepare nextkey, sql
845
+ # Clear the queue
846
+ @connection.get_last_result
842
847
  @statements[sql_key] = nextkey
843
848
  end
844
849
  @statements[sql_key]
@@ -915,6 +920,14 @@ module ActiveRecord
915
920
  exec_query(sql, name, binds)
916
921
  end
917
922
 
923
+ def select_raw(sql, name = nil)
924
+ res = execute(sql, name)
925
+ results = result_as_array(res)
926
+ fields = res.fields
927
+ res.clear
928
+ return fields, results
929
+ end
930
+
918
931
  # Returns the list of a table's column names, data types, and default values.
919
932
  #
920
933
  # The underlying query is roughly:
@@ -960,8 +973,12 @@ module ActiveRecord
960
973
  $1.strip if $1
961
974
  end
962
975
 
963
- def create_table_definition(name, temporary, options)
964
- TableDefinition.new native_database_types, name, temporary, options
976
+ def create_table_definition(name, temporary, options, as = nil)
977
+ TableDefinition.new native_database_types, name, temporary, options, as
978
+ end
979
+
980
+ def update_table_definition(table_name, base)
981
+ Table.new(table_name, base)
965
982
  end
966
983
  end
967
984
  end