Skip to content

fix(mysql): decode derived enums from NOT NULL ENUM columns - #4435

Open
Juice-de-Orange wants to merge 1 commit into
transact-rs:mainfrom
Juice-de-Orange:fix/mysql-enum-not-null-flags
Open

Juice-de-Orange wants to merge 1 commit into
transact-rs:mainfrom
Juice-de-Orange:fix/mysql-enum-not-null-flags

Conversation

@Juice-de-Orange

Copy link
Copy Markdown

Does your PR solve an issue?

fixes #3750, fixes #1379

#[derive(sqlx::Type)] on an enum only generates type_info() for MySQL, so compatible() falls back to comparing the column's MySqlTypeInfo with MySqlTypeInfo::__enum(), and for string types PartialEq requires all column flags to be equal. A NOT NULL ENUM column reports NOT_NULL | ENUM | NO_DEFAULT_VALUE (NOT_NULL | ENUM with a default, plus MULTIPLE_KEY/PRIMARY_KEY when indexed and BINARY with a _bin collation) on both MySQL 8 and MariaDB 10.11, so try_get fails with "Rust type Foo (as SQL type ENUM) is not compatible with SQL type ENUM". The existing test only uses nullable, unindexed columns, which is the one case where the flags match.

The derive now also emits a compatible() for MySQL that checks the ENUM flag through a new #[doc(hidden)] MySqlTypeInfo::__is_enum(), like it already does for SQLite (which delegates to &str). type_info() and parameter binding are unchanged, and PartialEq for MySqlTypeInfo is left alone (unlike #4154, which relaxed the equality check itself and was closed by its author). Happy to delegate to <str as Type<MySql>>::compatible instead if you'd rather have the looser check.

Regression test: test_derive_strong_enum_not_null in tests/mysql/derives.rs decodes NOT NULL, NOT NULL DEFAULT and indexed ENUM columns. It fails on main with the error above and passes with this change, on MySQL 8.0 and MariaDB 10.11.

Is this a breaking change?

No. Decoding a derived enum from these columns was a runtime error before and works now; nullable ENUM columns and encoding behave exactly as before.

The `Type` derive only generates `type_info()` for MySQL, so the default
`compatible()` compares the column's type info with `__enum()`, which for
string types requires all column flags to be equal. A `NOT NULL` ENUM
column reports `NOT_NULL | ENUM | NO_DEFAULT_VALUE`, so `try_get` failed
with "Rust type `Foo` (as SQL type `ENUM`) is not compatible with SQL
type `ENUM`".

Emit a `compatible()` that only checks the `ENUM` flag, the same way the
derive already overrides `compatible()` for SQLite, and add a regression
test with `NOT NULL`, `NOT NULL DEFAULT` and indexed ENUM columns.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Deriving sqlx::Type on an enum fails to decode a MySql enum SQLX Mysql Enum decode error

1 participant