MySQL version / commit
MySQL Community Server trunk
Steps to reproduce
Prerequisites:
- innodb_page_size=16384
- innodb_file_per_table=ON
- InnoDB ROW_FORMAT=COMPRESSED is supported
When innodb_strict_mode is OFF, create a compressed table using the invalid
table-level KEY_BLOCK_SIZE=32:
SELECT VERSION(),
@@GLOBAL.innodb_page_size,
@@GLOBAL.innodb_file_per_table;
DROP TABLE IF EXISTS k;
SET SESSION innodb_strict_mode=OFF;
CREATE TABLE k (
id INT PRIMARY KEY,
c1 INT,
KEY idx_c1 (c1)
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=32;
SHOW WARNINGS;
SHOW CREATE TABLE k;
SELECT NAME, ROW_FORMAT, ZIP_PAGE_SIZE
FROM information_schema.INNODB_TABLES
WHERE NAME=CONCAT(DATABASE(), '/k');
-- The stale per-index values survive a table rebuild.
ALTER TABLE k FORCE;
SHOW CREATE TABLE k;
-- Rebuilding the primary key also retains the stale value.
ALTER TABLE k DROP PRIMARY KEY, ADD PRIMARY KEY (id);
SHOW CREATE TABLE k;
-- Rebuilding the secondary index clears its stale value.
ALTER TABLE k DROP INDEX idx_c1;
ALTER TABLE k ADD INDEX idx_c1 (c1);
SHOW CREATE TABLE k;
DROP TABLE k;
### Expected vs actual result
Expected result
===============
After InnoDB rejects the invalid table-level KEY_BLOCK_SIZE=32 and selects the
final compressed page size, inherited per-index metadata should not retain the
invalid value.
For this case, the inherited index block_size values should either be
normalized to 8 or omitted as inherited metadata. PRIMARY and secondary index
rebuilds should produce consistent metadata.
Actual result
=============
CREATE TABLE emits the expected warning:
Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=32.
InnoDB correctly selects an 8KB compressed page size:
ROW_FORMAT ZIP_PAGE_SIZE
Compressed 8192
The table-level DD value is also corrected to KEY_BLOCK_SIZE=8. However,
SHOW CREATE TABLE reports stale index-level values:
CREATE TABLE `k` (
`id` int NOT NULL,
`c1` int DEFAULT NULL,
PRIMARY KEY (`id`) KEY_BLOCK_SIZE=32,
KEY `idx_c1` (`c1`) KEY_BLOCK_SIZE=32
) ENGINE=InnoDB ... ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8
The index-level KEY_BLOCK_SIZE=32 clauses survive ALTER TABLE FORCE and
DROP/ADD PRIMARY KEY.
Dropping and re-adding idx_c1 clears the value for that secondary index, while
PRIMARY still retains KEY_BLOCK_SIZE=32. Primary and secondary index rebuilds
therefore behave inconsistently.
A debug build confirms that mysql.indexes.options contains:
name options
idx_c1 block_size=32;flags=0;
PRIMARY block_size=32;flags=0;
The physical compressed page size is correct, and no data corruption has been
observed. This appears to be a data-dictionary metadata consistency issue.
Suspected cause
===============
The server copies a table-level KEY_BLOCK_SIZE into KEY::block_size for each
index, and persists nonzero values as the index DD "block_size" option.
In InnoDB dd_set_table_options(), the final table-level key_block_size is
derived from the finalized InnoDB flags, but the compressed-table path does
not normalize the already-created per-index block_size options. Consequently,
the ignored user value remains in the index DD metadata.
### Platform / compiler
Linux x86_64 GCC/G++ 12.3.0 CMake 3.26.5 Debug build
MySQL version / commit
MySQL Community Server trunk
Steps to reproduce
Prerequisites:
When innodb_strict_mode is OFF, create a compressed table using the invalid
table-level KEY_BLOCK_SIZE=32: