Bug #121613 CREATE TABLE with 100 varchar(200) latin1 columns is wrongly rejected with ERROR 1118 (Row size too large)
Submitted: 26 Oct 12:51
Reporter: Chunling Qin Email Updates:
Status: Open Impact on me:
None 
Category:MySQL Server: InnoDB storage engine Severity:S2 (Serious)
Version:26.10.0-trunk (commit 561753af986) OS:Linux (Linux x86_64, self-compiled trunk (test instance))
Assigned to: CPU Architecture:Any

[26 Oct 12:51] Chunling Qin
Description:
Creating a table with 100 varchar(200) columns in latin1 with ROW_FORMAT=DYNAMIC is rejected with

  ERROR 1118 (42000): Row size too large (> 8126). Changing some columns to TEXT or BLOB may help.
  In current row format, BLOB prefix of 0 bytes is stored inline.

This table is accepted by all MySQL versions before 8.0.46. The columns are variable-length, and
with ROW_FORMAT=DYNAMIC they can be stored fully off-page - the error message itself states that a
BLOB prefix of 0 bytes is stored inline. Rows holding short values therefore do fit in a page; only
rows where all 100 columns are at their maximum length cannot, and those should fail at INSERT time
with DB_TOO_BIG_RECORD rather than at CREATE time.

The regression comes from Bug#39129182, which made get_field_max_size() more accurate. That function
is also reused by the DDL page-fit check: for varchar(41-255) columns (1-byte length encoding, no
external-storage bit) the check now estimates the maximum declared length, so a wide but perfectly
usable table is refused.

Control experiment on the same instance: an identical table with 40 such columns (40 * 200 = 8000
bytes < 8126) is created successfully. This rules out an instance-level cause such as a special
innodb_strict_mode or page-size setting.

Affects: 26.10.0-trunk @ 561753af986 (verified 2026-10-26) and 26.7.0-debug @ 23e360a7fac.

How to repeat:
SET SESSION innodb_strict_mode = ON;
SET SESSION group_concat_max_len = 102400;

-- 100 columns x varchar(200) latin1
SET @cols = (SELECT GROUP_CONCAT(CONCAT('c', i, ' varchar(200)') ORDER BY i) FROM
  (WITH RECURSIVE n(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM n WHERE i < 100) SELECT i FROM n) x);
SET @sql = CONCAT('CREATE TABLE bigrow (', @cols,
                  ') ENGINE=InnoDB ROW_FORMAT=DYNAMIC DEFAULT CHARSET=latin1');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;

-- ACTUAL:
--   ERROR 1118 (42000): Row size too large (> 8126). Changing some columns to TEXT or BLOB
--   may help. In current row format, BLOB prefix of 0 bytes is stored inline.
-- EXPECTED: the CREATE succeeds (as in every version before 8.0.46); a row whose values are
--           actually too long is rejected later at INSERT time with DB_TOO_BIG_RECORD.

-- Control: 40 columns (40 * 200 = 8000 bytes) is accepted, so the instance configuration is fine
SET SESSION group_concat_max_len = 102400;
SET @cols2 = (SELECT GROUP_CONCAT(CONCAT('c', i, ' varchar(200)') ORDER BY i) FROM
  (WITH RECURSIVE n(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM n WHERE i < 40) SELECT i FROM n) x);
SET @sql2 = CONCAT('CREATE TABLE t40 (', @cols2,
                   ') ENGINE=InnoDB ROW_FORMAT=DYNAMIC DEFAULT CHARSET=latin1');
PREPARE s2 FROM @sql2; EXECUTE s2; DEALLOCATE PREPARE s2;   -- succeeds

Suggested fix:
Restore the previous behaviour, as done by Bug#39249507 / commit 99960bf74fa: let the CREATE
succeed, and raise DB_TOO_BIG_RECORD at INSERT time when the actual row does not fit. That is also
consistent with the record format, where a declared length <= 255 cannot flag external storage.