summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Botchkov <holyfoot@askmonty.org>2019-10-14 14:24:22 +0400
committerAlexey Botchkov <holyfoot@askmonty.org>2019-10-14 14:24:22 +0400
commitba8e5e689c8a1756573c9cbf6a59e9ec32d86457 (patch)
tree28767f4bb6609bea651a179da5214129438f0be7
parentb1c2c4ee1b246144033c95d849d59ed0a1192829 (diff)
downloadmariadb-git-ba8e5e689c8a1756573c9cbf6a59e9ec32d86457.tar.gz
MDEV-16620 JSON_ARRAYAGG and JSON_OBJECTAGG.
Ison_objectagg implemented.
-rw-r--r--mysql-test/main/func_json.result10
-rw-r--r--mysql-test/main/func_json.test13
-rw-r--r--sql/item_jsonfunc.cc116
-rw-r--r--sql/item_jsonfunc.h55
-rw-r--r--sql/item_sum.cc8
-rw-r--r--sql/lex.h1
-rw-r--r--sql/sql_yacc.yy25
-rw-r--r--sql/sql_yacc_ora.yy25
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: