Commit bb47050e authored by Alexey Botchkov's avatar Alexey Botchkov

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.
parent e7bab059
...@@ -1229,6 +1229,12 @@ select json_arrayagg(a) over () from (select 1 a) t; ...@@ -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' 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; 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' 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 # End of 10.5 tests
# #
...@@ -752,6 +752,9 @@ select json_arrayagg(a) over () from (select 1 a) t; ...@@ -752,6 +752,9 @@ select json_arrayagg(a) over () from (select 1 a) t;
--error ER_NOT_SUPPORTED_YET --error ER_NOT_SUPPORTED_YET
select json_objectagg(a, b) over () from (select 1 a, 2 b) t; 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 #
--echo # End of 10.5 tests --echo # End of 10.5 tests
--echo # --echo #
......
...@@ -3621,12 +3621,12 @@ int Arg_comparator::compare_e_json_str_basic(Item *j, Item *s) ...@@ -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; String tmp;
res->length(0); m_tmp_json.length(0);
append_json_value(res, item, &tmp); append_json_value(&m_tmp_json, item, &tmp);
return res; return &m_tmp_json;
} }
......
...@@ -537,7 +537,15 @@ class Item_func_json_format: public Item_json_func ...@@ -537,7 +537,15 @@ class Item_func_json_format: public Item_json_func
class Item_func_json_arrayagg : public Item_func_group_concat 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: public:
String m_tmp_json; /* Used in convert_to_json. */
Item_func_json_arrayagg(THD *thd, Name_resolution_context *context_arg, Item_func_json_arrayagg(THD *thd, Name_resolution_context *context_arg,
bool is_distinct, List<Item> *is_select, bool is_distinct, List<Item> *is_select,
const SQL_I_List<ORDER> &is_order, String *is_separator, const SQL_I_List<ORDER> &is_order, String *is_separator,
...@@ -552,14 +560,9 @@ class Item_func_json_arrayagg : public Item_func_group_concat ...@@ -552,14 +560,9 @@ class Item_func_json_arrayagg : public Item_func_group_concat
const char *func_name() const { return "json_arrayagg("; } const char *func_name() const { return "json_arrayagg("; }
enum Sumfunctype sum_func() const {return JSON_ARRAYAGG_FUNC;} 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); 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) Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_json_arrayagg>(thd, this); } { return get_item_copy<Item_func_json_arrayagg>(thd, this); }
}; };
......
...@@ -3674,20 +3674,18 @@ int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)), ...@@ -3674,20 +3674,18 @@ int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)),
else else
res= (*arg)->val_str(&tmp); 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
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);
Item_func_json_arrayagg *arrayagg= (Item_func_json_arrayagg *) item_arg; }
res= arrayagg->convert_to_json(*arg, res);
}
if (res)
result->append(*res); result->append(*res);
}
} }
if (item->limit_clause) if (item->limit_clause)
...@@ -4151,13 +4149,10 @@ bool Item_func_group_concat::setup(THD *thd) ...@@ -4151,13 +4149,10 @@ bool Item_func_group_concat::setup(THD *thd)
Item *item= args[i]; Item *item= args[i];
if (list.push_back(item, thd->mem_root)) if (list.push_back(item, thd->mem_root))
DBUG_RETURN(TRUE); 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);
}
} }
} }
......
...@@ -1918,6 +1918,12 @@ class Item_func_group_concat : public Item_sum ...@@ -1918,6 +1918,12 @@ class Item_func_group_concat : public Item_sum
bool repack_tree(THD *thd); 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: public:
// Methods used by ColumnStore // Methods used by ColumnStore
bool get_distinct() const { return distinct; } bool get_distinct() const { return distinct; }
...@@ -1947,7 +1953,7 @@ class Item_func_group_concat : public Item_sum ...@@ -1947,7 +1953,7 @@ class Item_func_group_concat : public Item_sum
void clear(); void clear();
bool add() bool add()
{ {
return add(true); return add(skip_nulls());
} }
void reset_field() { DBUG_ASSERT(0); } // not used void reset_field() { DBUG_ASSERT(0); } // not used
void update_field() { DBUG_ASSERT(0); } // not used void update_field() { DBUG_ASSERT(0); } // not used
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment