diff --git a/mysql-test/suite/json/r/json_innodb.result b/mysql-test/suite/json/r/json_innodb.result index d00a93e304b..053544e0263 100644 --- a/mysql-test/suite/json/r/json_innodb.result +++ b/mysql-test/suite/json/r/json_innodb.result @@ -258,3 +258,21 @@ SUM(col_int) col_int 4572643328 NULL DROP VIEW view1; DROP TABLE D; +# +# BUG#100307: JSON field datatype changes unexpectedly +# +CREATE TABLE json ( +id int NOT NULL, +j json DEFAULT NULL, +s tinyint NOT NULL, +PRIMARY KEY (id) +) ENGINE=InnoDB; +INSERT INTO json VALUES (2, '{"amount": 70.0}', 1); +SELECT json_type(j->"$.amount") FROM json; +json_type(j->"$.amount") +DOUBLE +INSERT INTO json VALUES (2, '{}', 1) ON DUPLICATE KEY UPDATE j=if(s=0, '{}', j); +SELECT json_type(j->"$.amount") FROM json; +json_type(j->"$.amount") +DOUBLE +DROP TABLE json; diff --git a/mysql-test/suite/json/t/json_innodb.test b/mysql-test/suite/json/t/json_innodb.test index f8388daab0c..0ec72c3dc03 100644 --- a/mysql-test/suite/json/t/json_innodb.test +++ b/mysql-test/suite/json/t/json_innodb.test @@ -249,3 +249,18 @@ DROP TABLE D; --source include/restore_sql_mode_after_turn_off_only_full_group_by.inc +--echo # +--echo # BUG#100307: JSON field datatype changes unexpectedly +--echo # + +CREATE TABLE json ( +id int NOT NULL, +j json DEFAULT NULL, +s tinyint NOT NULL, +PRIMARY KEY (id) +) ENGINE=InnoDB; +INSERT INTO json VALUES (2, '{"amount": 70.0}', 1); +SELECT json_type(j->"$.amount") FROM json; +INSERT INTO json VALUES (2, '{}', 1) ON DUPLICATE KEY UPDATE j=if(s=0, '{}', j); +SELECT json_type(j->"$.amount") FROM json; +DROP TABLE json; diff --git a/sql/field.cc b/sql/field.cc index 62663bb2c2a..57ac9063d76 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -9125,6 +9125,27 @@ bool Field_json::get_time(MYSQL_TIME *ltime) return result; } +int Field_json::cmp_binary(const uchar *a_ptr, const uchar *b_ptr, + uint32 /* max_length */) +{ + char *a; + char *b; + memcpy(&a, a_ptr + packlength, sizeof(a)); + memcpy(&b, b_ptr + packlength, sizeof(b)); + uint32 a_length= get_length(a_ptr); + uint32 b_length= get_length(b_ptr); + using namespace json_binary; + /* + The length is 0 if NULL has been inserted into a NOT NULL column + using INSERT IGNORE or similar. If so, interpret the value as the + JSON null literal. + */ + Value null_literal(Value::LITERAL_NULL); + Json_wrapper aw(a_length == 0 ? null_literal : parse_binary(a, a_length)); + Json_wrapper bw(b_length == 0 ? null_literal : parse_binary(b, b_length)); + return aw.compare(bw); +} + void Field_json::make_sort_key(uchar *to, size_t length) { diff --git a/sql/field.h b/sql/field.h index 0b8f06b82aa..92e624be638 100644 --- a/sql/field.h +++ b/sql/field.h @@ -4139,6 +4139,7 @@ public: Field_json *clone() const; uint is_equal(Create_field *new_field); Item_result cast_to_int_type () const { return INT_RESULT; } + int cmp_binary(const uchar *a, const uchar *b, uint32 max_length= ~0L); void make_sort_key(uchar *to, size_t length); /**