activerecord 4.1.8 → 4.2.11.3

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 (186) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1165 -1591
  3. data/README.rdoc +15 -10
  4. data/lib/active_record/aggregations.rb +15 -8
  5. data/lib/active_record/association_relation.rb +13 -0
  6. data/lib/active_record/associations/alias_tracker.rb +3 -12
  7. data/lib/active_record/associations/association.rb +16 -4
  8. data/lib/active_record/associations/association_scope.rb +84 -43
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -10
  10. data/lib/active_record/associations/builder/association.rb +16 -5
  11. data/lib/active_record/associations/builder/belongs_to.rb +7 -29
  12. data/lib/active_record/associations/builder/collection_association.rb +5 -1
  13. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +9 -14
  14. data/lib/active_record/associations/builder/has_many.rb +1 -1
  15. data/lib/active_record/associations/builder/has_one.rb +2 -2
  16. data/lib/active_record/associations/builder/singular_association.rb +8 -1
  17. data/lib/active_record/associations/collection_association.rb +87 -30
  18. data/lib/active_record/associations/collection_proxy.rb +33 -35
  19. data/lib/active_record/associations/foreign_association.rb +11 -0
  20. data/lib/active_record/associations/has_many_association.rb +83 -22
  21. data/lib/active_record/associations/has_many_through_association.rb +49 -26
  22. data/lib/active_record/associations/has_one_association.rb +1 -1
  23. data/lib/active_record/associations/join_dependency/join_association.rb +25 -15
  24. data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
  25. data/lib/active_record/associations/join_dependency.rb +26 -12
  26. data/lib/active_record/associations/preloader/association.rb +14 -10
  27. data/lib/active_record/associations/preloader/through_association.rb +4 -3
  28. data/lib/active_record/associations/preloader.rb +37 -26
  29. data/lib/active_record/associations/singular_association.rb +17 -2
  30. data/lib/active_record/associations/through_association.rb +16 -12
  31. data/lib/active_record/associations.rb +158 -49
  32. data/lib/active_record/attribute.rb +163 -0
  33. data/lib/active_record/attribute_assignment.rb +20 -12
  34. data/lib/active_record/attribute_decorators.rb +66 -0
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  36. data/lib/active_record/attribute_methods/dirty.rb +107 -43
  37. data/lib/active_record/attribute_methods/primary_key.rb +7 -8
  38. data/lib/active_record/attribute_methods/query.rb +1 -1
  39. data/lib/active_record/attribute_methods/read.rb +22 -59
  40. data/lib/active_record/attribute_methods/serialization.rb +16 -150
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -28
  42. data/lib/active_record/attribute_methods/write.rb +9 -24
  43. data/lib/active_record/attribute_methods.rb +57 -95
  44. data/lib/active_record/attribute_set/builder.rb +106 -0
  45. data/lib/active_record/attribute_set.rb +81 -0
  46. data/lib/active_record/attributes.rb +147 -0
  47. data/lib/active_record/autosave_association.rb +30 -12
  48. data/lib/active_record/base.rb +13 -24
  49. data/lib/active_record/callbacks.rb +6 -6
  50. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +85 -53
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +52 -50
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +60 -60
  54. data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +39 -4
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +139 -57
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +271 -74
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -60
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +295 -141
  62. data/lib/active_record/connection_adapters/column.rb +29 -240
  63. data/lib/active_record/connection_adapters/connection_specification.rb +15 -24
  64. data/lib/active_record/connection_adapters/mysql2_adapter.rb +17 -33
  65. data/lib/active_record/connection_adapters/mysql_adapter.rb +68 -145
  66. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
  67. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  68. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -25
  69. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -385
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +46 -136
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
  97. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  98. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +134 -43
  99. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  100. data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -477
  101. data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
  102. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -75
  103. data/lib/active_record/connection_handling.rb +1 -1
  104. data/lib/active_record/core.rb +163 -40
  105. data/lib/active_record/counter_cache.rb +60 -6
  106. data/lib/active_record/enum.rb +10 -12
  107. data/lib/active_record/errors.rb +53 -30
  108. data/lib/active_record/explain.rb +1 -1
  109. data/lib/active_record/explain_subscriber.rb +1 -1
  110. data/lib/active_record/fixtures.rb +62 -74
  111. data/lib/active_record/gem_version.rb +4 -4
  112. data/lib/active_record/inheritance.rb +35 -10
  113. data/lib/active_record/integration.rb +4 -4
  114. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  115. data/lib/active_record/locking/optimistic.rb +46 -26
  116. data/lib/active_record/migration/command_recorder.rb +19 -2
  117. data/lib/active_record/migration/join_table.rb +1 -1
  118. data/lib/active_record/migration.rb +79 -47
  119. data/lib/active_record/model_schema.rb +52 -58
  120. data/lib/active_record/nested_attributes.rb +18 -8
  121. data/lib/active_record/no_touching.rb +1 -1
  122. data/lib/active_record/persistence.rb +48 -27
  123. data/lib/active_record/query_cache.rb +3 -3
  124. data/lib/active_record/querying.rb +10 -7
  125. data/lib/active_record/railtie.rb +19 -14
  126. data/lib/active_record/railties/databases.rake +55 -56
  127. data/lib/active_record/readonly_attributes.rb +0 -1
  128. data/lib/active_record/reflection.rb +281 -117
  129. data/lib/active_record/relation/batches.rb +0 -1
  130. data/lib/active_record/relation/calculations.rb +41 -37
  131. data/lib/active_record/relation/delegation.rb +1 -1
  132. data/lib/active_record/relation/finder_methods.rb +71 -48
  133. data/lib/active_record/relation/merger.rb +39 -29
  134. data/lib/active_record/relation/predicate_builder/array_handler.rb +32 -13
  135. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  136. data/lib/active_record/relation/predicate_builder.rb +42 -12
  137. data/lib/active_record/relation/query_methods.rb +130 -73
  138. data/lib/active_record/relation/spawn_methods.rb +10 -3
  139. data/lib/active_record/relation.rb +57 -25
  140. data/lib/active_record/result.rb +18 -7
  141. data/lib/active_record/sanitization.rb +12 -2
  142. data/lib/active_record/schema.rb +0 -1
  143. data/lib/active_record/schema_dumper.rb +59 -28
  144. data/lib/active_record/schema_migration.rb +5 -4
  145. data/lib/active_record/scoping/default.rb +6 -4
  146. data/lib/active_record/scoping/named.rb +4 -0
  147. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  148. data/lib/active_record/statement_cache.rb +95 -10
  149. data/lib/active_record/store.rb +5 -5
  150. data/lib/active_record/tasks/database_tasks.rb +61 -8
  151. data/lib/active_record/tasks/mysql_database_tasks.rb +32 -17
  152. data/lib/active_record/tasks/postgresql_database_tasks.rb +20 -9
  153. data/lib/active_record/timestamp.rb +9 -7
  154. data/lib/active_record/transactions.rb +54 -28
  155. data/lib/active_record/type/big_integer.rb +13 -0
  156. data/lib/active_record/type/binary.rb +50 -0
  157. data/lib/active_record/type/boolean.rb +31 -0
  158. data/lib/active_record/type/date.rb +50 -0
  159. data/lib/active_record/type/date_time.rb +54 -0
  160. data/lib/active_record/type/decimal.rb +64 -0
  161. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  162. data/lib/active_record/type/decorator.rb +14 -0
  163. data/lib/active_record/type/float.rb +19 -0
  164. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  165. data/lib/active_record/type/integer.rb +59 -0
  166. data/lib/active_record/type/mutable.rb +16 -0
  167. data/lib/active_record/type/numeric.rb +36 -0
  168. data/lib/active_record/type/serialized.rb +62 -0
  169. data/lib/active_record/type/string.rb +40 -0
  170. data/lib/active_record/type/text.rb +11 -0
  171. data/lib/active_record/type/time.rb +26 -0
  172. data/lib/active_record/type/time_value.rb +38 -0
  173. data/lib/active_record/type/type_map.rb +64 -0
  174. data/lib/active_record/type/unsigned_integer.rb +15 -0
  175. data/lib/active_record/type/value.rb +110 -0
  176. data/lib/active_record/type.rb +23 -0
  177. data/lib/active_record/validations/associated.rb +5 -3
  178. data/lib/active_record/validations/presence.rb +5 -3
  179. data/lib/active_record/validations/uniqueness.rb +24 -20
  180. data/lib/active_record/validations.rb +25 -19
  181. data/lib/active_record.rb +5 -0
  182. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  183. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
  184. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  185. metadata +66 -11
  186. data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -36,9 +36,9 @@ module ActiveRecord
