activerecord 4.2.6 → 5.0.0

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 (246) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1307 -1105
  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/aggregations.rb +37 -23
  8. data/lib/active_record/association_relation.rb +3 -3
  9. data/lib/active_record/associations/alias_tracker.rb +19 -16
  10. data/lib/active_record/associations/association.rb +11 -9
  11. data/lib/active_record/associations/association_scope.rb +73 -102
  12. data/lib/active_record/associations/belongs_to_association.rb +21 -32
  13. data/lib/active_record/associations/builder/association.rb +28 -34
  14. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  15. data/lib/active_record/associations/builder/collection_association.rb +7 -19
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +14 -11
  17. data/lib/active_record/associations/builder/has_many.rb +4 -4
  18. data/lib/active_record/associations/builder/has_one.rb +11 -6
  19. data/lib/active_record/associations/builder/singular_association.rb +3 -10
  20. data/lib/active_record/associations/collection_association.rb +50 -31
  21. data/lib/active_record/associations/collection_proxy.rb +69 -29
  22. data/lib/active_record/associations/foreign_association.rb +1 -1
  23. data/lib/active_record/associations/has_many_association.rb +20 -71
  24. data/lib/active_record/associations/has_many_through_association.rb +8 -47
  25. data/lib/active_record/associations/has_one_association.rb +12 -5
  26. data/lib/active_record/associations/join_dependency/join_association.rb +20 -8
  27. data/lib/active_record/associations/join_dependency.rb +29 -19
  28. data/lib/active_record/associations/preloader/association.rb +46 -52
  29. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  30. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  31. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  32. data/lib/active_record/associations/preloader/through_association.rb +27 -14
  33. data/lib/active_record/associations/preloader.rb +14 -4
  34. data/lib/active_record/associations/singular_association.rb +7 -1
  35. data/lib/active_record/associations/through_association.rb +11 -3
  36. data/lib/active_record/associations.rb +317 -209
  37. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  38. data/lib/active_record/attribute.rb +68 -18
  39. data/lib/active_record/attribute_assignment.rb +20 -141
  40. data/lib/active_record/attribute_decorators.rb +6 -5
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  42. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  43. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  44. data/lib/active_record/attribute_methods/query.rb +2 -2
  45. data/lib/active_record/attribute_methods/read.rb +31 -59
  46. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
  48. data/lib/active_record/attribute_methods/write.rb +14 -38
  49. data/lib/active_record/attribute_methods.rb +70 -45
  50. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  51. data/lib/active_record/attribute_set/builder.rb +6 -4
  52. data/lib/active_record/attribute_set.rb +30 -3
  53. data/lib/active_record/attributes.rb +199 -80
  54. data/lib/active_record/autosave_association.rb +49 -16
  55. data/lib/active_record/base.rb +32 -23
  56. data/lib/active_record/callbacks.rb +39 -43
  57. data/lib/active_record/coders/json.rb +1 -1
  58. data/lib/active_record/coders/yaml_column.rb +20 -8
  59. data/lib/active_record/collection_cache_key.rb +40 -0
  60. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +452 -182
  61. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  62. data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -61
  63. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -2
  64. data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -9
  65. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  66. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  67. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -185
  68. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  69. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +378 -140
  70. data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
  71. data/lib/active_record/connection_adapters/abstract_adapter.rb +153 -59
  72. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +405 -362
  73. data/lib/active_record/connection_adapters/column.rb +28 -43
  74. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  75. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  76. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  77. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  78. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  79. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  80. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  81. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  82. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  83. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  84. data/lib/active_record/connection_adapters/mysql2_adapter.rb +25 -176
  85. data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
  86. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +10 -72
  87. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -56
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  95. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  96. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  97. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  98. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  100. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  101. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  102. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  103. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  104. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  105. data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
  106. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  107. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  108. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  109. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +234 -148
  110. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  111. data/lib/active_record/connection_adapters/postgresql_adapter.rb +248 -160
  112. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  113. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  114. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  115. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  116. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  117. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +148 -203
  118. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  119. data/lib/active_record/connection_handling.rb +37 -14
  120. data/lib/active_record/core.rb +89 -107
  121. data/lib/active_record/counter_cache.rb +13 -24
  122. data/lib/active_record/dynamic_matchers.rb +1 -20
  123. data/lib/active_record/enum.rb +113 -76
  124. data/lib/active_record/errors.rb +87 -48
  125. data/lib/active_record/explain_registry.rb +1 -1
  126. data/lib/active_record/explain_subscriber.rb +1 -1
  127. data/lib/active_record/fixture_set/file.rb +26 -5
  128. data/lib/active_record/fixtures.rb +76 -40
  129. data/lib/active_record/gem_version.rb +3 -3
  130. data/lib/active_record/inheritance.rb +32 -40
  131. data/lib/active_record/integration.rb +4 -4
  132. data/lib/active_record/internal_metadata.rb +56 -0
  133. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  134. data/lib/active_record/locale/en.yml +3 -2
  135. data/lib/active_record/locking/optimistic.rb +15 -15
  136. data/lib/active_record/locking/pessimistic.rb +1 -1
  137. data/lib/active_record/log_subscriber.rb +43 -21
  138. data/lib/active_record/migration/command_recorder.rb +59 -18
  139. data/lib/active_record/migration/compatibility.rb +126 -0
  140. data/lib/active_record/migration.rb +364 -109
  141. data/lib/active_record/model_schema.rb +128 -38
  142. data/lib/active_record/nested_attributes.rb +58 -29
  143. data/lib/active_record/null_relation.rb +16 -8
  144. data/lib/active_record/persistence.rb +121 -80
  145. data/lib/active_record/query_cache.rb +15 -18
  146. data/lib/active_record/querying.rb +10 -9
  147. data/lib/active_record/railtie.rb +27 -18
  148. data/lib/active_record/railties/controller_runtime.rb +1 -1
  149. data/lib/active_record/railties/databases.rake +58 -45
  150. data/lib/active_record/readonly_attributes.rb +1 -1
  151. data/lib/active_record/reflection.rb +282 -115
  152. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  153. data/lib/active_record/relation/batches.rb +139 -34
  154. data/lib/active_record/relation/calculations.rb +80 -102
  155. data/lib/active_record/relation/delegation.rb +7 -20
  156. data/lib/active_record/relation/finder_methods.rb +163 -81
  157. data/lib/active_record/relation/from_clause.rb +32 -0
  158. data/lib/active_record/relation/merger.rb +16 -42
  159. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -15
  160. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  161. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  162. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  163. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  164. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  165. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  166. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  167. data/lib/active_record/relation/predicate_builder.rb +120 -107
  168. data/lib/active_record/relation/query_attribute.rb +19 -0
  169. data/lib/active_record/relation/query_methods.rb +308 -244
  170. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  171. data/lib/active_record/relation/spawn_methods.rb +4 -7
  172. data/lib/active_record/relation/where_clause.rb +174 -0
  173. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  174. data/lib/active_record/relation.rb +176 -116
  175. data/lib/active_record/result.rb +4 -3
  176. data/lib/active_record/runtime_registry.rb +1 -1
  177. data/lib/active_record/sanitization.rb +95 -66
  178. data/lib/active_record/schema.rb +26 -22
  179. data/lib/active_record/schema_dumper.rb +62 -38
  180. data/lib/active_record/schema_migration.rb +11 -17
  181. data/lib/active_record/scoping/default.rb +23 -9
  182. data/lib/active_record/scoping/named.rb +49 -28
  183. data/lib/active_record/scoping.rb +32 -15
  184. data/lib/active_record/secure_token.rb +38 -0
  185. data/lib/active_record/serialization.rb +2 -4
  186. data/lib/active_record/statement_cache.rb +16 -14
  187. data/lib/active_record/store.rb +8 -3
  188. data/lib/active_record/suppressor.rb +58 -0
  189. data/lib/active_record/table_metadata.rb +68 -0
  190. data/lib/active_record/tasks/database_tasks.rb +58 -41
  191. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -20
  192. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
  193. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  194. data/lib/active_record/timestamp.rb +20 -9
  195. data/lib/active_record/touch_later.rb +58 -0
  196. data/lib/active_record/transactions.rb +138 -56
  197. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  198. data/lib/active_record/type/date.rb +2 -41
  199. data/lib/active_record/type/date_time.rb +2 -49
  200. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  201. data/lib/active_record/type/internal/timezone.rb +15 -0
  202. data/lib/active_record/type/serialized.rb +15 -14
  203. data/lib/active_record/type/time.rb +10 -16
  204. data/lib/active_record/type/type_map.rb +4 -4
  205. data/lib/active_record/type.rb +66 -17
  206. data/lib/active_record/type_caster/connection.rb +29 -0
  207. data/lib/active_record/type_caster/map.rb +19 -0
  208. data/lib/active_record/type_caster.rb +7 -0
  209. data/lib/active_record/validations/absence.rb +23 -0
  210. data/lib/active_record/validations/associated.rb +10 -3
  211. data/lib/active_record/validations/length.rb +24 -0
  212. data/lib/active_record/validations/presence.rb +11 -12
  213. data/lib/active_record/validations/uniqueness.rb +30 -29
  214. data/lib/active_record/validations.rb +33 -32
  215. data/lib/active_record.rb +7 -2
  216. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  217. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  218. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
  219. data/lib/rails/generators/active_record/migration.rb +7 -0
  220. data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
  221. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  222. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  223. metadata +58 -34
  224. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  225. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  226. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  227. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  228. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  229. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  230. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  231. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  232. data/lib/active_record/type/big_integer.rb +0 -13
  233. data/lib/active_record/type/binary.rb +0 -50
  234. data/lib/active_record/type/boolean.rb +0 -31
  235. data/lib/active_record/type/decimal.rb +0 -50
  236. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  237. data/lib/active_record/type/decorator.rb +0 -14
  238. data/lib/active_record/type/float.rb +0 -19
  239. data/lib/active_record/type/integer.rb +0 -59
  240. data/lib/active_record/type/mutable.rb +0 -16
  241. data/lib/active_record/type/numeric.rb +0 -36
  242. data/lib/active_record/type/string.rb +0 -40
  243. data/lib/active_record/type/text.rb +0 -11
  244. data/lib/active_record/type/time_value.rb +0 -38
  245. data/lib/active_record/type/unsigned_integer.rb +0 -15
  246. data/lib/active_record/type/value.rb +0 -105
@@ -1,31 +1,23 @@
1
- require 'active_record/connection_adapters/abstract_adapter'
2
- require 'active_record/connection_adapters/statement_pool'
3
-
4
- require 'active_record/connection_adapters/postgresql/utils'
5
- require 'active_record/connection_adapters/postgresql/column'
6
- require 'active_record/connection_adapters/postgresql/oid'
7
- require 'active_record/connection_adapters/postgresql/quoting'
8
- require 'active_record/connection_adapters/postgresql/referential_integrity'
9
- require 'active_record/connection_adapters/postgresql/schema_definitions'
10
- require 'active_record/connection_adapters/postgresql/schema_statements'
11
- require 'active_record/connection_adapters/postgresql/database_statements'
12
-
13
- require 'arel/visitors/bind_visitor'
14
-
15
- # Make sure we're using pg high enough for PGResult#values
16
- gem 'pg', '~> 0.15'
1
+ # Make sure we're using pg high enough for type casts and Ruby 2.2+ compatibility
2
+ gem 'pg', '~> 0.18'
17
3
  require 'pg'
18
4
 
19
- require 'ipaddr'
5
+ require "active_record/connection_adapters/abstract_adapter"
6
+ require "active_record/connection_adapters/postgresql/column"
7
+ require "active_record/connection_adapters/postgresql/database_statements"
8
+ require "active_record/connection_adapters/postgresql/explain_pretty_printer"
9
+ require "active_record/connection_adapters/postgresql/oid"
10
+ require "active_record/connection_adapters/postgresql/quoting"
11
+ require "active_record/connection_adapters/postgresql/referential_integrity"
12
+ require "active_record/connection_adapters/postgresql/schema_definitions"
13
+ require "active_record/connection_adapters/postgresql/schema_dumper"
14
+ require "active_record/connection_adapters/postgresql/schema_statements"
15
+ require "active_record/connection_adapters/postgresql/type_metadata"
16
+ require "active_record/connection_adapters/postgresql/utils"
17
+ require "active_record/connection_adapters/statement_pool"
20
18
 
21
19
  module ActiveRecord
22
20
  module ConnectionHandling # :nodoc:
23
- VALID_CONN_PARAMS = [:host, :hostaddr, :port, :dbname, :user, :password, :connect_timeout,
24
- :client_encoding, :options, :application_name, :fallback_application_name,
25
- :keepalives, :keepalives_idle, :keepalives_interval, :keepalives_count,
26
- :tty, :sslmode, :requiressl, :sslcompression, :sslcert, :sslkey,
27
- :sslrootcert, :sslcrl, :requirepeer, :krbsrvname, :gsslib, :service]
28
-
29
21
  # Establishes a connection to the database that's used by all Active Record objects
30
22
  def postgresql_connection(config)
31
23
  conn_params = config.symbolize_keys
@@ -37,7 +29,8 @@ module ActiveRecord
37
29
  conn_params[:dbname] = conn_params.delete(:database) if conn_params[:database]
38
30
 
39
31
  # Forward only valid config params to PGconn.connect.
40
- conn_params.keep_if { |k, _| VALID_CONN_PARAMS.include?(k) }
32
+ valid_conn_param_keys = PGconn.conndefaults_hash.keys + [:requiressl]
33
+ conn_params.slice!(*valid_conn_param_keys)
41
34
 
42
35
  # The postgres drivers don't allow the creation of an unconnected PGconn object,
43
36
  # so just pass a nil connection object for the time being.
@@ -68,17 +61,16 @@ module ActiveRecord
68
61
  # defaults to true.
69
62
  #
70
63
  # Any further options are used as connection parameters to libpq. See
71
- # http://www.postgresql.org/docs/9.1/static/libpq-connect.html for the
64
+ # http://www.postgresql.org/docs/current/static/libpq-connect.html for the
72
65
  # list of parameters.
73
66
  #
74
67
  # In addition, default connection parameters of libpq can be set per environment variables.
75
- # See http://www.postgresql.org/docs/9.1/static/libpq-envars.html .
68
+ # See http://www.postgresql.org/docs/current/static/libpq-envars.html .
76
69
  class PostgreSQLAdapter < AbstractAdapter
77
70
  ADAPTER_NAME = 'PostgreSQL'.freeze
78
71
 
79
72
  NATIVE_DATABASE_TYPES = {
80
73
  primary_key: "serial primary key",
81
- bigserial: "bigserial",
82
74
  string: { name: "character varying" },
83
75
  text: { name: "text" },
84
76
  integer: { name: "integer" },
@@ -95,7 +87,6 @@ module ActiveRecord
95
87
  int8range: { name: "int8range" },
96
88
  binary: { name: "bytea" },
97
89
  boolean: { name: "boolean" },
98
- bigint: { name: "bigint" },
99
90
  xml: { name: "xml" },
100
91
  tsvector: { name: "tsvector" },
101
92
  hstore: { name: "hstore" },
@@ -108,6 +99,12 @@ module ActiveRecord
108
99
  ltree: { name: "ltree" },
109
100
  citext: { name: "citext" },
110
101
  point: { name: "point" },
102
+ line: { name: "line" },
103
+ lseg: { name: "lseg" },
104
+ box: { name: "box" },
105
+ path: { name: "path" },
106
+ polygon: { name: "polygon" },
107
+ circle: { name: "circle" },
111
108
  bit: { name: "bit" },
112
109
  bit_varying: { name: "bit varying" },
113
110
  money: { name: "money" },
@@ -119,27 +116,17 @@ module ActiveRecord
119
116
  include PostgreSQL::ReferentialIntegrity
120
117
  include PostgreSQL::SchemaStatements
121
118
  include PostgreSQL::DatabaseStatements
122
- include Savepoints
119
+ include PostgreSQL::ColumnDumper
123
120
 
124
121
  def schema_creation # :nodoc:
125
122
  PostgreSQL::SchemaCreation.new self
126
123
  end
127
124
 
128
- # Adds +:array+ option to the default set provided by the
129
- # AbstractAdapter
130
- def prepare_column_options(column, types) # :nodoc:
131
- spec = super
132
- spec[:array] = 'true' if column.respond_to?(:array) && column.array
133
- spec[:default] = "\"#{column.default_function}\"" if column.default_function
134
- spec
135
- end
136
-
137
- # Adds +:array+ as a valid migration key
138
- def migration_keys
139
- super + [:array]
125
+ def arel_visitor # :nodoc:
126
+ Arel::Visitors::PostgreSQL.new(self)
140
127
  end
141
128
 
142
- # Returns +true+, since this connection adapter supports prepared statement
129
+ # Returns true, since this connection adapter supports prepared statement
143
130
  # caching.
144
131
  def supports_statement_cache?
145
132
  true
@@ -153,6 +140,10 @@ module ActiveRecord
153
140
  true
154
141
  end
155
142
 
143
+ def supports_expression_index?
144
+ true
145
+ end
146
+
156
147
  def supports_transaction_isolation?
157
148
  true
158
149
  end
@@ -165,52 +156,43 @@ module ActiveRecord
165
156
  true
166
157
  end
167
158
 
159
+ def supports_datetime_with_precision?
160
+ true
161
+ end
162
+
163
+ def supports_json?
164
+ postgresql_version >= 90200
165
+ end
166
+
167
+ def supports_comments?
168
+ true
169
+ end
170
+
171
+ def supports_savepoints?
172
+ true
173
+ end
174
+
168
175
  def index_algorithms
169
176
  { concurrently: 'CONCURRENTLY' }
170
177
  end
171
178
 
172
179
  class StatementPool < ConnectionAdapters::StatementPool
173
180
  def initialize(connection, max)
174
- super
181
+ super(max)
182
+ @connection = connection
175
183
  @counter = 0
176
- @cache = Hash.new { |h,pid| h[pid] = {} }
177
184
  end
178
185
 
179
- def each(&block); cache.each(&block); end
180
- def key?(key); cache.key?(key); end
181
- def [](key); cache[key]; end
182
- def length; cache.length; end
183
-
184
186
  def next_key
185
187
  "a#{@counter + 1}"
186
188
  end
187
189
 
188
190
  def []=(sql, key)
189
- while @max <= cache.size
190
- dealloc(cache.shift.last)
191
- end
192
- @counter += 1
193
- cache[sql] = key
194
- end
195
-
196
- def clear
197
- cache.each_value do |stmt_key|
198
- dealloc stmt_key
199
- end
200
- cache.clear
201
- end
202
-
203
- def delete(sql_key)
204
- dealloc cache[sql_key]
205
- cache.delete sql_key
191
+ super.tap { @counter += 1 }
206
192
  end
207
193
 
208
194
  private
209
195
 
210
- def cache
211
- @cache[Process.pid]
212
- end
213
-
214
196
  def dealloc(key)
215
197
  @connection.query "DEALLOCATE #{key}" if connection_active?
216
198
  end
@@ -224,29 +206,25 @@ module ActiveRecord
224
206
 
225
207
  # Initializes and connects a PostgreSQL adapter.
226
208
  def initialize(connection, logger, connection_parameters, config)
227
- super(connection, logger)
209
+ super(connection, logger, config)
228
210
 
229
- @visitor = Arel::Visitors::PostgreSQL.new self
230
- if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
231
- @prepared_statements = true
232
- else
233
- @prepared_statements = false
234
- end
235
-
236
- @connection_parameters, @config = connection_parameters, config
211
+ @connection_parameters = connection_parameters
237
212
 
238
213
  # @local_tz is initialized as nil to avoid warnings when connect tries to use it
239
214
  @local_tz = nil
240
215
  @table_alias_length = nil
241
216
 
242
217
  connect
218
+ add_pg_encoders
243
219
  @statements = StatementPool.new @connection,
244
- self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 })
220
+ self.class.type_cast_config_to_integer(config[:statement_limit])
245
221
 
246
- if postgresql_version < 80200
247
- raise "Your version of PostgreSQL (#{postgresql_version}) is too old, please upgrade!"
222
+ if postgresql_version < 90100
223
+ raise "Your version of PostgreSQL (#{postgresql_version}) is too old. Active Record supports PostgreSQL >= 9.1."
248
224
  end
249
225
 
226
+ add_pg_decoders
227
+
250
228
  @type_map = Type::HashLookupTypeMap.new
251
229
  initialize_type_map(type_map)
252
230
  @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
@@ -316,13 +294,16 @@ module ActiveRecord
316
294
  true
317
295
  end
318
296
 
297
+ def supports_advisory_locks?
298
+ true
299
+ end
300
+
319
301
  def supports_explain?
320
302
  true
321
303
  end
322
304
 
323
- # Returns true if pg > 9.1
324
305
  def supports_extensions?
325
- postgresql_version >= 90100
306
+ true
326
307
  end
327
308
 
328
309
  # Range datatypes weren't introduced until PostgreSQL 9.2
@@ -334,6 +315,20 @@ module ActiveRecord
334
315
  postgresql_version >= 90300
335
316
  end
336
317
 
318
+ def get_advisory_lock(lock_id) # :nodoc:
319
+ unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
320
+ raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
321
+ end
322
+ select_value("SELECT pg_try_advisory_lock(#{lock_id});")
323
+ end
324
+
325
+ def release_advisory_lock(lock_id) # :nodoc:
326
+ unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
327
+ raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
328
+ end
329
+ select_value("SELECT pg_advisory_unlock(#{lock_id})")
330
+ end
331
+
337
332
  def enable_extension(name)
338
333
  exec_query("CREATE EXTENSION IF NOT EXISTS \"#{name}\"").tap {
339
334
  reload_type_map
@@ -400,14 +395,15 @@ module ActiveRecord
400
395
  "average" => "avg",
401
396
  }
402
397
 
403
- protected
398
+ # Returns the version of the connected PostgreSQL server.
399
+ def postgresql_version
400
+ @connection.server_version
401
+ end
404
402
 
405
- # Returns the version of the connected PostgreSQL server.
406
- def postgresql_version
407
- @connection.server_version
408
- end
403
+ protected
409
404
 
410
- # See http://www.postgresql.org/docs/9.1/static/errcodes-appendix.html
405
+ # See http://www.postgresql.org/docs/current/static/errcodes-appendix.html
406
+ VALUE_LIMIT_VIOLATION = "22001"
411
407
  FOREIGN_KEY_VIOLATION = "23503"
412
408
  UNIQUE_VIOLATION = "23505"
413
409
 
@@ -416,9 +412,11 @@ module ActiveRecord
416
412
 
417
413
  case exception.result.try(:error_field, PGresult::PG_DIAG_SQLSTATE)
418
414
  when UNIQUE_VIOLATION
419
- RecordNotUnique.new(message, exception)
415
+ RecordNotUnique.new(message)
420
416
  when FOREIGN_KEY_VIOLATION
421
- InvalidForeignKey.new(message, exception)
417
+ InvalidForeignKey.new(message)
418
+ when VALUE_LIMIT_VIOLATION
419
+ ValueTooLong.new(message)
422
420
  else
423
421
  super
424
422
  end
@@ -440,11 +438,11 @@ module ActiveRecord
440
438
  end
441
439
 
442
440
  def initialize_type_map(m) # :nodoc:
443
- register_class_with_limit m, 'int2', OID::Integer
444
- register_class_with_limit m, 'int4', OID::Integer
445
- register_class_with_limit m, 'int8', OID::Integer
441
+ register_class_with_limit m, 'int2', Type::Integer
442
+ register_class_with_limit m, 'int4', Type::Integer
443
+ register_class_with_limit m, 'int8', Type::Integer
446
444
  m.alias_type 'oid', 'int2'
447
- m.register_type 'float4', OID::Float.new
445
+ m.register_type 'float4', Type::Float.new
448
446
  m.alias_type 'float8', 'float4'
449
447
  m.register_type 'text', Type::Text.new
450
448
  register_class_with_limit m, 'varchar', Type::String
@@ -455,8 +453,7 @@ module ActiveRecord
455
453
  register_class_with_limit m, 'bit', OID::Bit
456
454
  register_class_with_limit m, 'varbit', OID::BitVarying
457
455
  m.alias_type 'timestamptz', 'timestamp'
