diff options
author | Alexey Botchkov <holyfoot@askmonty.org> | 2019-10-14 14:24:22 +0400 |
---|---|---|
committer | Alexey Botchkov <holyfoot@askmonty.org> | 2019-10-14 14:24:22 +0400 |
commit | ba8e5e689c8a1756573c9cbf6a59e9ec32d86457 (patch) | |
tree | 28767f4bb6609bea651a179da5214129438f0be7 | |
parent | b1c2c4ee1b246144033c95d849d59ed0a1192829 (diff) | |
download | mariadb-git-ba8e5e689c8a1756573c9cbf6a59e9ec32d86457.tar.gz |
MDEV-16620 JSON_ARRAYAGG and JSON_OBJECTAGG.
Ison_objectagg implemented.
-rw-r--r-- | mysql-test/main/func_json.result | 10 | ||||
-rw-r--r-- | mysql-test/main/func_json.test | 13 | ||||
-rw-r--r-- | sql/item_jsonfunc.cc | 116 | ||||
-rw-r--r-- | sql/item_jsonfunc.h | 55 | ||||
-rw-r--r-- | sql/item_sum.cc | 8 | ||||
-rw-r--r-- | sql/lex.h | 1 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 25 | ||||
-rw-r--r-- | sql/sql_yacc_ora.yy | 25 |
8 files changed, 237 insertions, 16 deletions
diff --git a/mysql-test/main/func_json.result b/mysql-test/main/func_json.result index f61cca9e48c..be6ea1a7b61 100644 --- a/mysql-test/main/func_json.result +++ b/mysql-test/main/func_json.result @@ -1198,7 +1198,17 @@ JSON_ARRAYAGG(JSON_OBJECT('a', a, 'b', b)) SELECT JSON_ARRAYAGG(a, b) FROM t1; ERROR 42000: Incorrect parameter count in the call to native function 'JSON_ARRAYAGG' SELECT JSON_ARRAYAGG(JSON_ARRAYAGG(a, b)) FROM t1; +ERROR 42000: Incorrect parameter count in the call to native function 'JSON_ARRAYAGG' +SELECT JSON_ARRAYAGG(JSON_ARRAYAGG(a)) FROM t1; ERROR HY000: Invalid use of group function +# +# MDEV-16620 JSON_OBJECTAGG +# +SELECT JSON_OBJECTAGG(a, b) FROM t1; +JSON_OBJECTAGG(a, b) +{"1":"Hello", "1":"World", "2":"This", "2":"Will", "2":"Work", "2":"!", "3":null, "1":"Hello", "1":"World", "2":"This", "2":"Will", "2":"Work", "2":"!", "3":null} +SELECT JSON_OBJECTAGG(a) FROM t1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ') FROM t1' at line 1 DROP TABLE t1; # # End of 10.4 tests diff --git a/mysql-test/main/func_json.test b/mysql-test/main/func_json.test index 13ebe986615..fea33b899b2 100644 --- a/mysql-test/main/func_json.test +++ b/mysql-test/main/func_json.test @@ -713,9 +713,20 @@ SELECT JSON_ARRAYAGG(JSON_OBJECT('a', a, 'b', b)) FROM t1 GROUP BY a; --error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT SELECT JSON_ARRAYAGG(a, b) FROM t1; ---error ER_INVALID_GROUP_FUNC_USE +--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT SELECT JSON_ARRAYAGG(JSON_ARRAYAGG(a, b)) FROM t1; +--error ER_INVALID_GROUP_FUNC_USE +SELECT JSON_ARRAYAGG(JSON_ARRAYAGG(a)) FROM t1; + +-- echo # +-- echo # MDEV-16620 JSON_OBJECTAGG +-- echo # + +SELECT JSON_OBJECTAGG(a, b) FROM t1; +--error ER_PARSE_ERROR +SELECT JSON_OBJECTAGG(a) FROM t1; + DROP TABLE t1; --echo # diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 72c0dfcdf6d..aa3993e57df 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -3643,3 +3643,119 @@ String* Item_func_json_arrayagg::val_str(String *str) return str; } + + +Item_func_json_objectagg:: +Item_func_json_objectagg(THD *thd, Item_func_json_objectagg *item) + :Item_sum(thd, item) +{ + result.set_charset(collation.collation); + result.append("{"); +} + + +bool +Item_func_json_objectagg::fix_fields(THD *thd, Item **ref) +{ + uint i; /* for loop variable */ + DBUG_ASSERT(fixed == 0); + + if (init_sum_func_check(thd)) + return TRUE; + + maybe_null= 1; + + /* + Fix fields for select list and ORDER clause + */ + + for (i=0 ; i < arg_count ; i++) + { + if (args[i]->fix_fields_if_needed_for_scalar(thd, &args[i])) + return TRUE; + m_with_subquery|= args[i]->with_subquery(); + with_param|= args[i]->with_param; + with_window_func|= args[i]->with_window_func; + } + + /* skip charset aggregation for order columns */ + if (agg_arg_charsets_for_string_result(collation, args, arg_count)) + return 1; + + result.set_charset(collation.collation); + result_field= 0; + null_value= 1; + max_length= (uint32)(thd->variables.group_concat_max_len + / collation.collation->mbminlen + * collation.collation->mbmaxlen); + + if (check_sum_func(thd, ref)) + return TRUE; + + fixed= 1; + return FALSE; +} + + +void Item_func_json_objectagg::cleanup() +{ + DBUG_ENTER("Item_func_json_objectagg::cleanup"); + Item_sum::cleanup(); + + result.length(1); + DBUG_VOID_RETURN; +} + + +Item *Item_func_json_objectagg::copy_or_same(THD* thd) +{ + return new (thd->mem_root) Item_func_json_objectagg(thd, this); +} + + +void Item_func_json_objectagg::clear() +{ + result.length(1); + null_value= 1; +} + + +bool Item_func_json_objectagg::add() +{ + StringBuffer<MAX_FIELD_WIDTH> buf; + String *key; + + key= args[0]->val_str(&buf); + if (args[0]->is_null()) + return 0; + + null_value= 0; + if (result.length() > 1) + result.append(", "); + + result.append("\""); + result.append(*key); + result.append("\":"); + + buf.length(0); + append_json_value(&result, args[1], &buf); + + return 0; +} + + +String* Item_func_json_objectagg::val_str(String* str) +{ + DBUG_ASSERT(fixed == 1); + if (null_value) + return 0; + + result.append("}"); + return &result; +} + + +void Item_func_json_objectagg::print(String *str, enum_query_type query_type) +{ +} + diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index eadfbba7f29..e61d0875056 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -527,7 +527,6 @@ public: class Item_func_json_arrayagg : public Item_func_group_concat { public: - 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, @@ -536,6 +535,8 @@ public: is_separator, limit_clause, row_limit, offset_limit) { } + Item_func_json_arrayagg(THD *thd, Item_func_json_arrayagg *item); + bool is_json_type() { return true; } const char *func_name() const { return "json_arrayagg("; } enum Sumfunctype sum_func() const {return JSON_ARRAYAGG_FUNC;} @@ -548,6 +549,58 @@ public: { return Item_func_group_concat::add(false); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_json_arrayagg>(thd, this); } +}; + + +class Item_func_json_objectagg : public Item_sum +{ + String result; +public: + Item_func_json_objectagg(THD *thd, Item *key, Item *value) : + Item_sum(thd, key, value) + { + result.append("{"); + } + + Item_func_json_objectagg(THD *thd, Item_func_json_objectagg *item); + bool is_json_type() { return true; } + void cleanup(); + + enum Sumfunctype sum_func () const {return GROUP_CONCAT_FUNC;} + const char *func_name() const { return "json_objectagg("; } + const Type_handler *type_handler() const + { + if (too_big_for_varchar()) + return &type_handler_blob; + return &type_handler_varchar; + } + void clear(); + bool add(); + void reset_field() { DBUG_ASSERT(0); } // not used + void update_field() { DBUG_ASSERT(0); } // not used + bool fix_fields(THD *,Item **); + + double val_real() + { return 0.0; } + longlong val_int() + { return 0; } + my_decimal *val_decimal(my_decimal *decimal_value) + { + my_decimal_set_zero(decimal_value); + return decimal_value; + } + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) + { + return get_date_from_string(thd, ltime, fuzzydate); + } + String* val_str(String* str); + Item *copy_or_same(THD* thd); + void no_rows_in_result() {} + void print(String *str, enum_query_type query_type); + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_json_objectagg>(thd, this); } }; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 5476ddd9151..a36bf4c140b 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3652,14 +3652,6 @@ int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)), if (item->limit_clause && !(*row_limit)) return 1; - if (item->sum_func() == Item_sum::JSON_ARRAYAGG_FUNC && - item->arg_count_field > 1) - { - /* JSON_ARRAYAGG supports only one parameter */ - my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), "JSON_ARRAYAGG"); - return 1; - } - if (item->no_appended) item->no_appended= FALSE; else diff --git a/sql/lex.h b/sql/lex.h index df2de54dbc5..bb998d5b70f 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -742,6 +742,7 @@ static SYMBOL sql_functions[] = { { "FIRST_VALUE", SYM(FIRST_VALUE_SYM)}, { "GROUP_CONCAT", SYM(GROUP_CONCAT_SYM)}, { "JSON_ARRAYAGG", SYM(JSON_ARRAYAGG_SYM)}, + { "JSON_OBJECTAGG", SYM(JSON_OBJECTAGG_SYM)}, { "LAG", SYM(LAG_SYM)}, { "LEAD", SYM(LEAD_SYM)}, { "MAX", SYM(MAX_SYM)}, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 036c9aaf3e7..bbc4c946020 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1007,6 +1007,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %token <kwd> GRANT /* SQL-2003-R */ %token <kwd> GROUP_CONCAT_SYM %token <rwd> JSON_ARRAYAGG_SYM +%token <rwd> JSON_OBJECTAGG_SYM %token <kwd> GROUP_SYM /* SQL-2003-R */ %token <kwd> HAVING /* SQL-2003-R */ %token <kwd> HOUR_MICROSECOND_SYM @@ -11508,19 +11509,26 @@ sum_expr: } | JSON_ARRAYAGG_SYM '(' opt_distinct { Select->in_sum_expr++; } - expr_list opt_glimit_clause + expr_list opt_gorder_clause opt_glimit_clause ')' { SELECT_LEX *sel= Select; + List<Item> *args= $5; sel->in_sum_expr--; + if (args && args->elements > 1) + { + /* JSON_ARRAYAGG supports only one parameter */ + my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), "JSON_ARRAYAGG"); + MYSQL_YYABORT; + } String* s= new (thd->mem_root) String(",", 1, &my_charset_latin1); if (unlikely(s == NULL)) MYSQL_YYABORT; $$= new (thd->mem_root) Item_func_json_arrayagg(thd, Lex->current_context(), - $3, $5, - sel->gorder_list, s, $6, + $3, args, + sel->gorder_list, s, $7, sel->select_limit, sel->offset_limit); if (unlikely($$ == NULL)) @@ -11531,6 +11539,17 @@ sum_expr: $5->empty(); sel->gorder_list.empty(); } + | JSON_OBJECTAGG_SYM '(' + { Select->in_sum_expr++; } + expr ',' expr ')' + { + SELECT_LEX *sel= Select; + sel->in_sum_expr--; + + $$= new (thd->mem_root) Item_func_json_objectagg(thd, $4, $6); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } ; window_func_expr: diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 471364e29b7..897ccd723fe 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -472,6 +472,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %token <kwd> GRANT /* SQL-2003-R */ %token <kwd> GROUP_CONCAT_SYM %token <rwd> JSON_ARRAYAGG_SYM +%token <rwd> JSON_OBJECTAGG_SYM %token <kwd> GROUP_SYM /* SQL-2003-R */ %token <kwd> HAVING /* SQL-2003-R */ %token <kwd> HOUR_MICROSECOND_SYM @@ -11608,19 +11609,26 @@ sum_expr: } | JSON_ARRAYAGG_SYM '(' opt_distinct { Select->in_sum_expr++; } - expr_list opt_glimit_clause + expr_list opt_gorder_clause opt_glimit_clause ')' { SELECT_LEX *sel= Select; + List<Item> *args= $5; sel->in_sum_expr--; + if (args && args->elements > 1) + { + /* JSON_ARRAYAGG supports only one parameter */ + my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), "JSON_ARRAYAGG"); + MYSQL_YYABORT; + } String* s= new (thd->mem_root) String(",", 1, &my_charset_latin1); if (unlikely(s == NULL)) MYSQL_YYABORT; $$= new (thd->mem_root) Item_func_json_arrayagg(thd, Lex->current_context(), - $3, $5, - sel->gorder_list, s, $6, + $3, args, + sel->gorder_list, s, $7, sel->select_limit, sel->offset_limit); if (unlikely($$ == NULL)) @@ -11631,6 +11639,17 @@ sum_expr: $5->empty(); sel->gorder_list.empty(); } + | JSON_OBJECTAGG_SYM '(' + { Select->in_sum_expr++; } + expr ',' expr ')' + { + SELECT_LEX *sel= Select; + sel->in_sum_expr--; + + $$= new (thd->mem_root) Item_func_json_objectagg(thd, $4, $6); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } ; window_func_expr: |