36
36
  ConnectionAdapters::MysqlAdapter.new(mysql, logger, options, config)
37
37
  rescue Mysql::Error => error
38
38
  if error.message.include?("Unknown database")
39
- raise ActiveRecord::NoDatabaseError.new(error.message)
39
+ raise ActiveRecord::NoDatabaseError.new(error.message, error)
40
40
  else
41
- raise error
41
+ raise
42
42
  end
43
43
  end
44
44
  end
@@ -57,8 +57,8 @@ module ActiveRecord
57
57
  # * <tt>:database</tt> - The name of the database. No default, must be provided.
58
58
  # * <tt>:encoding</tt> - (Optional) Sets the client encoding by executing "SET NAMES <encoding>" after connection.
59
59
  # * <tt>:reconnect</tt> - Defaults to false (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/auto-reconnect.html).
60
- # * <tt>:strict</tt> - Defaults to true. Enable STRICT_ALL_TABLES. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html)
61
- # * <tt>:variables</tt> - (Optional) A hash session variables to send as `SET @@SESSION.key = value` on each database connection. Use the value `:default` to set a variable to its DEFAULT value. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/set-statement.html).
60
+ # * <tt>:strict</tt> - Defaults to true. Enable STRICT_ALL_TABLES. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/sql-mode.html)
61
+ # * <tt>:variables</tt> - (Optional) A hash session variables to send as <tt>SET @@SESSION.key = value</tt> on each database connection. Use the value +:default+ to set a variable to its DEFAULT value. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/set-statement.html).
62
62
  # * <tt>:sslca</tt> - Necessary to use MySQL with an SSL connection.
