From 30903c37432e518e09b87610f6edd0a1d039669c Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 22 Jun 2020 15:43:53 +0400 Subject: [PATCH] MDEV-22976 CAST(JSON_EXTRACT() AS DECIMAL) does not handle boolean values Item_func_json_extract did not implement val_decimal(), so CAST(JSON_EXTRACT('{"x":true}', '$.x') AS DECIMAL) erroneously returned 0 with a warning because of convertion from the string "true" to decimal. Implementing val_decimal(), so boolean values are correctly handled. --- mysql-test/r/func_json.result | 13 +++++++++++++ mysql-test/t/func_json.test | 13 +++++++++++++ sql/item_jsonfunc.cc | 35 +++++++++++++++++++++++++++++++++++ sql/item_jsonfunc.h | 1 + 4 files changed, 62 insertions(+) diff --git a/mysql-test/r/func_json.result b/mysql-test/r/func_json.result index 94adf310fec..caf46eb5145 100644 --- a/mysql-test/r/func_json.result +++ b/mysql-test/r/func_json.result @@ -916,5 +916,18 @@ NULL Warnings: Warning 4037 Unexpected end of JSON text in argument 2 to function 'json_merge_patch' # +# MDEV-22976 CAST(JSON_EXTRACT() AS DECIMAL) does not handle boolean values +# +SELECT +CAST(JSON_EXTRACT('{"x":true}', '$.x') AS DOUBLE) AS cf, +CAST(JSON_EXTRACT('{"x":true}', '$.x') AS DECIMAL) AS cd; +cf cd +1 1 +SELECT +CAST(JSON_EXTRACT('{"x":false}', '$.x') AS DOUBLE) AS cf, +CAST(JSON_EXTRACT('{"x":false}', '$.x') AS DECIMAL) AS cd; +cf cd +0 0 +# # End of 10.2 tests # diff --git a/mysql-test/t/func_json.test b/mysql-test/t/func_json.test index 2eaaf218e5e..c9adbd945b1 100644 --- a/mysql-test/t/func_json.test +++ b/mysql-test/t/func_json.test @@ -540,6 +540,19 @@ SELECT JSON_MERGE_PATCH('{}'); SELECT JSON_MERGE_PATCH('{', '[1,2,3]'); SELECT JSON_MERGE_PATCH('{"a":"b"}', '[1,'); +--echo # +--echo # MDEV-22976 CAST(JSON_EXTRACT() AS DECIMAL) does not handle boolean values +--echo # + +SELECT + CAST(JSON_EXTRACT('{"x":true}', '$.x') AS DOUBLE) AS cf, + CAST(JSON_EXTRACT('{"x":true}', '$.x') AS DECIMAL) AS cd; + +SELECT + CAST(JSON_EXTRACT('{"x":false}', '$.x') AS DOUBLE) AS cf, + CAST(JSON_EXTRACT('{"x":false}', '$.x') AS DECIMAL) AS cd; + + --echo # --echo # End of 10.2 tests --echo # diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 4db4c563d97..b3c8366907a 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -962,6 +962,41 @@ double Item_func_json_extract::val_real() } +my_decimal *Item_func_json_extract::val_decimal(my_decimal *to) +{ + json_value_types type; + char *value; + int value_len; + + if (read_json(NULL, &type, &value, &value_len) != NULL) + { + switch (type) + { + case JSON_VALUE_STRING: + case JSON_VALUE_NUMBER: + { + my_decimal *res= decimal_from_string_with_check(to, collation.collation, + value, + value + value_len); + null_value= res == NULL; + return res; + } + case JSON_VALUE_TRUE: + int2my_decimal(E_DEC_FATAL_ERROR, 1, false/*unsigned_flag*/, to); + return to; + case JSON_VALUE_OBJECT: + case JSON_VALUE_ARRAY: + case JSON_VALUE_FALSE: + case JSON_VALUE_NULL: + break; + }; + } + int2my_decimal(E_DEC_FATAL_ERROR, 0, false/*unsigned_flag*/, to); + return to; +} + + + bool Item_func_json_contains::fix_length_and_dec() { a2_constant= args[1]->const_item(); diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index d7f804a1b60..0277cb15154 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -171,6 +171,7 @@ public: String *val_str(String *); longlong val_int(); double val_real(); + my_decimal *val_decimal(my_decimal *); uint get_n_paths() const { return arg_count - 1; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); }