diff --git a/mysql-test/main/func_json.result b/mysql-test/main/func_json.result index e40951a0b1f..bf8c85a59f1 100644 --- a/mysql-test/main/func_json.result +++ b/mysql-test/main/func_json.result @@ -1640,9 +1640,9 @@ SELECT t1.id, JSON_ARRAYAGG(JSON_OBJECT('id',t2.id) ORDER BY t2.id) as materials from t1 LEFT JOIN t2 on t1.id = t2.owner_id GROUP BY t1.id ORDER BY id; id materials -1 ["{\"id\": 1}","{\"id\": 2}"] -2 ["{\"id\": 3}"] -3 ["{\"id\": 4}"] +1 [{"id": 1},{"id": 2}] +2 [{"id": 3}] +3 [{"id": 4}] DROP TABLE t1; DROP TABLE t2; # diff --git a/mysql-test/suite/json/r/type_json.result b/mysql-test/suite/json/r/type_json.result index b9b70f24190..fc9bea9dc91 100644 --- a/mysql-test/suite/json/r/type_json.result +++ b/mysql-test/suite/json/r/type_json.result @@ -2880,5 +2880,13 @@ DROP PROCEDURE p1; DROP PROCEDURE p2; DROP TABLE t1, t1c, t2; # +# MDEV-30646 View created via JSON_ARRAYAGG returns incorrect json object +# +CREATE VIEW v1 AS SELECT JSON_OBJECT('plugin','unix_socket') as v1_json; +SELECT JSON_ARRAYAGG(v1_json) FROM v1; +JSON_ARRAYAGG(v1_json) +[{"plugin": "unix_socket"}] +DROP VIEW v1; +# # End of 10.5 tests # diff --git a/mysql-test/suite/json/t/type_json.test b/mysql-test/suite/json/t/type_json.test index f84bef780c3..03236070c8e 100644 --- a/mysql-test/suite/json/t/type_json.test +++ b/mysql-test/suite/json/t/type_json.test @@ -138,6 +138,15 @@ DROP PROCEDURE p2; DROP TABLE t1, t1c, t2; +--echo # +--echo # MDEV-30646 View created via JSON_ARRAYAGG returns incorrect json object +--echo # + +CREATE VIEW v1 AS SELECT JSON_OBJECT('plugin','unix_socket') as v1_json; +SELECT JSON_ARRAYAGG(v1_json) FROM v1; +DROP VIEW v1; + + --echo # --echo # End of 10.5 tests --echo # diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 25b74f8d0aa..fb2e995cd52 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -1633,7 +1633,7 @@ null_return: `CONVERT(arg USING charset)` is actually a general purpose string expression, not a JSON expression. */ -static bool is_json_type(const Item *item) +bool is_json_type(const Item *item) { for ( ; ; ) { diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index eea7605d8e8..c8e920dc083 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -640,5 +640,6 @@ public: { return get_item_copy(thd, this); } }; +extern bool is_json_type(const Item *item); #endif /* ITEM_JSONFUNC_INCLUDED */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a7b84bbfe3b..3b30c2f1789 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -18569,6 +18569,25 @@ Field *Item_func_sp::create_tmp_field_ex(MEM_ROOT *root, TABLE *table, return result; } + +static bool make_json_valid_expr(TABLE *table, Field *field) +{ + THD *thd= table->in_use; + Query_arena backup_arena; + Item *expr, *item_field; + + if (!table->expr_arena && table->init_expr_arena(thd->mem_root)) + return 1; + + thd->set_n_backup_active_arena(table->expr_arena, &backup_arena); + if ((item_field= new (thd->mem_root) Item_field(thd, field)) && + (expr= new (thd->mem_root) Item_func_json_valid(thd, item_field))) + field->check_constraint= add_virtual_expression(thd, expr); + thd->restore_active_arena(table->expr_arena, &backup_arena); + return field->check_constraint == NULL; +} + + /** Create field for temporary table. @@ -18614,6 +18633,9 @@ Field *create_tmp_field(TABLE *table, Item *item, make_copy_field); Field *result= item->create_tmp_field_ex(table->in_use->mem_root, table, &src, &prm); + if (is_json_type(item) && make_json_valid_expr(table, result)) + result= NULL; + *from_field= src.field(); *default_field= src.default_field(); if (src.item_result_field()) diff --git a/sql/table.cc b/sql/table.cc index 6633aa1ee04..610d94d413c 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -53,6 +53,17 @@ #define MYSQL57_GENERATED_FIELD 128 #define MYSQL57_GCOL_HEADER_SIZE 4 +bool TABLE::init_expr_arena(MEM_ROOT *mem_root) +{ + /* + We need to use CONVENTIONAL_EXECUTION here to ensure that + any new items created by fix_fields() are not reverted. + */ + expr_arena= new (alloc_root(mem_root, sizeof(Query_arena))) + Query_arena(mem_root, Query_arena::STMT_CONVENTIONAL_EXECUTION); + return expr_arena == NULL; +} + struct extra2_fields { LEX_CUSTRING version; @@ -1145,14 +1156,8 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table, table->s->table_check_constraints * sizeof(Virtual_column_info*)); DBUG_ASSERT(table->expr_arena == NULL); - /* - We need to use CONVENTIONAL_EXECUTION here to ensure that - any new items created by fix_fields() are not reverted. - */ - table->expr_arena= new (alloc_root(mem_root, sizeof(Query_arena))) - Query_arena(mem_root, - Query_arena::STMT_CONVENTIONAL_EXECUTION); - if (!table->expr_arena) + + if (table->init_expr_arena(mem_root)) DBUG_RETURN(1); thd->set_n_backup_active_arena(table->expr_arena, &backup_arena); diff --git a/sql/table.h b/sql/table.h index a63eae88cb6..97e595979b9 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1645,6 +1645,8 @@ public: m_needs_reopen= value; } + bool init_expr_arena(MEM_ROOT *mem_root); + bool alloc_keys(uint key_count); bool check_tmp_key(uint key, uint key_parts, uint (*next_field_no) (uchar *), uchar *arg);