Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check if insert_all/upsert_all can be implemented using MERGE #859

Closed
wpolicarpo opened this issue Mar 19, 2021 · 8 comments
Closed

Check if insert_all/upsert_all can be implemented using MERGE #859

wpolicarpo opened this issue Mar 19, 2021 · 8 comments

Comments

@wpolicarpo
Copy link
Member

Issue

Rails 6 introduced upsert_all and the SQL Server adapter does not implement it yet.

There's no such thing as MySQL's ON DUPLICATE KEY UPDATE in SQL Server, but we could possibly use the MERGE clause to achieve the same result.

Expected behavior

upsert_all and insert_all could possibly be implemented using MERGE.

Actual behavior

upsert_all and insert_all are not implemented.

@mgrunberg
Copy link
Contributor

@wpolicarpo I created PR #869 to explore this possibility. I found some issues.

@andyundso
Copy link
Member

Hi @aidanharan

I would like to pick up the work by @mgrunberg in #869, mostly because I would like to use Solid Queue with MSSQL. There is a recent comment by @justinko regarding a caveat.

I think MERGE is still appropriate for this ... it just doesn't support duplicates in the "source". More info on that here: https://www.ibm.com/docs/en/informix-servers/14.10?topic=statement-handling-duplicate-rows

Question is if it would be okay if the activerecord-sql-adapter diverges from the other reference implementations (MySQL, SQLite and PostgreSQL) and de-duplicates the rows in the source (using the uniquely identifiable information, as suggested in the PR). I would assume most users never update the same thing multiple times within the same database query, but for those who do, it could be documented in the code that SQL server does this.

Otherwise, an official gem for the insert / upsert functionality also might be an idea to signal "hey, we can offer this functionality, but since it has a catch, it is its own thing".

@aidanharan
Copy link
Contributor

@andyundso Yes, I think de-duplicating the rows in the source in the adapter is fine if it can be made to work. We can document the difference to other adapters in the README.

I'm no longer using MSSQL in work so I have limited time to give to the issue.

@andyundso
Copy link
Member

@aidanharan question about the tests: I do not really understand what this coerce does? does this disable tests from Rails upstream? how would I best go to add tests for this new MERGE mechanism?

@aidanharan
Copy link
Contributor

aidanharan commented Mar 13, 2025

@andyundso You only need to coerce a test if the Rails test doesn't suit the adapter. For example, in the ActiveRecord UniquenessValidationWithIndexTest#test_partial_index test the where option needed to be slightly modified for MSSQL. So we coerce the ActiveRecord test and re-implement it as UniquenessValidationWithIndexTest#test_partial_index_coerced. Note, the naming of the test with _coerced is just to let the developer know if it was a coerced test.

ActiveRecord: https://github.com/rails/rails/blob/3626b8f52c425c2dd7a0d0aa698cff9f10d789b3/activerecord/test/cases/validations/uniqueness_validation_test.rb#L728

MSSQL:

coerce_tests! :test_partial_index

For insert_all/upsert_all you should not need to coerce any tests. The adapter's supports_insert_on_duplicate_skip? and supports_insert_on_duplicate_update? flags should be enabled as part of the PR so that tests such as InsertAllTest#test_insert_all_with_skip_duplicates_and_autonumber_id_given will not be skipped when run against the MSSQL adapter.

ActiveRecord: https://github.com/rails/rails/blob/3626b8f52c425c2dd7a0d0aa698cff9f10d789b3/activerecord/test/cases/insert_all_test.rb#L177

@aidanharan
Copy link
Contributor

Closing as feature added in #1312

@aidanharan
Copy link
Contributor

Created v8.0.5 release with insert_all/upsert_all support.

@andyundso
Copy link
Member

cool stuff! now the next challenge is to see if we can get the solid trifecta (cache, queue and cable) to run. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants