activerecord 6.0.0.rc1 → 6.0.3.rc1

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 (168) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +251 -3
  3. data/README.rdoc +1 -1
  4. data/lib/active_record.rb +1 -0
  5. data/lib/active_record/advisory_lock_base.rb +18 -0
  6. data/lib/active_record/aggregations.rb +0 -1
  7. data/lib/active_record/association_relation.rb +10 -8
  8. data/lib/active_record/associations.rb +2 -2
  9. data/lib/active_record/associations/alias_tracker.rb +0 -1
  10. data/lib/active_record/associations/association.rb +5 -1
  11. data/lib/active_record/associations/builder/collection_association.rb +2 -2
  12. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -3
  13. data/lib/active_record/associations/collection_association.rb +6 -2
  14. data/lib/active_record/associations/collection_proxy.rb +2 -3
  15. data/lib/active_record/associations/has_many_association.rb +0 -1
  16. data/lib/active_record/associations/join_dependency.rb +23 -9
  17. data/lib/active_record/associations/join_dependency/join_association.rb +12 -3
  18. data/lib/active_record/associations/preloader.rb +2 -3
  19. data/lib/active_record/associations/preloader/association.rb +3 -1
  20. data/lib/active_record/attribute_assignment.rb +0 -1
  21. data/lib/active_record/attribute_decorators.rb +0 -2
  22. data/lib/active_record/attribute_methods.rb +0 -51
  23. data/lib/active_record/attribute_methods/before_type_cast.rb +0 -1
  24. data/lib/active_record/attribute_methods/dirty.rb +8 -3
  25. data/lib/active_record/attribute_methods/primary_key.rb +0 -2
  26. data/lib/active_record/attribute_methods/read.rb +0 -1
  27. data/lib/active_record/attribute_methods/serialization.rb +0 -1
  28. data/lib/active_record/attribute_methods/time_zone_conversion.rb +0 -2
  29. data/lib/active_record/attribute_methods/write.rb +0 -1
  30. data/lib/active_record/attributes.rb +0 -1
  31. data/lib/active_record/autosave_association.rb +11 -7
  32. data/lib/active_record/callbacks.rb +1 -2
  33. data/lib/active_record/coders/yaml_column.rb +0 -1
  34. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +107 -13
  35. data/lib/active_record/connection_adapters/abstract/database_statements.rb +21 -15
  36. data/lib/active_record/connection_adapters/abstract/query_cache.rb +5 -5
  37. data/lib/active_record/connection_adapters/abstract/quoting.rb +53 -0
  38. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +1 -2
  39. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +27 -27
  40. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -1
  41. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +55 -37
  42. data/lib/active_record/connection_adapters/abstract/transaction.rb +14 -7
  43. data/lib/active_record/connection_adapters/abstract_adapter.rb +62 -25
  44. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +25 -32
  45. data/lib/active_record/connection_adapters/connection_specification.rb +3 -4
  46. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -2
  47. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  48. data/lib/active_record/connection_adapters/mysql/database_statements.rb +8 -12
  49. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +0 -1
  50. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  51. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +1 -2
  52. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +3 -1
  53. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +8 -8
  54. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -4
  55. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +9 -3
  56. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
  57. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  58. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
  59. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +0 -1
  60. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  61. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  62. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +0 -1
  63. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +0 -1
  64. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  65. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +0 -1
  66. data/lib/active_record/connection_adapters/postgresql/quoting.rb +39 -2
  67. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  68. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +2 -2
  69. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
  70. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  71. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +15 -29
  72. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  73. data/lib/active_record/connection_adapters/postgresql_adapter.rb +17 -3
  74. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +8 -7
  75. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +38 -3
  76. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +3 -3
  77. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +23 -8
  78. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  79. data/lib/active_record/connection_handling.rb +17 -22
  80. data/lib/active_record/core.rb +8 -6
  81. data/lib/active_record/counter_cache.rb +4 -1
  82. data/lib/active_record/database_configurations.rb +60 -31
  83. data/lib/active_record/database_configurations/url_config.rb +0 -1
  84. data/lib/active_record/dynamic_matchers.rb +2 -3
  85. data/lib/active_record/enum.rb +9 -0
  86. data/lib/active_record/explain.rb +0 -1
  87. data/lib/active_record/fixture_set/table_row.rb +0 -1
  88. data/lib/active_record/fixture_set/table_rows.rb +0 -1
  89. data/lib/active_record/fixtures.rb +11 -9
  90. data/lib/active_record/gem_version.rb +1 -1
  91. data/lib/active_record/inheritance.rb +0 -3
  92. data/lib/active_record/insert_all.rb +5 -6
  93. data/lib/active_record/internal_metadata.rb +1 -1
  94. data/lib/active_record/locking/optimistic.rb +0 -1
  95. data/lib/active_record/log_subscriber.rb +1 -1
  96. data/lib/active_record/middleware/database_selector.rb +3 -4
  97. data/lib/active_record/middleware/database_selector/resolver.rb +5 -8
  98. data/lib/active_record/migration.rb +43 -32
  99. data/lib/active_record/migration/command_recorder.rb +6 -18
  100. data/lib/active_record/migration/compatibility.rb +3 -3
  101. data/lib/active_record/migration/join_table.rb +0 -1
  102. data/lib/active_record/model_schema.rb +3 -2
  103. data/lib/active_record/nested_attributes.rb +0 -2
  104. data/lib/active_record/no_touching.rb +2 -2
  105. data/lib/active_record/null_relation.rb +0 -1
  106. data/lib/active_record/persistence.rb +4 -5
  107. data/lib/active_record/querying.rb +1 -1
  108. data/lib/active_record/railtie.rb +1 -2
  109. data/lib/active_record/railties/collection_cache_association_loading.rb +1 -1
  110. data/lib/active_record/railties/databases.rake +63 -23
  111. data/lib/active_record/reflection.rb +9 -9
  112. data/lib/active_record/relation.rb +13 -1
  113. data/lib/active_record/relation/batches.rb +0 -1
  114. data/lib/active_record/relation/calculations.rb +3 -5
  115. data/lib/active_record/relation/delegation.rb +7 -6
  116. data/lib/active_record/relation/finder_methods.rb +14 -4
  117. data/lib/active_record/relation/from_clause.rb +4 -0
  118. data/lib/active_record/relation/merger.rb +6 -3
  119. data/lib/active_record/relation/predicate_builder.rb +1 -5
  120. data/lib/active_record/relation/query_methods.rb +94 -55
  121. data/lib/active_record/relation/spawn_methods.rb +0 -1
  122. data/lib/active_record/relation/where_clause.rb +0 -1
  123. data/lib/active_record/result.rb +0 -1
  124. data/lib/active_record/sanitization.rb +30 -2
  125. data/lib/active_record/schema.rb +1 -1
  126. data/lib/active_record/schema_dumper.rb +5 -1
  127. data/lib/active_record/schema_migration.rb +1 -1
  128. data/lib/active_record/scoping.rb +0 -1
  129. data/lib/active_record/scoping/default.rb +0 -1
  130. data/lib/active_record/scoping/named.rb +3 -3
  131. data/lib/active_record/store.rb +1 -1
  132. data/lib/active_record/suppressor.rb +2 -2
  133. data/lib/active_record/table_metadata.rb +21 -10
  134. data/lib/active_record/tasks/database_tasks.rb +76 -8
  135. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -2
  136. data/lib/active_record/tasks/postgresql_database_tasks.rb +0 -1
  137. data/lib/active_record/tasks/sqlite_database_tasks.rb +0 -1
  138. data/lib/active_record/test_databases.rb +1 -16
  139. data/lib/active_record/test_fixtures.rb +2 -1
  140. data/lib/active_record/timestamp.rb +26 -17
  141. data/lib/active_record/touch_later.rb +3 -2
  142. data/lib/active_record/transactions.rb +18 -19
  143. data/lib/active_record/type.rb +0 -1
  144. data/lib/active_record/type/adapter_specific_registry.rb +2 -5
  145. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  146. data/lib/active_record/type/serialized.rb +0 -1
  147. data/lib/active_record/type/type_map.rb +0 -1
  148. data/lib/active_record/type/unsigned_integer.rb +0 -1
  149. data/lib/active_record/type_caster/connection.rb +16 -10
  150. data/lib/active_record/validations.rb +3 -3
  151. data/lib/active_record/validations/associated.rb +1 -2
  152. data/lib/arel.rb +17 -6
  153. data/lib/arel/predications.rb +5 -6
  154. data/lib/arel/visitors/depth_first.rb +1 -2
  155. data/lib/arel/visitors/dot.rb +0 -1
  156. data/lib/arel/visitors/mssql.rb +0 -1
  157. data/lib/arel/visitors/oracle.rb +1 -2
  158. data/lib/arel/visitors/oracle12.rb +0 -1
  159. data/lib/arel/visitors/postgresql.rb +0 -1
  160. data/lib/arel/visitors/sqlite.rb +0 -1
  161. data/lib/arel/visitors/to_sql.rb +23 -27
  162. data/lib/arel/visitors/visitor.rb +9 -6
  163. data/lib/arel/visitors/where_sql.rb +0 -1
  164. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  165. data/lib/rails/generators/active_record/migration.rb +0 -1
  166. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +1 -1
  167. data/lib/rails/generators/active_record/model/model_generator.rb +0 -1
  168. metadata +13 -9
@@ -19,7 +19,7 @@ module ActiveRecord
19
19
 
20
20
  def visit_ChangeColumnDefinition(o)
21
21
  column = o.column
22
- column.sql_type = type_to_sql(column.type, column.options)
22
+ column.sql_type = type_to_sql(column.type, **column.options)
23
23
  quoted_column_name = quote_column_name(o.name)
24
24
 
25
25
  change_column_sql = +"ALTER COLUMN #{quoted_column_name} TYPE #{column.sql_type}"
@@ -33,7 +33,7 @@ module ActiveRecord
33
33
  if options[:using]
34
34
  change_column_sql << " USING #{options[:using]}"
35
35
  elsif options[:cast_as]
36
- cast_as_type = type_to_sql(options[:cast_as], options)
36
+ cast_as_type = type_to_sql(options[:cast_as], **options)
37
37
  change_column_sql << " USING CAST(#{quoted_column_name} AS #{cast_as_type})"
38
38
  end
39
39
 
@@ -186,7 +186,7 @@ module ActiveRecord
186
186
 
187
187
  attr_reader :unlogged
188
188
 
189
- def initialize(*)
189
+ def initialize(*, **)
190
190
  super
191
191
  @unlogged = ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables
192
192
  end
@@ -5,7 +5,6 @@ module ActiveRecord
5
5
  module PostgreSQL
6
6
  class SchemaDumper < ConnectionAdapters::SchemaDumper # :nodoc:
7
7
  private
8
-
9
8
  def extensions(stream)
10
9
  extensions = @connection.extensions
11
10
  if extensions.any?
@@ -74,7 +74,7 @@ module ActiveRecord
74
74
  INNER JOIN pg_index d ON t.oid = d.indrelid
75
75
  INNER JOIN pg_class i ON d.indexrelid = i.oid
76
76
  LEFT JOIN pg_namespace n ON n.oid = i.relnamespace
77
- WHERE i.relkind = 'i'
77
+ WHERE i.relkind IN ('i', 'I')
78
78
  AND i.relname = #{index[:name]}
79
79
  AND t.relname = #{table[:name]}
80
80
  AND n.nspname = #{index[:schema]}
@@ -92,7 +92,7 @@ module ActiveRecord
92
92
  INNER JOIN pg_index d ON t.oid = d.indrelid
93
93
  INNER JOIN pg_class i ON d.indexrelid = i.oid
94
94
  LEFT JOIN pg_namespace n ON n.oid = i.relnamespace
95
- WHERE i.relkind = 'i'
95
+ WHERE i.relkind IN ('i', 'I')
96
96
  AND d.indisprimary = 'f'
97
97
  AND t.relname = #{scope[:name]}
