activerecord 4.2.11.3 → 5.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (229) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1029 -1349
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -7
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record.rb +7 -3
  7. data/lib/active_record/aggregations.rb +35 -25
  8. data/lib/active_record/association_relation.rb +2 -2
  9. data/lib/active_record/associations.rb +305 -204
  10. data/lib/active_record/associations/alias_tracker.rb +19 -16
  11. data/lib/active_record/associations/association.rb +10 -8
  12. data/lib/active_record/associations/association_scope.rb +73 -102
  13. data/lib/active_record/associations/belongs_to_association.rb +20 -32
  14. data/lib/active_record/associations/builder/association.rb +28 -34
  15. data/lib/active_record/associations/builder/belongs_to.rb +41 -18
  16. data/lib/active_record/associations/builder/collection_association.rb +8 -24
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +11 -11
  18. data/lib/active_record/associations/builder/has_many.rb +4 -4
  19. data/lib/active_record/associations/builder/has_one.rb +10 -5
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -9
  21. data/lib/active_record/associations/collection_association.rb +40 -43
  22. data/lib/active_record/associations/collection_proxy.rb +55 -29
  23. data/lib/active_record/associations/foreign_association.rb +1 -1
  24. data/lib/active_record/associations/has_many_association.rb +20 -71
  25. data/lib/active_record/associations/has_many_through_association.rb +8 -52
  26. data/lib/active_record/associations/has_one_association.rb +12 -5
  27. data/lib/active_record/associations/join_dependency.rb +28 -18
  28. data/lib/active_record/associations/join_dependency/join_association.rb +13 -12
  29. data/lib/active_record/associations/preloader.rb +13 -4
  30. data/lib/active_record/associations/preloader/association.rb +45 -51
  31. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  32. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  33. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  34. data/lib/active_record/associations/preloader/through_association.rb +5 -4
  35. data/lib/active_record/associations/singular_association.rb +6 -0
  36. data/lib/active_record/associations/through_association.rb +11 -3
  37. data/lib/active_record/attribute.rb +61 -17
  38. data/lib/active_record/attribute/user_provided_default.rb +23 -0
  39. data/lib/active_record/attribute_assignment.rb +27 -140
  40. data/lib/active_record/attribute_decorators.rb +6 -5
  41. data/lib/active_record/attribute_methods.rb +79 -26
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  43. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  44. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  45. data/lib/active_record/attribute_methods/query.rb +2 -2
  46. data/lib/active_record/attribute_methods/read.rb +26 -42
  47. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +42 -9
  49. data/lib/active_record/attribute_methods/write.rb +13 -24
  50. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  51. data/lib/active_record/attribute_set.rb +30 -3
  52. data/lib/active_record/attribute_set/builder.rb +6 -4
  53. data/lib/active_record/attributes.rb +194 -81
  54. data/lib/active_record/autosave_association.rb +33 -15
  55. data/lib/active_record/base.rb +30 -18
  56. data/lib/active_record/callbacks.rb +36 -40
  57. data/lib/active_record/coders/yaml_column.rb +20 -8
  58. data/lib/active_record/collection_cache_key.rb +31 -0
  59. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +431 -122
  60. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  61. data/lib/active_record/connection_adapters/abstract/database_statements.rb +40 -22
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -8
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -38
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +229 -185
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +52 -13
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +275 -115
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +32 -33
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -32
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +384 -221
  70. data/lib/active_record/connection_adapters/column.rb +27 -41
  71. data/lib/active_record/connection_adapters/connection_specification.rb +2 -21
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +57 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +69 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +59 -0
  76. data/lib/active_record/connection_adapters/mysql2_adapter.rb +22 -101
  77. data/lib/active_record/connection_adapters/postgresql/column.rb +6 -10
  78. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +3 -3
  79. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  80. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +23 -57
  81. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  85. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  86. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  87. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +23 -16
  92. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  96. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -11
  97. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +54 -0
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +174 -128
  101. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  102. data/lib/active_record/connection_adapters/postgresql_adapter.rb +184 -112
  103. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  104. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  105. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +15 -0
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +134 -110
  107. data/lib/active_record/connection_adapters/statement_pool.rb +28 -11
  108. data/lib/active_record/connection_handling.rb +5 -5
  109. data/lib/active_record/core.rb +72 -104
  110. data/lib/active_record/counter_cache.rb +9 -20
  111. data/lib/active_record/dynamic_matchers.rb +1 -20
  112. data/lib/active_record/enum.rb +110 -76
  113. data/lib/active_record/errors.rb +72 -47
  114. data/lib/active_record/explain_registry.rb +1 -1
  115. data/lib/active_record/explain_subscriber.rb +1 -1
  116. data/lib/active_record/fixture_set/file.rb +19 -4
  117. data/lib/active_record/fixtures.rb +76 -40
  118. data/lib/active_record/gem_version.rb +4 -4
  119. data/lib/active_record/inheritance.rb +27 -40
  120. data/lib/active_record/integration.rb +4 -4
  121. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  122. data/lib/active_record/locale/en.yml +3 -2
  123. data/lib/active_record/locking/optimistic.rb +10 -14
  124. data/lib/active_record/locking/pessimistic.rb +1 -1
  125. data/lib/active_record/log_subscriber.rb +40 -22
  126. data/lib/active_record/migration.rb +304 -133
  127. data/lib/active_record/migration/command_recorder.rb +59 -18
  128. data/lib/active_record/migration/compatibility.rb +90 -0
  129. data/lib/active_record/model_schema.rb +92 -40
  130. data/lib/active_record/nested_attributes.rb +45 -34
  131. data/lib/active_record/null_relation.rb +15 -7
  132. data/lib/active_record/persistence.rb +112 -72
  133. data/lib/active_record/querying.rb +6 -5
  134. data/lib/active_record/railtie.rb +20 -13
  135. data/lib/active_record/railties/controller_runtime.rb +1 -1
  136. data/lib/active_record/railties/databases.rake +47 -38
  137. data/lib/active_record/readonly_attributes.rb +1 -1
  138. data/lib/active_record/reflection.rb +182 -57
  139. data/lib/active_record/relation.rb +152 -100
  140. data/lib/active_record/relation/batches.rb +133 -33
  141. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  142. data/lib/active_record/relation/calculations.rb +80 -101
  143. data/lib/active_record/relation/delegation.rb +6 -19
  144. data/lib/active_record/relation/finder_methods.rb +58 -46
  145. data/lib/active_record/relation/from_clause.rb +32 -0
  146. data/lib/active_record/relation/merger.rb +13 -42
  147. data/lib/active_record/relation/predicate_builder.rb +99 -105
  148. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  149. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +78 -0
  150. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  151. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  152. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  153. data/lib/active_record/relation/predicate_builder/range_handler.rb +17 -0
  154. data/lib/active_record/relation/query_attribute.rb +19 -0
  155. data/lib/active_record/relation/query_methods.rb +274 -238
  156. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  157. data/lib/active_record/relation/spawn_methods.rb +3 -6
  158. data/lib/active_record/relation/where_clause.rb +173 -0
  159. data/lib/active_record/relation/where_clause_factory.rb +37 -0
  160. data/lib/active_record/result.rb +4 -3
  161. data/lib/active_record/runtime_registry.rb +1 -1
  162. data/lib/active_record/sanitization.rb +94 -65
  163. data/lib/active_record/schema.rb +23 -22
  164. data/lib/active_record/schema_dumper.rb +33 -22
  165. data/lib/active_record/schema_migration.rb +10 -4
  166. data/lib/active_record/scoping.rb +17 -6
  167. data/lib/active_record/scoping/default.rb +19 -6
  168. data/lib/active_record/scoping/named.rb +39 -28
  169. data/lib/active_record/secure_token.rb +38 -0
  170. data/lib/active_record/serialization.rb +2 -4
  171. data/lib/active_record/statement_cache.rb +15 -13
  172. data/lib/active_record/store.rb +8 -3
  173. data/lib/active_record/suppressor.rb +54 -0
  174. data/lib/active_record/table_metadata.rb +64 -0
  175. data/lib/active_record/tasks/database_tasks.rb +30 -40
  176. data/lib/active_record/tasks/mysql_database_tasks.rb +7 -15
  177. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
  178. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  179. data/lib/active_record/timestamp.rb +16 -9
  180. data/lib/active_record/touch_later.rb +58 -0
  181. data/lib/active_record/transactions.rb +138 -56
  182. data/lib/active_record/type.rb +66 -17
  183. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  184. data/lib/active_record/type/date.rb +2 -45
  185. data/lib/active_record/type/date_time.rb +2 -49
  186. data/lib/active_record/type/internal/abstract_json.rb +33 -0
  187. data/lib/active_record/type/internal/timezone.rb +15 -0
  188. data/lib/active_record/type/serialized.rb +9 -14
  189. data/lib/active_record/type/time.rb +3 -21
  190. data/lib/active_record/type/type_map.rb +4 -4
  191. data/lib/active_record/type_caster.rb +7 -0
  192. data/lib/active_record/type_caster/connection.rb +29 -0
  193. data/lib/active_record/type_caster/map.rb +19 -0
  194. data/lib/active_record/validations.rb +33 -32
  195. data/lib/active_record/validations/absence.rb +24 -0
  196. data/lib/active_record/validations/associated.rb +10 -3
  197. data/lib/active_record/validations/length.rb +36 -0
  198. data/lib/active_record/validations/presence.rb +12 -12
  199. data/lib/active_record/validations/uniqueness.rb +24 -21
  200. data/lib/rails/generators/active_record/migration.rb +7 -0
  201. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  202. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  203. data/lib/rails/generators/active_record/migration/templates/migration.rb +4 -1
  204. data/lib/rails/generators/active_record/model/model_generator.rb +21 -15
  205. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  206. metadata +50 -35
  207. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  208. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  209. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  210. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  211. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  212. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  213. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  214. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  215. data/lib/active_record/type/big_integer.rb +0 -13
  216. data/lib/active_record/type/binary.rb +0 -50
  217. data/lib/active_record/type/boolean.rb +0 -31
  218. data/lib/active_record/type/decimal.rb +0 -64
  219. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  220. data/lib/active_record/type/decorator.rb +0 -14
  221. data/lib/active_record/type/float.rb +0 -19
  222. data/lib/active_record/type/integer.rb +0 -59
  223. data/lib/active_record/type/mutable.rb +0 -16
  224. data/lib/active_record/type/numeric.rb +0 -36
  225. data/lib/active_record/type/string.rb +0 -40
  226. data/lib/active_record/type/text.rb +0 -11
  227. data/lib/active_record/type/time_value.rb +0 -38
  228. data/lib/active_record/type/unsigned_integer.rb +0 -15
  229. 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
@@ -1,31 +1,24 @@
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
 
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/oid"
9
+ require "active_record/connection_adapters/postgresql/quoting"
10
+ require "active_record/connection_adapters/postgresql/referential_integrity"
11
+ require "active_record/connection_adapters/postgresql/schema_definitions"
12
+ require "active_record/connection_adapters/postgresql/schema_dumper"
13
+ require "active_record/connection_adapters/postgresql/schema_statements"
14
+ require "active_record/connection_adapters/postgresql/type_metadata"
15
+ require "active_record/connection_adapters/postgresql/utils"
16
+ require "active_record/connection_adapters/statement_pool"
17
+
19
18
  require 'ipaddr'
20
19
 
21
20
  module ActiveRecord
22
21
  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
22
  # Establishes a connection to the database that's used by all Active Record objects
30
23
  def postgresql_connection(config)
31
24
  conn_params = config.symbolize_keys
@@ -37,7 +30,8 @@ module ActiveRecord
37
30
  conn_params[:dbname] = conn_params.delete(:database) if conn_params[:database]
38
31
 
39
32
  # Forward only valid config params to PGconn.connect.
40
- conn_params.keep_if { |k, _| VALID_CONN_PARAMS.include?(k) }
33
+ valid_conn_param_keys = PGconn.conndefaults_hash.keys + [:requiressl]
34
+ conn_params.slice!(*valid_conn_param_keys)
41
35
 
42
36
  # The postgres drivers don't allow the creation of an unconnected PGconn object,
43
37
  # so just pass a nil connection object for the time being.
@@ -68,17 +62,16 @@ module ActiveRecord
68
62
  # defaults to true.
69
63
  #
70
64
  # 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
65
+ # http://www.postgresql.org/docs/current/static/libpq-connect.html for the
72
66
  # list of parameters.
73
67
  #
74
68
  # 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 .
69
+ # See http://www.postgresql.org/docs/current/static/libpq-envars.html .
76
70
  class PostgreSQLAdapter < AbstractAdapter
77
71
  ADAPTER_NAME = 'PostgreSQL'.freeze
78
72
 
79
73
  NATIVE_DATABASE_TYPES = {
80
74
  primary_key: "serial primary key",
81
- bigserial: "bigserial",
82
75
  string: { name: "character varying" },
83
76
  text: { name: "text" },
84
77
  integer: { name: "integer" },
@@ -95,7 +88,6 @@ module ActiveRecord
95
88
  int8range: { name: "int8range" },
96
89
  binary: { name: "bytea" },
97
90
  boolean: { name: "boolean" },
98
- bigint: { name: "bigint" },
99
91
  xml: { name: "xml" },
100
92
  tsvector: { name: "tsvector" },
101
93
  hstore: { name: "hstore" },
@@ -108,6 +100,12 @@ module ActiveRecord
108
100
  ltree: { name: "ltree" },
109
101
  citext: { name: "citext" },
110
102
  point: { name: "point" },
103
+ line: { name: "line" },
104
+ lseg: { name: "lseg" },
105
+ box: { name: "box" },
106
+ path: { name: "path" },
107
+ polygon: { name: "polygon" },
108
+ circle: { name: "circle" },
111
109
  bit: { name: "bit" },
112
110
  bit_varying: { name: "bit varying" },
113
111
  money: { name: "money" },
@@ -119,27 +117,14 @@ module ActiveRecord
119
117
  include PostgreSQL::ReferentialIntegrity
120
118
  include PostgreSQL::SchemaStatements
121
119
  include PostgreSQL::DatabaseStatements
120
+ include PostgreSQL::ColumnDumper
122
121
  include Savepoints
123
122
 
124
123
  def schema_creation # :nodoc:
125
124
  PostgreSQL::SchemaCreation.new self
126
125
  end
127
126
 
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]
140
- end
141
-
142
- # Returns +true+, since this connection adapter supports prepared statement
127
+ # Returns true, since this connection adapter supports prepared statement
143
128
  # caching.
144
129
  def supports_statement_cache?
145
130
  true
@@ -165,52 +150,35 @@ module ActiveRecord
165
150
  true
166
151
  end
167
152
 
153
+ def supports_datetime_with_precision?
154
+ true
155
+ end
156
+
157
+ def supports_json?
158
+ postgresql_version >= 90200
159
+ end
160
+
168
161
  def index_algorithms
169
162
  { concurrently: 'CONCURRENTLY' }
170
163
  end
171
164
 
172
165
  class StatementPool < ConnectionAdapters::StatementPool
173
166
  def initialize(connection, max)
174
- super
167
+ super(max)
168
+ @connection = connection
175
169
  @counter = 0
176
- @cache = Hash.new { |h,pid| h[pid] = {} }
177
170
  end
178
171
 
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
172
  def next_key
185
173
  "a#{@counter + 1}"
186
174
  end
187
175
 
188
176
  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
177
+ super.tap { @counter += 1 }
206
178
  end
207
179
 
208
180
  private
209
181
 
210
- def cache
211
- @cache[Process.pid]
212
- end
213
-
214
182
  def dealloc(key)
215
183
  @connection.query "DEALLOCATE #{key}" if connection_active?
216
184
  end
@@ -224,22 +192,24 @@ module ActiveRecord
224
192
 
225
193
  # Initializes and connects a PostgreSQL adapter.
226
194
  def initialize(connection, logger, connection_parameters, config)
227
- super(connection, logger)
195
+ super(connection, logger, config)
228
196
 
229
197
  @visitor = Arel::Visitors::PostgreSQL.new self
230
198
  if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
231
199
  @prepared_statements = true
200
+ @visitor.extend(DetermineIfPreparableVisitor)
232
201
  else
233
202
  @prepared_statements = false
234
203
  end
235
204
 
236
- @connection_parameters, @config = connection_parameters, config
205
+ @connection_parameters = connection_parameters
237
206
 
238
207
  # @local_tz is initialized as nil to avoid warnings when connect tries to use it
239
208
  @local_tz = nil
240
209
  @table_alias_length = nil
241
210
 
242
211
  connect
212
+ add_pg_encoders
243
213
  @statements = StatementPool.new @connection,
244
214
  self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 })
245
215
 
@@ -247,6 +217,8 @@ module ActiveRecord
247
217
  raise "Your version of PostgreSQL (#{postgresql_version}) is too old, please upgrade!"
248
218
  end
249
219
 
220
+ add_pg_decoders
221
+
250
222
  @type_map = Type::HashLookupTypeMap.new
251
223
  initialize_type_map(type_map)
252
224
  @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
@@ -316,6 +288,10 @@ module ActiveRecord
316
288
  true
317
289
  end
318
290
 
291
+ def supports_advisory_locks?
292
+ true
293
+ end
294
+
319
295
  def supports_explain?
320
296
  true
321
297
  end
@@ -334,6 +310,20 @@ module ActiveRecord
334
310
  postgresql_version >= 90300
335
311
  end
336
312
 
313
+ def get_advisory_lock(lock_id) # :nodoc:
314
+ unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
315
+ raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
316
+ end
317
+ select_value("SELECT pg_try_advisory_lock(#{lock_id});")
318
+ end
319
+
320
+ def release_advisory_lock(lock_id) # :nodoc:
321
+ unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
322
+ raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
323
+ end
324
+ select_value("SELECT pg_advisory_unlock(#{lock_id})")
325
+ end
326
+
337
327
  def enable_extension(name)
338
328
  exec_query("CREATE EXTENSION IF NOT EXISTS \"#{name}\"").tap {
339
329
  reload_type_map
@@ -407,7 +397,7 @@ module ActiveRecord
407
397
  @connection.server_version
408
398
  end
409
399
 
410
- # See http://www.postgresql.org/docs/9.1/static/errcodes-appendix.html
400
+ # See http://www.postgresql.org/docs/current/static/errcodes-appendix.html
411
401
  FOREIGN_KEY_VIOLATION = "23503"
412
402
  UNIQUE_VIOLATION = "23505"
413
403
 
@@ -416,9 +406,9 @@ module ActiveRecord
416
406
 
417
407
  case exception.result.try(:error_field, PGresult::PG_DIAG_SQLSTATE)
418
408
  when UNIQUE_VIOLATION
419
- RecordNotUnique.new(message, exception)
409
+ RecordNotUnique.new(message)
420
410
  when FOREIGN_KEY_VIOLATION
421
- InvalidForeignKey.new(message, exception)
411
+ InvalidForeignKey.new(message)
422
412
  else
423
413
  super
424
414
  end
@@ -440,11 +430,11 @@ module ActiveRecord
440
430
  end
441
431
 
442
432
  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
433
+ register_class_with_limit m, 'int2', Type::Integer
434
+ register_class_with_limit m, 'int4', Type::Integer
435
+ register_class_with_limit m, 'int8', Type::Integer
446
436
  m.alias_type 'oid', 'int2'
447
- m.register_type 'float4', OID::Float.new
437
+ m.register_type 'float4', Type::Float.new
448
438
  m.alias_type 'float8', 'float4'
449
439
  m.register_type 'text', Type::Text.new
450
440
  register_class_with_limit m, 'varchar', Type::String
@@ -455,8 +445,7 @@ module ActiveRecord
455
445
  register_class_with_limit m, 'bit', OID::Bit
456
446
  register_class_with_limit m, 'varbit', OID::BitVarying
457
447
  m.alias_type 'timestamptz', 'timestamp'
458
- m.register_type 'date', OID::Date.new
459
- m.register_type 'time', OID::Time.new
448
+ m.register_type 'date', Type::Date.new
460
449
 
461
450
  m.register_type 'money', OID::Money.new
462
451
  m.register_type 'bytea', OID::Bytea.new
@@ -472,20 +461,18 @@ module ActiveRecord
472
461
  m.register_type 'macaddr', OID::SpecializedString.new(:macaddr)
473
462
  m.register_type 'citext', OID::SpecializedString.new(:citext)
474
463
  m.register_type 'ltree', OID::SpecializedString.new(:ltree)
464
+ m.register_type 'line', OID::SpecializedString.new(:line)
465
+ m.register_type 'lseg', OID::SpecializedString.new(:lseg)
466
+ m.register_type 'box', OID::SpecializedString.new(:box)
467
+ m.register_type 'path', OID::SpecializedString.new(:path)
468
+ m.register_type 'polygon', OID::SpecializedString.new(:polygon)
469
+ m.register_type 'circle', OID::SpecializedString.new(:circle)
475
470
 
476
471
  # FIXME: why are we keeping these types as strings?
477
472
  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
473
+
474
+ register_class_with_precision m, 'time', Type::Time
475
+ register_class_with_precision m, 'timestamp', OID::DateTime
489
476
 
490
477
  m.register_type 'numeric' do |_, fmod, sql_type|
491
478
  precision = extract_precision(sql_type)
@@ -522,13 +509,13 @@ module ActiveRecord
522
509
  end
523
510
 
524
511
  # Extracts the value from a PostgreSQL column default definition.
525
- def extract_value_from_default(oid, default) # :nodoc:
512
+ def extract_value_from_default(default) # :nodoc:
526
513
  case default
527
514
  # Quoted types
528
515
  when /\A[\(B]?'(.*)'::/m
529
- $1.gsub(/''/, "'")
516
+ $1.gsub("''".freeze, "'".freeze)
530
517
  # Boolean types
531
- when 'true', 'false'
518
+ when 'true'.freeze, 'false'.freeze
532
519
  default
533
520
  # Numeric types
534
521
  when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/
@@ -580,29 +567,33 @@ module ActiveRecord
580
567
 
581
568
  FEATURE_NOT_SUPPORTED = "0A000" #:nodoc:
582
569
 
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)
570
+ def execute_and_clear(sql, name, binds, prepare: false)
571
+ if without_prepared_statement?(binds)
572
+ result = exec_no_cache(sql, name, [])
573
+ elsif !prepare
574
+ result = exec_no_cache(sql, name, binds)
575
+ else
576
+ result = exec_cache(sql, name, binds)
577
+ end
586
578
  ret = yield result
587
579
  result.clear
588
580
  ret
589
581
  end
590
582
 
591
583
  def exec_no_cache(sql, name, binds)
592
- log(sql, name, binds) { @connection.async_exec(sql, []) }
584
+ type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
585
+ log(sql, name, binds) { @connection.async_exec(sql, type_casted_binds) }
593
586
  end
594
587
 
595
588
  def exec_cache(sql, name, binds)
596
589
  stmt_key = prepare_statement(sql)
597
- type_casted_binds = binds.map { |col, val|
598
- [col, type_cast(val, col)]
599
- }
590
+ type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
600
591
 
601
- log(sql, name, type_casted_binds, stmt_key) do
602
- @connection.exec_prepared(stmt_key, type_casted_binds.map { |_, val| val })
592
+ log(sql, name, binds, stmt_key) do
593
+ @connection.exec_prepared(stmt_key, type_casted_binds)
603
594
  end
604
595
  rescue ActiveRecord::StatementInvalid => e
605
- pgerror = e.original_exception
596
+ pgerror = e.cause
606
597
 
607
598
  # Get the PG code for the failure. Annoyingly, the code for
608
599
  # prepared statements whose return value may have changed is
@@ -658,7 +649,7 @@ module ActiveRecord
658
649
  configure_connection
659
650
  rescue ::PG::Error => error
660
651
  if error.message.include?("does not exist")
661
- raise ActiveRecord::NoDatabaseError.new(error.message, error)
652
+ raise ActiveRecord::NoDatabaseError
662
653
  else
663
654
  raise
664
655
  end
@@ -686,7 +677,7 @@ module ActiveRecord
686
677
  end
687
678
 
688
679
  # SET statements from :variables config hash
689
- # http://www.postgresql.org/docs/8.3/static/sql-set.html
680
+ # http://www.postgresql.org/docs/current/static/sql-set.html
690
681
  variables = @config[:variables] || {}
691
682
  variables.map do |k, v|
692
683
  if v == ':default' || v == :default
@@ -730,9 +721,11 @@ module ActiveRecord
730
721
  # - format_type includes the column size constraint, e.g. varchar(50)
731
722
  # - ::regclass is a function that gives the id for a table name
732
723
  def column_definitions(table_name) # :nodoc:
733
- exec_query(<<-end_sql, 'SCHEMA').rows
724
+ query(<<-end_sql, 'SCHEMA')
734
725
  SELECT a.attname, format_type(a.atttypid, a.atttypmod),
735
- pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
726
+ pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
727
+ (SELECT c.collname FROM pg_collation c, pg_type t
728
+ WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation)
736
729
  FROM pg_attribute a LEFT JOIN pg_attrdef d
737
730
  ON a.attrelid = d.adrelid AND a.attnum = d.adnum
738
731
  WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
@@ -742,13 +735,92 @@ module ActiveRecord
742
735
  end
743
736
 
744
737
  def extract_table_ref_from_insert_sql(sql) # :nodoc:
745
- sql[/into\s+([^\(]*).*values\s*\(/im]
738
+ sql[/into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im]
746
739
  $1.strip if $1
747
740
  end
748
741
 
749
- def create_table_definition(name, temporary, options, as = nil) # :nodoc:
750
- PostgreSQL::TableDefinition.new native_database_types, name, temporary, options, as
742
+ def create_table_definition(name, temporary = false, options = nil, as = nil) # :nodoc:
743
+ PostgreSQL::TableDefinition.new(name, temporary, options, as)
744
+ end
745
+
746
+ def can_perform_case_insensitive_comparison_for?(column)
747
+ @case_insensitive_cache ||= {}
748
+ @case_insensitive_cache[column.sql_type] ||= begin
749
+ sql = <<-end_sql
750
+ SELECT exists(
751
+ SELECT * FROM pg_proc
752
+ INNER JOIN pg_cast
753
+ ON casttarget::text::oidvector = proargtypes
754
+ WHERE proname = 'lower'
755
+ AND castsource = '#{column.sql_type}'::regtype::oid
756
+ )
757
+ end_sql
758
+ execute_and_clear(sql, "SCHEMA", []) do |result|
759
+ result.getvalue(0, 0)
760
+ end
761
+ end
751
762
  end
763
+
764
+ def add_pg_encoders
765
+ map = PG::TypeMapByClass.new
766
+ map[Integer] = PG::TextEncoder::Integer.new
767
+ map[TrueClass] = PG::TextEncoder::Boolean.new
768
+ map[FalseClass] = PG::TextEncoder::Boolean.new
769
+ map[Float] = PG::TextEncoder::Float.new
770
+ @connection.type_map_for_queries = map
771
+ end
772
+
773
+ def add_pg_decoders
774
+ coders_by_name = {
775
+ 'int2' => PG::TextDecoder::Integer,
776
+ 'int4' => PG::TextDecoder::Integer,
777
+ 'int8' => PG::TextDecoder::Integer,
778
+ 'oid' => PG::TextDecoder::Integer,
779
+ 'float4' => PG::TextDecoder::Float,
780
+ 'float8' => PG::TextDecoder::Float,
781
+ 'bool' => PG::TextDecoder::Boolean,
782
+ }
783
+ known_coder_types = coders_by_name.keys.map { |n| quote(n) }
784
+ query = <<-SQL % known_coder_types.join(", ")
785
+ SELECT t.oid, t.typname
786
+ FROM pg_type as t
787
+ WHERE t.typname IN (%s)
788
+ SQL
789
+ coders = execute_and_clear(query, "SCHEMA", []) do |result|
790
+ result
791
+ .map { |row| construct_coder(row, coders_by_name[row['typname']]) }
792
+ .compact
793
+ end
794
+
795
+ map = PG::TypeMapByOid.new
796
+ coders.each { |coder| map.add_coder(coder) }
797
+ @connection.type_map_for_results = map
798
+ end
799
+
800
+ def construct_coder(row, coder_class)
801
+ return unless coder_class
802
+ coder_class.new(oid: row['oid'].to_i, name: row['typname'])
803
+ end
804
+
805
+ ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
806
+ ActiveRecord::Type.add_modifier({ range: true }, OID::Range, adapter: :postgresql)
807
+ ActiveRecord::Type.register(:bit, OID::Bit, adapter: :postgresql)
808
+ ActiveRecord::Type.register(:bit_varying, OID::BitVarying, adapter: :postgresql)
809
+ ActiveRecord::Type.register(:binary, OID::Bytea, adapter: :postgresql)
810
+ ActiveRecord::Type.register(:cidr, OID::Cidr, adapter: :postgresql)
811
+ ActiveRecord::Type.register(:date_time, OID::DateTime, adapter: :postgresql)
812
+ ActiveRecord::Type.register(:decimal, OID::Decimal, adapter: :postgresql)
813
+ ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
814
+ ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
815
+ ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql)
816
+ ActiveRecord::Type.register(:json, OID::Json, adapter: :postgresql)
817
+ ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
818
+ ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
819
+ ActiveRecord::Type.register(:point, OID::Rails51Point, adapter: :postgresql)
820
+ ActiveRecord::Type.register(:legacy_point, OID::Point, adapter: :postgresql)
821
+ ActiveRecord::Type.register(:uuid, OID::Uuid, adapter: :postgresql)
822
+ ActiveRecord::Type.register(:vector, OID::Vector, adapter: :postgresql)
823
+ ActiveRecord::Type.register(:xml, OID::Xml, adapter: :postgresql)
752
824
  end
753
825
  end
754
826
  end