activerecord 7.0.0.alpha2 → 7.0.0

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

Potentially problematic release.


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

Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +539 -11
  3. data/lib/active_record/associations/association.rb +2 -8
  4. data/lib/active_record/associations/builder/collection_association.rb +9 -2
  5. data/lib/active_record/associations/collection_association.rb +10 -2
  6. data/lib/active_record/associations/join_dependency.rb +6 -2
  7. data/lib/active_record/associations/preloader/association.rb +68 -48
  8. data/lib/active_record/associations/preloader/batch.rb +3 -6
  9. data/lib/active_record/associations/preloader/through_association.rb +19 -9
  10. data/lib/active_record/associations/preloader.rb +14 -24
  11. data/lib/active_record/associations/through_association.rb +2 -2
  12. data/lib/active_record/associations.rb +16 -3
  13. data/lib/active_record/asynchronous_queries_tracker.rb +3 -0
  14. data/lib/active_record/attribute_methods/dirty.rb +9 -1
  15. data/lib/active_record/attribute_methods.rb +7 -5
  16. data/lib/active_record/autosave_association.rb +3 -3
  17. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +6 -26
  18. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -2
  19. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +18 -5
  20. data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
  21. data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
  22. data/lib/active_record/connection_adapters/abstract/quoting.rb +33 -70
  23. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -0
  24. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +9 -2
  25. data/lib/active_record/connection_adapters/abstract/transaction.rb +12 -19
  26. data/lib/active_record/connection_adapters/abstract_adapter.rb +37 -8
  27. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +1 -0
  28. data/lib/active_record/connection_adapters/column.rb +4 -0
  29. data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -2
  30. data/lib/active_record/connection_adapters/mysql/quoting.rb +23 -24
  31. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -1
  32. data/lib/active_record/connection_adapters/pool_config.rb +7 -5
  33. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
  34. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +2 -0
  35. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -44
  36. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
  37. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +18 -1
  38. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
  39. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +15 -4
  40. data/lib/active_record/connection_adapters/postgresql_adapter.rb +48 -5
  41. data/lib/active_record/connection_adapters/schema_cache.rb +3 -1
  42. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +4 -2
  43. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +15 -16
  44. data/lib/active_record/connection_handling.rb +31 -19
  45. data/lib/active_record/core.rb +13 -24
  46. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
  47. data/lib/active_record/database_configurations/database_config.rb +0 -9
  48. data/lib/active_record/database_configurations/hash_config.rb +40 -8
  49. data/lib/active_record/database_configurations.rb +2 -27
  50. data/lib/active_record/delegated_type.rb +19 -0
  51. data/lib/active_record/encryption/encryptable_record.rb +1 -1
  52. data/lib/active_record/encryption/encrypted_attribute_type.rb +1 -1
  53. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +1 -2
  54. data/lib/active_record/encryption/message_serializer.rb +11 -1
  55. data/lib/active_record/encryption/scheme.rb +1 -1
  56. data/lib/active_record/enum.rb +8 -1
  57. data/lib/active_record/errors.rb +1 -1
  58. data/lib/active_record/explain_registry.rb +11 -6
  59. data/lib/active_record/fixture_set/table_row.rb +1 -1
  60. data/lib/active_record/fixtures.rb +1 -9
  61. data/lib/active_record/future_result.rb +2 -2
  62. data/lib/active_record/gem_version.rb +1 -1
  63. data/lib/active_record/insert_all.rb +52 -15
  64. data/lib/active_record/integration.rb +3 -2
  65. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  66. data/lib/active_record/locking/pessimistic.rb +9 -3
  67. data/lib/active_record/log_subscriber.rb +8 -1
  68. data/lib/active_record/middleware/shard_selector.rb +60 -0
  69. data/lib/active_record/migration.rb +2 -2
  70. data/lib/active_record/model_schema.rb +1 -28
  71. data/lib/active_record/nested_attributes.rb +11 -10
  72. data/lib/active_record/no_touching.rb +1 -1
  73. data/lib/active_record/persistence.rb +99 -21
  74. data/lib/active_record/query_logs.rb +18 -83
  75. data/lib/active_record/railtie.rb +11 -1
  76. data/lib/active_record/railties/databases.rake +4 -91
  77. data/lib/active_record/reflection.rb +22 -6
  78. data/lib/active_record/relation/calculations.rb +1 -10
  79. data/lib/active_record/relation/finder_methods.rb +0 -13
  80. data/lib/active_record/relation/query_methods.rb +5 -14
  81. data/lib/active_record/relation/record_fetch_warning.rb +5 -7
  82. data/lib/active_record/relation/where_clause.rb +2 -15
  83. data/lib/active_record/relation.rb +11 -15
  84. data/lib/active_record/result.rb +0 -5
  85. data/lib/active_record/runtime_registry.rb +10 -12
  86. data/lib/active_record/schema_dumper.rb +7 -0
  87. data/lib/active_record/schema_migration.rb +4 -0
  88. data/lib/active_record/scoping.rb +34 -22
  89. data/lib/active_record/suppressor.rb +11 -15
  90. data/lib/active_record/tasks/database_tasks.rb +18 -44
  91. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -1
  92. data/lib/active_record/validations/uniqueness.rb +1 -1
  93. data/lib/active_record.rb +41 -33
  94. data/lib/arel/crud.rb +12 -2
  95. data/lib/arel/delete_manager.rb +16 -0
  96. data/lib/arel/filter_predications.rb +9 -0
  97. data/lib/arel/nodes/delete_statement.rb +5 -1
  98. data/lib/arel/nodes/filter.rb +10 -0
  99. data/lib/arel/nodes/function.rb +1 -0
  100. data/lib/arel/nodes/update_statement.rb +5 -1
  101. data/lib/arel/nodes.rb +1 -0
  102. data/lib/arel/predications.rb +10 -2
  103. data/lib/arel/update_manager.rb +16 -0
  104. data/lib/arel/visitors/mysql.rb +2 -1
  105. data/lib/arel/visitors/to_sql.rb +15 -0
  106. data/lib/arel.rb +1 -0
  107. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  108. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  109. metadata +18 -12
