activerecord 4.2.11.3 → 5.0.7.2

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 (251) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1638 -1132
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -8
  5. data/examples/performance.rb +2 -3
  6. data/examples/simple.rb +0 -1
  7. data/lib/active_record.rb +7 -2
  8. data/lib/active_record/aggregations.rb +34 -21
  9. data/lib/active_record/association_relation.rb +7 -4
  10. data/lib/active_record/associations.rb +347 -218
  11. data/lib/active_record/associations/alias_tracker.rb +19 -16
  12. data/lib/active_record/associations/association.rb +22 -10
  13. data/lib/active_record/associations/association_scope.rb +75 -104
  14. data/lib/active_record/associations/belongs_to_association.rb +21 -32
  15. data/lib/active_record/associations/builder/association.rb +28 -34
  16. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  17. data/lib/active_record/associations/builder/collection_association.rb +7 -19
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +16 -11
  19. data/lib/active_record/associations/builder/has_many.rb +4 -4
  20. data/lib/active_record/associations/builder/has_one.rb +11 -6
  21. data/lib/active_record/associations/builder/singular_association.rb +13 -11
  22. data/lib/active_record/associations/collection_association.rb +85 -69
  23. data/lib/active_record/associations/collection_proxy.rb +104 -46
  24. data/lib/active_record/associations/foreign_association.rb +1 -1
  25. data/lib/active_record/associations/has_many_association.rb +21 -78
  26. data/lib/active_record/associations/has_many_through_association.rb +6 -47
  27. data/lib/active_record/associations/has_one_association.rb +12 -5
  28. data/lib/active_record/associations/join_dependency.rb +38 -22
  29. data/lib/active_record/associations/join_dependency/join_association.rb +15 -14
  30. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  31. data/lib/active_record/associations/preloader.rb +14 -4
  32. data/lib/active_record/associations/preloader/association.rb +52 -71
  33. data/lib/active_record/associations/preloader/collection_association.rb +0 -7
  34. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  35. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  36. data/lib/active_record/associations/preloader/singular_association.rb +0 -1
  37. data/lib/active_record/associations/preloader/through_association.rb +36 -17
  38. data/lib/active_record/associations/singular_association.rb +13 -1
  39. data/lib/active_record/associations/through_association.rb +12 -4
  40. data/lib/active_record/attribute.rb +69 -19
  41. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  42. data/lib/active_record/attribute_assignment.rb +19 -140
  43. data/lib/active_record/attribute_decorators.rb +6 -5
  44. data/lib/active_record/attribute_methods.rb +69 -44
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  46. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  47. data/lib/active_record/attribute_methods/primary_key.rb +16 -3
  48. data/lib/active_record/attribute_methods/query.rb +2 -2
  49. data/lib/active_record/attribute_methods/read.rb +31 -59
  50. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
  52. data/lib/active_record/attribute_methods/write.rb +13 -37
  53. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  54. data/lib/active_record/attribute_set.rb +32 -3
  55. data/lib/active_record/attribute_set/builder.rb +42 -16
  56. data/lib/active_record/attributes.rb +199 -81
  57. data/lib/active_record/autosave_association.rb +54 -17
  58. data/lib/active_record/base.rb +32 -23
  59. data/lib/active_record/callbacks.rb +39 -43
  60. data/lib/active_record/coders/json.rb +1 -1
  61. data/lib/active_record/coders/yaml_column.rb +20 -8
  62. data/lib/active_record/collection_cache_key.rb +50 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +467 -189
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -62
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +39 -4
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +86 -13
  68. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  69. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  70. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -188
  71. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  72. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +407 -156
  73. data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
  74. data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -71
  75. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +433 -399
  76. data/lib/active_record/connection_adapters/column.rb +28 -43
  77. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  78. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  79. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  80. data/lib/active_record/connection_adapters/mysql/database_statements.rb +108 -0
  81. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  82. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  83. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  84. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  86. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  87. data/lib/active_record/connection_adapters/mysql2_adapter.rb +25 -166
  88. data/lib/active_record/connection_adapters/postgresql/column.rb +33 -11
  89. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -72
  90. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +37 -57
  93. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +3 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -2
  95. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  96. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  97. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +13 -3
  98. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  99. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  101. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  102. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  106. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +56 -19
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +250 -154
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +264 -170
  116. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  118. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  121. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +151 -194
  122. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  123. data/lib/active_record/connection_handling.rb +37 -14
  124. data/lib/active_record/core.rb +92 -108
  125. data/lib/active_record/counter_cache.rb +13 -24
  126. data/lib/active_record/dynamic_matchers.rb +1 -20
  127. data/lib/active_record/enum.rb +116 -76
  128. data/lib/active_record/errors.rb +87 -48
  129. data/lib/active_record/explain.rb +20 -9
  130. data/lib/active_record/explain_registry.rb +1 -1
  131. data/lib/active_record/explain_subscriber.rb +1 -1
  132. data/lib/active_record/fixture_set/file.rb +26 -5
  133. data/lib/active_record/fixtures.rb +77 -41
  134. data/lib/active_record/gem_version.rb +4 -4
  135. data/lib/active_record/inheritance.rb +32 -40
  136. data/lib/active_record/integration.rb +17 -14
  137. data/lib/active_record/internal_metadata.rb +56 -0
  138. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  139. data/lib/active_record/locale/en.yml +3 -2
  140. data/lib/active_record/locking/optimistic.rb +15 -15
  141. data/lib/active_record/locking/pessimistic.rb +1 -1
  142. data/lib/active_record/log_subscriber.rb +48 -24
  143. data/lib/active_record/migration.rb +362 -111
  144. data/lib/active_record/migration/command_recorder.rb +59 -18
  145. data/lib/active_record/migration/compatibility.rb +126 -0
  146. data/lib/active_record/model_schema.rb +270 -73
  147. data/lib/active_record/nested_attributes.rb +58 -29
  148. data/lib/active_record/no_touching.rb +4 -0
  149. data/lib/active_record/null_relation.rb +16 -8
  150. data/lib/active_record/persistence.rb +152 -90
  151. data/lib/active_record/query_cache.rb +18 -23
  152. data/lib/active_record/querying.rb +12 -11
  153. data/lib/active_record/railtie.rb +23 -16
  154. data/lib/active_record/railties/controller_runtime.rb +1 -1
  155. data/lib/active_record/railties/databases.rake +52 -41
  156. data/lib/active_record/readonly_attributes.rb +1 -1
  157. data/lib/active_record/reflection.rb +302 -115
  158. data/lib/active_record/relation.rb +187 -120
  159. data/lib/active_record/relation/batches.rb +141 -36
  160. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  161. data/lib/active_record/relation/calculations.rb +92 -117
  162. data/lib/active_record/relation/delegation.rb +8 -20
  163. data/lib/active_record/relation/finder_methods.rb +173 -89
  164. data/lib/active_record/relation/from_clause.rb +32 -0
  165. data/lib/active_record/relation/merger.rb +16 -42
  166. data/lib/active_record/relation/predicate_builder.rb +120 -107
  167. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  168. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  169. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  170. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  171. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  172. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  173. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  174. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  175. data/lib/active_record/relation/query_attribute.rb +19 -0
  176. data/lib/active_record/relation/query_methods.rb +308 -244
  177. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  178. data/lib/active_record/relation/spawn_methods.rb +4 -7
  179. data/lib/active_record/relation/where_clause.rb +174 -0
  180. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  181. data/lib/active_record/result.rb +11 -4
  182. data/lib/active_record/runtime_registry.rb +1 -1
  183. data/lib/active_record/sanitization.rb +105 -66
  184. data/lib/active_record/schema.rb +26 -22
  185. data/lib/active_record/schema_dumper.rb +54 -37
  186. data/lib/active_record/schema_migration.rb +11 -14
  187. data/lib/active_record/scoping.rb +34 -16
  188. data/lib/active_record/scoping/default.rb +28 -10
  189. data/lib/active_record/scoping/named.rb +59 -26
  190. data/lib/active_record/secure_token.rb +38 -0
  191. data/lib/active_record/serialization.rb +3 -5
  192. data/lib/active_record/statement_cache.rb +17 -15
  193. data/lib/active_record/store.rb +8 -3
  194. data/lib/active_record/suppressor.rb +58 -0
  195. data/lib/active_record/table_metadata.rb +69 -0
  196. data/lib/active_record/tasks/database_tasks.rb +66 -49
  197. data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
  198. data/lib/active_record/tasks/postgresql_database_tasks.rb +12 -3
  199. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  200. data/lib/active_record/timestamp.rb +20 -9
  201. data/lib/active_record/touch_later.rb +63 -0
  202. data/lib/active_record/transactions.rb +139 -57
  203. data/lib/active_record/type.rb +66 -17
  204. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  205. data/lib/active_record/type/date.rb +2 -45
  206. data/lib/active_record/type/date_time.rb +2 -49
  207. data/lib/active_record/type/internal/abstract_json.rb +33 -0
  208. data/lib/active_record/type/internal/timezone.rb +15 -0
  209. data/lib/active_record/type/serialized.rb +15 -14
  210. data/lib/active_record/type/time.rb +10 -16
  211. data/lib/active_record/type/type_map.rb +4 -4
  212. data/lib/active_record/type_caster.rb +7 -0
  213. data/lib/active_record/type_caster/connection.rb +29 -0
  214. data/lib/active_record/type_caster/map.rb +19 -0
  215. data/lib/active_record/validations.rb +33 -32
  216. data/lib/active_record/validations/absence.rb +23 -0
  217. data/lib/active_record/validations/associated.rb +10 -3
  218. data/lib/active_record/validations/length.rb +24 -0
  219. data/lib/active_record/validations/presence.rb +11 -12
  220. data/lib/active_record/validations/uniqueness.rb +33 -33
  221. data/lib/rails/generators/active_record/migration.rb +15 -0
  222. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -5
  223. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  224. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
  225. data/lib/rails/generators/active_record/model/model_generator.rb +33 -16
  226. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  227. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  228. metadata +58 -34
  229. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  230. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  231. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  232. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  233. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  234. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  235. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  236. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  237. data/lib/active_record/type/big_integer.rb +0 -13
  238. data/lib/active_record/type/binary.rb +0 -50
  239. data/lib/active_record/type/boolean.rb +0 -31
  240. data/lib/active_record/type/decimal.rb +0 -64
  241. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  242. data/lib/active_record/type/decorator.rb +0 -14
  243. data/lib/active_record/type/float.rb +0 -19
  244. data/lib/active_record/type/integer.rb +0 -59
  245. data/lib/active_record/type/mutable.rb +0 -16
  246. data/lib/active_record/type/numeric.rb +0 -36
  247. data/lib/active_record/type/string.rb +0 -40
  248. data/lib/active_record/type/text.rb +0 -11
  249. data/lib/active_record/type/time_value.rb +0 -38
  250. data/lib/active_record/type/unsigned_integer.rb +0 -15
  251. data/lib/active_record/type/value.rb +0 -110
@@ -2,19 +2,41 @@ module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  # PostgreSQL-specific extensions to column definitions in a table.
4
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
5
+ delegate :array, :oid, :fmod, to: :sql_type_metadata
6
+ alias :array? :array
7
+
8
+ def initialize(*, max_identifier_length: 63, **)
9
+ super
10
+ @max_identifier_length = max_identifier_length
11
+ end
15
12
 
16
- @default_function = default_function
13
+ def serial?
14
+ return unless default_function
15
+
16
+ if %r{\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z} =~ default_function
17
+ sequence_name_from_parts(table_name, name, suffix) == sequence_name
18
+ end
17
19
  end
20
+
21
+ protected
22
+ attr_reader :max_identifier_length
23
+
24
+ private
25
+ def sequence_name_from_parts(table_name, column_name, suffix)
26
+ over_length = [table_name, column_name, suffix].map(&:length).sum + 2 - max_identifier_length
27
+
28
+ if over_length > 0
29
+ column_name_length = [(max_identifier_length - suffix.length - 2) / 2, column_name.length].min
30
+ over_length -= column_name.length - column_name_length
31
+ column_name = column_name[0, column_name_length - [over_length, 0].min]
32
+ end
33
+
34
+ if over_length > 0
35
+ table_name = table_name[0, table_name.length - over_length]
36
+ end
37
+
38
+ "#{table_name}_#{column_name}_#{suffix}"
39
+ end
18
40
  end
19
41
  end
20
42
  end
@@ -4,44 +4,7 @@ module ActiveRecord
4
4
  module DatabaseStatements
5
5
  def explain(arel, binds = [])
6
6
  sql = "EXPLAIN #{to_sql(arel, binds)}"
7
- ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', binds))
8
- end
9
-
10
- class ExplainPrettyPrinter # :nodoc:
11
- # Pretty prints the result of a EXPLAIN in a way that resembles the output of the
12
- # PostgreSQL shell:
13
- #
14
- # QUERY PLAN
15
- # ------------------------------------------------------------------------------
16
- # Nested Loop Left Join (cost=0.00..37.24 rows=8 width=0)
17
- # Join Filter: (posts.user_id = users.id)
18
- # -> Index Scan using users_pkey on users (cost=0.00..8.27 rows=1 width=4)
19
- # Index Cond: (id = 1)
20
- # -> Seq Scan on posts (cost=0.00..28.88 rows=8 width=4)
21
- # Filter: (posts.user_id = 1)
22
- # (6 rows)
23
- #
24
- def pp(result)
25
- header = result.columns.first
26
- lines = result.rows.map(&:first)
27
-
28
- # We add 2 because there's one char of padding at both sides, note
29
- # the extra hyphens in the example above.
30
- width = [header, *lines].map(&:length).max + 2
31
-
32
- pp = []
33
-
34
- pp << header.center(width).rstrip
35
- pp << '-' * width
36
-
37
- pp += lines.map {|line| " #{line}"}
38
-
39
- nrows = result.rows.length
40
- rows_label = nrows == 1 ? 'row' : 'rows'
41
- pp << "(#{nrows} #{rows_label})"
42
-
43
- pp.join("\n") + "\n"
44
- end
7
+ PostgreSQL::ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', binds))
45
8
  end
46
9
 
47
10
  def select_value(arel, name = nil, binds = [])
@@ -52,8 +15,8 @@ module ActiveRecord
52
15
  end
53
16
  end
54
17
 
55
- def select_values(arel, name = nil)
56
- arel, binds = binds_from_relation arel, []
18
+ def select_values(arel, name = nil, binds = [])
19
+ arel, binds = binds_from_relation arel, binds
57
20
  sql = to_sql(arel, binds)
58
21
  execute_and_clear(sql, name, binds) do |result|
59
22
  if result.nfields > 0
@@ -72,28 +35,6 @@ module ActiveRecord
72
35
  end
73
36
  end
74
37
 
75
- # Executes an INSERT query and returns the new record's ID
76
- def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
77
- unless pk
78
- # Extract the table from the insert sql. Yuck.
79
- table_ref = extract_table_ref_from_insert_sql(sql)
80
- pk = primary_key(table_ref) if table_ref
81
- end
82
-
83
- if pk && use_insert_returning?
84
- select_value("#{sql} RETURNING #{quote_column_name(pk)}")
85
- elsif pk
86
- super
87
- last_insert_id_value(sequence_name || default_sequence_name(table_ref, pk))
88
- else
89
- super
90
- end
91
- end
92
-
93
- def create
94
- super.insert
95
- end
96
-
97
38
  # The internal PostgreSQL identifier of the money data type.
98
39
  MONEY_COLUMN_TYPE_OID = 790 #:nodoc:
99
40
  # The internal PostgreSQL identifier of the BYTEA data type.
@@ -150,14 +91,16 @@ module ActiveRecord
150
91
 
151
92
  # Executes an SQL statement, returning a PGresult object on success
152
93
  # or raising a PGError exception otherwise.
94
+ # Note: the PGresult object is manually memory managed; if you don't
95
+ # need it specifically, you many want consider the exec_query wrapper.
153
96
  def execute(sql, name = nil)
154
97
  log(sql, name) do
155
98
  @connection.async_exec(sql)
156
99
  end
157
100
  end
158
101
 
159
- def exec_query(sql, name = 'SQL', binds = [])
160
- execute_and_clear(sql, name, binds) do |result|
102
+ def exec_query(sql, name = 'SQL', binds = [], prepare: false)
103
+ execute_and_clear(sql, name, binds, prepare: prepare) do |result|
161
104
  types = {}
162
105
  fields = result.fields
163
106
  fields.each_with_index do |fname, i|
@@ -174,18 +117,20 @@ module ActiveRecord
174
117
  end
175
118
  alias :exec_update :exec_delete
176
119
 
177
- def sql_for_insert(sql, pk, id_value, sequence_name, binds)
178
- unless pk
120
+ def sql_for_insert(sql, pk, id_value, sequence_name, binds) # :nodoc:
121
+ if pk.nil?
179
122
  # Extract the table from the insert sql. Yuck.
180
123
  table_ref = extract_table_ref_from_insert_sql(sql)
181
124
  pk = primary_key(table_ref) if table_ref
182
125
  end
183
126
 
127
+ pk = suppress_composite_primary_key(pk)
128
+
184
129
  if pk && use_insert_returning?
185
130
  sql = "#{sql} RETURNING #{quote_column_name(pk)}"
186
131
  end
187
132
 
188
- [sql, binds]
133
+ super
189
134
  end
190
135
 
191
136
  def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
@@ -202,11 +147,6 @@ module ActiveRecord
202
147
  end
203
148
  end
204
149
 
205
- # Executes an UPDATE query and returns the number of affected tuples.
206
- def update_sql(sql, name = nil)
207
- super.cmd_tuples
208
- end
209
-
210
150
  # Begins a transaction.
211
151
  def begin_db_transaction
212
152
  execute "BEGIN"
@@ -226,6 +166,12 @@ module ActiveRecord
226
166
  def exec_rollback_db_transaction
227
167
  execute "ROLLBACK"
228
168
  end
169
+
170
+ private
171
+
172
+ def suppress_composite_primary_key(pk)
173
+ pk unless pk.is_a?(Array)
174
+ end
229
175
  end
230
176
  end
231
177
  end
@@ -0,0 +1,42 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ class ExplainPrettyPrinter # :nodoc:
5
+ # Pretty prints the result of an EXPLAIN in a way that resembles the output of the
6
+ # PostgreSQL shell:
7
+ #
8
+ # QUERY PLAN
9
+ # ------------------------------------------------------------------------------
10
+ # Nested Loop Left Join (cost=0.00..37.24 rows=8 width=0)
11
+ # Join Filter: (posts.user_id = users.id)
12
+ # -> Index Scan using users_pkey on users (cost=0.00..8.27 rows=1 width=4)
13
+ # Index Cond: (id = 1)
14
+ # -> Seq Scan on posts (cost=0.00..28.88 rows=8 width=4)
15
+ # Filter: (posts.user_id = 1)
16
+ # (6 rows)
17
+ #
18
+ def pp(result)
19
+ header = result.columns.first
20
+ lines = result.rows.map(&:first)
21
+
22
+ # We add 2 because there's one char of padding at both sides, note
23
+ # the extra hyphens in the example above.
24
+ width = [header, *lines].map(&:length).max + 2
25
+
26
+ pp = []
27
+
28
+ pp << header.center(width).rstrip
29
+ pp << '-' * width
30
+
31
+ pp += lines.map {|line| " #{line}"}
32
+
33
+ nrows = result.rows.length
34
+ rows_label = nrows == 1 ? 'row' : 'rows'
35
+ pp << "(#{nrows} #{rows_label})"
36
+
37
+ pp.join("\n") + "\n"
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,25 +1,20 @@
1
- require 'active_record/connection_adapters/postgresql/oid/infinity'
2
-
3
1
  require 'active_record/connection_adapters/postgresql/oid/array'
4
2
  require 'active_record/connection_adapters/postgresql/oid/bit'
5
3
  require 'active_record/connection_adapters/postgresql/oid/bit_varying'
6
4
  require 'active_record/connection_adapters/postgresql/oid/bytea'
7
5
  require 'active_record/connection_adapters/postgresql/oid/cidr'
8
- require 'active_record/connection_adapters/postgresql/oid/date'
9
6
  require 'active_record/connection_adapters/postgresql/oid/date_time'
10
7
  require 'active_record/connection_adapters/postgresql/oid/decimal'
11
8
  require 'active_record/connection_adapters/postgresql/oid/enum'
12
- require 'active_record/connection_adapters/postgresql/oid/float'
13
9
  require 'active_record/connection_adapters/postgresql/oid/hstore'
14
10
  require 'active_record/connection_adapters/postgresql/oid/inet'
15
- require 'active_record/connection_adapters/postgresql/oid/integer'
16
11
  require 'active_record/connection_adapters/postgresql/oid/json'
17
12
  require 'active_record/connection_adapters/postgresql/oid/jsonb'
18
13
  require 'active_record/connection_adapters/postgresql/oid/money'
19
14
  require 'active_record/connection_adapters/postgresql/oid/point'
15
+ require 'active_record/connection_adapters/postgresql/oid/rails_5_1_point'
20
16
  require 'active_record/connection_adapters/postgresql/oid/range'
21
17
  require 'active_record/connection_adapters/postgresql/oid/specialized_string'
22
- require 'active_record/connection_adapters/postgresql/oid/time'
23
18
  require 'active_record/connection_adapters/postgresql/oid/uuid'
24
19
  require 'active_record/connection_adapters/postgresql/oid/vector'
25
20
  require 'active_record/connection_adapters/postgresql/oid/xml'
@@ -3,51 +3,67 @@ module ActiveRecord
3
3
  module PostgreSQL
4
4
  module OID # :nodoc:
5
5
  class Array < Type::Value # :nodoc:
6
- include Type::Mutable
6
+ include Type::Helpers::Mutable
7
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
8
+ Data = Struct.new(:encoder, :values) # :nodoc:
19
9
 
20
10
  attr_reader :subtype, :delimiter
21
- delegate :type, :limit, to: :subtype
11
+ delegate :type, :user_input_in_time_zone, :limit, to: :subtype
22
12
 
23
13
  def initialize(subtype, delimiter = ',')
24
14
  @subtype = subtype
25
15
  @delimiter = delimiter
16
+
17
+ @pg_encoder = PG::TextEncoder::Array.new name: "#{type}[]", delimiter: delimiter
18
+ @pg_decoder = PG::TextDecoder::Array.new name: "#{type}[]", delimiter: delimiter
26
19
  end
27
20
 
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)
21
+ def deserialize(value)
22
+ case value
23
+ when ::String
24
+ type_cast_array(@pg_decoder.decode(value), :deserialize)
25
+ when Data
26
+ type_cast_array(value.values, :deserialize)
31
27
  else
32
28
  super
33
29
  end
34
30
  end
35
31
 
36
- def type_cast_from_user(value)
32
+ def cast(value)
37
33
  if value.is_a?(::String)
38
- value = parse_pg_array(value)
34
+ value = @pg_decoder.decode(value)
39
35
  end
40
- type_cast_array(value, :type_cast_from_user)
36
+ type_cast_array(value, :cast)
41
37
  end
42
38
 
43
- def type_cast_for_database(value)
39
+ def serialize(value)
44
40
  if value.is_a?(::Array)
45
- cast_value_for_database(value)
41
+ casted_values = type_cast_array(value, :serialize)
42
+ Data.new(@pg_encoder, casted_values)
46
43
  else
47
44
  super
48
45
  end
49
46
  end
50
47
 
48
+ def ==(other)
49
+ other.is_a?(Array) &&
50
+ subtype == other.subtype &&
51
+ delimiter == other.delimiter
52
+ end
53
+
54
+ def type_cast_for_schema(value)
55
+ return super unless value.is_a?(::Array)
56
+ "[" + value.map { |v| subtype.type_cast_for_schema(v) }.join(", ") + "]"
57
+ end
58
+
59
+ def map(value, &block)
60
+ value.map(&block)
61
+ end
62
+
63
+ def changed_in_place?(raw_old_value, new_value)
64
+ deserialize(raw_old_value) != new_value
65
+ end
66
+
51
67
  private
52
68
 
53
69
  def type_cast_array(value, method)
@@ -57,42 +73,6 @@ module ActiveRecord
57
73
  @subtype.public_send(method, value)
58
74
  end
59
75
  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
76
  end
97
77
  end
98
78
  end
@@ -7,7 +7,7 @@ module ActiveRecord
7
7
  :bit
8
8
  end
9
9
 
10
- def type_cast(value)
10
+ def cast_value(value)
11
11
  if ::String === value
12
12
  case value
13
13
  when /^0x/i
@@ -16,11 +16,11 @@ module ActiveRecord
16
16
  value # Bit-string notation
17
17
  end
18
18
  else
19
- value
19
+ value.to_s
20
20
  end
21
21
  end
22
22
 
23
- def type_cast_for_database(value)
23
+ def serialize(value)
24
24
  Data.new(super) if value
25
25
  end
26
26
 
@@ -3,10 +3,10 @@ module ActiveRecord
3
3
  module PostgreSQL
4
4
  module OID # :nodoc:
5
5
  class Bytea < Type::Binary # :nodoc:
6
- def type_cast_from_database(value)
6
+ def deserialize(value)
7
7
  return if value.nil?
8
8
  return value.to_s if value.is_a?(Type::Binary::Data)
9
- PGconn.unescape_bytea(super)
9
+ PG::Connection.unescape_bytea(super)
10
10
  end
11
11
  end
12
12
  end
@@ -1,3 +1,5 @@
1
+ require 'ipaddr'
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module PostgreSQL
@@ -18,7 +20,7 @@ module ActiveRecord
18
20
  end
19
21
  end
20
22
 
21
- def type_cast_for_database(value)
23
+ def serialize(value)
22
24
  if IPAddr === value
23
25
  "#{value}/#{value.instance_variable_get(:@mask_addr).to_s(2).count('1')}"
24
26
  else