Skip to content

Three databases

10 / 11 · dialects in the full document · PDF

The same view loads and saves on PostgreSQL, MySQL 8 and SQLite through SQLx 0.9; each enabled database gets its own decoder and encoder, and a load runs on the database of the connection it is given. Where the databases differ, Mabat uses each one's own syntax; the shapes, plans, aliases, checks and errors are the same on all three.

PostgreSQLMySQL 8SQLite
Enabled bythe postgres feature, the default MPA-DB-1the mysql featurethe sqlite feature
Keys of a batched queryone array parameter: = ANY($1)IN (?, …), padded to a power of two so statements are reused, at most 1,000 keys a child statement MPA-DB-4as MySQL
Keys in an override= ANY(:keys), or $1 MPA-OVR-4IN (:keys), expanded to the placeholdersas MySQL
Key typesi16, i32, i64, String, Uuid MPA-VIEW-2also unsigned integersalso columns without a declared type, read by value
Case-insensitive matchILIKE MPA-LOAD-5LOWER(c) LIKE LOWER(?)LOWER(c) LIKE LOWER(?)
Enum tag columnsany type, such as a PostgreSQL enum, read as text MPA-SUM-1any type, such as ENUM(…), read as textany type, read as text
Concurrent loadsPooled::snapshot or Pooled::read_committed MPA-LOAD-11Pooled::read_committed; a snapshot does not compilePooled::read_committed; a snapshot does not compile
Save: a new rowINSERT … ON CONFLICT (key) DO UPDATE MPA-WRITE-3INSERT … AS new ON DUPLICATE KEY UPDATEINSERT … ON CONFLICT (key) DO UPDATE
Versioned insert, if absentINSERT … ON CONFLICT (key) DO NOTHING MPA-WRITE-9INSERT … SELECT … WHERE NOT EXISTS, since ON DUPLICATE KEY counts a found row as affectedINSERT … ON CONFLICT (key) DO NOTHING
Types only some support#[view(databases = "postgres, mysql")] limits a view to the listed databases, for field types not every enabled database can decode, such as a PostgreSQL array, or rust_decimal::Decimal on SQLite MPA-DB-2. A registry is built for one database; using it on another fails with Error::WrongBackend MPA-DB-3.

One trait, three implementations. mabat-sqlx runs everything through a Backend trait implemented for each database: how rows are fetched and decoded, how keys are read and bound, how statements and their arguments are executed, how column types are described for the checks, and how a snapshot begins. The derive generates a decoder and an encoder for each enabled database, so a view whose field type one database cannot handle fails to compile there, not at run time — unless it opts out of that database.

The same everywhere. The planner and the SQL renderer in mabat-core take a dialect, not a connection: the plan of a view, its query names, its aliases and the order of its queries do not depend on the database. The checks of overrides prepare and describe queries on whichever database the registry is built for, and the tests run on all three databases, including end-to-end suites against the Chinook sample database on each and Pagila on PostgreSQL.