activerecord 5.0.7 → 5.1.7
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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +657 -2080
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +28 -28
- data/examples/simple.rb +3 -3
- data/lib/active_record/aggregations.rb +244 -244
- data/lib/active_record/association_relation.rb +5 -5
- data/lib/active_record/associations/alias_tracker.rb +10 -11
- data/lib/active_record/associations/association.rb +23 -5
- data/lib/active_record/associations/association_scope.rb +95 -81
- data/lib/active_record/associations/belongs_to_association.rb +7 -4
- data/lib/active_record/associations/builder/belongs_to.rb +30 -16
- data/lib/active_record/associations/builder/collection_association.rb +1 -2
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
- data/lib/active_record/associations/collection_association.rb +36 -205
- data/lib/active_record/associations/collection_proxy.rb +132 -63
- data/lib/active_record/associations/has_many_association.rb +10 -19
- data/lib/active_record/associations/has_many_through_association.rb +12 -4
- data/lib/active_record/associations/has_one_association.rb +24 -28
- data/lib/active_record/associations/has_one_through_association.rb +5 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +4 -28
- data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +121 -118
- data/lib/active_record/associations/preloader/association.rb +64 -64
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
- data/lib/active_record/associations/preloader/collection_association.rb +6 -6
- data/lib/active_record/associations/preloader/has_many.rb +0 -2
- data/lib/active_record/associations/preloader/singular_association.rb +6 -8
- data/lib/active_record/associations/preloader/through_association.rb +41 -41
- data/lib/active_record/associations/preloader.rb +94 -94
- data/lib/active_record/associations/singular_association.rb +8 -25
- data/lib/active_record/associations/through_association.rb +2 -5
- data/lib/active_record/associations.rb +1591 -1562
- data/lib/active_record/attribute/user_provided_default.rb +4 -2
- data/lib/active_record/attribute.rb +98 -71
- data/lib/active_record/attribute_assignment.rb +61 -61
- data/lib/active_record/attribute_decorators.rb +35 -13
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
- data/lib/active_record/attribute_methods/dirty.rb +229 -46
- data/lib/active_record/attribute_methods/primary_key.rb +74 -73
- data/lib/active_record/attribute_methods/read.rb +39 -35
- data/lib/active_record/attribute_methods/serialization.rb +7 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
- data/lib/active_record/attribute_methods/write.rb +30 -33
- data/lib/active_record/attribute_methods.rb +56 -65
- data/lib/active_record/attribute_mutation_tracker.rb +63 -11
- data/lib/active_record/attribute_set/builder.rb +27 -33
- data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
- data/lib/active_record/attribute_set.rb +9 -6
- data/lib/active_record/attributes.rb +22 -22
- data/lib/active_record/autosave_association.rb +18 -13
- data/lib/active_record/base.rb +24 -22
- data/lib/active_record/callbacks.rb +56 -14
- data/lib/active_record/coders/yaml_column.rb +9 -11
- data/lib/active_record/collection_cache_key.rb +3 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +330 -284
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +39 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -51
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +10 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +74 -79
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +120 -100
- data/lib/active_record/connection_adapters/abstract/transaction.rb +49 -43
- data/lib/active_record/connection_adapters/abstract_adapter.rb +165 -135
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +404 -424
- data/lib/active_record/connection_adapters/column.rb +26 -4
- data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
- data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -49
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
- data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -28
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +7 -6
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +23 -27
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +32 -53
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +0 -10
- data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +32 -30
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
- data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -35
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +182 -222
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +6 -4
- data/lib/active_record/connection_adapters/postgresql/utils.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +198 -167
- data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -19
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +184 -167
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
- data/lib/active_record/connection_handling.rb +14 -26
- data/lib/active_record/core.rb +109 -93
- data/lib/active_record/counter_cache.rb +60 -13
- data/lib/active_record/define_callbacks.rb +20 -0
- data/lib/active_record/dynamic_matchers.rb +80 -79
- data/lib/active_record/enum.rb +8 -6
- data/lib/active_record/errors.rb +64 -15
- data/lib/active_record/explain.rb +1 -2
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +7 -4
- data/lib/active_record/fixture_set/file.rb +11 -8
- data/lib/active_record/fixtures.rb +66 -53
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +93 -79
- data/lib/active_record/integration.rb +7 -7
- data/lib/active_record/internal_metadata.rb +3 -16
- data/lib/active_record/legacy_yaml_adapter.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +69 -74
- data/lib/active_record/locking/pessimistic.rb +10 -1
- data/lib/active_record/log_subscriber.rb +23 -28
- data/lib/active_record/migration/command_recorder.rb +94 -94
- data/lib/active_record/migration/compatibility.rb +100 -47
- data/lib/active_record/migration/join_table.rb +6 -6
- data/lib/active_record/migration.rb +153 -155
- data/lib/active_record/model_schema.rb +94 -107
- data/lib/active_record/nested_attributes.rb +200 -199
- data/lib/active_record/null_relation.rb +11 -34
- data/lib/active_record/persistence.rb +65 -50
- data/lib/active_record/query_cache.rb +2 -6
- data/lib/active_record/querying.rb +3 -4
- data/lib/active_record/railtie.rb +16 -17
- data/lib/active_record/railties/controller_runtime.rb +6 -2
- data/lib/active_record/railties/databases.rake +105 -133
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +2 -2
- data/lib/active_record/reflection.rb +154 -108
- data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
- data/lib/active_record/relation/batches.rb +80 -51
- data/lib/active_record/relation/calculations.rb +169 -162
- data/lib/active_record/relation/delegation.rb +32 -31
- data/lib/active_record/relation/finder_methods.rb +197 -231
- data/lib/active_record/relation/merger.rb +58 -62
- data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
- data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
- data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
- data/lib/active_record/relation/predicate_builder.rb +92 -89
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +255 -293
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +4 -5
- data/lib/active_record/relation/where_clause.rb +80 -65
- data/lib/active_record/relation/where_clause_factory.rb +47 -8
- data/lib/active_record/relation.rb +93 -119
- data/lib/active_record/result.rb +41 -32
- data/lib/active_record/runtime_registry.rb +3 -3
- data/lib/active_record/sanitization.rb +176 -192
- data/lib/active_record/schema.rb +3 -3
- data/lib/active_record/schema_dumper.rb +15 -38
- data/lib/active_record/schema_migration.rb +8 -4
- data/lib/active_record/scoping/default.rb +90 -90
- data/lib/active_record/scoping/named.rb +11 -11
- data/lib/active_record/scoping.rb +6 -6
- data/lib/active_record/secure_token.rb +2 -2
- data/lib/active_record/statement_cache.rb +13 -15
- data/lib/active_record/store.rb +31 -32
- data/lib/active_record/suppressor.rb +2 -1
- data/lib/active_record/table_metadata.rb +9 -5
- data/lib/active_record/tasks/database_tasks.rb +65 -55
- data/lib/active_record/tasks/mysql_database_tasks.rb +76 -73
- data/lib/active_record/tasks/postgresql_database_tasks.rb +72 -47
- data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
- data/lib/active_record/timestamp.rb +46 -25
- data/lib/active_record/touch_later.rb +1 -2
- data/lib/active_record/transactions.rb +97 -109
- data/lib/active_record/type/adapter_specific_registry.rb +46 -42
- data/lib/active_record/type/decimal_without_scale.rb +13 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
- data/lib/active_record/type/internal/abstract_json.rb +4 -0
- data/lib/active_record/type/serialized.rb +14 -8
- data/lib/active_record/type/text.rb +9 -0
- data/lib/active_record/type/time.rb +0 -1
- data/lib/active_record/type/type_map.rb +11 -15
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type.rb +17 -13
- data/lib/active_record/type_caster/connection.rb +8 -6
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/type_caster.rb +2 -2
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +8 -39
- data/lib/active_record/validations.rb +4 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +20 -20
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
- data/lib/rails/generators/active_record/migration.rb +1 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
- data/lib/rails/generators/active_record.rb +4 -4
- metadata +24 -13
- data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -1,20 +1,29 @@
|
|
1
1
|
# Make sure we're using pg high enough for type casts and Ruby 2.2+ compatibility
|
2
2
|
gem "pg", ">= 0.18", "< 2.0"
|
3
|
-
require
|
3
|
+
require "pg"
|
4
|
+
|
5
|
+
# Use async_exec instead of exec_params on pg versions before 1.1
|
6
|
+
class ::PG::Connection
|
7
|
+
unless self.public_method_defined?(:async_exec_params)
|
8
|
+
remove_method :exec_params
|
9
|
+
alias exec_params async_exec
|
10
|
+
end
|
11
|
+
end
|
4
12
|
|
5
13
|
require "active_record/connection_adapters/abstract_adapter"
|
14
|
+
require "active_record/connection_adapters/statement_pool"
|
6
15
|
require "active_record/connection_adapters/postgresql/column"
|
7
16
|
require "active_record/connection_adapters/postgresql/database_statements"
|
8
17
|
require "active_record/connection_adapters/postgresql/explain_pretty_printer"
|
9
18
|
require "active_record/connection_adapters/postgresql/oid"
|
10
19
|
require "active_record/connection_adapters/postgresql/quoting"
|
11
20
|
require "active_record/connection_adapters/postgresql/referential_integrity"
|
21
|
+
require "active_record/connection_adapters/postgresql/schema_creation"
|
12
22
|
require "active_record/connection_adapters/postgresql/schema_definitions"
|
13
23
|
require "active_record/connection_adapters/postgresql/schema_dumper"
|
14
24
|
require "active_record/connection_adapters/postgresql/schema_statements"
|
15
25
|
require "active_record/connection_adapters/postgresql/type_metadata"
|
16
26
|
require "active_record/connection_adapters/postgresql/utils"
|
17
|
-
require "active_record/connection_adapters/statement_pool"
|
18
27
|
|
19
28
|
module ActiveRecord
|
20
29
|
module ConnectionHandling # :nodoc:
|
@@ -67,10 +76,10 @@ module ActiveRecord
|
|
67
76
|
# In addition, default connection parameters of libpq can be set per environment variables.
|
68
77
|
# See http://www.postgresql.org/docs/current/static/libpq-envars.html .
|
69
78
|
class PostgreSQLAdapter < AbstractAdapter
|
70
|
-
ADAPTER_NAME =
|
79
|
+
ADAPTER_NAME = "PostgreSQL".freeze
|
71
80
|
|
72
81
|
NATIVE_DATABASE_TYPES = {
|
73
|
-
primary_key: "
|
82
|
+
primary_key: "bigserial primary key",
|
74
83
|
string: { name: "character varying" },
|
75
84
|
text: { name: "text" },
|
76
85
|
integer: { name: "integer" },
|
@@ -108,6 +117,8 @@ module ActiveRecord
|
|
108
117
|
bit: { name: "bit" },
|
109
118
|
bit_varying: { name: "bit varying" },
|
110
119
|
money: { name: "money" },
|
120
|
+
interval: { name: "interval" },
|
121
|
+
oid: { name: "oid" },
|
111
122
|
}
|
112
123
|
|
113
124
|
OID = PostgreSQL::OID #:nodoc:
|
@@ -173,7 +184,7 @@ module ActiveRecord
|
|
173
184
|
end
|
174
185
|
|
175
186
|
def index_algorithms
|
176
|
-
{ concurrently:
|
187
|
+
{ concurrently: "CONCURRENTLY" }
|
177
188
|
end
|
178
189
|
|
179
190
|
class StatementPool < ConnectionAdapters::StatementPool
|
@@ -195,6 +206,7 @@ module ActiveRecord
|
|
195
206
|
|
196
207
|
def dealloc(key)
|
197
208
|
@connection.query "DEALLOCATE #{key}" if connection_active?
|
209
|
+
rescue PG::Error
|
198
210
|
end
|
199
211
|
|
200
212
|
def connection_active?
|
@@ -227,13 +239,15 @@ module ActiveRecord
|
|
227
239
|
|
228
240
|
@type_map = Type::HashLookupTypeMap.new
|
229
241
|
initialize_type_map(type_map)
|
230
|
-
@local_tz = execute(
|
242
|
+
@local_tz = execute("SHOW TIME ZONE", "SCHEMA").first["TimeZone"]
|
231
243
|
@use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true
|
232
244
|
end
|
233
245
|
|
234
246
|
# Clears the prepared statements cache.
|
235
247
|
def clear_cache!
|
236
|
-
@
|
248
|
+
@lock.synchronize do
|
249
|
+
@statements.clear
|
250
|
+
end
|
237
251
|
end
|
238
252
|
|
239
253
|
def truncate(table_name, name = nil)
|
@@ -242,7 +256,9 @@ module ActiveRecord
|
|
242
256
|
|
243
257
|
# Is this connection alive and ready for queries?
|
244
258
|
def active?
|
245
|
-
@
|
259
|
+
@lock.synchronize do
|
260
|
+
@connection.query "SELECT 1"
|
261
|
+
end
|
246
262
|
true
|
247
263
|
rescue PG::Error
|
248
264
|
false
|
@@ -250,44 +266,40 @@ module ActiveRecord
|
|
250
266
|
|
251
267
|
# Close then reopen the connection.
|
252
268
|
def reconnect!
|
253
|
-
|
254
|
-
|
255
|
-
|
269
|
+
@lock.synchronize do
|
270
|
+
super
|
271
|
+
@connection.reset
|
272
|
+
configure_connection
|
273
|
+
end
|
256
274
|
end
|
257
275
|
|
258
276
|
def reset!
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
@connection.
|
277
|
+
@lock.synchronize do
|
278
|
+
clear_cache!
|
279
|
+
reset_transaction
|
280
|
+
unless @connection.transaction_status == ::PG::PQTRANS_IDLE
|
281
|
+
@connection.query "ROLLBACK"
|
282
|
+
end
|
283
|
+
@connection.query "DISCARD ALL"
|
284
|
+
configure_connection
|
263
285
|
end
|
264
|
-
@connection.query 'DISCARD ALL'
|
265
|
-
configure_connection
|
266
286
|
end
|
267
287
|
|
268
288
|
# Disconnects from the database if already connected. Otherwise, this
|
269
289
|
# method does nothing.
|
270
290
|
def disconnect!
|
271
|
-
|
272
|
-
|
291
|
+
@lock.synchronize do
|
292
|
+
super
|
293
|
+
@connection.close rescue nil
|
294
|
+
end
|
273
295
|
end
|
274
296
|
|
275
297
|
def native_database_types #:nodoc:
|
276
298
|
NATIVE_DATABASE_TYPES
|
277
299
|
end
|
278
300
|
|
279
|
-
# Returns true, since this connection adapter supports migrations.
|
280
|
-
def supports_migrations?
|
281
|
-
true
|
282
|
-
end
|
283
|
-
|
284
|
-
# Does PostgreSQL support finding primary key on non-Active Record tables?
|
285
|
-
def supports_primary_key? #:nodoc:
|
286
|
-
true
|
287
|
-
end
|
288
|
-
|
289
301
|
def set_standard_conforming_strings
|
290
|
-
execute(
|
302
|
+
execute("SET standard_conforming_strings = on", "SCHEMA")
|
291
303
|
end
|
292
304
|
|
293
305
|
def supports_ddl_transactions?
|
@@ -315,18 +327,22 @@ module ActiveRecord
|
|
315
327
|
postgresql_version >= 90300
|
316
328
|
end
|
317
329
|
|
330
|
+
def supports_pgcrypto_uuid?
|
331
|
+
postgresql_version >= 90400
|
332
|
+
end
|
333
|
+
|
318
334
|
def get_advisory_lock(lock_id) # :nodoc:
|
319
335
|
unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
|
320
336
|
raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
|
321
337
|
end
|
322
|
-
|
338
|
+
query_value("SELECT pg_try_advisory_lock(#{lock_id})")
|
323
339
|
end
|
324
340
|
|
325
341
|
def release_advisory_lock(lock_id) # :nodoc:
|
326
342
|
unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
|
327
343
|
raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer")
|
328
344
|
end
|
329
|
-
|
345
|
+
query_value("SELECT pg_advisory_unlock(#{lock_id})")
|
330
346
|
end
|
331
347
|
|
332
348
|
def enable_extension(name)
|
@@ -343,15 +359,14 @@ module ActiveRecord
|
|
343
359
|
|
344
360
|
def extension_enabled?(name)
|
345
361
|
if supports_extensions?
|
346
|
-
res = exec_query
|
347
|
-
'SCHEMA'
|
362
|
+
res = exec_query("SELECT EXISTS(SELECT * FROM pg_available_extensions WHERE name = '#{name}' AND installed_version IS NOT NULL) as enabled", "SCHEMA")
|
348
363
|
res.cast_values.first
|
349
364
|
end
|
350
365
|
end
|
351
366
|
|
352
367
|
def extensions
|
353
368
|
if supports_extensions?
|
354
|
-
exec_query("SELECT extname
|
369
|
+
exec_query("SELECT extname FROM pg_extension", "SCHEMA").cast_values
|
355
370
|
else
|
356
371
|
super
|
357
372
|
end
|
@@ -359,7 +374,7 @@ module ActiveRecord
|
|
359
374
|
|
360
375
|
# Returns the configured supported identifier length supported by PostgreSQL
|
361
376
|
def max_identifier_length
|
362
|
-
@max_identifier_length ||=
|
377
|
+
@max_identifier_length ||= query_value("SHOW max_identifier_length", "SCHEMA").to_i
|
363
378
|
end
|
364
379
|
alias table_alias_length max_identifier_length
|
365
380
|
alias index_name_length max_identifier_length
|
@@ -367,26 +382,17 @@ module ActiveRecord
|
|
367
382
|
# Set the authorized user for this session
|
368
383
|
def session_auth=(user)
|
369
384
|
clear_cache!
|
370
|
-
|
385
|
+
execute("SET SESSION AUTHORIZATION #{user}")
|
371
386
|
end
|
372
387
|
|
373
388
|
def use_insert_returning?
|
374
389
|
@use_insert_returning
|
375
390
|
end
|
376
391
|
|
377
|
-
def valid_type?(type)
|
378
|
-
!native_database_types[type].nil?
|
379
|
-
end
|
380
|
-
|
381
392
|
def update_table_definition(table_name, base) #:nodoc:
|
382
393
|
PostgreSQL::Table.new(table_name, base)
|
383
394
|
end
|
384
395
|
|
385
|
-
def lookup_cast_type(sql_type) # :nodoc:
|
386
|
-
oid = execute("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").first['oid'].to_i
|
387
|
-
super(oid)
|
388
|
-
end
|
389
|
-
|
390
396
|
def column_name_for_operation(operation, node) # :nodoc:
|
391
397
|
OPERATION_ALIASES.fetch(operation) { operation.downcase }
|
392
398
|
end
|
@@ -402,12 +408,20 @@ module ActiveRecord
|
|
402
408
|
@connection.server_version
|
403
409
|
end
|
404
410
|
|
405
|
-
|
411
|
+
def default_index_type?(index) # :nodoc:
|
412
|
+
index.using == :btree || super
|
413
|
+
end
|
414
|
+
|
415
|
+
private
|
406
416
|
|
407
417
|
# See http://www.postgresql.org/docs/current/static/errcodes-appendix.html
|
408
418
|
VALUE_LIMIT_VIOLATION = "22001"
|
419
|
+
NUMERIC_VALUE_OUT_OF_RANGE = "22003"
|
420
|
+
NOT_NULL_VIOLATION = "23502"
|
409
421
|
FOREIGN_KEY_VIOLATION = "23503"
|
410
422
|
UNIQUE_VIOLATION = "23505"
|
423
|
+
SERIALIZATION_FAILURE = "40001"
|
424
|
+
DEADLOCK_DETECTED = "40P01"
|
411
425
|
|
412
426
|
def translate_exception(exception, message)
|
413
427
|
return exception unless exception.respond_to?(:result)
|
@@ -419,72 +433,80 @@ module ActiveRecord
|
|
419
433
|
InvalidForeignKey.new(message)
|
420
434
|
when VALUE_LIMIT_VIOLATION
|
421
435
|
ValueTooLong.new(message)
|
436
|
+
when NUMERIC_VALUE_OUT_OF_RANGE
|
437
|
+
RangeError.new(message)
|
438
|
+
when NOT_NULL_VIOLATION
|
439
|
+
NotNullViolation.new(message)
|
440
|
+
when SERIALIZATION_FAILURE
|
441
|
+
SerializationFailure.new(message)
|
442
|
+
when DEADLOCK_DETECTED
|
443
|
+
Deadlocked.new(message)
|
422
444
|
else
|
423
445
|
super
|
424
446
|
end
|
425
447
|
end
|
426
448
|
|
427
|
-
|
428
|
-
|
429
|
-
def get_oid_type(oid, fmod, column_name, sql_type = '') # :nodoc:
|
449
|
+
def get_oid_type(oid, fmod, column_name, sql_type = "".freeze)
|
430
450
|
if !type_map.key?(oid)
|
431
451
|
load_additional_types(type_map, [oid])
|
432
452
|
end
|
433
453
|
|
434
454
|
type_map.fetch(oid, fmod, sql_type) {
|
435
455
|
warn "unknown OID #{oid}: failed to recognize type of '#{column_name}'. It will be treated as String."
|
436
|
-
Type
|
456
|
+
Type.default_value.tap do |cast_type|
|
437
457
|
type_map.register_type(oid, cast_type)
|
438
458
|
end
|
439
459
|
}
|
440
460
|
end
|
441
461
|
|
442
|
-
def initialize_type_map(m)
|
443
|
-
register_class_with_limit m,
|
444
|
-
register_class_with_limit m,
|
445
|
-
register_class_with_limit m,
|
446
|
-
m.
|
447
|
-
m.register_type
|
448
|
-
m.alias_type
|
449
|
-
m.register_type
|
450
|
-
register_class_with_limit m,
|
451
|
-
m.alias_type
|
452
|
-
m.alias_type
|
453
|
-
m.alias_type
|
454
|
-
m.register_type
|
455
|
-
register_class_with_limit m,
|
456
|
-
register_class_with_limit m,
|
457
|
-
m.alias_type
|
458
|
-
m.register_type
|
459
|
-
|
460
|
-
m.register_type
|
461
|
-
m.register_type
|
462
|
-
m.register_type
|
463
|
-
m.register_type
|
464
|
-
m.register_type
|
465
|
-
m.register_type
|
466
|
-
m.register_type
|
467
|
-
m.register_type
|
468
|
-
m.register_type
|
469
|
-
m.register_type
|
470
|
-
m.register_type
|
471
|
-
m.register_type
|
472
|
-
m.register_type
|
473
|
-
m.register_type
|
474
|
-
m.register_type
|
475
|
-
m.register_type
|
476
|
-
m.register_type
|
477
|
-
m.register_type
|
478
|
-
m.register_type
|
479
|
-
m.register_type
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
m
|
462
|
+
def initialize_type_map(m)
|
463
|
+
register_class_with_limit m, "int2", Type::Integer
|
464
|
+
register_class_with_limit m, "int4", Type::Integer
|
465
|
+
register_class_with_limit m, "int8", Type::Integer
|
466
|
+
m.register_type "oid", OID::Oid.new
|
467
|
+
m.register_type "float4", Type::Float.new
|
468
|
+
m.alias_type "float8", "float4"
|
469
|
+
m.register_type "text", Type::Text.new
|
470
|
+
register_class_with_limit m, "varchar", Type::String
|
471
|
+
m.alias_type "char", "varchar"
|
472
|
+
m.alias_type "name", "varchar"
|
473
|
+
m.alias_type "bpchar", "varchar"
|
474
|
+
m.register_type "bool", Type::Boolean.new
|
475
|
+
register_class_with_limit m, "bit", OID::Bit
|
476
|
+
register_class_with_limit m, "varbit", OID::BitVarying
|
477
|
+
m.alias_type "timestamptz", "timestamp"
|
478
|
+
m.register_type "date", Type::Date.new
|
479
|
+
|
480
|
+
m.register_type "money", OID::Money.new
|
481
|
+
m.register_type "bytea", OID::Bytea.new
|
482
|
+
m.register_type "point", OID::Point.new
|
483
|
+
m.register_type "hstore", OID::Hstore.new
|
484
|
+
m.register_type "json", OID::Json.new
|
485
|
+
m.register_type "jsonb", OID::Jsonb.new
|
486
|
+
m.register_type "cidr", OID::Cidr.new
|
487
|
+
m.register_type "inet", OID::Inet.new
|
488
|
+
m.register_type "uuid", OID::Uuid.new
|
489
|
+
m.register_type "xml", OID::Xml.new
|
490
|
+
m.register_type "tsvector", OID::SpecializedString.new(:tsvector)
|
491
|
+
m.register_type "macaddr", OID::SpecializedString.new(:macaddr)
|
492
|
+
m.register_type "citext", OID::SpecializedString.new(:citext)
|
493
|
+
m.register_type "ltree", OID::SpecializedString.new(:ltree)
|
494
|
+
m.register_type "line", OID::SpecializedString.new(:line)
|
495
|
+
m.register_type "lseg", OID::SpecializedString.new(:lseg)
|
496
|
+
m.register_type "box", OID::SpecializedString.new(:box)
|
497
|
+
m.register_type "path", OID::SpecializedString.new(:path)
|
498
|
+
m.register_type "polygon", OID::SpecializedString.new(:polygon)
|
499
|
+
m.register_type "circle", OID::SpecializedString.new(:circle)
|
500
|
+
|
501
|
+
m.register_type "interval" do |_, _, sql_type|
|
502
|
+
precision = extract_precision(sql_type)
|
503
|
+
OID::SpecializedString.new(:interval, precision: precision)
|
504
|
+
end
|
505
|
+
|
506
|
+
register_class_with_precision m, "time", Type::Time
|
507
|
+
register_class_with_precision m, "timestamp", OID::DateTime
|
508
|
+
|
509
|
+
m.register_type "numeric" do |_, fmod, sql_type|
|
488
510
|
precision = extract_precision(sql_type)
|
489
511
|
scale = extract_scale(sql_type)
|
490
512
|
|
@@ -507,7 +529,7 @@ module ActiveRecord
|
|
507
529
|
load_additional_types(m)
|
508
530
|
end
|
509
531
|
|
510
|
-
def extract_limit(sql_type)
|
532
|
+
def extract_limit(sql_type)
|
511
533
|
case sql_type
|
512
534
|
when /^bigint/i, /^int8/i
|
513
535
|
8
|
@@ -519,41 +541,41 @@ module ActiveRecord
|
|
519
541
|
end
|
520
542
|
|
521
543
|
# Extracts the value from a PostgreSQL column default definition.
|
522
|
-
def extract_value_from_default(default)
|
544
|
+
def extract_value_from_default(default)
|
523
545
|
case default
|
524
546
|
# Quoted types
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
547
|
+
when /\A[\(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m
|
548
|
+
# The default 'now'::date is CURRENT_DATE
|
549
|
+
if $1 == "now".freeze && $2 == "date".freeze
|
550
|
+
nil
|
551
|
+
else
|
552
|
+
$1.gsub("''".freeze, "'".freeze)
|
553
|
+
end
|
532
554
|
# Boolean types
|
533
|
-
|
534
|
-
|
555
|
+
when "true".freeze, "false".freeze
|
556
|
+
default
|
535
557
|
# Numeric types
|
536
|
-
|
537
|
-
|
558
|
+
when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/
|
559
|
+
$1
|
538
560
|
# Object identifier types
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
561
|
+
when /\A-?\d+\z/
|
562
|
+
$1
|
563
|
+
else
|
564
|
+
# Anything else is blank, some user type, or some function
|
565
|
+
# and we can't know the value of that, so return nil.
|
566
|
+
nil
|
545
567
|
end
|
546
568
|
end
|
547
569
|
|
548
|
-
def extract_default_function(default_value, default)
|
570
|
+
def extract_default_function(default_value, default)
|
549
571
|
default if has_default_function?(default_value, default)
|
550
572
|
end
|
551
573
|
|
552
|
-
def has_default_function?(default_value, default)
|
553
|
-
!default_value &&
|
574
|
+
def has_default_function?(default_value, default)
|
575
|
+
!default_value && %r{\w+\(.*\)|\(.*\)::\w+|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
|
554
576
|
end
|
555
577
|
|
556
|
-
def load_additional_types(type_map, oids = nil)
|
578
|
+
def load_additional_types(type_map, oids = nil)
|
557
579
|
initializer = OID::TypeMapInitializer.new(type_map)
|
558
580
|
|
559
581
|
if supports_ranges?
|
@@ -575,7 +597,7 @@ module ActiveRecord
|
|
575
597
|
query += initializer.query_conditions_for_initial_load(type_map)
|
576
598
|
end
|
577
599
|
|
578
|
-
execute_and_clear(query,
|
600
|
+
execute_and_clear(query, "SCHEMA", []) do |records|
|
579
601
|
initializer.run(records)
|
580
602
|
end
|
581
603
|
end
|
@@ -597,7 +619,11 @@ module ActiveRecord
|
|
597
619
|
|
598
620
|
def exec_no_cache(sql, name, binds)
|
599
621
|
type_casted_binds = type_casted_binds(binds)
|
600
|
-
log(sql, name, binds, type_casted_binds)
|
622
|
+
log(sql, name, binds, type_casted_binds) do
|
623
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
624
|
+
@connection.exec_params(sql, type_casted_binds)
|
625
|
+
end
|
626
|
+
end
|
601
627
|
end
|
602
628
|
|
603
629
|
def exec_cache(sql, name, binds)
|
@@ -605,7 +631,9 @@ module ActiveRecord
|
|
605
631
|
type_casted_binds = type_casted_binds(binds)
|
606
632
|
|
607
633
|
log(sql, name, binds, type_casted_binds, stmt_key) do
|
608
|
-
|
634
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
635
|
+
@connection.exec_prepared(stmt_key, type_casted_binds)
|
636
|
+
end
|
609
637
|
end
|
610
638
|
rescue ActiveRecord::StatementInvalid => e
|
611
639
|
raise unless is_cached_plan_failure?(e)
|
@@ -615,8 +643,10 @@ module ActiveRecord
|
|
615
643
|
if in_transaction?
|
616
644
|
raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message)
|
617
645
|
else
|
618
|
-
|
619
|
-
|
646
|
+
@lock.synchronize do
|
647
|
+
# outside of transactions we can simply flush this query and retry
|
648
|
+
@statements.delete sql_key(sql)
|
649
|
+
end
|
620
650
|
retry
|
621
651
|
end
|
622
652
|
end
|
@@ -630,7 +660,7 @@ module ActiveRecord
|
|
630
660
|
#
|
631
661
|
# Check here for more details:
|
632
662
|
# http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
|
633
|
-
CACHED_PLAN_HEURISTIC =
|
663
|
+
CACHED_PLAN_HEURISTIC = "cached plan must not change result type".freeze
|
634
664
|
def is_cached_plan_failure?(e)
|
635
665
|
pgerror = e.cause
|
636
666
|
code = pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE)
|
@@ -652,19 +682,21 @@ module ActiveRecord
|
|
652
682
|
# Prepare the statement if it hasn't been prepared, return
|
653
683
|
# the statement key.
|
654
684
|
def prepare_statement(sql)
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
685
|
+
@lock.synchronize do
|
686
|
+
sql_key = sql_key(sql)
|
687
|
+
unless @statements.key? sql_key
|
688
|
+
nextkey = @statements.next_key
|
689
|
+
begin
|
690
|
+
@connection.prepare nextkey, sql
|
691
|
+
rescue => e
|
692
|
+
raise translate_exception_class(e, sql)
|
693
|
+
end
|
694
|
+
# Clear the queue
|
695
|
+
@connection.get_last_result
|
696
|
+
@statements[sql_key] = nextkey
|
662
697
|
end
|
663
|
-
|
664
|
-
@connection.get_last_result
|
665
|
-
@statements[sql_key] = nextkey
|
698
|
+
@statements[sql_key]
|
666
699
|
end
|
667
|
-
@statements[sql_key]
|
668
700
|
end
|
669
701
|
|
670
702
|
# Connects to a PostgreSQL server and sets up the adapter depending on the
|
@@ -686,7 +718,7 @@ module ActiveRecord
|
|
686
718
|
if @config[:encoding]
|
687
719
|
@connection.set_client_encoding(@config[:encoding])
|
688
720
|
end
|
689
|
-
self.client_min_messages = @config[:min_messages] ||
|
721
|
+
self.client_min_messages = @config[:min_messages] || "warning"
|
690
722
|
self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
|
691
723
|
|
692
724
|
# Use standard-conforming strings so we don't have to do the E'...' dance.
|
@@ -696,27 +728,27 @@ module ActiveRecord
|
|
696
728
|
# TIMESTAMP WITH ZONE types in UTC.
|
697
729
|
# (SET TIME ZONE does not use an equals sign like other SET variables)
|
698
730
|
if ActiveRecord::Base.default_timezone == :utc
|
699
|
-
execute("SET time zone 'UTC'",
|
731
|
+
execute("SET time zone 'UTC'", "SCHEMA")
|
700
732
|
elsif @local_tz
|
701
|
-
execute("SET time zone '#{@local_tz}'",
|
733
|
+
execute("SET time zone '#{@local_tz}'", "SCHEMA")
|
702
734
|
end
|
703
735
|
|
704
736
|
# SET statements from :variables config hash
|
705
737
|
# http://www.postgresql.org/docs/current/static/sql-set.html
|
706
738
|
variables = @config[:variables] || {}
|
707
739
|
variables.map do |k, v|
|
708
|
-
if v ==
|
740
|
+
if v == ":default" || v == :default
|
709
741
|
# Sets the value to the global or compile default
|
710
|
-
execute("SET SESSION #{k} TO DEFAULT",
|
742
|
+
execute("SET SESSION #{k} TO DEFAULT", "SCHEMA")
|
711
743
|
elsif !v.nil?
|
712
|
-
execute("SET SESSION #{k} TO #{quote(v)}",
|
744
|
+
execute("SET SESSION #{k} TO #{quote(v)}", "SCHEMA")
|
713
745
|
end
|
714
746
|
end
|
715
747
|
end
|
716
748
|
|
717
749
|
# Returns the current ID of a table's sequence.
|
718
|
-
def last_insert_id_result(sequence_name)
|
719
|
-
exec_query("SELECT currval('#{sequence_name}')",
|
750
|
+
def last_insert_id_result(sequence_name)
|
751
|
+
exec_query("SELECT currval('#{sequence_name}')", "SQL")
|
720
752
|
end
|
721
753
|
|
722
754
|
# Returns the list of a table's column names, data types, and default values.
|
@@ -737,27 +769,27 @@ module ActiveRecord
|
|
737
769
|
# Query implementation notes:
|
738
770
|
# - format_type includes the column size constraint, e.g. varchar(50)
|
739
771
|
# - ::regclass is a function that gives the id for a table name
|
740
|
-
def column_definitions(table_name)
|
741
|
-
query(<<-end_sql,
|
772
|
+
def column_definitions(table_name)
|
773
|
+
query(<<-end_sql, "SCHEMA")
|
742
774
|
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
|
743
775
|
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
WHERE a.attrelid =
|
776
|
+
c.collname, col_description(a.attrelid, a.attnum) AS comment
|
777
|
+
FROM pg_attribute a
|
778
|
+
LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
|
779
|
+
LEFT JOIN pg_type t ON a.atttypid = t.oid
|
780
|
+
LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
|
781
|
+
WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass
|
750
782
|
AND a.attnum > 0 AND NOT a.attisdropped
|
751
783
|
ORDER BY a.attnum
|
752
784
|
end_sql
|
753
785
|
end
|
754
786
|
|
755
|
-
def extract_table_ref_from_insert_sql(sql)
|
787
|
+
def extract_table_ref_from_insert_sql(sql)
|
756
788
|
sql[/into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im]
|
757
789
|
$1.strip if $1
|
758
790
|
end
|
759
791
|
|
760
|
-
def create_table_definition(*args)
|
792
|
+
def create_table_definition(*args)
|
761
793
|
PostgreSQL::TableDefinition.new(*args)
|
762
794
|
end
|
763
795
|
|
@@ -788,19 +820,18 @@ module ActiveRecord
|
|
788
820
|
map[Integer] = PG::TextEncoder::Integer.new
|
789
821
|
map[TrueClass] = PG::TextEncoder::Boolean.new
|
790
822
|
map[FalseClass] = PG::TextEncoder::Boolean.new
|
791
|
-
map[Float] = PG::TextEncoder::Float.new
|
792
823
|
@connection.type_map_for_queries = map
|
793
824
|
end
|
794
825
|
|
795
826
|
def add_pg_decoders
|
796
827
|
coders_by_name = {
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
828
|
+
"int2" => PG::TextDecoder::Integer,
|
829
|
+
"int4" => PG::TextDecoder::Integer,
|
830
|
+
"int8" => PG::TextDecoder::Integer,
|
831
|
+
"oid" => PG::TextDecoder::Integer,
|
832
|
+
"float4" => PG::TextDecoder::Float,
|
833
|
+
"float8" => PG::TextDecoder::Float,
|
834
|
+
"bool" => PG::TextDecoder::Boolean,
|
804
835
|
}
|
805
836
|
known_coder_types = coders_by_name.keys.map { |n| quote(n) }
|
806
837
|
query = <<-SQL % known_coder_types.join(", ")
|
@@ -810,7 +841,7 @@ module ActiveRecord
|
|
810
841
|
SQL
|
811
842
|
coders = execute_and_clear(query, "SCHEMA", []) do |result|
|
812
843
|
result
|
813
|
-
.map { |row| construct_coder(row, coders_by_name[row[
|
844
|
+
.map { |row| construct_coder(row, coders_by_name[row["typname"]]) }
|
814
845
|
.compact
|
815
846
|
end
|
816
847
|
|
@@ -821,7 +852,7 @@ module ActiveRecord
|
|
821
852
|
|
822
853
|
def construct_coder(row, coder_class)
|
823
854
|
return unless coder_class
|
824
|
-
coder_class.new(oid: row[
|
855
|
+
coder_class.new(oid: row["oid"].to_i, name: row["typname"])
|
825
856
|
end
|
826
857
|
|
827
858
|
ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
|
@@ -838,8 +869,8 @@ module ActiveRecord
|
|
838
869
|
ActiveRecord::Type.register(:json, OID::Json, adapter: :postgresql)
|
839
870
|
ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
|
840
871
|
ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
|
841
|
-
ActiveRecord::Type.register(:point, OID::
|
842
|
-
ActiveRecord::Type.register(:legacy_point, OID::
|
872
|
+
ActiveRecord::Type.register(:point, OID::Point, adapter: :postgresql)
|
873
|
+
ActiveRecord::Type.register(:legacy_point, OID::LegacyPoint, adapter: :postgresql)
|
843
874
|
ActiveRecord::Type.register(:uuid, OID::Uuid, adapter: :postgresql)
|
844
875
|
ActiveRecord::Type.register(:vector, OID::Vector, adapter: :postgresql)
|
845
876
|
ActiveRecord::Type.register(:xml, OID::Xml, adapter: :postgresql)
|