Details
-
Bug
-
Status: Confirmed (View Workflow)
-
Major
-
Resolution: Unresolved
-
10.11, 11.4, 11.8, 12.3, 12.3.2
-
ubuntu22.04
Description
Summary
SEQUENCE::read_stored_values() (sql/sql_sequence.cc) wraps its ha_read_first_row() call in an Internal_error_handler whose condition is unconditionally true, so it silences every condition raised during the read, not only tablespace errors.
// class Silence_table_space_errors : public Internal_error_handler
|
if (sql_errno == ER_TABLESPACE_DISCARDED || HA_ERR_TABLESPACE_MISSING) |
return true; // Silence it |
HA_ERR_TABLESPACE_MISSING is handler error code 194 (include/my_base.h). As a boolean operand, expr || 194 is always true. The intended code was almost certainly sql_errno == ER_TABLESPACE_DISCARDED || sql_errno == ER_TABLESPACE_MISSING — the second sql_errno == is missing and the constant is the wrong family (handler code 194 instead of an ER_ SQL error).
User-visible consequence: after ALTER TABLE … DISCARD TABLESPACE + FLUSH TABLES, reading a SEQUENCE drops the 1814 (ER_TABLESPACE_DISCARDED) diagnostic that a regular InnoDB table reports; only the generic 1030 survives. More importantly, any error raised during the sequence's first-row read is swallowed at condition level.
Root cause (verified in MariaDB 12.3.1 source)
File: build/mariadb-12.3.1-src/sql/sql_sequence.cc
| Location | Lines | Role |
|---|---|---|
| Silence_table_space_errors::handle_condition() | 708–724 | Returns true for all conditions (always-true || HA_ERR_TABLESPACE_MISSING) |
| SEQUENCE::read_stored_values() | 734–761 | push_internal_handler → ha_read_first_row() → on error pop_internal_handler() then print_error(error) |
class Silence_table_space_errors : public Internal_error_handler |
{
|
bool handle_condition(...) override |
{
|
if (sql_errno == ER_TABLESPACE_DISCARDED || HA_ERR_TABLESPACE_MISSING) |
return true; // Silence it |
return false; |
}
|
};
|
|
|
int SEQUENCE::read_stored_values(TABLE *table) |
{
|
thd->push_internal_handler(&error_handler);
|
error= table->file->ha_read_first_row(table->record[0], MAX_KEY);
|
if (unlikely(error)) |
{
|
thd->pop_internal_handler();
|
if (error == HA_ERR_TABLESPACE_MISSING && thd->tablespace_op) |
DBUG_RETURN(0); // Ignore error for ALTER TABLESPACE |
table->file->print_error(error, MYF(0));
|
...
|
}
|
}
|
Mechanism: ER_TABLESPACE_DISCARDED (1814) raised during ha_read_first_row() is silenced by the handler. Generic 1030 ("Got error 194 … from storage engine InnoDB") is emitted after pop_internal_handler() via print_error() — hence it is often the only warning that survives.
Constants (12.3.1 tree):
- HA_ERR_TABLESPACE_MISSING = 194 — include/my_base.h
- ER_TABLESPACE_DISCARDED = 1814 — libmariadb/include/mysqld_error.h
- ER_TABLESPACE_MISSING = 1812 — same header; mapped from 194 in sql/handler.cc
Reproducer
DROP DATABASE IF EXISTS seed_cmp; CREATE DATABASE seed_cmp; USE seed_cmp; |
|
|
-- A: regular InnoDB table (reference)
|
CREATE TABLE t_norm (id INT PRIMARY KEY) ENGINE=InnoDB; |
INSERT INTO t_norm VALUES (1); |
ALTER TABLE t_norm DISCARD TABLESPACE; |
FLUSH TABLES;
|
SELECT * FROM t_norm; SHOW WARNINGS; |
|
|
-- B: InnoDB SEQUENCE (aligned steps)
|
CREATE SEQUENCE s1 START WITH 1 INCREMENT BY 1; |
ALTER TABLE s1 DISCARD TABLESPACE; |
FLUSH TABLES;
|
SELECT NEXTVAL(s1); SHOW WARNINGS; |
SELECT * FROM s1; SHOW WARNINGS; |
Actual result (MariaDB 12.3.1-MariaDB-asan-log, verified)
A) SELECT * FROM t_norm -> client ERROR 1814; SHOW WARNINGS = {1814, 1030}
|
B) SELECT NEXTVAL(s1) -> client ERROR 1030; SHOW WARNINGS = {1030} (1814 missing)
|
SELECT * FROM s1 -> client ERROR 1030; SHOW WARNINGS = {1030} (1814 missing)
|
Example SHOW WARNINGS text (path A):
| Level | Code | Message |
|---|---|---|
| Error | 1814 | Tablespace has been discarded for table `t_norm` |
| Error | 1030 | Got error 194 "Tablespace is missing for a table" from storage engine InnoDB |
Path B (NEXTVAL / SELECT * FROM s1): 1030 only.
The SEQUENCE path loses 1814 for both NEXTVAL and plain SELECT, because read_stored_values() runs on table open — not NEXTVAL-specific.
Expected result
The SEQUENCE read should surface the same SQL-layer tablespace diagnostic class as a regular table (e.g. 1814), and — independent of diagnostics — the handler must not silence unrelated conditions.
Why this is not "intentional IMPORT TABLESPACE silencing"
read_stored_values() already handles the legitimate import/discard case explicitly after popping the handler:
if (error == HA_ERR_TABLESPACE_MISSING && thd->tablespace_op) |
DBUG_RETURN(0); // Ignore error for ALTER TABLESPACE |
So the intended suppression is keyed on thd->tablespace_op, not on a blanket "silence everything." The always-true handler is over-broad relative to that design and can mask genuine read errors.
Suggested fix
Restore the missing comparison and use SQL-layer error codes:
if (sql_errno == ER_TABLESPACE_DISCARDED || |
sql_errno == ER_TABLESPACE_MISSING)
|
return true; |
return false; |
(Confirm the exact ER_ set the handler should silence; the key defect is the always-true || HA_ERR_TABLESPACE_MISSING — handler code 194, not sql_errno.)
Environment
- Runtime reproduced on: MariaDB 12.3.1-MariaDB-asan-log + InnoDB (SELECT VERSION();)
- Source inspected: sql/sql_sequence.cc lines 708–724, 734–761 on 12.3.1 tree (build/mariadb-12.3.1-src)
- Client: mariadb --force --table