98
98
  AND n.nspname = #{scope[:schema]}
@@ -390,7 +390,7 @@ module ActiveRecord
390
390
  rename_table_indexes(table_name, new_name)
391
391
  end
392
392
 
393
- def add_column(table_name, column_name, type, options = {}) #:nodoc:
393
+ def add_column(table_name, column_name, type, **options) #:nodoc:
394
394
  clear_cache!
395
395
  super
396
396
  change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
@@ -439,7 +439,7 @@ module ActiveRecord
439
439
  end
440
440
 
441
441
  def add_index(table_name, column_name, options = {}) #:nodoc:
442
- index_name, index_type, index_columns_and_opclasses, index_options, index_algorithm, index_using, comment = add_index_options(table_name, column_name, options)
442
+ index_name, index_type, index_columns_and_opclasses, index_options, index_algorithm, index_using, comment = add_index_options(table_name, column_name, **options)
443
443
  execute("CREATE #{index_type} INDEX #{index_algorithm} #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} #{index_using} (#{index_columns_and_opclasses})#{index_options}").tap do
444
444
  execute "COMMENT ON INDEX #{quote_column_name(index_name)} IS #{quote(comment)}" if comment
445
445
  end
@@ -553,12 +553,12 @@ module ActiveRecord
553
553
  # requires that the ORDER BY include the distinct column.
554
554
  def columns_for_distinct(columns, orders) #:nodoc:
555
555
  order_columns = orders.reject(&:blank?).map { |s|
556
- # Convert Arel node to string
557
- s = s.to_sql unless s.is_a?(String)
558
- # Remove any ASC/DESC modifiers
559
- s.gsub(/\s+(?:ASC|DESC)\b/i, "")
560
- .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, "")
561
- }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
556
+ # Convert Arel node to string
557
+ s = visitor.compile(s) unless s.is_a?(String)
558
+ # Remove any ASC/DESC modifiers
559
+ s.gsub(/\s+(?:ASC|DESC)\b/i, "")
560
+ .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, "")
561
+ }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
562
562
 
563
563
  (order_columns << super).join(", ")
564
564
  end
@@ -613,8 +613,8 @@ module ActiveRecord
613
613
  PostgreSQL::SchemaCreation.new(self)
614
614
  end
615
615
 
616
- def create_table_definition(*args)
617
- PostgreSQL::TableDefinition.new(self, *args)
616
+ def create_table_definition(*args, **options)
617
+ PostgreSQL::TableDefinition.new(self, *args, **options)
618
618
  end
619
619
 
620
620
  def create_alter_table(name)
@@ -679,14 +679,14 @@ module ActiveRecord
679
679
  end
680
680
  end
681
681
 
682
- def add_column_for_alter(table_name, column_name, type, options = {})
682
+ def add_column_for_alter(table_name, column_name, type, **options)
683
683
  return super unless options.key?(:comment)
684
684
  [super, Proc.new { change_column_comment(table_name, column_name, options[:comment]) }]
685
685
  end
686
686
 
687
687
  def change_column_for_alter(table_name, column_name, type, options = {})
688
688
  td = create_table_definition(table_name)
689
- cd = td.new_column_definition(column_name, type, options)
689
+ cd = td.new_column_definition(column_name, type, **options)
690
690
  sqls = [schema_creation.accept(ChangeColumnDefinition.new(cd, column_name))]
691
691
  sqls << Proc.new { change_column_comment(table_name, column_name, options[:comment]) } if options.key?(:comment)
692
692
  sqls
@@ -711,20 +711,6 @@ module ActiveRecord
711
711
  "ALTER COLUMN #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL"
712
712
  end
713
713
 
714
- def add_timestamps_for_alter(table_name, options = {})
715
- options[:null] = false if options[:null].nil?
716
-
717
- if !options.key?(:precision) && supports_datetime_with_precision?
718
- options[:precision] = 6
719
- end
720
-
721
- [add_column_for_alter(table_name, :created_at, :datetime, options), add_column_for_alter(table_name, :updated_at, :datetime, options)]
722
- end
723
-
724
- def remove_timestamps_for_alter(table_name, options = {})
725
- [remove_column_for_alter(table_name, :updated_at), remove_column_for_alter(table_name, :created_at)]
726
- end
727
-
728
714
  def add_index_opclass(quoted_columns, **options)
729
715
  opclasses = options_for_index_columns(options[:opclass])
730
716
  quoted_columns.each do |name, column|
@@ -733,7 +719,7 @@ module ActiveRecord
733
719
  end
734
720
 
735
721
  def add_options_for_index_columns(quoted_columns, **options)
736
- quoted_columns = add_index_opclass(quoted_columns, options)
722
+ quoted_columns = add_index_opclass(quoted_columns, **options)
737
723
  super
738
724
  end
739
725
 
@@ -37,7 +37,6 @@ module ActiveRecord
37
37
  end
38
38
 
39
39
  protected
40
-
41
40
  def parts
42
41
  @parts ||= [@schema, @identifier].compact
43
42
  end
@@ -46,7 +46,7 @@ module ActiveRecord
46
46
  conn = PG.connect(conn_params)
47
47
  ConnectionAdapters::PostgreSQLAdapter.new(conn, logger, conn_params, config)
48
48
  rescue ::PG::Error => error
49
- if error.message.include?("does not exist")
49
+ if error.message.include?(conn_params[:dbname])
50
50
  raise ActiveRecord::NoDatabaseError
51
51
  else
52
52
  raise
@@ -156,6 +156,10 @@ module ActiveRecord
156
156
  true
157
157
  end
158
158
 
159
+ def supports_partitioned_indexes?
160
+ database_version >= 110_000
161
+ end
162
+
159
163
  def supports_partial_index?
160
164
  true
161
165
  end
@@ -259,6 +263,12 @@ module ActiveRecord
259
263
  @use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true
260
264
  end
261
265
 
266
+ def self.database_exists?(config)
267
+ !!ActiveRecord::Base.postgresql_connection(config)
268
+ rescue ActiveRecord::NoDatabaseError
269
+ false
270
+ end
271
+
262
272
  # Is this connection alive and ready for queries?
263
273
  def active?
264
274
  @lock.synchronize do
@@ -302,6 +312,7 @@ module ActiveRecord
302
312
  end
303
313
 
304
314
  def discard! # :nodoc:
315
+ super
305
316
  @connection.socket_io.reopen(IO::NULL) rescue nil
306
317
  @connection = nil
307
318
  end
@@ -354,6 +365,10 @@ module ActiveRecord
354
365
  @has_pg_hint_plan
355
366
  end
356
367
 
368
+ def supports_common_table_expressions?
369
+ true
370
+ end
371
+
357
372
  def supports_lazy_transactions?
358
373
  true
359
374
  end
@@ -452,7 +467,6 @@ module ActiveRecord
452
467
  end
453
468
 
454
469
  private
455
-
456
470
  # See https://www.postgresql.org/docs/current/static/errcodes-appendix.html
457
471
  VALUE_LIMIT_VIOLATION = "22001"
458
472
  NUMERIC_VALUE_OUT_OF_RANGE = "22003"
@@ -619,7 +633,7 @@ module ActiveRecord
619
633
  SQL
620
634
 
621
635
  if oids
622
- query += "WHERE t.oid::integer IN (%s)" % oids.join(", ")
636
+ query += "WHERE t.oid IN (%s)" % oids.join(", ")
623
637
  else
624
638
  query += initializer.query_conditions_for_initial_load
625
639
  end
@@ -4,7 +4,9 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module SQLite3
6
6
  module DatabaseStatements
7
- READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(:begin, :commit, :explain, :select, :pragma, :release, :savepoint, :rollback) # :nodoc:
7
+ READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
8
+ :begin, :commit, :explain, :select, :pragma, :release, :savepoint, :rollback, :with
9
+ ) # :nodoc:
8
10
  private_constant :READ_QUERY
9
11
 
10
12
  def write_query?(sql) # :nodoc:
@@ -81,7 +83,9 @@ module ActiveRecord
81
83
 
82
84
 
83
85
  private
84
- def execute_batch(sql, name = nil)
86
+ def execute_batch(statements, name = nil)
87
+ sql = combine_multi_statements(statements)
88
+
85
89
  if preventing_writes? && write_query?(sql)
86
90
  raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
87
91
  end
@@ -106,11 +110,8 @@ module ActiveRecord
106
110
  end.compact
107
111
  end
108
112
 
109
- def build_truncate_statements(*table_names)
110
- truncate_tables = table_names.map do |table_name|
111
- "DELETE FROM #{quote_table_name(table_name)}"
112
- end
113
- combine_multi_statements(truncate_tables)
113
+ def build_truncate_statement(table_name)
114
+ "DELETE FROM #{quote_table_name(table_name)}"
114
115
  end
115
116
  end
116
117
  end
@@ -13,11 +13,11 @@ module ActiveRecord
13
13
  end
14
14
 
15
15
  def quote_table_name(name)
16
- @quoted_table_names[name] ||= super.gsub(".", "\".\"").freeze
16
+ self.class.quoted_table_names[name] ||= super.gsub(".", "\".\"").freeze
17
17
  end
18
18
 
19
19
  def quote_column_name(name)
20
- @quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}")
20
+ self.class.quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}")
21
21
  end
22
22
 
23
23
  def quoted_time(value)
@@ -45,8 +45,43 @@ module ActiveRecord
45
45
  0
46
46
  end
47
47
 
48
- private
48
+ def column_name_matcher
49
+ COLUMN_NAME
50
+ end
51
+
52
+ def column_name_with_order_matcher
53
+ COLUMN_NAME_WITH_ORDER
54
+ end
49
55
 
56
+ COLUMN_NAME = /
57
+ \A
58
+ (
59
+ (?:
60
+ # "table_name"."column_name" | function(one or no argument)
61
+ ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")) | \w+\((?:|\g<2>)\)
62
+ )
63
+ (?:\s+AS\s+(?:\w+|"\w+"))?
64
+ )
65
+ (?:\s*,\s*\g<1>)*
66
+ \z
67
+ /ix
68
+
69
+ COLUMN_NAME_WITH_ORDER = /
70
+ \A
71
+ (
72
+ (?:
73
+ # "table_name"."column_name" | function(one or no argument)
74
+ ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")) | \w+\((?:|\g<2>)\)
75
+ )
76
+ (?:\s+ASC|\s+DESC)?
77
+ )
78
+ (?:\s*,\s*\g<1>)*
79
+ \z
80
+ /ix
81
+
82
+ private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
83
+
84
+ private
50
85
  def _type_cast(value)
51
86
  case value
52
87
  when BigDecimal
@@ -55,7 +55,7 @@ module ActiveRecord
55
55
  def add_foreign_key(from_table, to_table, **options)
56
56
  alter_table(from_table) do |definition|
57
57
  to_table = strip_table_name_prefix_and_suffix(to_table)
58
- definition.foreign_key(to_table, options)
58
+ definition.foreign_key(to_table, **options)
59
59
  end
60
60
  end
61
61
 
@@ -87,8 +87,8 @@ module ActiveRecord
87
87
  SQLite3::SchemaCreation.new(self)
88
88
  end
89
89
 
90
- def create_table_definition(*args)
91
- SQLite3::TableDefinition.new(self, *args)
90
+ def create_table_definition(*args, **options)
91
+ SQLite3::TableDefinition.new(self, *args, **options)
92
92
  end
93
93
 
94
94
  def new_column_from_field(table_name, field)
@@ -98,6 +98,16 @@ module ActiveRecord
98
98
  configure_connection
99
99
  end
100
100
 
101
+ def self.database_exists?(config)
102
+ config = config.symbolize_keys
103
+ if config[:database] == ":memory:"
104
+ true
105
+ else
106
+ database_file = defined?(Rails.root) ? File.expand_path(config[:database], Rails.root) : config[:database]
107
+ File.exist?(database_file)
108
+ end
109
+ end
110
+
101
111
  def supports_ddl_transactions?
102
112
  true
103
113
  end
@@ -134,6 +144,10 @@ module ActiveRecord
134
144
  true
135
145
  end
136
146
 
147
+ def supports_common_table_expressions?
148
+ database_version >= "3.8.3"
149
+ end
150
+
137
151
  def supports_insert_on_conflict?
138
152
  database_version >= "3.24.0"
139
153
  end
@@ -230,17 +244,17 @@ module ActiveRecord
230
244
  rename_table_indexes(table_name, new_name)
231
245
  end
232
246
 
233
- def add_column(table_name, column_name, type, options = {}) #:nodoc:
247
+ def add_column(table_name, column_name, type, **options) #:nodoc:
234
248
  if invalid_alter_table_type?(type, options)
235
249
  alter_table(table_name) do |definition|
236
- definition.column(column_name, type, options)
250
+ definition.column(column_name, type, **options)
237
251
  end
238
252
  else
239
253
  super
240
254
  end
241
255
  end
242
256
 
243
- def remove_column(table_name, column_name, type = nil, options = {}) #:nodoc:
257
+ def remove_column(table_name, column_name, type = nil, **options) #:nodoc:
244
258
  alter_table(table_name) do |definition|
245
259
  definition.remove_column column_name
246
260
  definition.foreign_keys.delete_if do |_, fk_options|
@@ -349,7 +363,8 @@ module ActiveRecord
349
363
  # See: https://www.sqlite.org/lang_altertable.html
350
364
  # SQLite has an additional restriction on the ALTER TABLE statement
351
365
  def invalid_alter_table_type?(type, options)
352
- type.to_sym == :primary_key || options[:primary_key]
366
+ type.to_sym == :primary_key || options[:primary_key] ||
367
+ options[:null] == false && options[:default].nil?
353
368
  end
354
369
 
355
370
  def alter_table(table_name, foreign_keys = foreign_keys(table_name), **options)
@@ -362,7 +377,7 @@ module ActiveRecord
362
377
  fk.options[:column] = column
363
378
  end
364
379
  to_table = strip_table_name_prefix_and_suffix(fk.to_table)
365
- definition.foreign_key(to_table, fk.options)
380
+ definition.foreign_key(to_table, **fk.options)
366
381
  end
367
382
 
368
383
  yield definition if block_given?
@@ -384,7 +399,7 @@ module ActiveRecord
384
399
  def copy_table(from, to, options = {})
385
400
  from_primary_key = primary_key(from)
386
401
  options[:id] = false
387
- create_table(to, options) do |definition|
402
+ create_table(to, **options) do |definition|
388
403
  @definition = definition
389
404
  if from_primary_key.is_a?(Array)
390
405
  @definition.primary_keys from_primary_key
@@ -485,9 +500,9 @@ module ActiveRecord
485
500
  result = exec_query(sql, "SCHEMA").first
486
501
 
487
502
  if result
488
- # Splitting with left parentheses and picking up last will return all
503
+ # Splitting with left parentheses and discarding the first part will return all
489
504
  # columns separated with comma(,).
490
- columns_string = result["sql"].split("(").last
505
+ columns_string = result["sql"].split("(", 2).last
491
506
 
492
507
  columns_string.split(",").each do |column_string|
493
508
  # This regex will match the column name and collation type and will save
@@ -48,7 +48,6 @@ module ActiveRecord
48
48
  end
49
49
 
50
50
  private
51
-
52
51
  def cache
53
52
  @cache[Process.pid]
54
53
  end
@@ -96,25 +96,11 @@ module ActiveRecord
96
96
  # # raises exception due to non-existent role
97
97
  # end
98
98
  #
99
- # For cases where you may want to connect to a database outside of the model,
100
- # you can use +connected_to+ with a +database+ argument. The +database+ argument
101
- # expects a symbol that corresponds to the database key in your config.
99
+ # The `database` kwarg is deprecated in 6.1 and will be removed in 6.2
102
100
  #
103
- # ActiveRecord::Base.connected_to(database: :animals_slow_replica) do
104
- # Dog.run_a_long_query # runs a long query while connected to the +animals_slow_replica+
105
- # end
106
- #
107
- # This will connect to a new database for the queries inside the block. By
108
- # default the `:writing` role will be used since all connections must be assigned
109
- # a role. If you would like to use a different role you can pass a hash to database:
110
- #
111
- # ActiveRecord::Base.connected_to(database: { readonly_slow: :animals_slow_replica }) do
112
- # # runs a long query while connected to the +animals_slow_replica+ using the readonly_slow role.
113
- # Dog.run_a_long_query
114
- # end
115
- #
116
- # When using the database key a new connection will be established every time.
117
- def connected_to(database: nil, role: nil, &blk)
101
+ # It is not recommended for use as it re-establishes a connection every
102
+ # time it is called.
103
+ def connected_to(database: nil, role: nil, prevent_writes: false, &blk)
118
104
  if database && role
119
105
  raise ArgumentError, "connected_to can only accept a `database` or a `role` argument, but not both arguments."
120
106
  elsif database
@@ -130,7 +116,11 @@ module ActiveRecord
130
116
 
131
117
  with_handler(role, &blk)
132
118
  elsif role
133
- with_handler(role.to_sym, &blk)
119
+ prevent_writes = true if role == reading_role
120
+
121
+ with_handler(role.to_sym) do
122
+ connection_handler.while_preventing_writes(prevent_writes, &blk)
123
+ end
134
124
  else
135
125
  raise ArgumentError, "must provide a `database` or a `role`."
136
126
  end
@@ -173,7 +163,7 @@ module ActiveRecord
173
163
  raise "Anonymous class is not allowed." unless name
174
164
 
175
165
  config_or_env ||= DEFAULT_ENV.call.to_sym
176
- pool_name = self == Base ? "primary" : name
166
+ pool_name = primary_class? ? "primary" : name
177
167
  self.connection_specification_name = pool_name
178
168
 
179
169
  resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new(Base.configurations)
@@ -209,6 +199,10 @@ module ActiveRecord
209
199
  @connection_specification_name
210
200
  end
211
201
 
202
+ def primary_class? # :nodoc:
203
+ self == Base || defined?(ApplicationRecord) && self == ApplicationRecord
204
+ end
205
+
212
206
  # Returns the configuration of the associated connection as a hash:
213
207
  #
214
208
  # ActiveRecord::Base.connection_config
@@ -252,10 +246,11 @@ module ActiveRecord
252
246
  :clear_all_connections!, :flush_idle_connections!, to: :connection_handler
253
247
 
254
248
  private
255
-
256
249
  def swap_connection_handler(handler, &blk) # :nodoc:
257
250
  old_handler, ActiveRecord::Base.connection_handler = ActiveRecord::Base.connection_handler, handler
258
- yield
251
+ return_value = yield
252
+ return_value.load if return_value.is_a? ActiveRecord::Relation
253
+ return_value
259
254
  ensure
260
255
  ActiveRecord::Base.connection_handler = old_handler
261
256
  end