Expand description
MySQL backend built on SQLx (MySQL 8.0.31+, tested on 9.x).
§Storage
Value | Column type | Notes |
|---|---|---|
Bool | TINYINT(1) | read back as Bool (a bare TINYINT reads as Int) |
Int | BIGINT / INT / … | unsigned columns above i64::MAX fail to decode |
Float | DOUBLE | |
Decimal | DECIMAL(p, s) | |
Text | VARCHAR(n) / TEXT | comparisons follow the column collation |
Bytes | BLOB / VARBINARY | |
Uuid | CHAR(36) | bound as hyphenated text, not as 16 raw bytes |
Date / Time | DATE / TIME(6) | |
Timestamp | DATETIME(6) | UTC; connections are pinned to +00:00 |
Json | JSON |
§No RETURNING
MySQL has no RETURNING, but the ORM’s save, create and
bulk_create need the stored rows back, so this adapter emulates it:
INSERT: a generatedAUTO_INCREMENTkey is recovered from the OK packet’sLAST_INSERT_ID()plus the consecutive values InnoDB hands out to one multi-rowINSERT(innodb_autoinc_lock_mode0, 1 and 2 all allocate the whole block of a plainINSERT .. VALUESat once; the step is@@auto_increment_increment). Supplied keys are used as they are. The rows are then re-read by key, in key order.UPDATE/DELETE: the affected keys are readFOR UPDATE(anUPDATEby primary-key equality skips that read), the statement runs, and the rows are read back (after anUPDATE) or were read beforehand (DELETE).
Each emulated write that reads rows back, single-row ones included, runs in a transaction (or the caller’s), so the rows read back are the ones written: no concurrent statement can change or delete them in between.
A single-row INSERT skips the read-back, and with it the
transaction, when the stored row is known without asking: the table has no
INSERT trigger (which takes the TRIGGER privilege, granted directly
and not through a role, to find out; without it the row is read back),
and every returned column is either the omitted
AUTO_INCREMENT column (taken from the OK packet) or a supplied value its
column stores unchanged. That holds for integers within the range of a
signed integer column, booleans in TINYINT(1), and text that fits a
VARCHAR / TEXT column (utf8mb4, or ASCII in any character set).
Everything else (defaults, generated columns, DECIMAL, temporal, JSON,
binary and CHAR columns) is read back as described above.
The columns of a table and whether it has an INSERT trigger are looked up
once per table in information_schema and cached;
execute_script clears the cache. A table or
trigger changed by other means (another process, execute_raw) while the
backend is in use is not noticed until then. A table without a primary key
cannot use the emulation.
§Session setup
MySqlBackend::connect configures every connection: time_zone is
+00:00 (so DATETIME, TIMESTAMP and date parts agree with the UTC
values the ORM writes), NO_BACKSLASH_ESCAPES is removed from sql_mode
(the compiler writes '\\' string literals) and group_concat_max_len is
raised (GROUP_CONCAT silently truncates at the default 1024 bytes).
Pools built elsewhere and passed to MySqlBackend::from_pool should do
the same.
Modules§
- native
- Opt-in native MySQL adapter (feature
mysql-native).
Structs§
- MySql
Backend - MySQL adapter executing compiled plans on a connection pool.