diff options
author | Alexey Botchkov <holyfoot@askmonty.org> | 2020-06-04 10:00:56 +0400 |
---|---|---|
committer | Alexey Botchkov <holyfoot@askmonty.org> | 2020-06-04 10:00:56 +0400 |
commit | bb47050e1fdc49aa56fb55c8c55ff81ba24d355b (patch) | |
tree | 4b0e592a38460d12b4baf61f4203abe366e9cc27 | |
parent | e7bab059b764bc58ee14e182b51f90c47a6c8e17 (diff) | |
download | mariadb-git-bb47050e1fdc49aa56fb55c8c55ff81ba24d355b.tar.gz |
MDEV-22640, MDEV-22449, MDEV-21528 JSON_ARRAYAGG crashes with NULL values.
We have to include NULL in the result which the GOUP_CONCAT doesn't
always do. Also converting should be done into another String instance
as these can be same.
-rw-r--r-- | mysql-test/main/func_json.result | 6 | ||||
-rw-r--r-- | mysql-test/main/func_json.test | 3 | ||||
-rw-r--r-- | sql/item_jsonfunc.cc | 8 | ||||
-rw-r--r-- | sql/item_jsonfunc.h | 15 | ||||
-rw-r--r-- | sql/item_sum.cc | 29 | ||||
-rw-r--r-- | sql/item_sum.h | 8 |
6 files changed, 41 insertions, 28 deletions
diff --git a/mysql-test/main/func_json.result b/mysql-test/main/func_json.result index cc87a935a85..ee312aac6cb 100644 --- a/mysql-test/main/func_json.result +++ b/mysql-test/main/func_json.result @@ -1229,6 +1229,12 @@ select json_arrayagg(a) over () from (select 1 a) t; ERROR 42000: This version of MariaDB doesn't yet support 'JSON_ARRAYAGG() aggregate as window function' select json_objectagg(a, b) over () from (select 1 a, 2 b) t; ERROR 42000: This version of MariaDB doesn't yet support 'JSON_OBJECTAGG() aggregate as window function' +SELECT JSON_ARRAYAGG(NULL) FROM (SELECT 1 AS t) AS A; +JSON_ARRAYAGG(NULL) +[null] +SELECT JSON_ARRAYAGG("null") FROM (SELECT 1 AS t) AS A; +JSON_ARRAYAGG("null") +["null"] # # End of 10.5 tests # diff --git a/mysql-test/main/func_json.test b/mysql-test/main/func_json.test index 216d51b4c36..95d35d22d1e 100644 --- a/mysql-test/main/func_json.test +++ b/mysql-test/main/func_json.test @@ -752,6 +752,9 @@ select json_arrayagg(a) over () from (select 1 a) t; --error ER_NOT_SUPPORTED_YET select json_objectagg(a, b) over () from (select 1 a, 2 b) t; +SELECT JSON_ARRAYAGG(NULL) FROM (SELECT 1 AS t) AS A; +SELECT JSON_ARRAYAGG("null") FROM (SELECT 1 AS t) AS A; + --echo # --echo # End of 10.5 tests --echo # diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 134c2573ea7..45f57d99011 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -3621,12 +3621,12 @@ int Arg_comparator::compare_e_json_str_basic(Item *j, Item *s) } -String* Item_func_json_arrayagg::convert_to_json(Item *item, String *res) +String* Item_func_json_arrayagg::convert_to_json(Item *item) { String tmp; - res->length(0); - append_json_value(res, item, &tmp); - return res; + m_tmp_json.length(0); + append_json_value(&m_tmp_json, item, &tmp); + return &m_tmp_json; } diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index f1afaf6cc31..e5676768854 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -537,7 +537,15 @@ public: class Item_func_json_arrayagg : public Item_func_group_concat { +protected: + /* + Overrides Item_func_group_concat::skip_nulls() + NULL-s should be added to the result as JSON null value. + */ + virtual bool skip_nulls() const { return false; } + public: + String m_tmp_json; /* Used in convert_to_json. */ Item_func_json_arrayagg(THD *thd, Name_resolution_context *context_arg, bool is_distinct, List<Item> *is_select, const SQL_I_List<ORDER> &is_order, String *is_separator, @@ -552,14 +560,9 @@ public: const char *func_name() const { return "json_arrayagg("; } enum Sumfunctype sum_func() const {return JSON_ARRAYAGG_FUNC;} - String* convert_to_json(Item *item, String *str); + String* convert_to_json(Item *item); String* val_str(String *str); - /* Overrides Item_func_group_concat::add() */ - bool add() - { - return Item_func_group_concat::add(false); - } Item *get_copy(THD *thd) { return get_item_copy<Item_func_json_arrayagg>(thd, this); } }; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index b676186f571..0ce5352ccfb 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3674,20 +3674,18 @@ int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)), else res= (*arg)->val_str(&tmp); } - if (res) + if (item->sum_func() == Item_sum::JSON_ARRAYAGG_FUNC) { - if (item->sum_func() == Item_sum::JSON_ARRAYAGG_FUNC) - { - /* - JSON_ARRAYAGG needs to convert the type into valid JSON before - appending it to the result - */ - Item_func_json_arrayagg *arrayagg= (Item_func_json_arrayagg *) item_arg; - res= arrayagg->convert_to_json(*arg, res); - } + /* + JSON_ARRAYAGG needs to convert the type into valid JSON before + appending it to the result + */ + Item_func_json_arrayagg *arrayagg= (Item_func_json_arrayagg *) item_arg; + res= arrayagg->convert_to_json(*arg); + } + if (res) result->append(*res); - } } if (item->limit_clause) @@ -4151,13 +4149,10 @@ bool Item_func_group_concat::setup(THD *thd) Item *item= args[i]; if (list.push_back(item, thd->mem_root)) DBUG_RETURN(TRUE); - if (item->const_item()) + if (item->const_item() && item->is_null() && skip_nulls()) { - if (item->is_null()) - { - always_null= 1; - DBUG_RETURN(FALSE); - } + always_null= 1; + DBUG_RETURN(FALSE); } } diff --git a/sql/item_sum.h b/sql/item_sum.h index 7ff71c84209..7c69dea4a9a 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1918,6 +1918,12 @@ protected: bool repack_tree(THD *thd); + /* + Says whether the function should skip NULL arguments + or add them to the result. + Redefined in JSON_ARRAYAGG. + */ + virtual bool skip_nulls() const { return true; } public: // Methods used by ColumnStore bool get_distinct() const { return distinct; } @@ -1947,7 +1953,7 @@ public: void clear(); bool add() { - return add(true); + return add(skip_nulls()); } void reset_field() { DBUG_ASSERT(0); } // not used void update_field() { DBUG_ASSERT(0); } // not used |