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
@@ -0,0 +1,35 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ class PostgreSQLTypeMetadata < DelegateClass(SqlTypeMetadata)
4
+ attr_reader :oid, :fmod, :array
5
+
6
+ def initialize(type_metadata, oid: nil, fmod: nil)
7
+ super(type_metadata)
8
+ @type_metadata = type_metadata
9
+ @oid = oid
10
+ @fmod = fmod
11
+ @array = /\[\]$/ === type_metadata.sql_type
12
+ end
13
+
14
+ def sql_type
15
+ super.gsub(/\[\]$/, "".freeze)
16
+ end
17
+
18
+ def ==(other)
19
+ other.is_a?(PostgreSQLTypeMetadata) &&
20
+ attributes_for_hash == other.attributes_for_hash
21
+ end
22
+ alias eql? ==
23
+
24
+ def hash
25
+ attributes_for_hash.hash
26
+ end
27
+
28
+ protected
29
+
30
+ def attributes_for_hash
31
+ [self.class, @type_metadata, oid, fmod]
32
+ end
33
+ end
34
+ end
35
+ end
@@ -19,9 +19,9 @@ module ActiveRecord
19
19
 
20
20
  def quoted
21
21
  if schema
22
- PGconn.quote_ident(schema) << SEPARATOR << PGconn.quote_ident(identifier)
22
+ PG::Connection.quote_ident(schema) << SEPARATOR << PG::Connection.quote_ident(identifier)
23
23
  else
24
- PGconn.quote_ident(identifier)
24
+ PG::Connection.quote_ident(identifier)
25
25
  end
26
26
  end
27
27
 
@@ -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", "< 2.0"
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
@@ -36,10 +28,11 @@ module ActiveRecord
36
28
  conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
37
29
  conn_params[:dbname] = conn_params.delete(:database) if conn_params[:database]
38
30
 
39
- # Forward only valid config params to PGconn.connect.
40
- conn_params.keep_if { |k, _| VALID_CONN_PARAMS.include?(k) }
31
+ # Forward only valid config params to PG::Connection.connect.
32
+ valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
33
+ conn_params.slice!(*valid_conn_param_keys)
41
34
 
42
- # The postgres drivers don't allow the creation of an unconnected PGconn object,
35
+ # The postgres drivers don't allow the creation of an unconnected PG::Connection object,
43
36
  # so just pass a nil connection object for the time being.
44
37
  ConnectionAdapters::PostgreSQLAdapter.new(nil, logger, conn_params, config)
45
38
  end
@@ -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,88 +156,75 @@ 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
217
199
 
218
200
  def connection_active?
219
- @connection.status == PGconn::CONNECTION_OK
220
- rescue PGError
201
+ @connection.status == PG::CONNECTION_OK
202
+ rescue PG::Error
221
203
  false
222
204
  end
223
205
  end
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
- @table_alias_length = nil
215
+ @max_identifier_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"]
@@ -266,7 +244,7 @@ module ActiveRecord
266
244
  def active?
267
245
  @connection.query 'SELECT 1'
268
246
  true
269
- rescue PGError
247
+ rescue PG::Error
270
248
  false
271
249
  end
272
250
 
@@ -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
@@ -363,9 +358,11 @@ module ActiveRecord
363
358
  end
364
359
 
365
360
  # Returns the configured supported identifier length supported by PostgreSQL
366
- def table_alias_length
367
- @table_alias_length ||= query('SHOW max_identifier_length', 'SCHEMA')[0][0].to_i
361
+ def max_identifier_length
362
+ @max_identifier_length ||= query('SHOW max_identifier_length', 'SCHEMA')[0][0].to_i
368
363
  end
364
+ alias table_alias_length max_identifier_length
365
+ alias index_name_length max_identifier_length
369
366
 
370
367
  # Set the authorized user for this session
371
368
  def session_auth=(user)
@@ -400,25 +397,28 @@ module ActiveRecord
400
397
  "average" => "avg",
401
398
  }
402
399
 
403
- protected
400
+ # Returns the version of the connected PostgreSQL server.
401
+ def postgresql_version
402
+ @connection.server_version
403
+ end
404
404
 
405
- # Returns the version of the connected PostgreSQL server.
406
- def postgresql_version
407
- @connection.server_version
408
- end
405
+ protected
409
406
 
410
- # See http://www.postgresql.org/docs/9.1/static/errcodes-appendix.html
407
+ # See http://www.postgresql.org/docs/current/static/errcodes-appendix.html
408
+ VALUE_LIMIT_VIOLATION = "22001"
411
409
  FOREIGN_KEY_VIOLATION = "23503"
412
410
  UNIQUE_VIOLATION = "23505"
413
411
 
414
412
  def translate_exception(exception, message)
415
413
  return exception unless exception.respond_to?(:result)
416
414
 
417
- case exception.result.try(:error_field, PGresult::PG_DIAG_SQLSTATE)
415
+ case exception.result.try(:error_field, PG::PG_DIAG_SQLSTATE)
418
416
  when UNIQUE_VIOLATION
419
- RecordNotUnique.new(message, exception)
417
+ RecordNotUnique.new(message)
420
418
  when FOREIGN_KEY_VIOLATION
421
- InvalidForeignKey.new(message, exception)
419
+ InvalidForeignKey.new(message)
420
+ when VALUE_LIMIT_VIOLATION
421
+ ValueTooLong.new(message)
422
422
  else
423
423
  super
424
424
  end
@@ -440,11 +440,11 @@ module ActiveRecord
440
440
  end
441
441
 
442
442
  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
443
+ register_class_with_limit m, 'int2', Type::Integer
444
+ register_class_with_limit m, 'int4', Type::Integer
445
+ register_class_with_limit m, 'int8', Type::Integer
446
446
  m.alias_type 'oid', 'int2'
447
- m.register_type 'float4', OID::Float.new
447
+ m.register_type 'float4', Type::Float.new
448
448
  m.alias_type 'float8', 'float4'
449
449
  m.register_type 'text', Type::Text.new
450
450
  register_class_with_limit m, 'varchar', Type::String
@@ -455,8 +455,7 @@ module ActiveRecord
455
455
  register_class_with_limit m, 'bit', OID::Bit
456
456
  register_class_with_limit m, 'varbit', OID::BitVarying
457
457
  m.alias_type 'timestamptz', 'timestamp'
458
- m.register_type 'date', OID::Date.new
459
- m.register_type 'time', OID::Time.new
458
+ m.register_type 'date', Type::Date.new
460
459
 
461
460
  m.register_type 'money', OID::Money.new
462
461
  m.register_type 'bytea', OID::Bytea.new
@@ -472,20 +471,18 @@ module ActiveRecord
472
471
  m.register_type 'macaddr', OID::SpecializedString.new(:macaddr)
473
472
  m.register_type 'citext', OID::SpecializedString.new(:citext)
474
473
  m.register_type 'ltree', OID::SpecializedString.new(:ltree)
474
+ m.register_type 'line', OID::SpecializedString.new(:line)
475
+ m.register_type 'lseg', OID::SpecializedString.new(:lseg)
476
+ m.register_type 'box', OID::SpecializedString.new(:box)
477
+ m.register_type 'path', OID::SpecializedString.new(:path)
478
+ m.register_type 'polygon', OID::SpecializedString.new(:polygon)
479
+ m.register_type 'circle', OID::SpecializedString.new(:circle)
475
480
 
476
481
  # FIXME: why are we keeping these types as strings?
477
482
  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
483
+
484
+ register_class_with_precision m, 'time', Type::Time
485
+ register_class_with_precision m, 'timestamp', OID::DateTime
489
486
 
490
487
  m.register_type 'numeric' do |_, fmod, sql_type|
491
488
  precision = extract_precision(sql_type)
@@ -522,13 +519,18 @@ module ActiveRecord
522
519
  end
523
520
 
524
521
  # Extracts the value from a PostgreSQL column default definition.
525
- def extract_value_from_default(oid, default) # :nodoc:
522
+ def extract_value_from_default(default) # :nodoc:
526
523
  case default
527
524
  # Quoted types
528
- when /\A[\(B]?'(.*)'::/m
529
- $1.gsub(/''/, "'")
525
+ when /\A[\(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m
526
+ # The default 'now'::date is CURRENT_DATE
527
+ if $1 == "now".freeze && $2 == "date".freeze
528
+ nil
529
+ else
530
+ $1.gsub("''".freeze, "'".freeze)
531
+ end
530
532
  # Boolean types
531
- when 'true', 'false'
533
+ when 'true'.freeze, 'false'.freeze
532
534
  default
533
535
  # Numeric types
534
536
  when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/
@@ -548,7 +550,7 @@ module ActiveRecord
548
550
  end
549
551
 
550
552
  def has_default_function?(default_value, default) # :nodoc:
551
- !default_value && (%r{\w+\(.*\)} === default)
553
+ !default_value && (%r{\w+\(.*\)|\(.*\)::\w+} === default)
552
554
  end
553
555
 
554
556
  def load_additional_types(type_map, oids = nil) # :nodoc:
@@ -580,47 +582,67 @@ module ActiveRecord
580
582
 
581
583
  FEATURE_NOT_SUPPORTED = "0A000" #:nodoc:
582
584
 
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)
585
+ def execute_and_clear(sql, name, binds, prepare: false)
586
+ if without_prepared_statement?(binds)
587
+ result = exec_no_cache(sql, name, [])
588
+ elsif !prepare
589
+ result = exec_no_cache(sql, name, binds)
590
+ else
591
+ result = exec_cache(sql, name, binds)
592
+ end
586
593
  ret = yield result
587
594
  result.clear
588
595
  ret
589
596
  end
590
597
 
591
598
  def exec_no_cache(sql, name, binds)
592
- log(sql, name, binds) { @connection.async_exec(sql, []) }
599
+ type_casted_binds = type_casted_binds(binds)
600
+ log(sql, name, binds, type_casted_binds) { @connection.async_exec(sql, type_casted_binds) }
593
601
  end
594
602
 
595
603
  def exec_cache(sql, name, binds)
596
604
  stmt_key = prepare_statement(sql)
597
- type_casted_binds = binds.map { |col, val|
598
- [col, type_cast(val, col)]
599
- }
605
+ type_casted_binds = type_casted_binds(binds)
600
606
 
601
- log(sql, name, type_casted_binds, stmt_key) do
602
- @connection.exec_prepared(stmt_key, type_casted_binds.map { |_, val| val })
607
+ log(sql, name, binds, type_casted_binds, stmt_key) do
608
+ @connection.exec_prepared(stmt_key, type_casted_binds)
603
609
  end
604
610
  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
611
+ raise unless is_cached_plan_failure?(e)
612
+
613
+ # Nothing we can do if we are in a transaction because all commands
614
+ # will raise InFailedSQLTransaction
615
+ if in_transaction?
616
+ raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message)
617
+ else
618
+ # outside of transactions we can simply flush this query and retry
617
619
  @statements.delete sql_key(sql)
618
620
  retry
619
- else
620
- raise e
621
621
  end
622
622
  end
623
623
 
624
+ # Annoyingly, the code for prepared statements whose return value may
625
+ # have changed is FEATURE_NOT_SUPPORTED.
626
+ #
627
+ # This covers various different error types so we need to do additional
628
+ # work to classify the exception definitively as a
629
+ # ActiveRecord::PreparedStatementCacheExpired
630
+ #
631
+ # Check here for more details:
632
+ # http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
633
+ CACHED_PLAN_HEURISTIC = 'cached plan must not change result type'.freeze
634
+ def is_cached_plan_failure?(e)
635
+ pgerror = e.cause
636
+ code = pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE)
637
+ code == FEATURE_NOT_SUPPORTED && pgerror.message.include?(CACHED_PLAN_HEURISTIC)
638
+ rescue
639
+ false
640
+ end
641
+
642
+ def in_transaction?
643
+ open_transactions > 0
644
+ end
645
+
624
646
  # Returns the statement identifier for the client side cache
625
647
  # of statements
626
648
  def sql_key(sql)
@@ -648,17 +670,11 @@ module ActiveRecord
648
670
  # Connects to a PostgreSQL server and sets up the adapter depending on the
649
671
  # connected server's characteristics.
650
672
  def connect
651
- @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
-
673
+ @connection = PG.connect(@connection_parameters)
658
674
  configure_connection
659
675
  rescue ::PG::Error => error
660
676
  if error.message.include?("does not exist")
661
- raise ActiveRecord::NoDatabaseError.new(error.message, error)
677
+ raise ActiveRecord::NoDatabaseError
662
678
  else
663
679
  raise
664
680
  end
@@ -686,7 +702,7 @@ module ActiveRecord
686
702
  end
687
703
 
688
704
  # SET statements from :variables config hash
689
- # http://www.postgresql.org/docs/8.3/static/sql-set.html
705
+ # http://www.postgresql.org/docs/current/static/sql-set.html
690
706
  variables = @config[:variables] || {}
691
707
  variables.map do |k, v|
692
708
  if v == ':default' || v == :default
@@ -699,22 +715,14 @@ module ActiveRecord
699
715
  end
700
716
 
701
717
  # 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:
718
+ def last_insert_id_result(sequence_name) # :nodoc:
711
719
  exec_query("SELECT currval('#{sequence_name}')", 'SQL')
712
720
  end
713
721
 
714
722
  # Returns the list of a table's column names, data types, and default values.
715
723
  #
716
724
  # The underlying query is roughly:
717
- # SELECT column.name, column.type, default.value
725
+ # SELECT column.name, column.type, default.value, column.comment
718
726
  # FROM column LEFT JOIN default
719
727
  # ON column.table_id = default.table_id
720
728
  # AND column.num = default.column_num
@@ -730,9 +738,12 @@ module ActiveRecord
730
738
  # - format_type includes the column size constraint, e.g. varchar(50)
731
739
  # - ::regclass is a function that gives the id for a table name
732
740
  def column_definitions(table_name) # :nodoc:
733
- exec_query(<<-end_sql, 'SCHEMA').rows
741
+ query(<<-end_sql, 'SCHEMA')
734
742
  SELECT a.attname, format_type(a.atttypid, a.atttypmod),
735
- pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
743
+ pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
744
+ (SELECT c.collname FROM pg_collation c, pg_type t
745
+ WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation),
746
+ col_description(a.attrelid, a.attnum) AS comment
736
747
  FROM pg_attribute a LEFT JOIN pg_attrdef d
737
748
  ON a.attrelid = d.adrelid AND a.attnum = d.adnum
738
749
  WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
@@ -742,13 +753,96 @@ module ActiveRecord
742
753
  end
743
754
 
744
755
  def extract_table_ref_from_insert_sql(sql) # :nodoc:
745
- sql[/into\s+([^\(]*).*values\s*\(/im]
756
+ sql[/into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im]
746
757
  $1.strip if $1
747
758
  end
748
759
 
749
- def create_table_definition(name, temporary, options, as = nil) # :nodoc:
750
- PostgreSQL::TableDefinition.new native_database_types, name, temporary, options, as
760
+ def create_table_definition(*args) # :nodoc:
761
+ PostgreSQL::TableDefinition.new(*args)
762
+ end
763
+
764
+ def can_perform_case_insensitive_comparison_for?(column)
765
+ @case_insensitive_cache ||= {}
766
+ @case_insensitive_cache[column.sql_type] ||= begin
767
+ sql = <<-end_sql
768
+ SELECT exists(
769
+ SELECT * FROM pg_proc
770
+ WHERE proname = 'lower'
771
+ AND proargtypes = ARRAY[#{quote column.sql_type}::regtype]::oidvector
772
+ ) OR exists(
773
+ SELECT * FROM pg_proc
774
+ INNER JOIN pg_cast
775
+ ON ARRAY[casttarget]::oidvector = proargtypes
776
+ WHERE proname = 'lower'
777
+ AND castsource = #{quote column.sql_type}::regtype
778
+ )
779
+ end_sql
780
+ execute_and_clear(sql, "SCHEMA", []) do |result|
781
+ result.getvalue(0, 0)
782
+ end
783
+ end
751
784
  end
785
+
786
+ def add_pg_encoders
787
+ map = PG::TypeMapByClass.new
788
+ map[Integer] = PG::TextEncoder::Integer.new
789
+ map[TrueClass] = PG::TextEncoder::Boolean.new
790
+ map[FalseClass] = PG::TextEncoder::Boolean.new
791
+ map[Float] = PG::TextEncoder::Float.new
792
+ @connection.type_map_for_queries = map
793
+ end
794
+
795
+ def add_pg_decoders
796
+ coders_by_name = {
797
+ 'int2' => PG::TextDecoder::Integer,
798
+ 'int4' => PG::TextDecoder::Integer,
799
+ 'int8' => PG::TextDecoder::Integer,
800
+ 'oid' => PG::TextDecoder::Integer,
801
+ 'float4' => PG::TextDecoder::Float,
802
+ 'float8' => PG::TextDecoder::Float,
803
+ 'bool' => PG::TextDecoder::Boolean,
804
+ }
805
+ known_coder_types = coders_by_name.keys.map { |n| quote(n) }
806
+ query = <<-SQL % known_coder_types.join(", ")
807
+ SELECT t.oid, t.typname
808
+ FROM pg_type as t
809
+ WHERE t.typname IN (%s)
810
+ SQL
811
+ coders = execute_and_clear(query, "SCHEMA", []) do |result|
812
+ result
813
+ .map { |row| construct_coder(row, coders_by_name[row['typname']]) }
814
+ .compact
815
+ end
816
+
817
+ map = PG::TypeMapByOid.new
818
+ coders.each { |coder| map.add_coder(coder) }
819
+ @connection.type_map_for_results = map
820
+ end
821
+
822
+ def construct_coder(row, coder_class)
823
+ return unless coder_class
824
+ coder_class.new(oid: row['oid'].to_i, name: row['typname'])
825
+ end
826
+
827
+ ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
828
+ ActiveRecord::Type.add_modifier({ range: true }, OID::Range, adapter: :postgresql)
829
+ ActiveRecord::Type.register(:bit, OID::Bit, adapter: :postgresql)
830
+ ActiveRecord::Type.register(:bit_varying, OID::BitVarying, adapter: :postgresql)
831
+ ActiveRecord::Type.register(:binary, OID::Bytea, adapter: :postgresql)
832
+ ActiveRecord::Type.register(:cidr, OID::Cidr, adapter: :postgresql)
833
+ ActiveRecord::Type.register(:datetime, OID::DateTime, adapter: :postgresql)
834
+ ActiveRecord::Type.register(:decimal, OID::Decimal, adapter: :postgresql)
835
+ ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
836
+ ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
837
+ ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql)
838
+ ActiveRecord::Type.register(:json, OID::Json, adapter: :postgresql)
839
+ ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
840
+ ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
841
+ ActiveRecord::Type.register(:point, OID::Rails51Point, adapter: :postgresql)
842
+ ActiveRecord::Type.register(:legacy_point, OID::Point, adapter: :postgresql)
843
+ ActiveRecord::Type.register(:uuid, OID::Uuid, adapter: :postgresql)
844
+ ActiveRecord::Type.register(:vector, OID::Vector, adapter: :postgresql)
845
+ ActiveRecord::Type.register(:xml, OID::Xml, adapter: :postgresql)
752
846
  end
753
847
  end
754
848
  end