Skip to content

Commit 75d30f7

Browse files
committed
Bug#22278524: ALTER TABLE SOMETIMES CONVERTS TEXT TO JSON WITHOUT
SYNTAX CHECKING If ALTER TABLE changes the type of a JSON column to TEXT with character set utf8mb4 and collation utf8mb4_bin (the same character set and collation as the JSON type has), it does not convert the existing column values from JSON binary format to JSON text format. Instead, the resulting column values will contain the raw binary representation of the original JSON values. If the type is changed in the opposite direction, the same thing happens, with the result that the JSON column contains text data instead of binary data. Subsequent attempts to access the column values will raise an error because the JSON binary parser doesn't understand JSON text format. This patch makes Copy_field::get_copy_func() pick do_conv_blob() instead of do_copy_blob() when copying between JSON and non-JSON types. This ensures that the values are properly converted between the different formats, and not just copied byte by byte.
1 parent 3d70e80 commit 75d30f7

File tree

3 files changed

+57
-1
lines changed

3 files changed

+57
-1
lines changed

mysql-test/r/json.result

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13410,3 +13410,31 @@ Warning 1235 This version of MySQL doesn't yet support 'comparison of JSON in th
1341013410
Warning 1235 This version of MySQL doesn't yet support 'comparison of JSON in the LEAST and GREATEST operators'
1341113411
Warning 1235 This version of MySQL doesn't yet support 'comparison of JSON in the LEAST and GREATEST operators'
1341213412
Warning 1235 This version of MySQL doesn't yet support 'comparison of JSON in the LEAST and GREATEST operators'
13413+
#
13414+
# Bug#22278524: ALTER TABLE SOMETIMES CONVERTS TEXT TO JSON WITHOUT
13415+
# SYNTAX CHECKING
13416+
#
13417+
CREATE TABLE t1(txt TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin);
13418+
INSERT INTO t1 VALUES ('not JSON');
13419+
ALTER TABLE t1 MODIFY COLUMN txt JSON;
13420+
ERROR 22032: Invalid JSON text: "Invalid value." at position 1 in value (or column) 'not JSON'.
13421+
SELECT * FROM t1;
13422+
txt
13423+
not JSON
13424+
CREATE TABLE t2(j JSON);
13425+
INSERT INTO t2 VALUES (JSON_OBJECT('a', 'b'));
13426+
ALTER TABLE t2 MODIFY COLUMN j TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
13427+
SELECT * FROM t2;
13428+
j
13429+
{"a": "b"}
13430+
CREATE TABLE t3 (j JSON);
13431+
INSERT INTO t3 VALUES (JSON_OBJECT('a', 'b'));
13432+
CREATE TABLE t4 AS SELECT UPPER(j) AS jj FROM t3;
13433+
INSERT INTO t4 VALUES ('not JSON');
13434+
ALTER TABLE t4 MODIFY COLUMN jj JSON;
13435+
ERROR 22032: Invalid JSON text: "Invalid value." at position 1 in value (or column) 'not JSON'.
13436+
SELECT * FROM t4;
13437+
jj
13438+
{"A": "B"}
13439+
not JSON
13440+
DROP TABLE t1, t2, t3, t4;

mysql-test/t/json.test

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6144,6 +6144,28 @@ SELECT JSON_ARRAY(LEAST(NULL, NULL), GREATEST(NULL, NULL), LEAST(j1, NULL),
61446144
GREATEST(NULL, j2), LEAST(j1, j2), GREATEST(j1, j2)) AS j
61456145
FROM (SELECT CAST('1' AS JSON) AS j1, CAST('2' AS JSON) AS j2) t;
61466146

6147+
--echo #
6148+
--echo # Bug#22278524: ALTER TABLE SOMETIMES CONVERTS TEXT TO JSON WITHOUT
6149+
--echo # SYNTAX CHECKING
6150+
--echo #
6151+
CREATE TABLE t1(txt TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin);
6152+
INSERT INTO t1 VALUES ('not JSON');
6153+
--error ER_INVALID_JSON_TEXT
6154+
ALTER TABLE t1 MODIFY COLUMN txt JSON;
6155+
SELECT * FROM t1;
6156+
CREATE TABLE t2(j JSON);
6157+
INSERT INTO t2 VALUES (JSON_OBJECT('a', 'b'));
6158+
ALTER TABLE t2 MODIFY COLUMN j TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
6159+
SELECT * FROM t2;
6160+
CREATE TABLE t3 (j JSON);
6161+
INSERT INTO t3 VALUES (JSON_OBJECT('a', 'b'));
6162+
CREATE TABLE t4 AS SELECT UPPER(j) AS jj FROM t3;
6163+
INSERT INTO t4 VALUES ('not JSON');
6164+
--error ER_INVALID_JSON_TEXT
6165+
ALTER TABLE t4 MODIFY COLUMN jj JSON;
6166+
SELECT * FROM t4;
6167+
DROP TABLE t1, t2, t3, t4;
6168+
61476169

61486170
# Local Variables:
61496171
# mode: sql

sql/field_conv.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -749,7 +749,13 @@ Copy_field::get_copy_func(Field *to,Field *from)
749749
}
750750
else if (to->flags & BLOB_FLAG)
751751
{
752-
if (!(from->flags & BLOB_FLAG) || from->charset() != to->charset())
752+
/*
753+
We need to do conversion if we are copying from BLOB to
754+
non-BLOB, or if we are copying between BLOBs with different
755+
character sets, or if we are copying between JSON and non-JSON.
756+
*/
757+
if (!(from->flags & BLOB_FLAG) || from->charset() != to->charset() ||
758+
((to->type() == MYSQL_TYPE_JSON) != (from->type() == MYSQL_TYPE_JSON)))
753759
return do_conv_blob;
754760
if (m_from_length != m_to_length || !compatible_db_low_byte_first)
755761
{

0 commit comments

Comments
 (0)