Bug #121623 InnoDB: INPLACE ALTER crashes after row conversion error with fixed B-tree pages
Submitted: 28 Oct 9:00
Reporter: Xingyu Yang (OCA) Email Updates:
Status: Open Impact on me:
None 
Category:MySQL Server: DDL Severity:S3 (Non-critical)
Version:8.4.13 OS:Any
Assigned to: CPU Architecture:Any

[28 Oct 9:00] Xingyu Yang
Description:
On a MySQL 8.4.13 Debug build, an INPLACE table rebuild can abort when a row
conversion error occurs after direct B-tree loading has begun. The scan returns
the row error without asking the active DDL builders to finish their B-tree
loads. A page remains buffer-fixed, and `Page_load::~Page_load()` asserts while
the ALTER is being cleaned up.

Expected: the ALTER reports `ER_INVALID_USE_OF_NULL` (1138), and mysqld stays
available. Actual: the client receives `ERROR 2013 (HY000): Lost connection to
MySQL server during query`; mysqld aborts with
`btr0load.cc:89:m_n_blocks_buf_fixed == 0`.

Tested on Linux x86_64, source tag `mysql-8.4.13`
(`8a180268d832300c09a375115dfa0ea77d83f1af`), built with
`CMAKE_BUILD_TYPE=Debug`. The server reports `8.4.13-debug`.

The crash stack includes:

```text
Page_load::~Page_load()    storage/innobase/btr/btr0load.cc:89
Btree_load::~Btree_load()  storage/innobase/btr/btr0load.cc:1005
ddl::Builder::~Builder()  storage/innobase/ddl/ddl0builder.cc:619
ddl::Loader::~Loader()    storage/innobase/ddl/ddl0loader.cc:279
ddl::Context::build()     storage/innobase/ddl/ddl0ctx.cc:517

How to repeat:
Run these statements on an `8.4.13-debug` server:

```sql
CREATE TABLE t_scan_error (id INT PRIMARY KEY, c INT NULL);
INSERT INTO t_scan_error VALUES (1,1),(2,2),(3,3),(4,NULL);
SET DEBUG='+d,ddl_buf_add_two';
ALTER TABLE t_scan_error MODIFY c INT NOT NULL, ALGORITHM=INPLACE;
```

`ddl_buf_add_two` makes this small test enter direct B-tree loading before the
last row triggers `DB_INVALID_NULL`. In our run the server aborted during the
ALTER. The attached patch includes `innodb.ddl_scan_error_cleanup`, an MTR
regression test that checks the expected SQL error, zero fixed index pages,
and clean shutdown.

Suggested fix:
In `Loader::scan_and_build_indexes()`, when the scan or its finalization fails,
call `Context::set_error(err)` and then `Builder::handle_error(err)` for every
active builder before destroying the loader. `Builder::handle_error()` latches
and finishes any direct B-tree load, releasing its buffer fixes. Keep the
existing `load()` path for a successful scan.
[28 Oct 9:01] Xingyu Yang
8.4.13 patch

(*) I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.

Contribution: 0001-InnoDB-Release-B-tree-page-fixes-after-DDL-scan-erro.patch (application/octet-stream, text), 3.33 KiB.