@@ -19,6 +19,13 @@ module ActiveRecord
19
19
  def set_schema_cache(cache)
20
20
  self.schema_cache = cache
21
21
  end
22
+
23
+ def lazily_set_schema_cache
24
+ return unless ActiveRecord.lazily_load_schema_cache
25
+
26
+ cache = SchemaCache.load_from(db_config.lazy_schema_cache_path)
27
+ set_schema_cache(cache)
28
+ end
22
29
  end
23
30
 
24
31
  class NullPool # :nodoc:
@@ -26,7 +33,7 @@ module ActiveRecord
26
33
 
27
34
  attr_accessor :schema_cache
28
35
 
29
- def connection_klass; end
36
+ def connection_class; end
30
37
  def checkin(_); end
31
38
  def remove(_); end
32
39
  def async_executor; end
@@ -98,8 +105,10 @@ module ActiveRecord
98
105
  include ConnectionAdapters::AbstractPool
99
106
 
100
107
  attr_accessor :automatic_reconnect, :checkout_timeout
101
- attr_reader :db_config, :size, :reaper, :pool_config, :connection_klass, :async_executor
108
+ attr_reader :db_config, :size, :reaper, :pool_config, :connection_class, :async_executor, :role, :shard
102
109
 
110
+ alias_method :connection_klass, :connection_class
111
+ deprecate :connection_klass
103
112
  delegate :schema_cache, :schema_cache=, to: :pool_config
104
113
 
105
114
  # Creates a new ConnectionPool object. +pool_config+ is a PoolConfig
@@ -113,7 +122,9 @@ module ActiveRecord
113
122
 
114
123
  @pool_config = pool_config
115
124
  @db_config = pool_config.db_config
116
- @connection_klass = pool_config.connection_klass
125
+ @connection_class = pool_config.connection_class
126
+ @role = pool_config.role
127
+ @shard = pool_config.shard
117
128
 
118
129
  @checkout_timeout = db_config.checkout_timeout
119
130
  @idle_timeout = db_config.idle_timeout
@@ -147,6 +158,8 @@ module ActiveRecord
147
158
 
148
159
  @async_executor = build_async_executor
149
160
 
161
+ lazily_set_schema_cache
162
+
150
163
  @reaper = Reaper.new(self, db_config.reaping_frequency)
151
164
  @reaper.run
152
165
  end
@@ -518,13 +531,13 @@ module ActiveRecord
518
531
  end
519
532
 
520
533
  newly_checked_out = []
521
- timeout_time = Concurrent.monotonic_time + (@checkout_timeout * 2)
534
+ timeout_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) + (@checkout_timeout * 2)
522
535
 
523
536
  @available.with_a_bias_for(Thread.current) do
524
537
  loop do
525
538
  synchronize do
526
539
  return if collected_conns.size == @connections.size && @now_connecting == 0
527
- remaining_timeout = timeout_time - Concurrent.monotonic_time
540
+ remaining_timeout = timeout_time - Process.clock_gettime(Process::CLOCK_MONOTONIC)
528
541
  remaining_timeout = 0 if remaining_timeout < 0
529
542
  conn = checkout_for_exclusive_access(remaining_timeout)
530
543
  collected_conns << conn
@@ -12,28 +12,11 @@ module ActiveRecord
12
12
  max_identifier_length
13
13
  end
14
14
 
15
- # Returns the maximum allowed length for an index name. This
16
- # limit is enforced by \Rails and is less than or equal to
17
- # #index_name_length. The gap between
18
- # #index_name_length is to allow internal \Rails
19
- # operations to use prefixes in temporary operations.
20
- def allowed_index_name_length
21
- index_name_length
22
- end
23
- deprecate :allowed_index_name_length
24
-
25
15
  # Returns the maximum length of an index name.
26
16
  def index_name_length
27
17
  max_identifier_length
28
18
  end
29
19
 
