activerecord 7.0.0.rc2 → 7.0.2

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +200 -3
  3. data/MIT-LICENSE +1 -1
  4. data/lib/active_record/associations/join_dependency.rb +6 -2
  5. data/lib/active_record/associations.rb +29 -8
  6. data/lib/active_record/attribute_methods.rb +1 -1
  7. data/lib/active_record/autosave_association.rb +2 -2
  8. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
  9. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -4
  10. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  11. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +9 -4
  12. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +1 -1
  13. data/lib/active_record/connection_adapters/mysql/database_statements.rb +3 -1
  14. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
  15. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -0
  16. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +2 -0
  17. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +2 -0
  18. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +9 -4
  19. data/lib/active_record/connection_adapters/postgresql_adapter.rb +2 -2
  20. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +2 -0
  21. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -0
  22. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +12 -12
  23. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +28 -0
  24. data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -0
  25. data/lib/active_record/database_configurations.rb +1 -1
  26. data/lib/active_record/encryption/configurable.rb +2 -2
  27. data/lib/active_record/encryption/encryptable_record.rb +1 -1
  28. data/lib/active_record/encryption/extended_deterministic_queries.rb +28 -28
  29. data/lib/active_record/fixtures.rb +1 -1
  30. data/lib/active_record/gem_version.rb +2 -2
  31. data/lib/active_record/integration.rb +2 -2
  32. data/lib/active_record/migration/compatibility.rb +24 -2
  33. data/lib/active_record/migration.rb +1 -1
  34. data/lib/active_record/railtie.rb +2 -2
  35. data/lib/active_record/reflection.rb +1 -1
  36. data/lib/active_record/relation/calculations.rb +3 -2
  37. data/lib/active_record/relation/delegation.rb +1 -1
  38. data/lib/active_record/relation/query_methods.rb +19 -5
  39. data/lib/active_record/relation.rb +17 -4
  40. data/lib/active_record/schema.rb +38 -23
  41. data/lib/active_record/schema_dumper.rb +15 -16
  42. data/lib/active_record/schema_migration.rb +4 -0
  43. data/lib/active_record/tasks/database_tasks.rb +6 -2
  44. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
  45. data/lib/active_record.rb +1 -1
  46. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  47. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  48. metadata +17 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a4539228a5a4d1ea117028c87edfd08f5c511b547a79ce04f6863635e9cc9cb
4
- data.tar.gz: 69dd81febcea0dc545c22d323a32307ae44f44e3db82641639bd547595e41557
3
+ metadata.gz: da2fb0412054b1d4bb0376fdefd081df9e1a775086b26c990a3ef2c4694c2f5f
4
+ data.tar.gz: 93e85094985b3aa298e20f69231ef317fe2bbf13c8172262d7e8bf2a4baedb9c
5
5
  SHA512:
6
- metadata.gz: ac13312b9a4db3f53f2e92eafd5748ed7f9a387b90f73951a11d13992bfe2790cdc92ea96c452303bba8445ca447fced07c1ffe75401525a42b2ab711823b399
7
- data.tar.gz: 4de0cd55849db0983210cc4afb1d5d240dd0b3f242edd1db7e78b97bc5d75931c7d96c0a0bb8641e00351bb1df2f77a28561c86f8756f4f63cf610a31bf2b84d
6
+ metadata.gz: aecf41a61f98af43c3861ca75c584af4b58d2613e1cc3f10746b7b4b058c6995e7a7fc5f1f44ec68f845e0b9c54b83cad732a7e31ecd6e34b513098a0fe7fe98
7
+ data.tar.gz: 1eedc6462f61e6724a43a77dc5848cb3a381bc9caa4ea4913a3995af8458e38d9cfbd7592ae331c2fff42745101aeae2feb0361167b5754c8171ea938229582d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,201 @@
1
+ ## Rails 7.0.2 (February 08, 2022) ##
2
+
3
+ * Fix `PG.connect` keyword arguments deprecation warning on ruby 2.7.
4
+
5
+ *Nikita Vasilevsky*
6
+
7
+ * Fix the ability to exclude encryption params from being autofiltered.
8
+
9
+ *Mark Gangl*
10
+
11
+ * Dump the precision for datetime columns following the new defaults.
12
+
13
+ *Rafael Mendonça França*
14
+
15
+ * Make sure encrypted attributes are not being filtered twice.
16
+
17
+ *Nikita Vasilevsky*
18
+
19
+ * Dump the database schema containing the current Rails version.
20
+
21
+ Since https://github.com/rails/rails/pull/42297, Rails now generate datetime columns
22
+ with a default precision of 6. This means that users upgrading to Rails 7.0 from 6.1,
23
+ when loading the database schema, would get the new precision value, which would not match
24
+ the production schema.
25
+
26
+ To avoid this the schema dumper will generate the new format which will include the Rails
27
+ version and will look like this:
28
+
29
+ ```
30
+ ActiveRecord::Schema[7.0].define
31
+ ```
32
+
33
+ When upgrading from Rails 6.1 to Rails 7.0, you can run the `rails app:update` task that will
34
+ set the current schema version to 6.1.
35
+
36
+ *Rafael Mendonça França*
37
+
38
+ * Fix parsing expression for PostgreSQL generated column.
39
+
40
+ *fatkodima*
41
+
42
+ * Fix `Mysql2::Error: Commands out of sync; you can't run this command now`
43
+ when bulk-inserting fixtures that exceed `max_allowed_packet` configuration.
44
+
45
+ *Nikita Vasilevsky*
46
+
47
+ * Fix error when saving an association with a relation named `record`.
48
+
49
+ *Dorian Marié*
50
+
51
+ * Fix `MySQL::SchemaDumper` behavior about datetime precision value.
52
+
53
+ *y0t4*
54
+
55
+ * Improve associated with no reflection error.
56
+
57
+ *Nikolai*
58
+
59
+ * Fix PG.connect keyword arguments deprecation warning on ruby 2.7.
60
+
61
+ Fixes #44307.
62
+
63
+ *Nikita Vasilevsky*
64
+
65
+ * Fix passing options to `check_constraint` from `change_table`.
66
+
67
+ *Frederick Cheung*
68
+
69
+
70
+ ## Rails 7.0.1 (January 06, 2022) ##
71
+
72
+
73
+ * Change `QueryMethods#in_order_of` to drop records not listed in values.
74
+
75
+ `in_order_of` now filters down to the values provided, to match the behavior of the `Enumerable` version.
76
+
77
+ *Kevin Newton*
78
+
79
+ * Allow named expression indexes to be revertible.
80
+
81
+ Previously, the following code would raise an error in a reversible migration executed while rolling back, due to the index name not being used in the index removal.
82
+
83
+ ```ruby
84
+ add_index(:settings, "(data->'property')", using: :gin, name: :index_settings_data_property)
85
+ ```
86
+
87
+ Fixes #43331.
88
+
89
+ *Oliver Günther*
90
+
91
+ * Better error messages when association name is invalid in the argument of `ActiveRecord::QueryMethods::WhereChain#missing`.
92
+
93
+ *ykpythemind*
94
+
95
+ * Fix ordered migrations for single db in multi db environment.
96
+
97
+ *Himanshu*
98
+
99
+ * Extract `on update CURRENT_TIMESTAMP` for mysql2 adapter.
100
+
101
+ *Kazuhiro Masuda*
102
+
103
+ * Fix incorrect argument in PostgreSQL structure dump tasks.
104
+
105
+ Updating the `--no-comment` argument added in Rails 7 to the correct `--no-comments` argument.
106
+
107
+ *Alex Dent*
108
+
109
+ * Fix schema dumping column default SQL values for sqlite3.
110
+
111
+ *fatkodima*
112
+
113
+ * Correctly parse complex check constraint expressions for PostgreSQL.
114
+
115
+ *fatkodima*
116
+
117
+ * Fix `timestamptz` attributes on PostgreSQL handle blank inputs.
118
+
119
+ *Alex Ghiculescu*
120
+
121
+ * Fix migration compatibility to create SQLite references/belongs_to column as integer when migration version is 6.0.
122
+
123
+ Reference/belongs_to in migrations with version 6.0 were creating columns as
124
+ bigint instead of integer for the SQLite Adapter.
125
+
126
+ *Marcelo Lauxen*
127
+
128
+ * Fix joining through a polymorphic association.
129
+
130
+ *Alexandre Ruban*
131
+
132
+ * Fix `QueryMethods#in_order_of` to handle empty order list.
133
+
134
+ ```ruby
135
+ Post.in_order_of(:id, []).to_a
136
+ ```
137
+
138
+ Also more explicitly set the column as secondary order, so that any other
139
+ value is still ordered.
140
+
141
+ *Jean Boussier*
142
+
143
+ * Fix `rails dbconsole` for 3-tier config.
144
+
145
+ *Eileen M. Uchitelle*
146
+
147
+ * Fix quoting of column aliases generated by calculation methods.
148
+
149
+ Since the alias is derived from the table name, we can't assume the result
150
+ is a valid identifier.
151
+
152
+ ```ruby
153
+ class Test < ActiveRecord::Base
154
+ self.table_name = '1abc'
155
+ end
156
+ Test.group(:id).count
157
+ # syntax error at or near "1" (ActiveRecord::StatementInvalid)
158
+ # LINE 1: SELECT COUNT(*) AS count_all, "1abc"."id" AS 1abc_id FROM "1...
159
+ ```
160
+
161
+ *Jean Boussier*
162
+
163
+
164
+ ## Rails 7.0.0 (December 15, 2021) ##
165
+
166
+ * Better handle SQL queries with invalid encoding.
167
+
168
+ ```ruby
169
+ Post.create(name: "broken \xC8 UTF-8")
170
+ ```
171
+
172
+ Would cause all adapters to fail in a non controlled way in the code
173
+ responsible to detect write queries.
174
+
175
+ The query is now properly passed to the database connection, which might or might
176
+ not be able to handle it, but will either succeed or failed in a more correct way.
177
+
178
+ *Jean Boussier*
179
+
180
+ * Move database and shard selection config options to a generator.
181
+
182
+ Rather than generating the config options in `production.rb` when applications are created, applications can now run a generator to create an initializer and uncomment / update options as needed. All multi-db configuration can be implemented in this initializer.
183
+
184
+ *Eileen M. Uchitelle*
185
+
186
+
187
+ ## Rails 7.0.0.rc3 (December 14, 2021) ##
188
+
189
+ * No changes.
190
+
191
+
1
192
  ## Rails 7.0.0.rc2 (December 14, 2021) ##
2
193
 
194
+ * No changes.
195
+
196
+
197
+ ## Rails 7.0.0.rc1 (December 06, 2021) ##
198
+
3
199
  * Remove deprecated `ActiveRecord::DatabaseConfigurations::DatabaseConfig#spec_name`.
4
200
 
5
201
  *Rafael Mendonça França*
@@ -307,7 +503,6 @@
307
503
 
308
504
  Applications may now set their the filename or path of the schema / structure dump file in their database configuration.
309
505
 
310
-
311
506
  ```yaml
312
507
  production:
313
508
  primary:
@@ -394,6 +589,8 @@
394
589
  `#with_lock` now accepts transaction options like `requires_new:`,
395
590
  `isolation:`, and `joinable:`
396
591
 
592
+ *John Mileham*
593
+
397
594
  * Adds support for deferrable foreign key constraints in PostgreSQL.
398
595
 
399
596
  By default, foreign key constraints in PostgreSQL are checked after each statement. This works for most use cases,
@@ -470,7 +667,7 @@
470
667
 
471
668
  *Alex Ghiculescu*
472
669
 
473
- * Avoid COMMENT statements in PostgreSQL structure dumps
670
+ * Avoid COMMENT statements in PostgreSQL structure dumps
474
671
 
475
672
  COMMENT statements are now omitted from the output of `db:structure:dump` when using PostgreSQL >= 11.
476
673
  This allows loading the dump without a pgsql superuser account.
@@ -523,7 +720,7 @@
523
720
 
524
721
  *Sam Bostock*
525
722
 
526
- * Add ssl support for postgresql database tasks
723
+ * Add ssl support for postgresql database tasks
527
724
 
528
725
  Add `PGSSLMODE`, `PGSSLCERT`, `PGSSLKEY` and `PGSSLROOTCERT` to pg_env from database config
529
726
  when running postgresql database tasks.
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2004-2021 David Heinemeier Hansson
1
+ Copyright (c) 2004-2022 David Heinemeier Hansson
2
2
 
3
3
  Arel originally copyright (c) 2007-2016 Nick Kallen, Bryan Helmkamp, Emilio Tagua, Aaron Patterson
4
4
 
@@ -3,8 +3,12 @@
3
3
  module ActiveRecord
4
4
  module Associations
5
5
  class JoinDependency # :nodoc:
6
- autoload :JoinBase, "active_record/associations/join_dependency/join_base"
7
- autoload :JoinAssociation, "active_record/associations/join_dependency/join_association"
6
+ extend ActiveSupport::Autoload
7
+
8
+ eager_autoload do
9
+ autoload :JoinBase
10
+ autoload :JoinAssociation
11
+ end
8
12
 
9
13
  class Aliases # :nodoc:
10
14
  def initialize(tables)
@@ -290,6 +290,7 @@ module ActiveRecord
290
290
  def self.eager_load!
291
291
  super
292
292
  Preloader.eager_load!
293
+ JoinDependency.eager_load!
293
294
  end
294
295
 
295
296
  # Returns the association instance for the given name, instantiating it if it doesn't already exist
@@ -594,19 +595,27 @@ module ActiveRecord
594
595
  # you can also define callbacks that get triggered when you add an object to or remove an
595
596
  # object from an association collection.
596
597
  #
597
- # class Project
598
- # has_and_belongs_to_many :developers, after_add: :evaluate_velocity
598
+ # class Firm < ActiveRecord::Base
599
+ # has_many :clients,
600
+ # dependent: :destroy,
601
+ # after_add: :congratulate_client,
602
+ # after_remove: :log_after_remove
599
603
  #
600
- # def evaluate_velocity(developer)
601
- # ...
604
+ # def congratulate_client(record)
605
+ # # ...
606
+ # end
607
+ #
608
+ # def log_after_remove(record)
609
+ # # ...
602
610
  # end
603
- # end
604
611
  #
605
612
  # It's possible to stack callbacks by passing them as an array. Example:
606
613
  #
607
- # class Project
608
- # has_and_belongs_to_many :developers,
609
- # after_add: [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}]
614
+ # class Firm < ActiveRecord::Base
615
+ # has_many :clients,
616
+ # dependent: :destroy,
617
+ # after_add: [:congratulate_client, -> (firm, record) { firm.log << "after_adding#{record.id}" }],
618
+ # after_remove: :log_after_remove
610
619
  # end
611
620
  #
612
621
  # Possible callbacks are: +before_add+, +after_add+, +before_remove+ and +after_remove+.
@@ -617,6 +626,18 @@ module ActiveRecord
617
626
  # Similarly, if any of the +before_remove+ callbacks throw an exception, the object
618
627
  # will not be removed from the collection.
619
628
  #
629
+ # Note: To trigger remove callbacks, you must use +destroy+ / +destroy_all+ methods. For example:
630
+ #
631
+ # * <tt>firm.clients.destroy(client)</tt>
632
+ # * <tt>firm.clients.destroy(*clients)</tt>
633
+ # * <tt>firm.clients.destroy_all</tt>
634
+ #
635
+ # +delete+ / +delete_all+ methods like the following do *not* trigger remove callbacks:
636
+ #
637
+ # * <tt>firm.clients.delete(client)</tt>
638
+ # * <tt>firm.clients.delete(*clients)</tt>
639
+ # * <tt>firm.clients.delete_all</tt>
640
+ #
620
641
  # == Association extensions
621
642
  #
622
643
  # The proxy objects that control the access to associations can be extended through anonymous
@@ -413,7 +413,7 @@ module ActiveRecord
413
413
  inspected_value = if value.is_a?(String) && value.length > 50
414
414
  "#{value[0, 50]}...".inspect
415
415
  elsif value.is_a?(Date) || value.is_a?(Time)
416
- %("#{value.to_formatted_s(:inspect)}")
416
+ %("#{value.to_fs(:inspect)}")
417
417
  else
418
418
  value.inspect
419
419
  end
@@ -446,7 +446,7 @@ module ActiveRecord
446
446
  elsif autosave != false
447
447
  key = reflection.options[:primary_key] ? public_send(reflection.options[:primary_key]) : id
448
448
 
449
- if (autosave && record.changed_for_autosave?) || record_changed?(reflection, record, key)
449
+ if (autosave && record.changed_for_autosave?) || _record_changed?(reflection, record, key)
450
450
  unless reflection.through_reflection
451
451
  record[reflection.foreign_key] = key
452
452
  association.set_inverse_instance(record)
@@ -461,7 +461,7 @@ module ActiveRecord
461
461
  end
462
462
 
463
463
  # If the record is new or it has changed, returns true.
464
- def record_changed?(reflection, record, key)
464
+ def _record_changed?(reflection, record, key)
465
465
  record.new_record? ||
466
466
  association_foreign_key_changed?(reflection, record, key) ||
467
467
  record.will_save_change_to_attribute?(reflection.foreign_key)
@@ -128,7 +128,7 @@ module ActiveRecord
128
128
  end
129
129
  end
130
130
 
131
- result = value.to_formatted_s(:db)
131
+ result = value.to_fs(:db)
132
132
  if value.respond_to?(:usec) && value.usec > 0
133
133
  result << "." << sprintf("%06d", value.usec)
134
134
  else
@@ -810,8 +810,8 @@ module ActiveRecord
810
810
  # t.check_constraint("price > 0", name: "price_check")
811
811
  #
812
812
  # See {connection.add_check_constraint}[rdoc-ref:SchemaStatements#add_check_constraint]
813
- def check_constraint(*args)
814
- @base.add_check_constraint(name, *args)
813
+ def check_constraint(*args, **options)
814
+ @base.add_check_constraint(name, *args, **options)
815
815
  end
816
816
 
817
817
  # Removes the given check constraint from the table.
@@ -819,8 +819,8 @@ module ActiveRecord
819
819
  # t.remove_check_constraint(name: "price_check")
820
820
  #
821
821
  # See {connection.remove_check_constraint}[rdoc-ref:SchemaStatements#remove_check_constraint]
822
- def remove_check_constraint(*args)
823
- @base.remove_check_constraint(name, *args)
822
+ def remove_check_constraint(*args, **options)
823
+ @base.remove_check_constraint(name, *args, **options)
824
824
  end
825
825
  end
826
826
  end
@@ -3,6 +3,8 @@
3
3
  module ActiveRecord
4
4
  module ConnectionAdapters # :nodoc:
5
5
  class SchemaDumper < SchemaDumper # :nodoc:
6
+ DEFAULT_DATETIME_PRECISION = 6 # :nodoc:
7
+
6
8
  def self.create(connection, options)
7
9
  new(connection, options)
8
10
  end
@@ -63,7 +65,18 @@ module ActiveRecord
63
65
  end
64
66
 
65
67
  def schema_precision(column)
66
- column.precision.inspect if column.precision
68
+ if column.type == :datetime
69
+ case column.precision
70
+ when nil
71
+ "nil"
72
+ when DEFAULT_DATETIME_PRECISION
73
+ nil
74
+ else
75
+ column.precision.inspect
76
+ end
77
+ elsif column.precision
78
+ column.precision.inspect
79
+ end
67
80
  end
68
81
 
69
82
  def schema_scale(column)
@@ -1438,7 +1438,7 @@ module ActiveRecord
1438
1438
 
1439
1439
  checks = []
1440
1440
 
1441
- if !options.key?(:name) && column_name.is_a?(String) && /\W/.match?(column_name)
1441
+ if !options.key?(:name) && expression_column_name?(column_name)
1442
1442
  options[:name] = index_name(table_name, column_name)
1443
1443
  column_names = []
1444
1444
  else
@@ -1447,7 +1447,7 @@ module ActiveRecord
1447
1447
 
1448
1448
  checks << lambda { |i| i.name == options[:name].to_s } if options.key?(:name)
1449
1449
 
1450
- if column_names.present?
1450
+ if column_names.present? && !(options.key?(:name) && expression_column_name?(column_names))
1451
1451
  checks << lambda { |i| index_name(table_name, i.columns) == index_name(table_name, column_names) }
1452
1452
  end
1453
1453
 
@@ -1515,7 +1515,7 @@ module ActiveRecord
1515
1515
  end
1516
1516
 
1517
1517
  def index_column_names(column_names)
