activerecord 7.0.0.alpha1 → 7.0.0.rc3
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 +4 -4
- data/CHANGELOG.md +516 -10
- data/lib/active_record/associations/association.rb +2 -8
- data/lib/active_record/associations/builder/collection_association.rb +9 -2
- data/lib/active_record/associations/collection_association.rb +10 -2
- data/lib/active_record/associations/preloader/association.rb +68 -48
- data/lib/active_record/associations/preloader/batch.rb +3 -6
- data/lib/active_record/associations/preloader/through_association.rb +19 -9
- data/lib/active_record/associations/preloader.rb +14 -24
- data/lib/active_record/associations/through_association.rb +2 -2
- data/lib/active_record/associations.rb +16 -3
- data/lib/active_record/asynchronous_queries_tracker.rb +3 -0
- data/lib/active_record/attribute_methods/dirty.rb +9 -1
- data/lib/active_record/attribute_methods.rb +7 -5
- data/lib/active_record/autosave_association.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +6 -26
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +18 -5
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +33 -70
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +9 -2
- data/lib/active_record/connection_adapters/abstract/transaction.rb +12 -19
- data/lib/active_record/connection_adapters/abstract_adapter.rb +37 -8
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +2 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +23 -24
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/pool_config.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -44
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +18 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +15 -4
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +48 -5
- data/lib/active_record/connection_adapters/schema_cache.rb +3 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +15 -16
- data/lib/active_record/connection_handling.rb +31 -19
- data/lib/active_record/core.rb +13 -24
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
- data/lib/active_record/database_configurations/database_config.rb +0 -9
- data/lib/active_record/database_configurations/hash_config.rb +40 -8
- data/lib/active_record/database_configurations.rb +2 -27
- data/lib/active_record/delegated_type.rb +19 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +1 -1
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +1 -2
- data/lib/active_record/encryption/message_serializer.rb +11 -1
- data/lib/active_record/encryption/scheme.rb +1 -1
- data/lib/active_record/enum.rb +8 -1
- data/lib/active_record/errors.rb +1 -1
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/fixture_set/table_row.rb +1 -1
- data/lib/active_record/fixtures.rb +1 -9
- data/lib/active_record/future_result.rb +2 -2
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/insert_all.rb +52 -15
- data/lib/active_record/integration.rb +3 -2
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/pessimistic.rb +9 -3
- data/lib/active_record/log_subscriber.rb +8 -1
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/model_schema.rb +1 -28
- data/lib/active_record/nested_attributes.rb +11 -10
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +99 -21
- data/lib/active_record/query_logs.rb +18 -83
- data/lib/active_record/railtie.rb +11 -1
- data/lib/active_record/railties/databases.rake +4 -91
- data/lib/active_record/reflection.rb +22 -6
- data/lib/active_record/relation/calculations.rb +1 -10
- data/lib/active_record/relation/finder_methods.rb +0 -13
- data/lib/active_record/relation/query_methods.rb +5 -14
- data/lib/active_record/relation/record_fetch_warning.rb +5 -7
- data/lib/active_record/relation/where_clause.rb +2 -15
- data/lib/active_record/relation.rb +11 -13
- data/lib/active_record/result.rb +0 -5
- data/lib/active_record/runtime_registry.rb +10 -12
- data/lib/active_record/schema_dumper.rb +7 -0
- data/lib/active_record/scoping.rb +34 -22
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/tasks/database_tasks.rb +18 -44
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -1
- data/lib/active_record/validations/uniqueness.rb +1 -1
- data/lib/active_record.rb +41 -33
- data/lib/arel/crud.rb +12 -2
- data/lib/arel/delete_manager.rb +16 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/nodes/delete_statement.rb +5 -1
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/update_statement.rb +5 -1
- data/lib/arel/nodes.rb +1 -0
- data/lib/arel/predications.rb +10 -2
- data/lib/arel/update_manager.rb +16 -0
- data/lib/arel/visitors/mysql.rb +2 -1
- data/lib/arel/visitors/to_sql.rb +15 -0
- data/lib/arel.rb +1 -0
- metadata +17 -13
@@ -9,45 +9,46 @@ module ActiveRecord
|
|
9
9
|
# Quotes the column value to help prevent
|
10
10
|
# {SQL injection attacks}[https://en.wikipedia.org/wiki/SQL_injection].
|
11
11
|
def quote(value)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
case value
|
13
|
+
when String, Symbol, ActiveSupport::Multibyte::Chars
|
14
|
+
"'#{quote_string(value.to_s)}'"
|
15
|
+
when true then quoted_true
|
16
|
+
when false then quoted_false
|
17
|
+
when nil then "NULL"
|
18
|
+
# BigDecimals need to be put in a non-normalized form and quoted.
|
19
|
+
when BigDecimal then value.to_s("F")
|
20
|
+
when Numeric, ActiveSupport::Duration then value.to_s
|
21
|
+
when Type::Binary::Data then quoted_binary(value)
|
22
|
+
when Type::Time::Value then "'#{quoted_time(value)}'"
|
23
|
+
when Date, Time then "'#{quoted_date(value)}'"
|
24
|
+
when Class then "'#{value}'"
|
25
|
+
else raise TypeError, "can't quote #{value.class.name}"
|
18
26
|
end
|
19
|
-
|
20
|
-
_quote(value)
|
21
27
|
end
|
22
28
|
|
23
29
|
# Cast a +value+ to a type that the database understands. For example,
|
24
30
|
# SQLite does not understand dates, so this method will convert a Date
|
25
31
|
# to a String.
|
26
|
-
def type_cast(value
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
MSG
|
39
|
-
type = lookup_cast_type_from_column(column)
|
40
|
-
value = type.serialize(value)
|
32
|
+
def type_cast(value)
|
33
|
+
case value
|
34
|
+
when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data
|
35
|
+
value.to_s
|
36
|
+
when true then unquoted_true
|
37
|
+
when false then unquoted_false
|
38
|
+
# BigDecimals need to be put in a non-normalized form and quoted.
|
39
|
+
when BigDecimal then value.to_s("F")
|
40
|
+
when nil, Numeric, String then value
|
41
|
+
when Type::Time::Value then quoted_time(value)
|
42
|
+
when Date, Time then quoted_date(value)
|
43
|
+
else raise TypeError, "can't cast #{value.class.name}"
|
41
44
|
end
|
42
|
-
|
43
|
-
_type_cast(value)
|
44
45
|
end
|
45
46
|
|
46
47
|
# Quote a value to be used as a bound parameter of unknown type. For example,
|
47
48
|
# MySQL might perform dangerous castings when comparing a string to a number,
|
48
49
|
# so this method will cast numbers to string.
|
49
50
|
def quote_bound_value(value)
|
50
|
-
|
51
|
+
quote(value)
|
51
52
|
end
|
52
53
|
|
53
54
|
# If you are having to call this function, you are likely doing something
|
@@ -127,7 +128,7 @@ module ActiveRecord
|
|
127
128
|
end
|
128
129
|
end
|
129
130
|
|
130
|
-
result = value.
|
131
|
+
result = value.to_formatted_s(:db)
|
131
132
|
if value.respond_to?(:usec) && value.usec > 0
|
132
133
|
result << "." << sprintf("%06d", value.usec)
|
133
134
|
else
|
@@ -203,16 +204,11 @@ module ActiveRecord
|
|
203
204
|
|
204
205
|
private
|
205
206
|
def type_casted_binds(binds)
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
if ActiveModel::Attribute === value
|
212
|
-
type_cast(value.value_for_database)
|
213
|
-
else
|
214
|
-
type_cast(value)
|
215
|
-
end
|
207
|
+
binds.map do |value|
|
208
|
+
if ActiveModel::Attribute === value
|
209
|
+
type_cast(value.value_for_database)
|
210
|
+
else
|
211
|
+
type_cast(value)
|
216
212
|
end
|
217
213
|
end
|
218
214
|
end
|
@@ -220,39 +216,6 @@ module ActiveRecord
|
|
220
216
|
def lookup_cast_type(sql_type)
|
221
217
|
type_map.lookup(sql_type)
|
222
218
|
end
|
223
|
-
|
224
|
-
def _quote(value)
|
225
|
-
case value
|
226
|
-
when String, Symbol, ActiveSupport::Multibyte::Chars
|
227
|
-
"'#{quote_string(value.to_s)}'"
|
228
|
-
when true then quoted_true
|
229
|
-
when false then quoted_false
|
230
|
-
when nil then "NULL"
|
231
|
-
# BigDecimals need to be put in a non-normalized form and quoted.
|
232
|
-
when BigDecimal then value.to_s("F")
|
233
|
-
when Numeric, ActiveSupport::Duration then value.to_s
|
234
|
-
when Type::Binary::Data then quoted_binary(value)
|
235
|
-
when Type::Time::Value then "'#{quoted_time(value)}'"
|
236
|
-
when Date, Time then "'#{quoted_date(value)}'"
|
237
|
-
when Class then "'#{value}'"
|
238
|
-
else raise TypeError, "can't quote #{value.class.name}"
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
def _type_cast(value)
|
243
|
-
case value
|
244
|
-
when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data
|
245
|
-
value.to_s
|
246
|
-
when true then unquoted_true
|
247
|
-
when false then unquoted_false
|
248
|
-
# BigDecimals need to be put in a non-normalized form and quoted.
|
249
|
-
when BigDecimal then value.to_s("F")
|
250
|
-
when nil, Numeric, String then value
|
251
|
-
when Type::Time::Value then quoted_time(value)
|
252
|
-
when Date, Time then quoted_date(value)
|
253
|
-
else raise TypeError, "can't cast #{value.class.name}"
|
254
|
-
end
|
255
|
-
end
|
256
219
|
end
|
257
220
|
end
|
258
221
|
end
|
@@ -124,6 +124,9 @@ module ActiveRecord
|
|
124
124
|
# column_exists?(:suppliers, :name)
|
125
125
|
#
|
126
126
|
# # Check a column exists of a particular type
|
127
|
+
# #
|
128
|
+
# # This works for standard non-casted types (eg. string) but is unreliable
|
129
|
+
# # for types that may get cast to something else (eg. char, bigint).
|
127
130
|
# column_exists?(:suppliers, :name, :string)
|
128
131
|
#
|
129
132
|
# # Check a column exists with a specific definition
|
@@ -653,7 +656,8 @@ module ActiveRecord
|
|
653
656
|
# The +type+ and +options+ parameters will be ignored if present. It can be helpful
|
654
657
|
# to provide these in a migration's +change+ method so it can be reverted.
|
655
658
|
# In that case, +type+ and +options+ will be used by #add_column.
|
656
|
-
#
|
659
|
+
# Depending on the database you're using, indexes using this column may be
|
660
|
+
# automatically removed or modified to remove this column from the index.
|
657
661
|
#
|
658
662
|
# If the options provided include an +if_exists+ key, it will be used to check if the
|
659
663
|
# column does not exist. This will silently ignore the migration rather than raising
|
@@ -778,7 +782,7 @@ module ActiveRecord
|
|
778
782
|
#
|
779
783
|
# CREATE INDEX by_name_surname ON accounts(name(10), surname(15))
|
780
784
|
#
|
781
|
-
# Note:
|
785
|
+
# Note: only supported by MySQL
|
782
786
|
#
|
783
787
|
# ====== Creating an index with a sort order (desc or asc, asc is the default)
|
784
788
|
#
|
@@ -1075,6 +1079,9 @@ module ActiveRecord
|
|
1075
1079
|
# duplicate column errors.
|
1076
1080
|
# [<tt>:validate</tt>]
|
1077
1081
|
# (PostgreSQL only) Specify whether or not the constraint should be validated. Defaults to +true+.
|
1082
|
+
# [<tt>:deferrable</tt>]
|
1083
|
+
# (PostgreSQL only) Specify whether or not the foreign key should be deferrable. Valid values are booleans or
|
1084
|
+
# +:deferred+ or +:immediate+ to specify the default behavior. Defaults to +false+.
|
1078
1085
|
def add_foreign_key(from_table, to_table, **options)
|
1079
1086
|
return unless supports_foreign_keys?
|
1080
1087
|
return if options[:if_not_exists] == true && foreign_key_exists?(from_table, to_table)
|
@@ -333,26 +333,19 @@ module ActiveRecord
|
|
333
333
|
# @connection still holds an open or invalid transaction, so we must not
|
334
334
|
# put it back in the pool for reuse.
|
335
335
|
@connection.throw_away! unless transaction.state.rolledback?
|
336
|
+
elsif Thread.current.status == "aborting" || (!completed && transaction.written)
|
337
|
+
# The transaction is still open but the block returned earlier.
|
338
|
+
#
|
339
|
+
# The block could return early because of a timeout or because the thread is aborting,
|
340
|
+
# so we are rolling back to make sure the timeout didn't caused the transaction to be
|
341
|
+
# committed incompletely.
|
342
|
+
rollback_transaction
|
336
343
|
else
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
Using `return`, `break` or `throw` to exit a transaction block is
|
343
|
-
deprecated without replacement. If the `throw` came from
|
344
|
-
`Timeout.timeout(duration)`, pass an exception class as a second
|
345
|
-
argument so it doesn't use `throw` to abort its block. This results
|
346
|
-
in the transaction being committed, but in the next release of Rails
|
347
|
-
it will rollback.
|
348
|
-
EOW
|
349
|
-
end
|
350
|
-
begin
|
351
|
-
commit_transaction
|
352
|
-
rescue Exception
|
353
|
-
rollback_transaction(transaction) unless transaction.state.completed?
|
354
|
-
raise
|
355
|
-
end
|
344
|
+
begin
|
345
|
+
commit_transaction
|
346
|
+
rescue Exception
|
347
|
+
rollback_transaction(transaction) unless transaction.state.completed?
|
348
|
+
raise
|
356
349
|
end
|
357
350
|
end
|
358
351
|
end
|
@@ -88,7 +88,7 @@ module ActiveRecord
|
|
88
88
|
@logger = logger
|
89
89
|
@config = config
|
90
90
|
@pool = ActiveRecord::ConnectionAdapters::NullPool.new
|
91
|
-
@idle_since =
|
91
|
+
@idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
92
92
|
@visitor = arel_visitor
|
93
93
|
@statements = build_statement_pool
|
94
94
|
@lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
|
@@ -141,9 +141,9 @@ module ActiveRecord
|
|
141
141
|
def preventing_writes?
|
142
142
|
return true if replica?
|
143
143
|
return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord.legacy_connection_handling
|
144
|
-
return false if
|
144
|
+
return false if connection_class.nil?
|
145
145
|
|
146
|
-
|
146
|
+
connection_class.current_preventing_writes
|
147
147
|
end
|
148
148
|
|
149
149
|
def migrations_paths # :nodoc:
|
@@ -178,7 +178,7 @@ module ActiveRecord
|
|
178
178
|
alias :prepared_statements :prepared_statements?
|
179
179
|
|
180
180
|
def prepared_statements_disabled_cache # :nodoc:
|
181
|
-
|
181
|
+
ActiveSupport::IsolatedExecutionState[:active_record_prepared_statements_disabled_cache] ||= Set.new
|
182
182
|
end
|
183
183
|
|
184
184
|
class Version
|
@@ -220,8 +220,20 @@ module ActiveRecord
|
|
220
220
|
@owner = Thread.current
|
221
221
|
end
|
222
222
|
|
223
|
-
def
|
224
|
-
@pool.
|
223
|
+
def connection_class # :nodoc:
|
224
|
+
@pool.connection_class
|
225
|
+
end
|
226
|
+
|
227
|
+
# The role (ie :writing) for the current connection. In a
|
228
|
+
# non-multi role application, `:writing` is returned.
|
229
|
+
def role
|
230
|
+
@pool.role
|
231
|
+
end
|
232
|
+
|
233
|
+
# The shard (ie :default) for the current connection. In
|
234
|
+
# a non-sharded application, `:default` is returned.
|
235
|
+
def shard
|
236
|
+
@pool.shard
|
225
237
|
end
|
226
238
|
|
227
239
|
def schema_cache
|
@@ -242,7 +254,7 @@ module ActiveRecord
|
|
242
254
|
"Current thread: #{Thread.current}."
|
243
255
|
end
|
244
256
|
|
245
|
-
@idle_since =
|
257
|
+
@idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
246
258
|
@owner = nil
|
247
259
|
else
|
248
260
|
raise ActiveRecordError, "Cannot expire connection, it is not currently leased."
|
@@ -265,7 +277,7 @@ module ActiveRecord
|
|
265
277
|
# Seconds since this connection was returned to the pool
|
266
278
|
def seconds_idle # :nodoc:
|
267
279
|
return 0 if in_use?
|
268
|
-
|
280
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC) - @idle_since
|
269
281
|
end
|
270
282
|
|
271
283
|
def unprepared_statement
|
@@ -363,6 +375,11 @@ module ActiveRecord
|
|
363
375
|
false
|
364
376
|
end
|
365
377
|
|
378
|
+
# Does this adapter support creating deferrable constraints?
|
379
|
+
def supports_deferrable_constraints?
|
380
|
+
false
|
381
|
+
end
|
382
|
+
|
366
383
|
# Does this adapter support creating check constraints?
|
367
384
|
def supports_check_constraints?
|
368
385
|
false
|
@@ -454,6 +471,10 @@ module ActiveRecord
|
|
454
471
|
def enable_extension(name)
|
455
472
|
end
|
456
473
|
|
474
|
+
# This is meant to be implemented by the adapters that support custom enum types
|
475
|
+
def create_enum(*) # :nodoc:
|
476
|
+
end
|
477
|
+
|
457
478
|
def advisory_locks_enabled? # :nodoc:
|
458
479
|
supports_advisory_locks? && @advisory_locks_enabled
|
459
480
|
end
|
@@ -632,6 +653,14 @@ module ActiveRecord
|
|
632
653
|
def check_version # :nodoc:
|
633
654
|
end
|
634
655
|
|
656
|
+
# Returns the version identifier of the schema currently available in
|
657
|
+
# the database. This is generally equal to the number of the highest-
|
658
|
+
# numbered migration that has been executed, or 0 if no schema
|
659
|
+
# information is present / the database is empty.
|
660
|
+
def schema_version
|
661
|
+
migration_context.current_version
|
662
|
+
end
|
663
|
+
|
635
664
|
def field_ordered_value(column, values) # :nodoc:
|
636
665
|
node = Arel::Nodes::Case.new(column)
|
637
666
|
values.each.with_index(1) do |value, order|
|
@@ -31,6 +31,7 @@ module ActiveRecord
|
|
31
31
|
string: { name: "varchar", limit: 255 },
|
32
32
|
text: { name: "text" },
|
33
33
|
integer: { name: "int", limit: 4 },
|
34
|
+
bigint: { name: "bigint" },
|
34
35
|
float: { name: "float", limit: 24 },
|
35
36
|
decimal: { name: "decimal" },
|
36
37
|
datetime: { name: "datetime" },
|
@@ -30,9 +30,9 @@ module ActiveRecord
|
|
30
30
|
|
31
31
|
def explain(arel, binds = [])
|
32
32
|
sql = "EXPLAIN #{to_sql(arel, binds)}"
|
33
|
-
start =
|
33
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
34
34
|
result = exec_query(sql, "EXPLAIN", binds)
|
35
|
-
elapsed =
|
35
|
+
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
36
36
|
|
37
37
|
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
|
38
38
|
end
|
@@ -9,15 +9,15 @@ module ActiveRecord
|
|
9
9
|
def quote_bound_value(value)
|
10
10
|
case value
|
11
11
|
when Numeric
|
12
|
-
|
12
|
+
quote(value.to_s)
|
13
13
|
when BigDecimal
|
14
|
-
|
14
|
+
quote(value.to_s("F"))
|
15
15
|
when true
|
16
16
|
"'1'"
|
17
17
|
when false
|
18
18
|
"'0'"
|
19
19
|
else
|
20
|
-
|
20
|
+
quote(value)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -49,6 +49,26 @@ module ActiveRecord
|
|
49
49
|
"x'#{value.hex}'"
|
50
50
|
end
|
51
51
|
|
52
|
+
# Override +type_cast+ we pass to mysql2 Date and Time objects instead
|
53
|
+
# of Strings since mysql2 is able to handle those classes more efficiently.
|
54
|
+
def type_cast(value) # :nodoc:
|
55
|
+
case value
|
56
|
+
when ActiveSupport::TimeWithZone
|
57
|
+
# We need to check explicitly for ActiveSupport::TimeWithZone because
|
58
|
+
# we need to transform it to Time objects but we don't want to
|
59
|
+
# transform Time objects to themselves.
|
60
|
+
if ActiveRecord.default_timezone == :utc
|
61
|
+
value.getutc
|
62
|
+
else
|
63
|
+
value.getlocal
|
64
|
+
end
|
65
|
+
when Date, Time
|
66
|
+
value
|
67
|
+
else
|
68
|
+
super
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
52
72
|
def column_name_matcher
|
53
73
|
COLUMN_NAME
|
54
74
|
end
|
@@ -84,27 +104,6 @@ module ActiveRecord
|
|
84
104
|
/ix
|
85
105
|
|
86
106
|
private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
|
87
|
-
|
88
|
-
private
|
89
|
-
# Override +_type_cast+ we pass to mysql2 Date and Time objects instead
|
90
|
-
# of Strings since mysql2 is able to handle those classes more efficiently.
|
91
|
-
def _type_cast(value)
|
92
|
-
case value
|
93
|
-
when ActiveSupport::TimeWithZone
|
94
|
-
# We need to check explicitly for ActiveSupport::TimeWithZone because
|
95
|
-
# we need to transform it to Time objects but we don't want to
|
96
|
-
# transform Time objects to themselves.
|
97
|
-
if ActiveRecord.default_timezone == :utc
|
98
|
-
value.getutc
|
99
|
-
else
|
100
|
-
value.getlocal
|
101
|
-
end
|
102
|
-
when Date, Time
|
103
|
-
value
|
104
|
-
else
|
105
|
-
super
|
106
|
-
end
|
107
|
-
end
|
108
107
|
end
|
109
108
|
end
|
110
109
|
end
|
@@ -206,7 +206,7 @@ module ActiveRecord
|
|
206
206
|
def data_source_sql(name = nil, type: nil)
|
207
207
|
scope = quoted_scope(name, type: type)
|
208
208
|
|
209
|
-
sql = +"SELECT table_name FROM (SELECT
|
209
|
+
sql = +"SELECT table_name FROM (SELECT table_name, table_type FROM information_schema.tables "
|
210
210
|
sql << " WHERE table_schema = #{scope[:schema]}) _subquery"
|
211
211
|
if scope[:type] || scope[:name]
|
212
212
|
conditions = []
|
@@ -5,7 +5,7 @@ module ActiveRecord
|
|
5
5
|
class PoolConfig # :nodoc:
|
6
6
|
include Mutex_m
|
7
7
|
|
8
|
-
attr_reader :db_config, :
|
8
|
+
attr_reader :db_config, :connection_class, :role, :shard
|
9
9
|
attr_accessor :schema_cache
|
10
10
|
|
11
11
|
INSTANCES = ObjectSpace::WeakMap.new
|
@@ -17,19 +17,21 @@ module ActiveRecord
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
def initialize(
|
20
|
+
def initialize(connection_class, db_config, role, shard)
|
21
21
|
super()
|
22
|
-
@
|
22
|
+
@connection_class = connection_class
|
23
23
|
@db_config = db_config
|
24
|
+
@role = role
|
25
|
+
@shard = shard
|
24
26
|
@pool = nil
|
25
27
|
INSTANCES[self] = self
|
26
28
|
end
|
27
29
|
|
28
30
|
def connection_specification_name
|
29
|
-
if
|
31
|
+
if connection_class.primary_class?
|
30
32
|
"ActiveRecord::Base"
|
31
33
|
else
|
32
|
-
|
34
|
+
connection_class.name
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
@@ -1,25 +1,41 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/object/blank"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
module ConnectionAdapters
|
5
7
|
module PostgreSQL
|
6
8
|
class Column < ConnectionAdapters::Column # :nodoc:
|
7
9
|
delegate :oid, :fmod, to: :sql_type_metadata
|
8
10
|
|
9
|
-
def initialize(*, serial: nil, **)
|
11
|
+
def initialize(*, serial: nil, generated: nil, **)
|
10
12
|
super
|
11
13
|
@serial = serial
|
14
|
+
@generated = generated
|
12
15
|
end
|
13
16
|
|
14
17
|
def serial?
|
15
18
|
@serial
|
16
19
|
end
|
17
20
|
|
21
|
+
def virtual?
|
22
|
+
# We assume every generated column is virtual, no matter the concrete type
|
23
|
+
@generated.present?
|
24
|
+
end
|
25
|
+
|
26
|
+
def has_default?
|
27
|
+
super && !virtual?
|
28
|
+
end
|
29
|
+
|
18
30
|
def array
|
19
31
|
sql_type_metadata.sql_type.end_with?("[]")
|
20
32
|
end
|
21
33
|
alias :array? :array
|
22
34
|
|
35
|
+
def enum?
|
36
|
+
type == :enum
|
37
|
+
end
|
38
|
+
|
23
39
|
def sql_type
|
24
40
|
super.delete_suffix("[]")
|
25
41
|
end
|
@@ -16,6 +16,31 @@ module ActiveRecord
|
|
16
16
|
@connection.unescape_bytea(value) if value
|
17
17
|
end
|
18
18
|
|
19
|
+
def quote(value) # :nodoc:
|
20
|
+
case value
|
21
|
+
when OID::Xml::Data
|
22
|
+
"xml '#{quote_string(value.to_s)}'"
|
23
|
+
when OID::Bit::Data
|
24
|
+
if value.binary?
|
25
|
+
"B'#{value}'"
|
26
|
+
elsif value.hex?
|
27
|
+
"X'#{value}'"
|
28
|
+
end
|
29
|
+
when Numeric
|
30
|
+
if value.finite?
|
31
|
+
super
|
32
|
+
else
|
33
|
+
"'#{value}'"
|
34
|
+
end
|
35
|
+
when OID::Array::Data
|
36
|
+
quote(encode_array(value))
|
37
|
+
when Range
|
38
|
+
quote(encode_range(value))
|
39
|
+
else
|
40
|
+
super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
19
44
|
# Quotes strings for use in SQL input.
|
20
45
|
def quote_string(s) # :nodoc:
|
21
46
|
PG::Connection.escape(s)
|
@@ -74,6 +99,24 @@ module ActiveRecord
|
|
74
99
|
end
|
75
100
|
end
|
76
101
|
|
102
|
+
def type_cast(value) # :nodoc:
|
103
|
+
case value
|
104
|
+
when Type::Binary::Data
|
105
|
+
# Return a bind param hash with format as binary.
|
106
|
+
# See https://deveiate.org/code/pg/PG/Connection.html#method-i-exec_prepared-doc
|
107
|
+
# for more information
|
108
|
+
{ value: value.to_s, format: 1 }
|
109
|
+
when OID::Xml::Data, OID::Bit::Data
|
110
|
+
value.to_s
|
111
|
+
when OID::Array::Data
|
112
|
+
encode_array(value)
|
113
|
+
when Range
|
114
|
+
encode_range(value)
|
115
|
+
else
|
116
|
+
super
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
77
120
|
def lookup_cast_type_from_column(column) # :nodoc:
|
78
121
|
type_map.lookup(column.oid, column.fmod, column.sql_type)
|
79
122
|
end
|
@@ -120,49 +163,6 @@ module ActiveRecord
|
|
120
163
|
super(query_value("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").to_i)
|
121
164
|
end
|
122
165
|
|
123
|
-
def _quote(value)
|
124
|
-
case value
|
125
|
-
when OID::Xml::Data
|
126
|
-
"xml '#{quote_string(value.to_s)}'"
|
127
|
-
when OID::Bit::Data
|
128
|
-
if value.binary?
|
129
|
-
"B'#{value}'"
|
130
|
-
elsif value.hex?
|
131
|
-
"X'#{value}'"
|
132
|
-
end
|
133
|
-
when Numeric
|
134
|
-
if value.finite?
|
135
|
-
super
|
136
|
-
else
|
137
|
-
"'#{value}'"
|
138
|
-
end
|
139
|
-
when OID::Array::Data
|
140
|
-
_quote(encode_array(value))
|
141
|
-
when Range
|
142
|
-
_quote(encode_range(value))
|
143
|
-
else
|
144
|
-
super
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
def _type_cast(value)
|
149
|
-
case value
|
150
|
-
when Type::Binary::Data
|
151
|
-
# Return a bind param hash with format as binary.
|
152
|
-
# See https://deveiate.org/code/pg/PG/Connection.html#method-i-exec_prepared-doc
|
153
|
-
# for more information
|
154
|
-
{ value: value.to_s, format: 1 }
|
155
|
-
when OID::Xml::Data, OID::Bit::Data
|
156
|
-
value.to_s
|
157
|
-
when OID::Array::Data
|
158
|
-
encode_array(value)
|
159
|
-
when Range
|
160
|
-
encode_range(value)
|
161
|
-
else
|
162
|
-
super
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
166
|
def encode_array(array_data)
|
167
167
|
encoder = array_data.encoder
|
168
168
|
values = type_cast_array(array_data.values)
|
@@ -188,7 +188,7 @@ module ActiveRecord
|
|
188
188
|
def type_cast_array(values)
|
189
189
|
case values
|
190
190
|
when ::Array then values.map { |item| type_cast_array(item) }
|
191
|
-
else
|
191
|
+
else type_cast(values)
|
192
192
|
end
|
193
193
|
end
|
194
194
|
|