Replies: 2 comments 1 reply
|
Update: I went ahead and fixed the sqlx 0.9 incompatibility I mentioned at the bottom of the proposal, rather than leaving it as a separate question. It turned out to be a prerequisite rather than a footnote, so it is now the bottom of the stack — reviewable and mergeable entirely on its own, without any of the engine work. Revised stack (each based on the one above it):
On the fix itself: run-time SQL now goes through The e2e fixtures move from sqlx 0.8 to 0.9 so the suite finally covers the same version the workspace declares. That is the gap that hid this: the fixtures were a version behind, and no example had a This does set a version floor. With the fix in place both new examples now carry a real |
|
@jrandolf any chance to look at this proposal |
Uh oh!
There was an error while loading. Please reload this page.
Problem
sqlc-gen-sqlxonly generates for PostgreSQL. sqlc itself reports the target backend inGenerateRequest.settings.engine, but the generator ignores it and hardcodessqlx::Postgres,PgPool,PgQueryResultand the PostgreSQL type table throughout. Pointing the plugin at aengine: mysqlorengine: sqliteconfig today produces code that does not compile.sqlx supports all three backends with the same
Executor/FromRow/query_assurface, so most of the generator is already engine-agnostic — the backend-specific parts are few and identifiable.Result I'd like
sql[*].engineselects the sqlx driver, withpostgresqlbehaviour unchanged,mysqlandsqlitesupported, and anything else rejected with a clear error.What actually differs between the engines
I went through this carefully, because a couple of the differences are not obvious:
PgPool/PgQueryResultMySqlPool/MySqlQueryResultSqlitePool/SqliteQueryResult$1numbered?ordinal?ordinal:execlastidRETURNINGcolumnu64fromlast_insert_id()i64fromlast_insert_rowid()#[sqlx(type_name)]Typeimpl (below)Two findings worth flagging on their own, since they are the parts most likely to be got wrong:
1.
sqlc.slice()bind order on?engines. sqlc lifts the slice out of the ordinal numbering. ForWHERE id IN (sqlc.slice(ids)) AND country = ?it reportscountryas number 1 andidsas number 2 — even though the slice comes first in the query text. Ordering binds byParameter.numbertherefore silently swaps the arguments. The order has to come from the query text itself. Relatedly, the/*SLICE:ids*/marker follows the column'sname(ids), notoriginal_name(id); the PostgreSQL path never noticed because it falls back to replacing the bare$N.2. MySQL enums cannot use
#[derive(sqlx::Type)]. sqlx's derive reportsMySqlTypeInfo::__enum(), whosePartialEqcompares column flags, so a realENUMcolumn never matches andtry_getfails at runtime with "Rust typeStatus(as SQL typeENUM) is not compatible with SQL typeENUM". Since the derive expands toEncode + Decode + Type, deriving only the first two and writing theTypeimpl (deferring compatibility tostr) fixes it.Reference implementation
I have this working end to end, split into two reviewable changes on my fork. Offered as prior art for whoever picks this up — happy for it to be rewritten, or to rework it against your review:
Engineabstraction — feat(engine): add MySQL support iamralch/sqlc-gen-sqlx#1Notes on the shape of it:
matchonEngineis exhaustive, so adding the third backend made the compiler list exactly the four decision points that needed a SQLite answer.engine:from each case's sqlc config and starts one container per engine in use (SQLite runs off a temp file). Six new cases cover CRUD, slice expansion including the interleaved-scalar ordering,ENUMroundtrips and a 250-row:copyfrom. There are also 18 new codegen tests and 12 snapshots.Separate pre-existing bug found along the way
The dynamic-slice codegen emits
sqlx::query_as(&sql), which sqlx 0.9 rejects — it now requiresSqlSafeStr, and&Stringis not&'static str. This affects PostgreSQL identically and is unrelated to engine support; no existing example exercises a non-ANYslice, which is why it has gone unnoticed. The workspace declares sqlx 0.9 while the e2e fixtures pin 0.8, so the test suite does not catch it either.The fix is
sqlx::query_as(sqlx::AssertSqlSafe(sql)), which does not exist in 0.8 — so it is a "which sqlx version does generated code target" decision rather than a mechanical fix, and I left it alone. Happy to open a separate Discussion for it if you'd prefer it tracked on its own.All reactions