63
63
  # * <tt>:sslkey</tt> - Necessary to use MySQL with an SSL connection.
64
64
  # * <tt>:sslcert</tt> - Necessary to use MySQL with an SSL connection.
@@ -66,36 +66,7 @@ module ActiveRecord
66
66
  # * <tt>:sslcipher</tt> - Necessary to use MySQL with an SSL connection.
67
67
  #
68
68
  class MysqlAdapter < AbstractMysqlAdapter
69
-
70
- class Column < AbstractMysqlAdapter::Column #:nodoc:
71
- def self.string_to_time(value)
72
- return super unless Mysql::Time === value
73
- new_time(
74
- value.year,
75
- value.month,
76
- value.day,
77
- value.hour,
78
- value.minute,
79
- value.second,
80
- value.second_part)
81
- end
82
-
83
- def self.string_to_dummy_time(v)
84
- return super unless Mysql::Time === v
85
- new_time(2000, 01, 01, v.hour, v.minute, v.second, v.second_part)
86
- end
87
-
88
- def self.string_to_date(v)
89
- return super unless Mysql::Time === v
90
- new_date(v.year, v.month, v.day)
91
- end
92
-
93
- def adapter
94
- MysqlAdapter
95
- end
96
- end
97
-
98
- ADAPTER_NAME = 'MySQL'
69
+ ADAPTER_NAME = 'MySQL'.freeze
99
70
 
100
71
  class StatementPool < ConnectionAdapters::StatementPool
101
72
  def initialize(connection, max = 1000)
@@ -117,7 +88,7 @@ module ActiveRecord
117
88
  end
118
89
 
119
90
  def clear
120
- cache.values.each do |hash|
91
+ cache.each_value do |hash|
121
92
  hash[:stmt].close