1518
- if column_names.is_a?(String) && /\W/.match?(column_names)
1518
+ if expression_column_name?(column_names)
1519
1519
  column_names
1520
1520
  else
1521
1521
  Array(column_names)
@@ -1523,13 +1523,18 @@ module ActiveRecord
1523
1523
  end
1524
1524
 
1525
1525
  def index_name_options(column_names)
1526
- if column_names.is_a?(String) && /\W/.match?(column_names)
1526
+ if expression_column_name?(column_names)
1527
1527
  column_names = column_names.scan(/\w+/).join("_")
1528
1528
  end
1529
1529
 
1530
1530
  { column: column_names }
1531
1531
  end
1532
1532
 
1533
+ # Try to identify whether the given column name is an expression
1534
+ def expression_column_name?(column_name)
1535
+ column_name.is_a?(String) && /\W/.match?(column_name)
1536
+ end
1537
+
1533
1538
  def strip_table_name_prefix_and_suffix(table_name)
1534
1539
  prefix = Base.table_name_prefix
1535
1540
  suffix = Base.table_name_suffix
@@ -197,7 +197,7 @@ module ActiveRecord
197
197
 
198
198
  # Executes the SQL statement in the context of this connection.
199
199
  def execute(sql, name = nil, async: false)
200
- raw_execute(sql, name, async)
200
+ raw_execute(sql, name, async: async)
201
201
  end
202
202
 
203
203
  # Mysql2Adapter doesn't have to free a result after using it, but we use this method
@@ -26,6 +26,8 @@ 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 = [])
@@ -98,8 +100,8 @@ module ActiveRecord
98
100
  statements = statements.map { |sql| transform_query(sql) }
99
101
  combine_multi_statements(statements).each do |statement|
100
102
  raw_execute(statement, name)
103
+ @connection.abandon_results!
101
104
  end
102
- @connection.abandon_results!
103
105
  end
104
106
 
105
107
  def default_insert_value(column)
@@ -53,7 +53,13 @@ module ActiveRecord
53
53
  end
54
54
 
55
55
  def schema_precision(column)
56
- super unless /\A(?:date)?time(?:stamp)?\b/.match?(column.sql_type) && column.precision == 0
56
+ if /\Atime(?:stamp)?\b/.match?(column.sql_type) && column.precision == 0
57
+ nil
58
+ elsif column.type == :datetime
59
+ column.precision == 0 ? "nil" : super
60
+ else
61
+ super
62
+ end
57
63
  end
58
64
 
59
65
  def schema_collation(column)
@@ -163,6 +163,7 @@ module ActiveRecord
163
163
  default, default_function = field[:Default], nil
164
164
 
165
165
  if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(default)
166
+ default = "#{default} ON UPDATE #{default}" if /on update CURRENT_TIMESTAMP/i.match?(field[:Extra])
166
167
  default, default_function = nil, default
167
168
  elsif type_metadata.extra == "DEFAULT_GENERATED"
168
169
  default = +"(#{default})" unless default.start_with?("(")
@@ -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
@@ -10,6 +10,8 @@ module ActiveRecord
10
10
  end
11
11
 
12
12
  def cast_value(value)
13
+ return if value.blank?
14
+
13
15
  time = super
14
16
  return time if time.is_a?(ActiveSupport::TimeWithZone)
15
17
 
@@ -525,7 +525,7 @@ module ActiveRecord
525
525
  scope = quoted_scope(table_name)
526
526
 
527
527
  check_info = exec_query(<<-SQL, "SCHEMA")
528
- SELECT conname, pg_get_constraintdef(c.oid) AS constraintdef, c.convalidated AS valid
528
+ SELECT conname, pg_get_constraintdef(c.oid, true) AS constraintdef, c.convalidated AS valid
529
529
  FROM pg_constraint c
530
530
  JOIN pg_class t ON c.conrelid = t.oid
531
531
  WHERE c.contype = 'c'
@@ -537,7 +537,7 @@ module ActiveRecord
537
537
  name: row["conname"],
538
538
  validate: row["valid"]
539
539
  }
540
- expression = row["constraintdef"][/CHECK \({2}(.+)\){2}/, 1]
540
+ expression = row["constraintdef"][/CHECK \((.+)\)/m, 1]
541
541
 
542
542
  CheckConstraintDefinition.new(table_name, expression, options)
543
543
  end
@@ -569,7 +569,7 @@ module ActiveRecord
569
569
  else raise ArgumentError, "No integer type has byte size #{limit}. Use a numeric with scale 0 instead."
570
570
  end
571
571
  when "enum"
572
- raise ArgumentError "enum_type is required for enums" if enum_type.nil?
572
+ raise ArgumentError, "enum_type is required for enums" if enum_type.nil?
573
573
 
574
574
  enum_type
575
575
  else
@@ -663,7 +663,12 @@ module ActiveRecord
663
663
  column_name, type, default, notnull, oid, fmod, collation, comment, attgenerated = field
664
664
  type_metadata = fetch_type_metadata(column_name, type, oid.to_i, fmod.to_i)
665
665
  default_value = extract_value_from_default(default)
666
- default_function = extract_default_function(default_value, default)
666
+
667
+ if attgenerated.present?
668
+ default_function = default
669
+ else
670
+ default_function = extract_default_function(default_value, default)
671
+ end
667
672
 
668
673
  if match = default_function&.match(/\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z/)
669
674
  serial = sequence_name_from_parts(table_name, column_name, match[:suffix]) == match[:sequence_name]
@@ -75,7 +75,7 @@ module ActiveRecord
75
75
 
76
76
  class << self
77
77
  def new_client(conn_params)
78
- PG.connect(conn_params)
78
+ PG.connect(**conn_params)
79
79
  rescue ::PG::Error => error
80
80
  if conn_params && conn_params[:dbname] && error.message.include?(conn_params[:dbname])
81
81
  raise ActiveRecord::NoDatabaseError.db_error(conn_params[:dbname])
@@ -281,7 +281,7 @@ module ActiveRecord
281
281
  def initialize(connection, logger, connection_parameters, config)
282
282
  super(connection, logger, config)
283
283
 
284
- @connection_parameters = connection_parameters
284
+ @connection_parameters = connection_parameters || {}
285
285
 
286
286
  # @local_tz is initialized as nil to avoid warnings when connect tries to use it
287
287
  @local_tz = nil
@@ -11,6 +11,8 @@ module ActiveRecord
11
11
 
12
12
  def write_query?(sql) # :nodoc:
13
13
  !READ_QUERY.match?(sql)
14
+ rescue ArgumentError # Invalid encoding
15
+ !READ_QUERY.match?(sql.b)
14
16
  end
15
17
 
16
18
  def explain(arel, binds = [])
@@ -45,6 +45,19 @@ module ActiveRecord
45
45
  0
46
46
  end
47
47
 
48
+ def quote_default_expression(value, column) # :nodoc:
49
+ if value.is_a?(Proc)
50
+ value = value.call
51
+ if value.match?(/\A\w+\(.*\)\z/)
52
+ "(#{value})"
53
+ else
54
+ value
55
+ end
56
+ else
57
+ super
58
+ end
59
+ end
60
+
48
61
  def type_cast(value) # :nodoc:
49
62
  case value
50
63
  when BigDecimal
@@ -127,20 +127,20 @@ module ActiveRecord
127
127
  end
128
128
 
129
129
  def new_column_from_field(table_name, field)
130
- default = \
131
- case field["dflt_value"]
132
- when /^null$/i
133
- nil
134
- when /^'(.*)'$/m
135
- $1.gsub("''", "'")
136
- when /^"(.*)"$/m
137
- $1.gsub('""', '"')
138
- else
139
- field["dflt_value"]
140
- end
130
+ default = field["dflt_value"]
141
131
 
142
132
  type_metadata = fetch_type_metadata(field["type"])
143
- Column.new(field["name"], default, type_metadata, field["notnull"].to_i == 0, collation: field["collation"])
133
+ default_value = extract_value_from_default(default)
134
+ default_function = extract_default_function(default_value, default)
135
+
136
+ Column.new(
137
+ field["name"],
138
+ default_value,
139
+ type_metadata,
140
+ field["notnull"].to_i == 0,
141
+ default_function,
142
+ collation: field["collation"]
143
+ )
144
144
  end
145
145
 
146
146
  def data_source_sql(name = nil, type: nil)