Details
-
Bug
-
Status: Confirmed (View Workflow)
-
Minor
-
Resolution: Unresolved
-
10.11, 11.4, 11.8, 12.3, 13.1, 10.6.28
Description
A numeric dynamic-column number must be in 0..65535; 65536 and -1 are rejected
with ERROR 1921 "Illegal value used as argument of dynamic column function". A
number of 2^32 or more is not rejected: it is first truncated to 32 bits, and the
function then writes, adds or deletes a different, existing column:
SELECT COLUMN_JSON(COLUMN_CREATE(65535, 'a')); -- {"65535":"a"} |
SELECT COLUMN_JSON(COLUMN_CREATE(65536, 'a')); -- ERROR 1921 |
SELECT COLUMN_JSON(COLUMN_CREATE(-1, 'a')); -- ERROR 1921 |
SELECT COLUMN_JSON(COLUMN_CREATE(4294967296, 'a')); -- {"0":"a"} |
SELECT COLUMN_JSON(COLUMN_CREATE(4294967297, 'a')); -- {"1":"a"} |
|
|
SELECT COLUMN_JSON(COLUMN_ADD(COLUMN_CREATE(1, 'a'), 4294967298, 'b')); |
-- {"1":"a","2":"b"} |
SELECT COLUMN_JSON(COLUMN_ADD(COLUMN_CREATE(1, 'a', 2, 'x'), 4294967298, 'b')); |
-- {"1":"a","2":"b"} (column 2 overwritten) |
SELECT COLUMN_JSON(COLUMN_DELETE(COLUMN_CREATE(1, 'a', 2, 'b'), 4294967297)); |
-- {"2":"b"} (column 1 deleted) |
COLUMN_DELETE with 2^32+1 deletes column 1, and COLUMN_ADD with 2^32+2
overwrites column 2 if it exists, so an out-of-range number silently changes
data. (COLUMN_GET and COLUMN_EXISTS with 4294967297 return NULL – they take a
different path and are not affected.)
Where (main, 82964737): sql/item_strfunc.cc,
Item_func_dyncol_create::prepare_arguments(), line 4915:
keys_num[i]= (uint) args[i * 2]->val_int();
|
The 65535 check in the dynamic-column library sees the truncated value.
COLUMN_ADD (Item_func_dyncol_add, a subclass) and COLUMN_DELETE (built by
create_func_dyncol_delete() in sql/item_create.cc as an Item_func_dyncol_add with
NULL values) go through the same prepare_arguments().
Not the same code path as MDEV-40971 / MDEV-40987 (JSON path indexes, PERIOD_ADD,
SUBSTRING_INDEX, ELT): this is the column-number argument of the dynamic-column functions, in Item_func_dyncol_create::prepare_arguments() (sql/item_strfunc.cc);
a fix there does not change this one.
================================================================================
STEPS TO REPRODUCE
================================================================================
SELECT COLUMN_JSON(COLUMN_CREATE(65536, 'a')); -- 1 |
SELECT COLUMN_JSON(COLUMN_CREATE(4294967297, 'a')); -- 2 |
SELECT COLUMN_JSON(COLUMN_DELETE(COLUMN_CREATE(1, 'a', 2, 'b'), 4294967297)); -- 3 |
SELECT COLUMN_JSON(COLUMN_ADD(COLUMN_CREATE(1, 'a'), 4294967298, 'b')); -- 4 |
================================================================================
EXPECTED
================================================================================
1. ERROR 1921 Illegal value used as argument of dynamic column function
|
2. ERROR 1921
|
3. ERROR 1921
|
4. ERROR 1921
|
================================================================================
ACTUAL (13.2.0 main 82964737; identical on 13.0.2, 11.8.9, 10.11.19, 10.6.28)
================================================================================
1. ERROR 1921 Illegal value used as argument of dynamic column function
|
2. {"1":"a"}
|
3. {"2":"b"}
|
4. {"1":"a","2":"b"}
|
================================================================================
SUGGESTED FIX
================================================================================
Check the longlong value (and unsigned_flag) against 0..65535 – or at least
against 0..UINT_MAX32 – before the (uint) cast in prepare_arguments(), and raise
ER_DYN_COL_DATA (1921) as for 65536.
================================================================================
ATTACHMENTS
================================================================================
repro.py (pymysql; exits 1 while the recorded wrong answers are returned).
VERIFY-main-82964737-2026-10-14.txt: transcript on main and the four release images.