122
93
  end
123
94
  cache.clear
@@ -156,10 +127,6 @@ module ActiveRecord
156
127
  end
157
128
  end
158
129
 
159
- def new_column(field, default, type, null, collation, extra = "") # :nodoc:
160
- Column.new(field, default, type, null, collation, strict_mode?, extra)
161
- end
162
-
163
130
  def error_number(exception) # :nodoc:
164
131
  exception.errno if exception.respond_to?(:errno)
165
132
  end
@@ -170,7 +137,9 @@ module ActiveRecord
170
137
  @connection.quote(string)
171
138
  end
172
139
 
140
+ #--
173
141
  # CONNECTION MANAGEMENT ====================================
142
+ #++
174
143
 
175
144
  def active?
176
145
  if @connection.respond_to?(:stat)
@@ -211,7 +180,9 @@ module ActiveRecord
211
180
  end
212
181
  end
213
182
 
183
+ #--
214
184
  # DATABASE STATEMENTS ======================================
185
+ #++
215
186
 
216
187
  def select_rows(sql, name = nil, binds = [])
217
188
  @connection.query_with_result = true
@@ -222,6 +193,7 @@ module ActiveRecord
222
193
 
223
194
  # Clears the prepared statements cache.
224
195
  def clear_cache!
196
+ super
225
197
  @statements.clear
226
198
  end
227
199
 
@@ -273,7 +245,7 @@ module ActiveRecord
273
245
  return @client_encoding if @client_encoding
274
246
 
275
247
  result = exec_query(
276
- "SHOW VARIABLES WHERE Variable_name = 'character_set_client'",
248
+ "select @@character_set_client",
277
249
  'SCHEMA')
278
250
  @client_encoding = ENCODINGS[result.rows.last.last]
279
251
  end
@@ -294,125 +266,76 @@ module ActiveRecord
294
266
  @connection.insert_id
295
267
  end
296
268
 
297
- module Fields
298
- class Type
299
- def type; end
300
-
301
- def type_cast_for_write(value)
302
- value
303
- end
304
- end
305
-
306
- class Identity < Type
307
- def type_cast(value); value; end
308
- end
309
-
310
- class Integer < Type
311
- def type_cast(value)
312
- return if value.nil?
313
-
314
- value.to_i rescue value ? 1 : 0
269
+ module Fields # :nodoc:
270
+ class DateTime < Type::DateTime # :nodoc:
271
+ def cast_value(value)
272
+ if Mysql::Time === value
273
+ new_time(
274
+ value.year,
275
+ value.month,
276
+ value.day,
277
+ value.hour,
278
+ value.minute,
279
+ value.second,
280
+ value.second_part)
281
+ else
282
+ super
283
+ end
315
284
  end
316
- end
317
-
318
- class Date < Type
319
- def type; :date; end
320
285
 
321
- def type_cast(value)
322
- return if value.nil?
323
-
324
- # FIXME: probably we can improve this since we know it is mysql
325
- # specific
326
- ConnectionAdapters::Column.value_to_date value
286
+ def has_precision?
287
+ precision || 0
327
288
  end
328
289
  end
329
290
 
330
- class DateTime < Type
331
- def type; :datetime; end
332
-
333
- def type_cast(value)
334
- return if value.nil?
335
-
336
- # FIXME: probably we can improve this since we know it is mysql
337
- # specific
338
- ConnectionAdapters::Column.string_to_time value
291
+ class Time < Type::Time # :nodoc:
292
+ def cast_value(value)
293
+ if Mysql::Time === value
294
+ new_time(
295
+ 2000,
296
+ 01,
297
+ 01,
298
+ value.hour,
299
+ value.minute,
300
+ value.second,
301
+ value.second_part)
302
+ else
303
+ super
304
+ end
339
305
  end
340
306
  end
341
307
 
342
- class Time < Type
343
- def type; :time; end
308
+ class << self
309
+ TYPES = Type::HashLookupTypeMap.new # :nodoc:
344
310
 
345
- def type_cast(value)
346
- return if value.nil?
311
+ delegate :register_type, :alias_type, to: :TYPES
347
312
 
348
- # FIXME: probably we can improve this since we know it is mysql
349
- # specific
350
- ConnectionAdapters::Column.string_to_dummy_time value
313
+ def find_type(field)
314
+ if field.type == Mysql::Field::TYPE_TINY && field.length > 1
315
+ TYPES.lookup(Mysql::Field::TYPE_LONG)
316
+ else
317
+ TYPES.lookup(field.type)
318
+ end
351
319
  end
352
320
  end
353
321
 
354
- class Float < Type
355
- def type; :float; end
356
-
357
- def type_cast(value)
358
- return if value.nil?
359
-
360
- value.to_f
361
- end
362
- end
363
-
364
- class Decimal < Type
365
- def type_cast(value)
366
- return if value.nil?
367
-
368
- ConnectionAdapters::Column.value_to_decimal value
369
- end
370
- end
371
-
372
- class Boolean < Type
373
- def type_cast(value)
374
- return if value.nil?
375
-
376
- ConnectionAdapters::Column.value_to_boolean value
377
- end
378
- end
379
-
380
- TYPES = {}
381
-
382
- # Register an MySQL +type_id+ with a typecasting object in
383
- # +type+.
384
- def self.register_type(type_id, type)
385
- TYPES[type_id] = type
386
- end
387
-
388
- def self.alias_type(new, old)
389
- TYPES[new] = TYPES[old]
390
- end
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
-
400
- register_type Mysql::Field::TYPE_TINY, Fields::Boolean.new
401
- register_type Mysql::Field::TYPE_LONG, Fields::Integer.new
322
+ register_type Mysql::Field::TYPE_TINY, Type::Boolean.new
323
+ register_type Mysql::Field::TYPE_LONG, Type::Integer.new
402
324
  alias_type Mysql::Field::TYPE_LONGLONG, Mysql::Field::TYPE_LONG
403
325
  alias_type Mysql::Field::TYPE_NEWDECIMAL, Mysql::Field::TYPE_LONG
404
326
 
405
- register_type Mysql::Field::TYPE_VAR_STRING, Fields::Identity.new
406
- register_type Mysql::Field::TYPE_BLOB, Fields::Identity.new
407
- register_type Mysql::Field::TYPE_DATE, Fields::Date.new
327
+ register_type Mysql::Field::TYPE_DATE, Type::Date.new
408
328
  register_type Mysql::Field::TYPE_DATETIME, Fields::DateTime.new
409
329
  register_type Mysql::Field::TYPE_TIME, Fields::Time.new
410
- register_type Mysql::Field::TYPE_FLOAT, Fields::Float.new
330
+ register_type Mysql::Field::TYPE_FLOAT, Type::Float.new
331
+ end
411
332
 
412
- Mysql::Field.constants.grep(/TYPE/).map { |class_name|
413
- Mysql::Field.const_get class_name
414
- }.reject { |const| TYPES.key? const }.each do |const|
415
- register_type const, Fields::Identity.new
333
+ def initialize_type_map(m) # :nodoc:
334
+ super
335
+ m.register_type %r(time)i, Fields::Time.new
336
+ m.register_type(%r(datetime)i) do |sql_type|
337
+ precision = extract_precision(sql_type)
338
+ Fields::DateTime.new(precision: precision)
416
339
  end
417
340
  end
418
341
 
@@ -431,7 +354,7 @@ module ActiveRecord
431
354
  fields << field_name
432
355
 
433
356
  if field.decimals > 0
434
- types[field_name] = Fields::Decimal.new
357
+ types[field_name] = Type::Decimal.new
435
358
  else
436
359
  types[field_name] = Fields.find_type field
437
360
  end
@@ -447,7 +370,7 @@ module ActiveRecord
447
370
  end
448
371
  end
449
372
 
450
- def execute_and_free(sql, name = nil)
373
+ def execute_and_free(sql, name = nil) # :nodoc:
451
374
  result = execute(sql, name)
452
375
  ret = yield result
453
376
  result.free
@@ -460,7 +383,7 @@ module ActiveRecord
460
383
  end
461
384
  alias :create :insert_sql
462
385
 
463
- def exec_delete(sql, name, binds)
386
+ def exec_delete(sql, name, binds) # :nodoc:
464
387
  affected_rows = 0
465
388
 
466
389
  exec_query(sql, name, binds) do |n|
@@ -497,7 +420,7 @@ module ActiveRecord
497
420
  stmt.execute(*type_casted_binds.map { |_, val| val })
498
421
  rescue Mysql::Error => e
499
422
  # Older versions of MySQL leave the prepared statement in a bad
500
- # place when an error occurs. To support older mysql versions, we
423
+ # place when an error occurs. To support older MySQL versions, we
501
424
  # need to close the statement and delete the statement from the
502
425
  # cache.
503
426
  stmt.close
@@ -553,7 +476,7 @@ module ActiveRecord
553
476
 
554
477
  def select(sql, name = nil, binds = [])
555
478
  @connection.query_with_result = true
556
- rows = exec_query(sql, name, binds)
479
+ rows = super
557
480
  @connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
558
481
  rows
559
482
  end
@@ -1,7 +1,7 @@
1
1
  module ActiveRecord
2
2
  module ConnectionAdapters
3
- class PostgreSQLColumn < Column
4
- module ArrayParser
3
+ module PostgreSQL
4
+ module ArrayParser # :nodoc:
5
5
 
6
6
  DOUBLE_QUOTE = '"'
7
7
  BACKSLASH = "\\"
@@ -9,35 +9,23 @@ module ActiveRecord
9
9
  BRACKET_OPEN = '{'
10
10
  BRACKET_CLOSE = '}'
11
11
 
12
- private
13
- # Loads pg_array_parser if available. String parsing can be
14
- # performed quicker by a native extension, which will not create
15
- # a large amount of Ruby objects that will need to be garbage
16
- # collected. pg_array_parser has a C and Java extension
17
- begin
18
- require 'pg_array_parser'
19
- include PgArrayParser
20
- rescue LoadError
21
- def parse_pg_array(string)
22
- parse_data(string)
12
+ def parse_pg_array(string) # :nodoc:
13
+ local_index = 0
14
+ array = []
15
+ while(local_index < string.length)
16
+ case string[local_index]
17
+ when BRACKET_OPEN
18
+ local_index,array = parse_array_contents(array, string, local_index + 1)
19
+ when BRACKET_CLOSE
20
+ return array
23
21
  end
22
+ local_index += 1
24
23
  end
25
24
 
26
- def parse_data(string)
27
- local_index = 0
28
- array = []
29
- while(local_index < string.length)
30
- case string[local_index]
31
- when BRACKET_OPEN
32
- local_index,array = parse_array_contents(array, string, local_index + 1)
33
- when BRACKET_CLOSE
34
- return array
35
- end
36
- local_index += 1
37
- end
25
+ array
26
+ end
38
27
 
39
- array
40
- end
28
+ private
41
29
 
42
30
  def parse_array_contents(array, string, index)
43
31
  is_escaping = false
@@ -0,0 +1,20 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ # PostgreSQL-specific extensions to column definitions in a table.
4
+ class PostgreSQLColumn < Column #:nodoc:
5
+ attr_accessor :array
6
+
7
+ def initialize(name, default, cast_type, sql_type = nil, null = true, default_function = nil)
8
+ if sql_type =~ /\[\]$/
9
+ @array = true
10
+ super(name, default, cast_type, sql_type[0..sql_type.length - 3], null)
11
+ else
12
+ @array = false
13
+ super(name, default, cast_type, sql_type, null)
14
+ end
15
+
16
+ @default_function = default_function
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,6 +1,6 @@
1
1
  module ActiveRecord
2
2
  module ConnectionAdapters
3
- class PostgreSQLAdapter < AbstractAdapter
3
+ module PostgreSQL
4
4
  module DatabaseStatements
5
5
  def explain(arel, binds = [])
6
6
  sql = "EXPLAIN #{to_sql(arel, binds)}"
@@ -44,10 +44,32 @@ module ActiveRecord
44
44
  end
45
45
  end
46
46
 
47
+ def select_value(arel, name = nil, binds = [])
48
+ arel, binds = binds_from_relation arel, binds
49
+ sql = to_sql(arel, binds)
50
+ execute_and_clear(sql, name, binds) do |result|
51
+ result.getvalue(0, 0) if result.ntuples > 0 && result.nfields > 0
52
+ end
53
+ end
54
+
55
+ def select_values(arel, name = nil)
56
+ arel, binds = binds_from_relation arel, []
57
+ sql = to_sql(arel, binds)
58
+ execute_and_clear(sql, name, binds) do |result|
59
+ if result.nfields > 0
60
+ result.column_values(0)
61
+ else
62
+ []
63
+ end
64
+ end
65
+ end
66
+
47
67
  # Executes a SELECT query and returns an array of rows. Each row is an
48
68
  # array of field values.
49
69
  def select_rows(sql, name = nil, binds = [])
50
- exec_query(sql, name, binds).rows
70
+ execute_and_clear(sql, name, binds) do |result|
71
+ result.values
72
+ end
51
73
  end
52
74
 
53
75
  # Executes an INSERT query and returns the new record's ID
@@ -72,6 +94,11 @@ module ActiveRecord
72
94
  super.insert
73
95
  end
74
96
 
97
+ # The internal PostgreSQL identifier of the money data type.
98
+ MONEY_COLUMN_TYPE_OID = 790 #:nodoc:
99
+ # The internal PostgreSQL identifier of the BYTEA data type.
100
+ BYTEA_COLUMN_TYPE_OID = 17 #:nodoc:
101
+
75
102
  # create a 2D array representing the result set
76
103
  def result_as_array(res) #:nodoc:
77
104
  # check if we have any binary column and if they need escaping
@@ -129,33 +156,21 @@ module ActiveRecord
129
156
  end
130
157
  end
131
158
 
132
- def substitute_at(column, index)
133
- Arel::Nodes::BindParam.new "$#{index + 1}"
134
- end
135
-
136
159
  def exec_query(sql, name = 'SQL', binds = [])
137
- result = without_prepared_statement?(binds) ? exec_no_cache(sql, name, binds) :
138
- exec_cache(sql, name, binds)
139
-
140
- types = {}
141
- fields = result.fields
142
- fields.each_with_index do |fname, i|
143
- ftype = result.ftype i
144
- fmod = result.fmod i
145
- types[fname] = get_oid_type(ftype, fmod, fname)
160
+ execute_and_clear(sql, name, binds) do |result|
161
+ types = {}
162
+ fields = result.fields
163
+ fields.each_with_index do |fname, i|
164
+ ftype = result.ftype i
165
+ fmod = result.fmod i
166
+ types[fname] = get_oid_type(ftype, fmod, fname)
167
+ end
168
+ ActiveRecord::Result.new(fields, result.values, types)
146
169
  end
147
-
148
- ret = ActiveRecord::Result.new(fields, result.values, types)
149
- result.clear
150
- return ret
151
170
  end
152
171
 
153
172
  def exec_delete(sql, name = 'SQL', binds = [])
154
- result = without_prepared_statement?(binds) ? exec_no_cache(sql, name, binds) :
155
- exec_cache(sql, name, binds)
156
- affected = result.cmd_tuples
157
- result.clear
158
- affected
173
+ execute_and_clear(sql, name, binds) {|result| result.cmd_tuples }
159
174
  end
160
175
  alias :exec_update :exec_delete
161
176
 
@@ -208,7 +223,7 @@ module ActiveRecord
208
223
  end
209
224
 
210
225
  # Aborts a transaction.
211
- def rollback_db_transaction
226
+ def exec_rollback_db_transaction
212
227
  execute "ROLLBACK"
213
228
  end
214
229
  end
@@ -0,0 +1,100 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class Array < Type::Value # :nodoc:
6
+ include Type::Mutable
7
+
8
+ # Loads pg_array_parser if available. String parsing can be
9
+ # performed quicker by a native extension, which will not create
10
+ # a large amount of Ruby objects that will need to be garbage
11
+ # collected. pg_array_parser has a C and Java extension
12
+ begin
13
+ require 'pg_array_parser'
14
+ include PgArrayParser
15
+ rescue LoadError
16
+ require 'active_record/connection_adapters/postgresql/array_parser'
17
+ include PostgreSQL::ArrayParser
18
+ end
19
+
20
+ attr_reader :subtype, :delimiter
21
+ delegate :type, :limit, to: :subtype
22
+
23
+ def initialize(subtype, delimiter = ',')
24
+ @subtype = subtype
25
+ @delimiter = delimiter
26
+ end
27
+
28
+ def type_cast_from_database(value)
29
+ if value.is_a?(::String)
30
+ type_cast_array(parse_pg_array(value), :type_cast_from_database)
31
+ else
32
+ super
33
+ end
34
+ end
35
+
36
+ def type_cast_from_user(value)
37
+ if value.is_a?(::String)
38
+ value = parse_pg_array(value)
39
+ end
40
+ type_cast_array(value, :type_cast_from_user)
41
+ end
42
+
43
+ def type_cast_for_database(value)
44
+ if value.is_a?(::Array)
45
+ cast_value_for_database(value)
46
+ else
47
+ super
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def type_cast_array(value, method)
54
+ if value.is_a?(::Array)
55
+ value.map { |item| type_cast_array(item, method) }
56
+ else
57
+ @subtype.public_send(method, value)
58
+ end
59
+ end
60
+
61
+ def cast_value_for_database(value)
62
+ if value.is_a?(::Array)
63
+ casted_values = value.map { |item| cast_value_for_database(item) }
64
+ "{#{casted_values.join(delimiter)}}"
65
+ else
66
+ quote_and_escape(subtype.type_cast_for_database(value))
67
+ end
68
+ end
69
+
70
+ ARRAY_ESCAPE = "\\" * 2 * 2 # escape the backslash twice for PG arrays
71
+
72
+ def quote_and_escape(value)
73
+ case value
74
+ when ::String
75
+ if string_requires_quoting?(value)
76
+ value = value.gsub(/\\/, ARRAY_ESCAPE)
77
+ value.gsub!(/"/,"\\\"")
78
+ %("#{value}")
79
+ else
80
+ value
81
+ end
82
+ when nil then "NULL"
83
+ when ::Date, ::DateTime, ::Time then subtype.type_cast_for_schema(value)
84
+ else value
85
+ end
86
+ end
87
+
88
+ # See http://www.postgresql.org/docs/9.2/static/arrays.html#ARRAYS-IO
89
+ # for a list of all cases in which strings will be quoted.
90
+ def string_requires_quoting?(string)
91
+ string.empty? ||
92
+ string == "NULL" ||
93
+ string =~ /[\{\}"\\\s]/ ||
94
+ string.include?(delimiter)
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,52 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class Bit < Type::Value # :nodoc:
6
+ def type
7
+ :bit
8
+ end
9
+
10
+ def type_cast(value)
11
+ if ::String === value
12
+ case value
13
+ when /^0x/i
14
+ value[2..-1].hex.to_s(2) # Hexadecimal notation
15
+ else
16
+ value # Bit-string notation
17
+ end
18
+ else
19
+ value
20
+ end
21
+ end
22
+
23
+ def type_cast_for_database(value)
24
+ Data.new(super) if value
25
+ end
26
+
27
+ class Data
28
+ def initialize(value)
29
+ @value = value
30
+ end
31
+
32
+ def to_s
33
+ value
34
+ end
35
+
36
+ def binary?
37
+ /\A[01]*\Z/ === value
38
+ end
39
+
40
+ def hex?
41
+ /\A[0-9A-F]*\Z/i === value
42
+ end
43
+
44
+ protected
45
+
46
+ attr_reader :value
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,13 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class BitVarying < OID::Bit # :nodoc:
6
+ def type
7
+ :bit_varying
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end