January 16, 2024
New gem release: unreliable 0.10
I released a new version of a gem!
unreliable is a gem I wrote that makes your test suite and your app more robust against undefined database behevior.
During the running of your test suite, it adds randomness to the order of all your ActiveRecord relations. If their existing order is well-defined, that won’t change a thing.
But if you have any relations where ordering actually matters, and you don’t fully specify that order, the gem may surface some of those bugs.
SQL order can be undefined
Many people don’t know that if a query has an ORDER BY clause that’s ambiguous, the database can return results in any order. That’s in the spec!
Because most databases, most of the time, return data in primary key order, we as programmers get used to that and maybe sometimes rely on it.
“unreliable” forces you not to rely on it.
Bugfixes and tests
Version 0.10 has several bugfixes related to Postgres. And it’s got a large test suite that should give some confidence it’s doing the right thing.
(It does exactly nothing outside of a Rails test environment anyway, so have no fear, it can’t cause problems in your actual app.)
Give it a try!
Arel 8, subqueries, and update
Okay, this is just a footnote. Here’s something that came up while I was writing “unreliable”’s test suite.
I found an odd edge case bug in Arel 8, the library used by the ORM in ActiveRecord 5.0 and 5.1. And although Arel was a public API at that point, really nobody but Rails was using it, and 5.1 is long-since end-of-lifed, so none of this really matters.
Where ActiveRecord calls Arel’s compile_update, the relation is unscoped, so it can’t have an order or limit.
But if it did, then when visit_Arel_Nodes_UpdateStatement built the SQL, it would construct an IN subquery and pass it a primary key that’s quoted.
The resulting query that the visitor would build would be:
UPDATE foo SET bar=1 WHERE ‘id’ IN (SELECT 'id’ FROM foo WHERE foo.id=2)
See the bug? 'id’ should have been “id”, which would have referenced the column. But it’s single-quoted, and in SQL, that’s a string literal!
So every row matches and the whole table gets updated! Yikes!
The bug never triggers for MySQL because MySQL forbids same-table subqueries on UPDATEs, so Rails special-cases around this.
And as I said, this is all ancient history, and almost certainly affects no one. But I think this is technically an Arel 8 bug that has been lurking undiscovered since February 2017.
This behavior was fixed in Arel 9. That’s why “unreliable”, which forces an order on most relations internally, after ActiveRecord forces an unscoping, now requires ActiveRecord >= 5.2.