Commit Graph

539 Commits

Author SHA1 Message Date
Nikita Vasilevsky 24570678d6
[Tests only] Expand trigger populated PK test case to run against more DBs 2024-01-18 17:28:12 +00:00
Nikita Vasilevsky c2c861f98a
Always request `primary_key` in `RETURNING` if no other columns requested
Prior 7.1 Rails always included `primary_key` in `RETURNING` clause on
record creation. This was changed in 7.1 to include more auto-populated
columns if such columns exist. This change lead to situations where
no columns were requested in `RETURNING` clause, even the `primary_key`.

This change brings back the old behavior of always requesting the
`primary_key` in `RETURNING` clause if no other columns are requested.
2024-01-17 18:19:40 +00:00
Yash Kapadia 0702c24e7b Fix single quote escapes on default generated MySQL columns
MySQL 5.7.5+ supports generated columns, which can be used to create a column that is computed from an expression. This commit fixes the escaping of the default value for such expressions if a single quote is included.

See the following for more: https://dev.mysql.com/blog-archive/generated-columns-in-mysql-5-7-5/
2024-01-17 07:12:27 -05:00
Rafael Mendonça França af2bbd5f66
Merge pull request #46383 from dmytro-savochkin/fix-activerecord-reload-association-cache
Ensure `reload` sets correct owner for each association (ActiveRecord::Persistence)
2024-01-15 15:48:25 -05:00
Eileen M. Uchitelle 0745043c7a
Merge pull request #50319 from fatkodima/fix-where-for-polymorphic-cpk
Fix predicate builder for polymorphic models referencing models with composite primary keys
2023-12-11 10:20:07 -05:00
fatkodima f99d05e722 Fix polymorphic `belongs_to` to correctly use parent's `query_constraints` 2023-12-10 22:04:05 +02:00
fatkodima 0663b44bd9 Fix predicate builder for polymorphic models referencing models with composite primary keys 2023-12-10 15:26:23 +02:00
Dmytro Savochkin 781ecc22eb Ensure `reload` sets correct owner for each association
Fix #46363.

Currently calling `reload` re-calculates the association cache based
on the object freshly loaded from the database. The fresh object gets
assigned as `owner` for each association in the association cache.
That object however is not the same as `self` (even though they
both point to the same record). Under some specific circumstances
(using `has_one/has_many through` associations and transactions with
`after_commit` callbacks) this might lead to losing the effects of
assignments done inside the callback.

This commit fixes it by making `reload` point to `self` as `owner`
for each association in the association cache.
2023-11-18 15:59:09 +02:00
Cody Cutrer f9fee1a3cb Add `set_constraints` helper for PostgreSQL
The docs already talk about how to set up deferrable constraints, but
then rely on the user crafting custom SQL to actually use the feature.
The helper makes it easier to handle juggling multiple specific
constraints and quoting issues.
2023-10-24 11:49:11 -06:00
fatkodima 796e36451f Fix detecting `IDENTITY` columns for PostgreSQL < 10 2023-10-12 12:30:33 +03:00
fatkodima cb1a13aeab Fix ActiveRecord tests for PostgreSQL < 10 2023-10-12 12:29:27 +03:00
fatkodima f592d50837 Fix auto populating `IDENTITY` columns for PostgreSQL
Fixes #49502.

This bug was introduced in https://github.com/rails/rails/pull/48241. Since `IDENTITY` columns
in PostgreSQL do not have defaults, they are not auto populated via the changes made in that PR.
Thus we need to consider them separately.
2023-10-05 23:42:29 +03:00
Ryuta Kamizono b2790b6680 Rename back unique keys to unique constraints
As we (I and @yahonda) talked about the naming in person, naming unique
constraints as unique keys is very confusing to me.
All documents and descriptions says it's unique constraints, but naming
unique keys leads to misunderstanding it's a short-hand of unique
indexes.
Just naming it unique constraints is not misleading.
2023-09-26 17:52:09 +09:00
Eileen M. Uchitelle f57d54cde4
Merge pull request #49336 from fatkodima/fix-mysql-expression-index-dumping
Fix MySQL expression index dumping with escaped quotes
2023-09-25 10:22:34 -06:00
fatkodima 69b32bd95b Fix MySQL expression index dumping with escaped quotes 2023-09-20 20:30:21 +03:00
Stephen Margheim 9bbbf4b8b9 The SQLite3 adapter now supports `supports_insert_returning?`
Implementing the full `supports_insert_returning?` contract means the SQLite3 adapter supports auto-populated columns (#48241) as well as custom primary keys.
2023-09-20 19:28:17 +02:00
Rafael Mendonça França 9eb16e77da
Revert "Merge pull request #49242 from eileencodes/fix-inferred-query-constraints"
This reverts commit 213e8ff95e, reversing
changes made to b5d63b9b16.

It broke a lot of test.

It also changed how lazy loading of model code works.

With this change a simple `belongs_to :owner` is now loading `owner.rb`
when that line is executed, where before it wasn't doing that.
This can have serious impact on boot time in development.

We should make this as lazy as possible.
2023-09-12 22:36:33 +00:00
eileencodes a8ea8bb4bd
Fix inferred query constraints
While working on implementing query constraints in our vitess gem, I
noticed that we were applying query constraints even when we didn't have
them on both sides of the association. We only want to infer query
constraints if both the `klass` and `active_record` have them set.

* If both the `klass` and `active_record` on the association don't have
query constraints set, use the `foreign_key` and don't infer query
constraints.
* Adds an error if the `active_record` and `klass` query constraints
don't match.
* Calling `klass` in `derive_fk_query_constraints` revealed that a bunch
of our tests are missing requires, without these we'll see test failures
that an association can't compute the klass name. Adding the requires
fixes those.
2023-09-12 11:57:51 -04:00
Nikita Vasilevsky 118135982e
Drop `id` column from `cpk_order_tags` table 2023-09-08 17:16:40 +00:00
Robert DiMartino eceaa38e06
Fix tracking previous changes for ActiveRecord::Store accessors with underlying JSON data column 2023-08-07 22:26:45 -04:00
Gregory Jones 4837bcaeef
Merge branch 'main' into postgres-index-nulls-not-distinct 2023-07-18 15:05:24 -04:00
Jacopo 186474f273 Fix counter_cache create/concat with overlapping counter_cache_column
Fix when multiple `belongs_to` maps to the same counter_cache column.
In such situation `inverse_which_updates_counter_cache` may find the
wrong relation which leads into an invalid increment of the
counter_cache.

This is done by releying on the `inverse_of` property of the relation
as well as comparing the models the association points two.

Note however that this second check doesn't work for polymorphic
associations.

Fixes #41250

Co-Authored-By: Jean Boussier <jean.boussier@gmail.com>
2023-07-13 12:06:08 +02:00
Gregory Jones 52eb5d9c56 Add a schema dumper test for nulls_not_distinct 2023-06-29 00:40:49 -04:00
Gannon McGibbon e224768d14 Use id instead of number in composite key for Cpk::Book
Use [:author_id, :id] instead of [:author_id, :number] as
the primary key of Cpk::Book.
2023-06-26 15:33:28 -05:00
Gannon McGibbon 622485ae4b Add support for nullifying CPK has_one associations
Composite primary key records need to conditionally unset multiple
column attributes from the associated record in order to properly
support dependent: nullify.
2023-06-21 11:08:06 -05:00
Nikita Vasilevsky 892e4ae24c
Fix `destroy_all` for `has_many :through` associations that points to a CPK model 2023-06-14 17:48:13 +00:00
Alex Baldwin 9b57b83c76 Test virtual stored columns on create for Postgres
Closes: https://github.com/rails/rails/issues/45736

Codify example from #45736 into test suite
2023-06-06 14:58:57 -04:00
Eileen M. Uchitelle 254f1d8ded
Merge pull request #48357 from gmcgibbon/belongs_to_cpk
Add composite primary key validity check on belongs_to associations.
2023-06-02 08:25:16 -04:00
Gannon McGibbon f9a8f9c976 Add composite primary key validity check to associations.
Raise ActiveRecord::CompositePrimaryKeyMismatchError when a belongs_to,
has_one, or has_many foreign key and primary key don't have the same length.
2023-06-02 01:32:59 -05:00
Nikita Vasilevsky c92933265e
Assign auto populated columns on Active Record object creation
This commit extends Active Record creation logic to allow for a database
auto-populated attributes to be assigned on object creation.

Given a `Post` model represented by the following schema:
```ruby
create_table :posts, id: false do |t|
  t.integer :sequential_number, auto_increment: true
  t.string :title, primary_key: true
  t.string :ruby_on_rails, default: -> { "concat('R', 'o', 'R')" }
end
```
where `title` is being used as a primary key, the table has an
integer `sequential_number` column populated by a sequence and
`ruby_on_rails` column has a default function - creation of
`Post` records should populate the `sequential_number` and
`ruby_on_rails` attributes:

```ruby
new_post = Post.create(title: 'My first post')
new_post.sequential_number # => 1
new_post.ruby_on_rails # => 'RoR'
```

* At this moment MySQL and SQLite adapters are limited to only one
column being populated and the column must be the `auto_increment`
while PostgreSQL adapter supports any number of auto-populated
columns through `RETURNING` statement.
2023-06-01 14:39:12 +00:00
fatkodima a7dc348406 Fix decrementing counter caches for parent records using optimistic locking 2023-05-30 02:17:37 +03:00
Jean Boussier 108617eb74 Fix change_in_place? for binary serialized columns
Followup: https://github.com/rails/rails/pull/40383
Fix: https://github.com/rails/rails/issues/48255
Fix: https://github.com/rails/rails/pull/48262

If the serialized attribute is backed by a binary column, we must ensure
that both the `raw_old_value` and the `raw_new_value` are casted to
`Binary::Data`.

Additionally, `Binary::Data` must cast it's backing string in
`Encoding::BINARY` otherwise comparison of strings containing bytes
outside the ASCII range will fail.
2023-05-22 13:01:42 +02:00
Nikita Vasilevsky 2f29722e7f
[Tests only] Populate auto-generated UUID primary key 2023-05-15 21:20:01 +00:00
eileencodes 58a0a52019
Fix config and copy over trilogy schema
We had a mysql2_specific_schema.rb file but not one for trilogy that was
causing tests to break. I also removed the prepared statements from
trilogy because it is not supported.
2023-04-21 17:33:25 -04:00
eileencodes 6577e8b1e1
Revert "Merge pull request #47864 from zenspider/zenspider/ar_core_hash"
This reverts commit 2815cb9620, reversing
changes made to 11a5e37715.

The change broke application code and if we are going to make this
change we will need to deprecate the prior behavior. See #47864 for more
details.
2023-04-18 17:23:45 -04:00
Adrianna Chang 5ed3f60df6
Introduce adapter for Trilogy, a MySQL-compatible DB client
The [Trilogy database client][trilogy-client] and corresponding
[Active Record adapter][ar-adapter] were both open sourced by GitHub last year.

Shopify has recently taken the plunge and successfully adopted Trilogy in their Rails monolith.
With two major Rails applications running Trilogy successfully, we'd like to propose upstreaming the adapter
to Rails as a MySQL-compatible alternative to Mysql2Adapter.

[trilogy-client]: https://github.com/github/trilogy
[ar-adapter]: https://github.com/github/activerecord-trilogy-adapter

Co-authored-by: Aaron Patterson <tenderlove@github.com>
Co-authored-by: Adam Roben <adam@roben.org>
Co-authored-by: Ali Ibrahim <aibrahim2k2@gmail.com>
Co-authored-by: Aman Gupta <aman@tmm1.net>
Co-authored-by: Arthur Nogueira Neves <github@arthurnn.com>
Co-authored-by: Arthur Schreiber <arthurschreiber@github.com>
Co-authored-by: Ashe Connor <kivikakk@github.com>
Co-authored-by: Brandon Keepers <brandon@opensoul.org>
Co-authored-by: Brian Lopez <seniorlopez@gmail.com>
Co-authored-by: Brooke Kuhlmann <brooke@testdouble.com>
Co-authored-by: Bryana Knight <bryanaknight@github.com>
Co-authored-by: Carl Brasic <brasic@github.com>
Co-authored-by: Chris Bloom <chrisbloom7@github.com>
Co-authored-by: Cliff Pruitt <cliff.pruitt@cliffpruitt.com>
Co-authored-by: Daniel Colson <composerinteralia@github.com>
Co-authored-by: David Calavera <david.calavera@gmail.com>
Co-authored-by: David Celis <davidcelis@github.com>
Co-authored-by: David Ratajczak <david@mockra.com>
Co-authored-by: Dirkjan Bussink <d.bussink@gmail.com>
Co-authored-by: Eileen Uchitelle <eileencodes@gmail.com>
Co-authored-by: Enrique Gonzalez <enriikke@gmail.com>
Co-authored-by: Garrett Bjerkhoel <garrett@github.com>
Co-authored-by: Georgi Knox <georgicodes@github.com>
Co-authored-by: HParker <HParker@github.com>
Co-authored-by: Hailey Somerville <hailey@hailey.lol>
Co-authored-by: James Dennes <jdennes@gmail.com>
Co-authored-by: Jane Sternbach <janester@github.com>
Co-authored-by: Jess Bees <toomanybees@github.com>
Co-authored-by: Jesse Toth <jesse.toth@github.com>
Co-authored-by: Joel Hawksley <joelhawksley@github.com>
Co-authored-by: John Barnette <jbarnette@github.com>
Co-authored-by: John Crepezzi <john.crepezzi@gmail.com>
Co-authored-by: John Hawthorn <john@hawthorn.email>
Co-authored-by: John Nunemaker <nunemaker@gmail.com>
Co-authored-by: Jonathan Hoyt <hoyt@github.com>
Co-authored-by: Katrina Owen <kytrinyx@github.com>
Co-authored-by: Keeran Raj Hawoldar <keeran@gmail.com>
Co-authored-by: Kevin Solorio <soloriok@gmail.com>
Co-authored-by: Leo Correa <lcorr005@gmail.com>
Co-authored-by: Lizz Hale <lizzhale@github.com>
Co-authored-by: Lorin Thwaits <lorint@gmail.com>
Co-authored-by: Matt Jones <al2o3cr@gmail.com>
Co-authored-by: Matthew Draper <matthewd@github.com>
Co-authored-by: Max Veytsman <mveytsman@github.com>
Co-authored-by: Nathan Witmer <nathan@zerowidth.com>
Co-authored-by: Nick Holden <nick.r.holden@gmail.com>
Co-authored-by: Paarth Madan <paarth.madan@shopify.com>
Co-authored-by: Patrick Reynolds <patrick.reynolds@github.com>
Co-authored-by: Rob Sanheim <rsanheim@gmail.com>
Co-authored-by: Rocio Delgado <rocio@github.com>
Co-authored-by: Sam Lambert <sam.lambert@github.com>
Co-authored-by: Shay Frendt <shay@github.com>
Co-authored-by: Shlomi Noach <shlomi-noach@github.com>
Co-authored-by: Sophie Haskins <sophaskins@github.com>
Co-authored-by: Thomas Maurer <tma@github.com>
Co-authored-by: Tim Pease <tim.pease@gmail.com>
Co-authored-by: Yossef Mendelssohn <ymendel@pobox.com>
Co-authored-by: Zack Koppert <zkoppert@github.com>
Co-authored-by: Zhongying Qiao <cryptoque@users.noreply.github.com>
2023-04-17 11:49:07 -04:00
Paarth Madan 3d820195a0 Support fixture associations for composite models
Most of the support here is in implementing how to correctly substitute
multiple values in place of one, for composite caes. In composite cases,
it's not sufficient to hash a label into a single integer value.
Instead, we build an API that accepts a single label, and a list of
columns that we'd like to map to. The algorithm used internally is very
similar to #identify, with an additional bit shift and modulo to cycle
the hash and ensure it doesn't exceed a max.
2023-04-14 18:12:18 -04:00
Paarth Madan 6afc035cbc Support deleting records from associations for CPK 2023-04-12 17:53:20 -04:00
eileencodes 885bd850e3
Ensure that ids_writer and ids_reader is working for CPK
This fixes `ids_writer` so that it can handle a composite primary key.
Using a CPK model associated with a non-CPK model was working correctly
(which I added a test for). Using a CPK model associated with another
CPK model was not working correctly. It now takes it into account to
write the correct ids.

While working on `ids_reader` I found that `pluck` is not working for
CPK because it's passing an array of attributes and that's not supported
by `disallow_raw_sql!`. I chose to call `flatten` in `pluck` but not
conditionally because this seems like it could be a problem elsewhere as
well. This fixes pluck by CPK overall and fixes a test in the
calculations test file.
2023-04-12 15:02:58 -04:00
Nikita Vasilevsky 5cbdfba670 Fix associations associated with a CPK model by id attribute
Given a model associated with a composite primary key by `id` attribute,
for example:
```ruby
Order.primary_key = [:shop_id, :id]
OrderAgreement.primary_key = :id

Order.has_many :order_agreements, primary_key: :id
```

Accessing the association should perform queries using
the `id` attribute value and not the `id` as Order's composite primary key.

```ruby
order = Order.last # => #<Order id: 1, shop_id: 2>

order.order_agreements.to_a
```
2023-04-12 16:02:24 +00:00
Aaron Patterson cd84c0ad3a Add a test for eql? on new objects
New objects shouldn't eql? other new objects even if the id column sets
the value to a default value
2023-04-08 13:33:45 -07:00
Eileen M. Uchitelle fc2b937d56
Merge pull request #47819 from Shopify/always-respect-explicitly-configured-query-constraints
Respect explicitly configured `query_constraints`
2023-03-30 11:59:05 -04:00
Nikita Vasilevsky 767cd52e76 Respect explicitly configured `query_constraints` 2023-03-30 15:15:46 +00:00
Nikita Vasilevsky f29ff0f0a0 Fix precedence of `primary_key:` in associations with `query_constraints` 2023-03-23 23:01:06 +00:00
alpaca-tc cbc7b59749 Adds support for deferrable exclude constraints in PostgreSQL.
By default, exclude constraints in PostgreSQL are checked after each statement.
This works for most use cases, but becomes a major limitation when replacing
records with overlapping ranges by using multiple statements.

```ruby
exclusion_constraint :users, "daterange(valid_from, valid_to) WITH &&", deferrable: :immediate
```

Passing `deferrable: :immediate` checks constraint after each statement,
but allows manually deferring the check using `SET CONSTRAINTS ALL DEFERRED`
within a transaction. This will cause the excludes to be checked after the transaction.

It's also possible to change the default behavior from an immediate check
(after the statement), to a deferred check (after the transaction):

```ruby
exclusion_constraint :users, "daterange(valid_from, valid_to) WITH &&", deferrable: :deferred
```

*Hiroyuki Ishii*
2023-03-14 23:29:35 +09:00
fatkodima fe97e26785 Optimize slow tests in activerecord 2023-03-13 14:07:28 +02:00
Yasuo Honda 3025eaa091
Merge pull request #46192 from alpaca-tc/support_unique_constraints
Add support for unique constraints (PostgreSQL-only).
2023-03-12 18:31:38 +09:00
Nikita Vasilevsky fb127c0d42 Define `ActiveRecord::Base#id` API for composite primary key models
Given a model with a composite primary key:
```ruby
class Order < ActiveRecord::Base
  self.primary_key = [:shop_id, :id]
end
```

`ActiveRecord::Base#id` method will return an array of values for every
column of the primary key.

```ruby
order = Order.create!(shop_id: 1, id: 2)
order.id # => [1, 2]
```

The `id` column is accessible through the `read_attribute` method:

```ruby
order.read_attribute(:id) # => 2
```
2023-03-10 14:42:57 +00:00
alpaca-tc d849ee04c6 Add support for unique constraints (PostgreSQL-only).
```ruby
add_unique_key :sections, [:position], deferrable: :deferred, name: "unique_section_position"
remove_unique_key :sections, name: "unique_section_position"
```

See PostgreSQL's [Unique Constraints](https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-UNIQUE-CONSTRAINTS) documentation for more on unique constraints.

By default, unique constraints in PostgreSQL are checked after each statement.
This works for most use cases, but becomes a major limitation when replacing
records with unique column by using multiple statements.

An example of swapping unique columns between records.

```ruby
old_item = Item.create!(position: 1)
new_item = Item.create!(position: 2)

Item.transaction do
  old_item.update!(position: 2)
  new_item.update!(position: 1)
end
```

Using the default behavior, the transaction would fail when executing the
first `UPDATE` statement.

By passing the `:deferrable` option to the `add_unique_key` statement in
migrations, it's possible to defer this check.

```ruby
add_unique_key :items, [:position], deferrable: :immediate
```

Passing `deferrable: :immediate` does not change the behaviour of the previous example,
but allows manually deferring the check using `SET CONSTRAINTS ALL DEFERRED` within a transaction.
This will cause the unique constraints to be checked after the transaction.

It's also possible to adjust the default behavior from an immediate
check (after the statement), to a deferred check (after the transaction):

```ruby
add_unique_key :items, [:position], deferrable: :deferred
```

PostgreSQL allows users to create a unique constraints on top of the unique
index that cannot be deferred. In this case, even if users creates deferrable
unique constraint, the existing unique index does not allow users to violate uniqueness
within the transaction. If you want to change existing unique index to deferrable,
you need execute `remove_index` before creating deferrable unique constraints.

*Hiroyuki Ishii*
2023-03-10 16:09:32 +09:00
Nikita Vasilevsky c12a77da40 Fix assigning through records when using polymorphic has many through association 2023-02-28 17:56:56 +00:00