30
- # Returns the maximum number of elements in an IN (x,y,z) clause.
31
- # +nil+ means no limit.
32
- def in_clause_length
33
- nil
34
- end
35
- deprecate :in_clause_length
36
-
37
20
  private
38
21
  def bind_params_length
39
22
  65535
@@ -469,7 +469,7 @@ module ActiveRecord
469
469
  end
470
470
 
471
471
  def build_fixture_sql(fixtures, table_name)
472
- columns = schema_cache.columns_hash(table_name)
472
+ columns = schema_cache.columns_hash(table_name).reject { |_, column| supports_virtual_columns? && column.virtual? }
473
473
 
474
474
  values_list = fixtures.map do |fixture|
475
475
  fixture = fixture.stringify_keys
@@ -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
- if value.is_a?(Base)
13
- ActiveSupport::Deprecation.warn(<<~MSG)
14
- Passing an Active Record object to `quote` directly is deprecated
15
- and will be no longer quoted as id value in Rails 7.0.
16
- MSG
17
- value = value.id_for_database
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, column = nil)
27
- if value.is_a?(Base)
28
- ActiveSupport::Deprecation.warn(<<~MSG)
29
- Passing an Active Record object to `type_cast` directly is deprecated
30
- and will be no longer type casted as id value in Rails 7.0.
31
- MSG
32
- value = value.id_for_database
33
- end
34
-
35
- if column
36
- ActiveSupport::Deprecation.warn(<<~MSG)
37
- Passing a column to `type_cast` is deprecated and will be removed in Rails 7.0.
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
- _quote(value)
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.to_s(:db)
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
- case binds.first
207
- when Array
208
- binds.map { |column, value| type_cast(value, column) }
209
- else
210
- binds.map do |value|
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
@@ -106,6 +106,10 @@ module ActiveRecord
106
106
  options[:on_update]
107
107
  end
108
108
 
109
+ def deferrable
110
+ options[:deferrable]
111
+ end
112
+
109
113
  def custom_primary_key?
110
114
  options[:primary_key] != default_primary_key
111
115
  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
- # Indexes on the column are automatically removed.
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: SQLite doesn't support index length.
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
- if Thread.current.status == "aborting"
338
- rollback_transaction
339
- else
340
- if !completed && transaction.written
341
- ActiveSupport::Deprecation.warn(<<~EOW)
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 = Concurrent.monotonic_time
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 connection_klass.nil?
144
+ return false if connection_class.nil?
145
145
 
146
- connection_klass.current_preventing_writes
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
- Thread.current[:ar_prepared_statements_disabled_cache] ||= Set.new
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 connection_klass # :nodoc:
224
- @pool.connection_klass
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 = Concurrent.monotonic_time
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
- Concurrent.monotonic_time - @idle_since
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" },
@@ -87,6 +87,10 @@ module ActiveRecord
87
87
  comment.hash
88
88
  end
89
89
 
90
+ def virtual?
91
+ false
92
+ end
93
+
90
94
  private
91
95
  def deduplicated
92
96
  @name = -name
@@ -26,13 +26,15 @@ module ActiveRecord
26
26
 
27
27
  def write_query?(sql) # :nodoc:
28
28
  !READ_QUERY.match?(sql)
29
+ rescue ArgumentError # Invalid encoding
30
+ !READ_QUERY.match?(sql.b)
29
31
  end
30
32
 
31
33
  def explain(arel, binds = [])
32
34
  sql = "EXPLAIN #{to_sql(arel, binds)}"
33
- start = Concurrent.monotonic_time
35
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
34
36
  result = exec_query(sql, "EXPLAIN", binds)
35
- elapsed = Concurrent.monotonic_time - start
37
+ elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
36
38
 
37
39
  MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
38
40
  end
@@ -9,15 +9,15 @@ module ActiveRecord
9
9
  def quote_bound_value(value)
10
10
  case value
11
11
  when Numeric
12
- _quote(value.to_s)
12
+ quote(value.to_s)
13
13
  when BigDecimal
14
- _quote(value.to_s("F"))
14
+ quote(value.to_s("F"))
15
15
  when true
16
16
  "'1'"
17
17
  when false
18
18
  "'0'"
19
19
  else
20
- _quote(value)
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 * FROM information_schema.tables "
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, :connection_klass
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(connection_klass, db_config)
20
+ def initialize(connection_class, db_config, role, shard)
21
21
  super()
22
- @connection_klass = connection_klass
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 connection_klass.primary_class?
31
+ if connection_class.primary_class?
30
32
  "ActiveRecord::Base"
31
33
  else
32
- connection_klass.name
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
@@ -28,6 +28,8 @@ module ActiveRecord
28
28
 
29
29
  def write_query?(sql) # :nodoc:
30
30
  !READ_QUERY.match?(sql)
31
+ rescue ArgumentError # Invalid encoding
32
+ !READ_QUERY.match?(sql.b)
31
33
  end
32
34
 
33
35
  # Executes an SQL statement, returning a PG::Result object on success