Skip to main content

Module mysql

Module mysql 

Source
Expand description

MySQL backend built on SQLx (MySQL 8.0.31+, tested on 9.x).

§Storage

ValueColumn typeNotes
BoolTINYINT(1)read back as Bool (a bare TINYINT reads as Int)
IntBIGINT / INT / …unsigned columns above i64::MAX fail to decode
FloatDOUBLE
DecimalDECIMAL(p, s)
TextVARCHAR(n) / TEXTcomparisons follow the column collation
BytesBLOB / VARBINARY
UuidCHAR(36)bound as hyphenated text, not as 16 raw bytes
Date / TimeDATE / TIME(6)
TimestampDATETIME(6)UTC; connections are pinned to +00:00
JsonJSON

§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 generated AUTO_INCREMENT key is recovered from the OK packet’s LAST_INSERT_ID() plus the consecutive values InnoDB hands out to one multi-row INSERT (innodb_autoinc_lock_mode 0, 1 and 2 all allocate the whole block of a plain INSERT .. VALUES at 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 read FOR UPDATE (an UPDATE by primary-key equality skips that read), the statement runs, and the rows are read back (after an UPDATE) 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§

MySqlBackend
MySQL adapter executing compiled plans on a connection pool.