Details
-
Bug
-
Status: Confirmed (View Workflow)
-
Minor
-
Resolution: Unresolved
-
10.11, 11.4, 11.8, 12.3, 13.1
Description
CONV(N, from_base, to_base) returns NULL when a base is outside the allowed range: 2..62 in absolute value since MDEV-30879. For example, CONV('11', 63, 10) is NULL. But Item_func_conv::val_str() reads both bases with
int from_base= (int) args[1]->val_int(); |
int to_base= (int) args[2]->val_int(); |
(sql/item_strfunc.cc, main 82964737), and the range check is then applied to the low 32 bits only. So:
- 4294967298 (2^32 + 2) and -4294967294 are accepted as base 2;
- 4294967286 (2^32 - 10) becomes -10, a negative base, which switches CONV to signed output: CONV('-1', 10, 4294967286) = '-1', as for to_base -10, while to_base 10 gives 18446744073709551615;
- a BIGINT column holding 4294967312 (2^32 + 16) is used as base 16.
No warning is given. A base that does not fit in BIGINT (18446744073709551618) does give NULL with warning 1916, so only the values from 2^31 up to the BIGINT range are silently narrowed.
This is not the MDEV-40989 question (bases 37..62 are documented as legal). These bases are billions, and are accepted only because of the cast.
It is also not the code of MDEV-40971 / MDEV-40987 (JSON path indexes, PERIOD_ADD, SUBSTRING_INDEX, ELT): the narrowing here is the (int) cast of the two bases in Item_func_conv::val_str() (sql/item_strfunc.cc), and a fix for those issues does not change this one.
How to repeat
SELECT CONV('11', 2, 10) AS b2, CONV('11', 4294967298, 10) AS b2p32_2, |
CONV('11', -4294967294, 10) AS bm2p32_2, CONV('11', 63, 10) AS b63; |
-- 3, 3, 3, NULL
|
|
|
SELECT CONV('3', 10, 2) AS t2, CONV('3', 10, 4294967298) AS t2p32_2, CONV('3', 10, 63) AS t63; |
-- 11, 11, NULL
|
|
|
SELECT CONV('-1', 10, 10) AS unsigned_out, CONV('-1', 10, -10) AS signed_out, |
CONV('-1', 10, 4294967286) AS t2p32_m10; |
-- 18446744073709551615, -1, -1
|
|
|
CREATE TABLE t015 (b BIGINT); |
INSERT INTO t015 VALUES (16), (4294967312); |
SELECT b, CONV('ff', b, 10) AS v FROM t015 ORDER BY b; |
-- 16 255
|
-- 4294967312 255 |
+------+---------+----------+------+
|
| b2 | b2p32_2 | bm2p32_2 | b63 |
|
+------+---------+----------+------+
|
| 3 | 3 | 3 | NULL |
|
+------+---------+----------+------+
|
Expected
NULL for every base whose absolute value is outside 2..62, as for 63. MySQL 26.10 has the same defect (with limit 36). TiDB returns NULL for all of the out-of-range bases above.
Suggested fix
Keep the bases as longlong until the range check passes (and take unsigned_flag into account, so that an unsigned value above LONGLONG_MAX does not wrap into the negative range):
longlong from_base= args[1]->val_int();
|
longlong to_base= args[2]->val_int();
|
if (... || from_base < -62 || from_base > 62 || (from_base > -2 && from_base < 2) || |
to_base < -62 || to_base > 62 || (to_base > -2 && to_base < 2) || ...)
|
Attachments
Issue Links
- relates to
-
MDEV-30879 Add conversion to based 62 for CONV function
-
- Closed
-