458
- m.register_type 'date', OID::Date.new
459
- m.register_type 'time', OID::Time.new
456
+ m.register_type 'date', Type::Date.new
460
457
 
461
458
  m.register_type 'money', OID::Money.new
462
459
  m.register_type 'bytea', OID::Bytea.new
@@ -472,20 +469,18 @@ module ActiveRecord
472
469
  m.register_type 'macaddr', OID::SpecializedString.new(:macaddr)
473
470
  m.register_type 'citext', OID::SpecializedString.new(:citext)
474
471
  m.register_type 'ltree', OID::SpecializedString.new(:ltree)
472
+ m.register_type 'line', OID::SpecializedString.new(:line)
473
+ m.register_type 'lseg', OID::SpecializedString.new(:lseg)
474
+ m.register_type 'box', OID::SpecializedString.new(:box)
475
+ m.register_type 'path', OID::SpecializedString.new(:path)
476
+ m.register_type 'polygon', OID::SpecializedString.new(:polygon)
477
+ m.register_type 'circle', OID::SpecializedString.new(:circle)
475
478
 
476
479
  # FIXME: why are we keeping these types as strings?
477
480
  m.alias_type 'interval', 'varchar'
478
- m.alias_type 'path', 'varchar'
479
- m.alias_type 'line', 'varchar'
480
- m.alias_type 'polygon', 'varchar'
481
- m.alias_type 'circle', 'varchar'
482
- m.alias_type 'lseg', 'varchar'
483
- m.alias_type 'box', 'varchar'
484
-
485
- m.register_type 'timestamp' do |_, _, sql_type|
486
- precision = extract_precision(sql_type)
487
- OID::DateTime.new(precision: precision)
488
- end
481
+
482
+ register_class_with_precision m, 'time', Type::Time
483
+ register_class_with_precision m, 'timestamp', OID::DateTime
489
484
 
490
485
  m.register_type 'numeric' do |_, fmod, sql_type|
491
486
  precision = extract_precision(sql_type)
@@ -522,13 +517,18 @@ module ActiveRecord
522
517
  end
523
518
 
524
519
  # Extracts the value from a PostgreSQL column default definition.
525
- def extract_value_from_default(oid, default) # :nodoc:
520
+ def extract_value_from_default(default) # :nodoc:
526
521
  case default
527
522
  # Quoted types
528
- when /\A[\(B]?'(.*)'::/m
529
- $1.gsub(/''/, "'")
523
+ when /\A[\(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m
524
+ # The default 'now'::date is CURRENT_DATE
525
+ if $1 == "now".freeze && $2 == "date".freeze
526
+ nil
527
+ else
528
+ $1.gsub("''".freeze, "'".freeze)
529
+ end
530
530
  # Boolean types
531
- when 'true', 'false'
531
+ when 'true'.freeze, 'false'.freeze
532
532
  default
533
533
  # Numeric types
534
534
  when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/
@@ -548,7 +548,7 @@ module ActiveRecord
548
548
  end
549
549
 
550
550
  def has_default_function?(default_value, default) # :nodoc:
551
- !default_value && (%r{\w+\(.*\)} === default)
551
+ !default_value && (%r{\w+\(.*\)|\(.*\)::\w+} === default)
552
552
  end
553
553
 
554
554
  def load_additional_types(type_map, oids = nil) # :nodoc:
@@ -580,47 +580,67 @@ module ActiveRecord
580
580
 
581
581
  FEATURE_NOT_SUPPORTED = "0A000" #:nodoc:
582
582
 
583
- def execute_and_clear(sql, name, binds)
584
- result = without_prepared_statement?(binds) ? exec_no_cache(sql, name, binds) :
585
- exec_cache(sql, name, binds)
583
+ def execute_and_clear(sql, name, binds, prepare: false)
584
+ if without_prepared_statement?(binds)
585
+ result = exec_no_cache(sql, name, [])
586
+ elsif !prepare
587
+ result = exec_no_cache(sql, name, binds)
588
+ else
589
+ result = exec_cache(sql, name, binds)
590
+ end
586
591
  ret = yield result
587
592
  result.clear
588
593
  ret
589
594
  end
590
595
 
591
596
  def exec_no_cache(sql, name, binds)
592
- log(sql, name, binds) { @connection.async_exec(sql, []) }
597
+ type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
598
+ log(sql, name, binds) { @connection.async_exec(sql, type_casted_binds) }
593
599
  end
594
600
 
595
601
  def exec_cache(sql, name, binds)
596
602
  stmt_key = prepare_statement(sql)
597
- type_casted_binds = binds.map { |col, val|
598
- [col, type_cast(val, col)]
599
- }
603
+ type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
600
604
 
601
- log(sql, name, type_casted_binds, stmt_key) do
602
- @connection.exec_prepared(stmt_key, type_casted_binds.map { |_, val| val })
605
+ log(sql, name, binds, stmt_key) do
606
+ @connection.exec_prepared(stmt_key, type_casted_binds)
603
607
  end
604
608
  rescue ActiveRecord::StatementInvalid => e
605
- pgerror = e.original_exception
606
-
607
- # Get the PG code for the failure. Annoyingly, the code for
608
- # prepared statements whose return value may have changed is
609
- # FEATURE_NOT_SUPPORTED. Check here for more details:
610
- # http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
611
- begin
612
- code = pgerror.result.result_error_field(PGresult::PG_DIAG_SQLSTATE)
613
- rescue
614
- raise e
615
- end
616
- if FEATURE_NOT_SUPPORTED == code
609
+ raise unless is_cached_plan_failure?(e)
610
+
611
+ # Nothing we can do if we are in a transaction because all commands
612
+ # will raise InFailedSQLTransaction
613
+ if in_transaction?
614
+ raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message)
615
+ else
616
+ # outside of transactions we can simply flush this query and retry
617
617
  @statements.delete sql_key(sql)
618
618
  retry
619
- else
620
- raise e
621
619
  end
622
620
  end
623
621
 
622
+ # Annoyingly, the code for prepared statements whose return value may
623
+ # have changed is FEATURE_NOT_SUPPORTED.
624
+ #
625
+ # This covers various different error types so we need to do additional
626
+ # work to classify the exception definitively as a
627
+ # ActiveRecord::PreparedStatementCacheExpired
628
+ #
629
+ # Check here for more details:
630
+ # http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
631
+ CACHED_PLAN_HEURISTIC = 'cached plan must not change result type'.freeze
632
+ def is_cached_plan_failure?(e)
633
+ pgerror = e.cause
634
+ code = pgerror.result.result_error_field(PGresult::PG_DIAG_SQLSTATE)
635
+ code == FEATURE_NOT_SUPPORTED && pgerror.message.include?(CACHED_PLAN_HEURISTIC)
636
+ rescue
637
+ false
638
+ end
639
+
640
+ def in_transaction?
641
+ open_transactions > 0
642
+ end
643
+
624
644
  # Returns the statement identifier for the client side cache
625
645
  # of statements
626
646
  def sql_key(sql)
@@ -649,16 +669,10 @@ module ActiveRecord
649
669
  # connected server's characteristics.
650
670
  def connect
651
671
  @connection = PGconn.connect(@connection_parameters)
652
-
653
- # Money type has a fixed precision of 10 in PostgreSQL 8.2 and below, and as of
654
- # PostgreSQL 8.3 it has a fixed precision of 19. PostgreSQLColumn.extract_precision
655
- # should know about this but can't detect it there, so deal with it here.
656
- OID::Money.precision = (postgresql_version >= 80300) ? 19 : 10
657
-
658
672
  configure_connection
659
673
  rescue ::PG::Error => error
660
674
  if error.message.include?("does not exist")
661
- raise ActiveRecord::NoDatabaseError.new(error.message, error)
675
+ raise ActiveRecord::NoDatabaseError
662
676
  else
663
677
  raise
664
678
  end
@@ -686,7 +700,7 @@ module ActiveRecord
686
700
  end
687
701
 
688
702
  # SET statements from :variables config hash
689
- # http://www.postgresql.org/docs/8.3/static/sql-set.html
703
+ # http://www.postgresql.org/docs/current/static/sql-set.html
690
704
  variables = @config[:variables] || {}
691
705
  variables.map do |k, v|
692
706
  if v == ':default' || v == :default
@@ -699,22 +713,14 @@ module ActiveRecord
699
713
  end
700
714
 
701
715
  # Returns the current ID of a table's sequence.
702
- def last_insert_id(sequence_name) #:nodoc:
703
- Integer(last_insert_id_value(sequence_name))
704
- end
705
-
706
- def last_insert_id_value(sequence_name)
707
- last_insert_id_result(sequence_name).rows.first.first
708
- end
709
-
710
- def last_insert_id_result(sequence_name) #:nodoc:
716
+ def last_insert_id_result(sequence_name) # :nodoc:
711
717
  exec_query("SELECT currval('#{sequence_name}')", 'SQL')
712
718
  end
713
719
 
714
720
  # Returns the list of a table's column names, data types, and default values.
715
721
  #
716
722
  # The underlying query is roughly:
717
- # SELECT column.name, column.type, default.value
723
+ # SELECT column.name, column.type, default.value, column.comment
718
724
  # FROM column LEFT JOIN default
719
725
  # ON column.table_id = default.table_id
720
726
  # AND column.num = default.column_num
@@ -730,9 +736,12 @@ module ActiveRecord
730
736
  # - format_type includes the column size constraint, e.g. varchar(50)
731
737
  # - ::regclass is a function that gives the id for a table name
732
738
  def column_definitions(table_name) # :nodoc:
733
- exec_query(<<-end_sql, 'SCHEMA').rows
739
+ query(<<-end_sql, 'SCHEMA')
734
740
  SELECT a.attname, format_type(a.atttypid, a.atttypmod),
735
- pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
741
+ pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
742
+ (SELECT c.collname FROM pg_collation c, pg_type t
743
+ WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation),
744
+ col_description(a.attrelid, a.attnum) AS comment
736
745
  FROM pg_attribute a LEFT JOIN pg_attrdef d
737
746
  ON a.attrelid = d.adrelid AND a.attnum = d.adnum
738
747
  WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
@@ -742,13 +751,92 @@ module ActiveRecord
742
751
  end
743
752
 
744
753
  def extract_table_ref_from_insert_sql(sql) # :nodoc:
745
- sql[/into\s+([^\(]*).*values\s*\(/im]
754
+ sql[/into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im]
746
755
  $1.strip if $1
747
756
  end
748
757
 
749
- def create_table_definition(name, temporary, options, as = nil) # :nodoc:
750
- PostgreSQL::TableDefinition.new native_database_types, name, temporary, options, as
758
+ def create_table_definition(*args) # :nodoc:
759
+ PostgreSQL::TableDefinition.new(*args)
760
+ end
761
+
762
+ def can_perform_case_insensitive_comparison_for?(column)
763
+ @case_insensitive_cache ||= {}
764
+ @case_insensitive_cache[column.sql_type] ||= begin
765
+ sql = <<-end_sql
766
+ SELECT exists(
767
+ SELECT * FROM pg_proc
768
+ INNER JOIN pg_cast
769
+ ON casttarget::text::oidvector = proargtypes
770
+ WHERE proname = 'lower'
771
+ AND castsource = '#{column.sql_type}'::regtype::oid
772
+ )
773
+ end_sql
774
+ execute_and_clear(sql, "SCHEMA", []) do |result|
775
+ result.getvalue(0, 0)
776
+ end
777
+ end
751
778
  end
779
+
780
+ def add_pg_encoders
781
+ map = PG::TypeMapByClass.new
782
+ map[Integer] = PG::TextEncoder::Integer.new
783
+ map[TrueClass] = PG::TextEncoder::Boolean.new
784
+ map[FalseClass] = PG::TextEncoder::Boolean.new
785
+ map[Float] = PG::TextEncoder::Float.new
786
+ @connection.type_map_for_queries = map
787
+ end
788
+
789
+ def add_pg_decoders
790
+ coders_by_name = {
791
+ 'int2' => PG::TextDecoder::Integer,
792
+ 'int4' => PG::TextDecoder::Integer,
793
+ 'int8' => PG::TextDecoder::Integer,
794
+ 'oid' => PG::TextDecoder::Integer,
795
+ 'float4' => PG::TextDecoder::Float,
796
+ 'float8' => PG::TextDecoder::Float,
797
+ 'bool' => PG::TextDecoder::Boolean,
798
+ }
799
+ known_coder_types = coders_by_name.keys.map { |n| quote(n) }
800
+ query = <<-SQL % known_coder_types.join(", ")
801
+ SELECT t.oid, t.typname
802
+ FROM pg_type as t
803
+ WHERE t.typname IN (%s)
804
+ SQL
805
+ coders = execute_and_clear(query, "SCHEMA", []) do |result|
806
+ result
807
+ .map { |row| construct_coder(row, coders_by_name[row['typname']]) }
808
+ .compact
809
+ end
810
+
811
+ map = PG::TypeMapByOid.new
812
+ coders.each { |coder| map.add_coder(coder) }
813
+ @connection.type_map_for_results = map
814
+ end
815
+
816
+ def construct_coder(row, coder_class)
817
+ return unless coder_class
818
+ coder_class.new(oid: row['oid'].to_i, name: row['typname'])
819
+ end
820
+
821
+ ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
822
+ ActiveRecord::Type.add_modifier({ range: true }, OID::Range, adapter: :postgresql)
823
+ ActiveRecord::Type.register(:bit, OID::Bit, adapter: :postgresql)
824
+ ActiveRecord::Type.register(:bit_varying, OID::BitVarying, adapter: :postgresql)
825
+ ActiveRecord::Type.register(:binary, OID::Bytea, adapter: :postgresql)
826
+ ActiveRecord::Type.register(:cidr, OID::Cidr, adapter: :postgresql)
827
+ ActiveRecord::Type.register(:datetime, OID::DateTime, adapter: :postgresql)
828
+ ActiveRecord::Type.register(:decimal, OID::Decimal, adapter: :postgresql)
829
+ ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
830
+ ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
831
+ ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql)
832
+ ActiveRecord::Type.register(:json, OID::Json, adapter: :postgresql)
833
+ ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
834
+ ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
835
+ ActiveRecord::Type.register(:point, OID::Rails51Point, adapter: :postgresql)
836
+ ActiveRecord::Type.register(:legacy_point, OID::Point, adapter: :postgresql)
837
+ ActiveRecord::Type.register(:uuid, OID::Uuid, adapter: :postgresql)
838
+ ActiveRecord::Type.register(:vector, OID::Vector, adapter: :postgresql)
839
+ ActiveRecord::Type.register(:xml, OID::Xml, adapter: :postgresql)
752
840
  end
753
841
  end
754
842
  end