fix: select the MySQL adapter for Trilogy - #28
Merged
Conversation
Adapter selection matched the client name, not the protocol. Trilogy reports "Trilogy", so every call raised UnsupportedDatabase on a database Solid Objects fully supports. The match now resolves through one table of families used by adapter selection, owner-id casting, and wake-up selection alike, so a client cannot be accepted in one place and rejected in another. Owner-id casting was the second place: Trilogy fell through to CAST(x AS TEXT), which is not valid MySQL. Running the suite against real Trilogy found two more, both ours rather than Trilogy's. Instance.orphaned compared a cast against a column, and a cast result carries the connection collation rather than the column's. MySQL refuses to compare two collations. mysql2 negotiates the database default and Trilogy negotiates utf8mb4_general_ci, so the query raised Illegal mix of collations. A mysql2 application setting collation: in database.yml could already hit this. The comparison is pinned to the column's collation. A synchronous deadline is enforced by asking the server to interrupt the statement, and the interruption was matched only through mysql2's error_number. Trilogy names it error_code, so a deadline surfaced as a raw StatementTimeout instead of SyncEnqueueTimeout. CI runs the MySQL suite against both clients, and adapter-specific skips key to the family, so a Trilogy run no longer silently skips every MySQL test.
Greptile SummaryThe PR adds Trilogy as a supported MySQL client and centralizes database-family detection.
Confidence Score: 5/5The PR appears safe to merge with no concrete blocking or independently actionable non-blocking issue identified. The centralized family selection, Trilogy error handling, and MySQL collation behavior are applied consistently and covered by focused unit and integration tests. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
C[Active Record connection] --> F[DatabaseAdapter.family]
F -->|PostgreSQL| P[PostgreSQL adapter and wake-up]
F -->|Mysql2 or Trilogy| M[MySQL adapter]
F -->|SQLite| S[SQLite adapter]
M --> O[CHAR owner-ID cast with actor_id collation]
M --> D[Deadline interruption classification]
D --> E[Sync timeout error]
Reviews (1): Last reviewed commit: "fix: select the MySQL adapter for Trilog..." | Re-trigger Greptile |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the reported
UnsupportedDatabaseon Trilogy, and the two further defects that running the suite against real Trilogy exposed. Version bumped to 0.10.1.The reported bug
DatabaseAdapter.formatched the client name, not the protocol:Trilogy reports
"Trilogy", so every Solid Objects call raisedUnsupportedDatabase: unsupported database adapter "Trilogy"on a database the gem fully supports.Adapter names now resolve through one table of families:
DatabaseAdapter.familyis used by adapter selection, owner-id casting, and wake-up selection alike, so a client cannot be accepted in one place and rejected in another.That mattered immediately: owner-id casting was a second copy of the same match.
Instance#owner_id_cast_typesent Trilogy down theelsebranch toCAST(x AS TEXT), which is not valid MySQL syntax. That was a latent SQL error, not just a wrong classification.Two more defects, found by running against real Trilogy
Both are ours, not Trilogy's, and both are reachable on mysql2 too.
Collation mismatch in
Instance.orphaned. The query casts owner primary keys and compares them againstactor_id. A cast result carries the connection collation, not the column's, and MySQL refuses to compare two collations:Which collation the connection uses is a property of the client, measured here:
collation_connectioncollation_databaseutf8mb4_0900_ai_ciutf8mb4_0900_ai_ciutf8mb4_general_ciutf8mb4_0900_ai_cimysql2 happened to match, which is why this never surfaced. A mysql2 application that sets
collation:indatabase.ymlcould already hit it — a common setting. The comparison is now pinned to the column's own collation, read from the schema and validated before interpolation.Deadline interruption unrecognised. A synchronous deadline is enforced by asking the server to interrupt the statement; recognising that interruption is what turns it back into
SyncEnqueueTimeout. The match walked the cause chain for mysql2'serror_number == 3024. Trilogy exposeserror_code, noterror_number, so the deadline surfaced as a rawActiveRecord::StatementTimeout:Active Record's own classification is now trusted first, and the raw code fallback reads both names.
Test coverage
New
test/unit/deadline_error_test.rbcovers both client shapes without needing either gem installed, so this is caught on the default SQLite run rather than only under a Trilogy job. New unit tests pin the family table, and a new test pins the cast collation on the MySQL family.The skips were part of the problem. Adapter-specific tests skipped on
adapter_name.match?(/mysql/i), so a Trilogy run silently skipped every MySQL test while reporting green. All 13 such predicates now key todatabase_family, and CI runs the MySQL suite against both clients — passing on one proves nothing about the other.Validation
bundle exec rake(SQLite)Confirmed the MySQL-family tests genuinely execute under Trilogy rather than skip, and that reverting the pattern to
/mysql/ireproducesUnsupportedDatabase: unsupported database adapter "Trilogy".Trilogy is a development dependency only; it is not added to the gem's runtime requirements.