source/mysql 0.2.4 crashes (double-free / heap corruption) on every binlog row event with binlog_row_metadata=FULL
### Summary
The published **`source/mysql`** plugin (v0.2.4, the latest version compatible with `drasi-server` 0.2.0 / plugin-sdk 0.9.0) **crashes the entire server process with a native memory error on every binlog row event** when `binlog_row_metadata=FULL` is configured on the MySQL server. Because `FULL` metadata is *required* for the source to identify rows by key column name, and GTID is *required* by the source's `AUTO_POSITION` binlog streaming, there is no working configuration: the source either crashes (`FULL`) or cannot construct row identities (`MINIMAL`).
This makes the MySQL source unusable for live change capture.
### Environment
- `drasi-server` 0.2.0 (rustc 1.88.0, plugin-sdk 0.9.0)
- Plugins (auto-installed from `ghcr.io/drasi-project`): `source/mysql` **0.2.4**, `bootstrap/mysql` 0.2.7
- MySQL server: `mysql:8.0` (Docker), `binlog-format=ROW`, `binlog-row-image=FULL`, `gtid-mode=ON`, `enforce-gtid-consistency=ON`
- Reproduced on **both Windows (x86_64-pc-windows-msvc)** and **Linux (x86_64-unknown-linux-gnu)**.
- Source deps (from `components/sources/mysql/Cargo.toml`): `mysql_async = "0.34"`, `mysql_common = "0.32"`.
### Steps to reproduce
1. Start MySQL 8.0 with ROW binlog, GTID on, and `binlog-row-metadata=FULL`.
2. Create a table with a non-`id` primary key, e.g.:
```sql
CREATE TABLE vehicles (
plate VARCHAR(10) PRIMARY KEY,
location VARCHAR(20) NOT NULL DEFAULT 'Parking'
-- ...other columns
);
```
3. Configure a `source/mysql` with `tables: [vehicles]` and `tableKeys: [{ table: vehicles, keyColumns: [plate] }]`, plus `bootstrap/mysql`. Bootstrap succeeds and loads the seed rows.
4. Make **any** change to the table (INSERT *or* UPDATE), e.g. `UPDATE vehicles SET location='Curbside' WHERE plate='A1234';`.
### Actual behavior
The server process dies the instant the binlog row event is decoded:
- **Linux:** `double free or corruption (fasttop)` (glibc abort).
- **Windows:** exit code `0xC0000374` (`STATUS_HEAP_CORRUPTION`).
This happens for both INSERT and UPDATE events. The crash is in the native plugin while parsing the FULL binlog row metadata (`components/sources/mysql/src/decoder.rs` `row_to_element` path, which reads `column.name_str()` from the `mysql_common` binlog `TableMapEvent`/`BinlogRow`).
### Why `MINIMAL` metadata is not a workaround
With the MySQL 8.0 default `binlog_row_metadata=MINIMAL`, the binlog carries no column names, so `extract_column_names()` returns `col_0, col_1, ...`. The configured key column `plate` is never matched, and the decoder bails with:
```
Cannot construct a deterministic element ID for table 'vehicles':
no key columns configured and no 'id' column found. Configure key_columns for this table.
```
…then enters an endless reconnect loop (no changes are ever delivered). So `FULL` is required for correct operation, but `FULL` is what crashes.
### Why GTID cannot be disabled
Turning GTID off produces:
```
ERROR HY000 (1236): The replication sender thread cannot start in AUTO_POSITION mode:
this server has GTID_MODE = OFF instead of ON.
```
So `gtid-mode=ON` is mandatory; it cannot be used to avoid the FULL-metadata code path.
### Expected behavior
`source/mysql` should decode binlog row events with `binlog_row_metadata=FULL` without corrupting memory, and deliver INSERT/UPDATE/DELETE changes keyed by the configured `tableKeys`.
### Impact
The MySQL source cannot be used for any live-CDC scenario (e.g. porting the Curbside Pickup tutorial, which joins a PostgreSQL source to a MySQL source). The PostgreSQL source works correctly in the same setup.
### Notes / smaller papercuts found alongside
- `bootstrap/mysql` requires its **own** full connection config (`host`/`port`/`database`/`user`/`password`/`tables`/`tableKeys`); unlike `bootstrap/postgres`, it does not inherit the source's connection. With only `kind: mysql` it fails with `missing field 'database'`.
- Both `source/mysql` and `bootstrap/mysql` reject database-qualified table names (`PhysicalOperations.vehicles`) with `contains invalid characters. Only letters, numbers, and underscores are allowed`; the unqualified `vehicles` must be used (the source is already scoped by the `database` field).
0 条评论