summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlexey Botchkov <holyfoot@askmonty.org>2016-10-19 14:10:03 +0400
committerAlexey Botchkov <holyfoot@askmonty.org>2016-10-19 14:10:03 +0400
commit27025221fe2ea17aa737ad2ad31011407c00dcc9 (patch)
tree0f5352944d26aceb427320756c90bde3b00f13a3 /sql
parent8303aded294ce905bbc513e7ee42623d5f1fdb50 (diff)
downloadmariadb-git-27025221fe2ea17aa737ad2ad31011407c00dcc9.tar.gz
MDEV-9143 JSON_xxx functions.
strings/json_lib.c added as a JSON library. SQL frunction added with sql/item_jsonfunc.h/cc
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt2
-rw-r--r--sql/item.h15
-rw-r--r--sql/item_create.cc474
-rw-r--r--sql/item_jsonfunc.cc1109
-rw-r--r--sql/item_jsonfunc.h304
-rw-r--r--sql/item_xmlfunc.cc21
-rw-r--r--sql/item_xmlfunc.h5
-rw-r--r--sql/sql_yacc.yy4
8 files changed, 1907 insertions, 27 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 28072375bbc..d011b1a07d2 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -136,7 +136,7 @@ SET (SQL_SOURCE
opt_table_elimination.cc sql_expression_cache.cc
gcalc_slicescan.cc gcalc_tools.cc
threadpool_common.cc ../sql-common/mysql_async.c
- my_apc.cc my_apc.h mf_iocache_encr.cc
+ my_apc.cc my_apc.h mf_iocache_encr.cc item_jsonfunc.cc
my_json_writer.cc my_json_writer.h
rpl_gtid.cc rpl_parallel.cc
sql_type.cc sql_type.h
diff --git a/sql/item.h b/sql/item.h
index 28a14454c0b..76442351d0d 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -2997,6 +2997,20 @@ public:
};
+/*
+ We sometimes need to distinguish a number from a boolean:
+ a[1] and a[true] are different things in XPath.
+ Also in JSON boolean values should be treated differently.
+*/
+class Item_bool :public Item_int
+{
+public:
+ Item_bool(THD *thd, const char *str_arg, longlong i):
+ Item_int(thd, str_arg, i, 1) {}
+ bool is_bool_type() { return true; }
+};
+
+
class Item_uint :public Item_int
{
public:
@@ -4750,6 +4764,7 @@ public:
#include "item_timefunc.h"
#include "item_subselect.h"
#include "item_xmlfunc.h"
+#include "item_jsonfunc.h"
#include "item_create.h"
#endif
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 7f0d4144177..cf6f24eddb7 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -1708,6 +1708,201 @@ protected:
#endif
+class Create_func_json_exists : public Create_func_arg2
+{
+public:
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
+
+ static Create_func_json_exists s_singleton;
+
+protected:
+ Create_func_json_exists() {}
+ virtual ~Create_func_json_exists() {}
+};
+
+
+class Create_func_json_valid : public Create_func_arg1
+{
+public:
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
+
+ static Create_func_json_valid s_singleton;
+
+protected:
+ Create_func_json_valid() {}
+ virtual ~Create_func_json_valid() {}
+};
+
+
+class Create_func_json_type : public Create_func_arg1
+{
+public:
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
+
+ static Create_func_json_type s_singleton;
+
+protected:
+ Create_func_json_type() {}
+ virtual ~Create_func_json_type() {}
+};
+
+
+class Create_func_json_depth : public Create_func_arg1
+{
+public:
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
+
+ static Create_func_json_depth s_singleton;
+
+protected:
+ Create_func_json_depth() {}
+ virtual ~Create_func_json_depth() {}
+};
+
+
+class Create_func_json_value : public Create_func_arg2
+{
+public:
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
+
+ static Create_func_json_value s_singleton;
+
+protected:
+ Create_func_json_value() {}
+ virtual ~Create_func_json_value() {}
+};
+
+
+class Create_func_json_query : public Create_func_arg2
+{
+public:
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
+
+ static Create_func_json_query s_singleton;
+
+protected:
+ Create_func_json_query() {}
+ virtual ~Create_func_json_query() {}
+};
+
+
+class Create_func_json_contains: public Create_native_func
+{
+public:
+ virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
+
+ static Create_func_json_contains s_singleton;
+
+protected:
+ Create_func_json_contains() {}
+ virtual ~Create_func_json_contains() {}
+};
+
+
+class Create_func_json_contains_path : public Create_native_func
+{
+public:
+ virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
+
+ static Create_func_json_contains_path s_singleton;
+
+protected:
+ Create_func_json_contains_path() {}
+ virtual ~Create_func_json_contains_path() {}
+};
+
+
+class Create_func_json_extract : public Create_native_func
+{
+public:
+ virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
+
+ static Create_func_json_extract s_singleton;
+
+protected:
+ Create_func_json_extract() {}
+ virtual ~Create_func_json_extract() {}
+};
+
+
+class Create_func_json_array : public Create_native_func
+{
+public:
+ virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
+
+ static Create_func_json_array s_singleton;
+
+protected:
+ Create_func_json_array() {}
+ virtual ~Create_func_json_array() {}
+};
+
+
+class Create_func_json_array_append : public Create_native_func
+{
+public:
+ virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
+
+ static Create_func_json_array_append s_singleton;
+
+protected:
+ Create_func_json_array_append() {}
+ virtual ~Create_func_json_array_append() {}
+};
+
+
+class Create_func_json_object : public Create_native_func
+{
+public:
+ virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
+
+ static Create_func_json_object s_singleton;
+
+protected:
+ Create_func_json_object() {}
+ virtual ~Create_func_json_object() {}
+};
+
+
+class Create_func_json_length : public Create_native_func
+{
+public:
+ virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
+
+ static Create_func_json_length s_singleton;
+
+protected:
+ Create_func_json_length() {}
+ virtual ~Create_func_json_length() {}
+};
+
+
+class Create_func_json_merge : public Create_native_func
+{
+public:
+ virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
+
+ static Create_func_json_merge s_singleton;
+
+protected:
+ Create_func_json_merge() {}
+ virtual ~Create_func_json_merge() {}
+};
+
+
+class Create_func_json_quote : public Create_func_arg1
+{
+public:
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
+
+ static Create_func_json_quote s_singleton;
+
+protected:
+ Create_func_json_quote() {}
+ virtual ~Create_func_json_quote() {}
+};
+
+
class Create_func_last_day : public Create_func_arg1
{
public:
@@ -4572,6 +4767,69 @@ Create_func_issimple::create_1_arg(THD *thd, Item *arg1)
#endif
+Create_func_json_exists Create_func_json_exists::s_singleton;
+
+Item*
+Create_func_json_exists::create_2_arg(THD *thd, Item *arg1, Item *arg2)
+{
+ return new (thd->mem_root) Item_func_json_exists(thd, arg1, arg2);
+}
+
+
+Create_func_json_valid Create_func_json_valid::s_singleton;
+
+Item*
+Create_func_json_valid::create_1_arg(THD *thd, Item *arg1)
+{
+ return new (thd->mem_root) Item_func_json_valid(thd, arg1);
+}
+
+
+Create_func_json_type Create_func_json_type::s_singleton;
+
+Item*
+Create_func_json_type::create_1_arg(THD *thd, Item *arg1)
+{
+ return new (thd->mem_root) Item_func_json_type(thd, arg1);
+}
+
+
+Create_func_json_depth Create_func_json_depth::s_singleton;
+
+Item*
+Create_func_json_depth::create_1_arg(THD *thd, Item *arg1)
+{
+ return new (thd->mem_root) Item_func_json_depth(thd, arg1);
+}
+
+
+Create_func_json_value Create_func_json_value::s_singleton;
+
+Item*
+Create_func_json_value::create_2_arg(THD *thd, Item *arg1, Item *arg2)
+{
+ return new (thd->mem_root) Item_func_json_value(thd, arg1, arg2);
+}
+
+
+Create_func_json_query Create_func_json_query::s_singleton;
+
+Item*
+Create_func_json_query::create_2_arg(THD *thd, Item *arg1, Item *arg2)
+{
+ return new (thd->mem_root) Item_func_json_query(thd, arg1, arg2);
+}
+
+
+Create_func_json_quote Create_func_json_quote::s_singleton;
+
+Item*
+Create_func_json_quote::create_1_arg(THD *thd, Item *arg1)
+{
+ return new (thd->mem_root) Item_func_json_quote(thd, arg1);
+}
+
+
Create_func_last_day Create_func_last_day::s_singleton;
Item*
@@ -4581,6 +4839,207 @@ Create_func_last_day::create_1_arg(THD *thd, Item *arg1)
}
+Create_func_json_array Create_func_json_array::s_singleton;
+
+Item*
+Create_func_json_array::create_native(THD *thd, LEX_STRING name,
+ List<Item> *item_list)
+{
+ Item *func;
+
+ if (item_list != NULL)
+ {
+ func= new (thd->mem_root) Item_func_json_array(thd, *item_list);
+ }
+ else
+ {
+ func= new (thd->mem_root) Item_func_json_array(thd);
+ }
+
+ return func;
+}
+
+
+Create_func_json_array_append Create_func_json_array_append::s_singleton;
+
+Item*
+Create_func_json_array_append::create_native(THD *thd, LEX_STRING name,
+ List<Item> *item_list)
+{
+ Item *func= NULL;
+ int arg_count= 0;
+
+ if (item_list != NULL)
+ arg_count= item_list->elements;
+
+ if (arg_count < 3 || (arg_count & 1) == 0 /*is even*/)
+ {
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
+ }
+ else
+ {
+ func= new (thd->mem_root) Item_func_json_array_append(thd, *item_list);
+ }
+
+ return func;
+}
+
+
+Create_func_json_object Create_func_json_object::s_singleton;
+
+Item*
+Create_func_json_object::create_native(THD *thd, LEX_STRING name,
+ List<Item> *item_list)
+{
+ Item *func;
+ int arg_count;
+
+ if (item_list != NULL)
+ {
+ arg_count= item_list->elements;
+ if ((arg_count & 1) != 0 /*is odd*/)
+ {
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
+ func= NULL;
+ }
+ else
+ {
+ func= new (thd->mem_root) Item_func_json_object(thd, *item_list);
+ }
+ }
+ else
+ {
+ arg_count= 0;
+ func= new (thd->mem_root) Item_func_json_object(thd);
+ }
+
+ return func;
+}
+
+
+Create_func_json_length Create_func_json_length::s_singleton;
+
+Item*
+Create_func_json_length::create_native(THD *thd, LEX_STRING name,
+ List<Item> *item_list)
+{
+ Item *func;
+ int arg_count;
+
+ if (item_list == NULL ||
+ (arg_count= item_list->elements) == 0)
+ {
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
+ func= NULL;
+ }
+ else
+ {
+ func= new (thd->mem_root) Item_func_json_length(thd, *item_list);
+ }
+
+ return func;
+}
+
+
+Create_func_json_merge Create_func_json_merge::s_singleton;
+
+Item*
+Create_func_json_merge::create_native(THD *thd, LEX_STRING name,
+ List<Item> *item_list)
+{
+ Item *func;
+ int arg_count;
+
+ if (item_list == NULL ||
+ (arg_count= item_list->elements) == 0)
+ {
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
+ func= NULL;
+ }
+ else
+ {
+ func= new (thd->mem_root) Item_func_json_merge(thd, *item_list);
+ }
+
+ return func;
+}
+
+
+Create_func_json_contains Create_func_json_contains::s_singleton;
+
+Item*
+Create_func_json_contains::create_native(THD *thd, LEX_STRING name,
+ List<Item> *item_list)
+{
+ Item *func= NULL;
+ int arg_count= 0;
+
+ if (item_list != NULL)
+ arg_count= item_list->elements;
+
+ if (arg_count < 2 /* json_doc, val, [path]...*/)
+ {
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
+ }
+ else
+ {
+ func= new (thd->mem_root) Item_func_json_contains(thd, *item_list);
+ }
+
+ return func;
+}
+
+
+Create_func_json_contains_path Create_func_json_contains_path::s_singleton;
+
+Item*
+Create_func_json_contains_path::create_native(THD *thd, LEX_STRING name,
+ List<Item> *item_list)
+{
+ Item *func= NULL;
+ int arg_count= 0;
+
+ if (item_list != NULL)
+ arg_count= item_list->elements;
+
+ if (arg_count < 3 /* json_doc, one_or_all, path, [path]...*/)
+ {
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
+ }
+ else
+ {
+ func= new (thd->mem_root) Item_func_json_contains_path(thd, *item_list);
+ }
+
+ return func;
+}
+
+
+Create_func_json_extract Create_func_json_extract::s_singleton;
+
+Item*
+Create_func_json_extract::create_native(THD *thd, LEX_STRING name,
+ List<Item> *item_list)
+{
+ Item *func= NULL;
+ int arg_count= 0;
+
+ if (item_list != NULL)
+ arg_count= item_list->elements;
+
+ if (arg_count < 2 /* json_doc, path, [path]...*/)
+ {
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
+ }
+ else
+ {
+ func= new (thd->mem_root) Item_func_json_extract(thd, *item_list);
+ }
+
+ return func;
+}
+
+
Create_func_last_insert_id Create_func_last_insert_id::s_singleton;
Item*
@@ -5852,6 +6311,21 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)},
{ { C_STRING_WITH_LEN("IS_FREE_LOCK") }, BUILDER(Create_func_is_free_lock)},
{ { C_STRING_WITH_LEN("IS_USED_LOCK") }, BUILDER(Create_func_is_used_lock)},
+ { { C_STRING_WITH_LEN("JSON_ARRAY") }, BUILDER(Create_func_json_array)},
+ { { C_STRING_WITH_LEN("JSON_ARRAY_APPEND") }, BUILDER(Create_func_json_array_append)},
+ { { C_STRING_WITH_LEN("JSON_CONTAINS") }, BUILDER(Create_func_json_contains)},
+ { { C_STRING_WITH_LEN("JSON_CONTAINS_PATH") }, BUILDER(Create_func_json_contains_path)},
+ { { C_STRING_WITH_LEN("JSON_DEPTH") }, BUILDER(Create_func_json_depth)},
+ { { C_STRING_WITH_LEN("JSON_EXISTS") }, BUILDER(Create_func_json_exists)},
+ { { C_STRING_WITH_LEN("JSON_EXTRACT") }, BUILDER(Create_func_json_extract)},
+ { { C_STRING_WITH_LEN("JSON_LENGTH") }, BUILDER(Create_func_json_length)},
+ { { C_STRING_WITH_LEN("JSON_MERGE") }, BUILDER(Create_func_json_merge)},
+ { { C_STRING_WITH_LEN("JSON_QUERY") }, BUILDER(Create_func_json_query)},
+ { { C_STRING_WITH_LEN("JSON_QUOTE") }, BUILDER(Create_func_json_quote)},
+ { { C_STRING_WITH_LEN("JSON_OBJECT") }, BUILDER(Create_func_json_object)},
+ { { C_STRING_WITH_LEN("JSON_TYPE") }, BUILDER(Create_func_json_type)},
+ { { C_STRING_WITH_LEN("JSON_VALID") }, BUILDER(Create_func_json_valid)},
+ { { C_STRING_WITH_LEN("JSON_VALUE") }, BUILDER(Create_func_json_value)},
{ { C_STRING_WITH_LEN("LAST_DAY") }, BUILDER(Create_func_last_day)},
{ { C_STRING_WITH_LEN("LAST_INSERT_ID") }, BUILDER(Create_func_last_insert_id)},
{ { C_STRING_WITH_LEN("LCASE") }, BUILDER(Create_func_lcase)},
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc
new file mode 100644
index 00000000000..80713710927
--- /dev/null
+++ b/sql/item_jsonfunc.cc
@@ -0,0 +1,1109 @@
+/* Copyright (c) 2016, Monty Program Ab.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+
+#include <my_global.h>
+#include "sql_priv.h"
+#include "sql_class.h"
+#include "item.h"
+
+
+/*
+ Compare ASCII string against the string with the specified
+ character set.
+ Only compares the equality, case insencitive.
+*/
+static bool eq_ascii_string(const CHARSET_INFO *cs,
+ const char *ascii,
+ const char *s, uint32 s_len)
+{
+ const char *s_end= s + s_len;
+
+ while (*ascii && s < s_end)
+ {
+ my_wc_t wc;
+ int wc_len;
+
+ wc_len= cs->cset->mb_wc(cs, &wc, (uchar *) s, (uchar *) s_end);
+ if (wc_len <= 0 || (wc | 0x20) != (my_wc_t) *ascii)
+ return 0;
+
+ ascii++;
+ s+= wc_len;
+ }
+
+ return *ascii == 0 && s >= s_end;
+}
+
+
+/*
+ Appends arbitrary String to the JSON string taking charsets in
+ consideration.
+*/
+static int st_append_escaped(String *s, const String *a)
+{
+ /*
+ In the worst case one character from the 'a' string
+ turns into '\uXXXX\uXXXX' which is 12.
+ */
+ int str_len= a->length() * 12 * s->charset()->mbmaxlen /
+ a->charset()->mbminlen;
+ if (!s->reserve(str_len, 1024) &&
+ (str_len=
+ json_escape(a->charset(), (uchar *) a->ptr(), (uchar *)a->end(),
+ s->charset(),
+ (uchar *) s->end(), (uchar *)s->end() + str_len)) > 0)
+ {
+ s->length(s->length() + str_len);
+ return 0;
+ }
+
+ return a->length();
+}
+
+
+longlong Item_func_json_valid::val_int()
+{
+ String *js= args[0]->val_str(&tmp_value);
+ json_engine_t je;
+
+ if ((null_value= args[0]->null_value) || js == NULL)
+ return 0;
+
+ json_scan_start(&je, js->charset(), (const uchar *) js->ptr(),
+ (const uchar *) js->ptr()+js->length());
+
+ while (json_scan_next(&je) == 0) {}
+
+ return je.s.error == 0;
+}
+
+
+void Item_func_json_exists::fix_length_and_dec()
+{
+ Item_int_func::fix_length_and_dec();
+ maybe_null= 1;
+ path.set_constant_flag(args[1]->const_item());
+}
+
+
+longlong Item_func_json_exists::val_int()
+{
+ json_engine_t je;
+ uint array_counters[JSON_DEPTH_LIMIT];
+
+ String *js= args[0]->val_str(&tmp_js);
+
+ if (!path.parsed)
+ {
+ String *s_p= args[1]->val_str(&tmp_path);
+ if (s_p &&
+ json_path_setup(&path.p, s_p->charset(), (const uchar *) s_p->ptr(),
+ (const uchar *) s_p->ptr() + s_p->length()))
+ goto err_return;
+ path.parsed= path.constant;
+ }
+
+ if ((null_value= args[0]->null_value || args[1]->null_value))
+ {
+ null_value= 1;
+ return 0;
+ }
+
+ null_value= 0;
+ json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
+ (const uchar *) js->ptr() + js->length());
+
+ path.cur_step= path.p.steps;
+ if (json_find_path(&je, &path.p, &path.cur_step, array_counters))
+ {
+ if (je.s.error)
+ goto err_return;
+ return 0;
+ }
+
+ return 1;
+
+err_return:
+ null_value= 1;
+ return 0;
+}
+
+
+void Item_func_json_value::fix_length_and_dec()
+{
+ collation.set(args[0]->collation);
+ max_length= args[0]->max_length;
+ path.set_constant_flag(args[1]->const_item());
+}
+
+
+/*
+ Returns NULL, not an error if the found value
+ is not a scalar.
+*/
+String *Item_func_json_value::val_str(String *str)
+{
+ json_engine_t je;
+ String *js= args[0]->val_str(&tmp_js);
+ int error= 0;
+ uint array_counters[JSON_DEPTH_LIMIT];
+
+ if (!path.parsed)
+ {
+ String *s_p= args[1]->val_str(&tmp_path);
+ if (s_p &&
+ json_path_setup(&path.p, s_p->charset(), (const uchar *) s_p->ptr(),
+ (const uchar *) s_p->ptr() + s_p->length()))
+ goto err_return;
+ path.parsed= path.constant;
+ }
+
+ if ((null_value= args[0]->null_value || args[1]->null_value))
+ return NULL;
+
+ json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
+ (const uchar *) js->ptr() + js->length());
+
+ path.cur_step= path.p.steps;
+continue_search:
+ if (json_find_path(&je, &path.p, &path.cur_step, array_counters))
+ {
+ if (je.s.error)
+ goto err_return;
+
+ null_value= 1;
+ return 0;
+ }
+
+ if (json_read_value(&je))
+ goto err_return;
+
+ if (check_and_get_value(&je, str, &error))
+ {
+ if (error)
+ goto err_return;
+ goto continue_search;
+ }
+
+ return str;
+
+err_return:
+ null_value= 1;
+ return 0;
+}
+
+
+bool Item_func_json_value::check_and_get_value(json_engine_t *je, String *res,
+ int *error)
+{
+ if (!json_value_scalar(je))
+ {
+ /* We only look for scalar values! */
+ if (json_skip_level(je) || json_scan_next(je))
+ *error= 1;
+ return true;
+ }
+
+ res->set((const char *) je->value, je->value_len, je->s.cs);
+ return false;
+}
+
+
+bool Item_func_json_query::check_and_get_value(json_engine_t *je, String *res,
+ int *error)
+{
+ const uchar *value;
+ if (json_value_scalar(je))
+ {
+ /* We skip scalar values. */
+ if (json_scan_next(je))
+ *error= 1;
+ return true;
+ }
+
+ value= je->value;
+ if (json_skip_level(je))
+ {
+ *error= 1;
+ return true;
+ }
+
+ res->set((const char *) je->value, je->s.c_str - value, je->s.cs);
+ return false;
+}
+
+
+void Item_func_json_quote::fix_length_and_dec()
+{
+ collation.set(args[0]->collation);
+ /*
+ Odd but realistic worst case is when all characters
+ of the argument turn into '\uXXXX\uXXXX', which is 12.
+ */
+ max_length= args[0]->max_length * 12;
+}
+
+
+String *Item_func_json_quote::val_str(String *str)
+{
+ String *s= args[0]->val_str(&tmp_s);
+
+ if ((null_value= args[0]->null_value))
+ return NULL;
+
+ str->length(0);
+ str->set_charset(s->charset());
+
+ if (st_append_escaped(str, s))
+ {
+ /* Report an error. */
+ null_value= 1;
+ return 0;
+ }
+
+ return str;
+}
+
+
+static int alloc_tmp_paths(THD *thd, uint n_paths,
+ json_path_with_flags **paths,String **tmp_paths)
+{
+ if (n_paths > 0)
+ {
+ *paths= (json_path_with_flags *) alloc_root(thd->mem_root,
+ sizeof(json_path_with_flags) * n_paths);
+ *tmp_paths= (String *) alloc_root(thd->mem_root, sizeof(String) * n_paths);
+ if (*paths == 0 || *tmp_paths == 0)
+ return 1;
+
+ bzero(*tmp_paths, sizeof(String) * n_paths);
+
+ return 0;
+ }
+
+ /* n_paths == 0 */
+ *paths= 0;
+ *tmp_paths= 0;
+ return 0;
+}
+
+
+static void mark_constant_paths(json_path_with_flags *p,
+ Item** args, uint n_args)
+{
+ uint n;
+ for (n= 0; n < n_args; n++)
+ p[n].set_constant_flag(args[n]->const_item());
+}
+
+
+bool Item_json_str_multipath::fix_fields(THD *thd, Item **ref)
+{
+ return alloc_tmp_paths(thd, get_n_paths(), &paths, &tmp_paths) ||
+ Item_str_func::fix_fields(thd, ref);
+}
+
+
+void Item_json_str_multipath::cleanup()
+{
+ if (tmp_paths)
+ {
+ for (uint i= get_n_paths(); i>0; i--)
+ tmp_paths[i-1].free();
+ tmp_paths= 0;
+ }
+ Item_str_func::cleanup();
+}
+
+
+void Item_func_json_extract::fix_length_and_dec()
+{
+ collation.set(args[0]->collation);
+ max_length= args[0]->max_length * (arg_count - 1);
+
+ mark_constant_paths(paths, args+1, arg_count-1);
+}
+
+
+String *Item_func_json_extract::val_str(String *str)
+{
+ String *js= args[0]->val_str(&tmp_js);
+ json_engine_t je;
+ bool multiple_values_found= FALSE;
+ const uchar *value;
+ const char *first_value= NULL, *first_p_value;
+ uint n_arg, v_len, first_len, first_p_len;
+ uint array_counters[JSON_DEPTH_LIMIT];
+
+ if ((null_value= args[0]->null_value))
+ return 0;
+
+ str->set_charset(js->charset());
+ str->length(0);
+
+ for (n_arg=1; n_arg < arg_count; n_arg++)
+ {
+ json_path_with_flags *c_path= paths + n_arg - 1;
+ if (!c_path->parsed)
+ {
+ String *s_p= args[n_arg]->val_str(tmp_paths + (n_arg-1));
+ if (s_p &&
+ json_path_setup(&c_path->p,s_p->charset(),(const uchar *) s_p->ptr(),
+ (const uchar *) s_p->ptr() + s_p->length()))
+ goto error;
+ c_path->parsed= c_path->constant;
+ }
+
+ json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
+ (const uchar *) js->ptr() + js->length());
+
+ c_path->cur_step= c_path->p.steps;
+
+ if (json_find_path(&je, &c_path->p, &c_path->cur_step, array_counters))
+ {
+ /* Path wasn't found. */
+ if (je.s.error)
+ goto error;
+
+ continue;
+ }
+
+ if (json_read_value(&je))
+ goto error;
+
+ value= je.value_begin;
+ if (json_value_scalar(&je))
+ v_len= je.value_end - value;
+ else
+ {
+ if (json_skip_level(&je))
+ goto error;
+ v_len= je.s.c_str - value;
+ }
+
+ if (!multiple_values_found)
+ {
+ if (first_value == NULL)
+ {
+ /*
+ Just remember the first value as we don't know yet
+ if we need to create an array out of it or not.
+ */
+ first_value= (const char *) value;
+ first_len= v_len;
+ /*
+ We need this as we have to preserve quotes around string
+ constants if we use the value to create an array. Otherwise
+ we get the value without the quotes.
+ */
+ first_p_value= (const char *) je.value;
+ first_p_len= je.value_len;
+ continue;
+ }
+ else
+ {
+ multiple_values_found= TRUE; /* We have to make an JSON array. */
+ if (str->append("[", 1) ||
+ str->append(first_value, first_len))
+ goto error; /* Out of memory. */
+ }
+
+ }
+ if (str->append(", ", 2) ||
+ str->append((const char *) value, v_len))
+ goto error; /* Out of memory. */
+ }
+
+ if (first_value == NULL)
+ {
+ /* Nothing was found. */
+ null_value= 1;
+ return 0;
+ }
+
+ if (multiple_values_found ?
+ str->append("]") :
+ str->append(first_p_value, first_p_len))
+ goto error; /* Out of memory. */
+
+ return str;
+
+error:
+ /* TODO: launch error messages. */
+ null_value= 1;
+ return 0;
+}
+
+
+longlong Item_func_json_extract::val_int()
+{
+ String *js= args[0]->val_str(&tmp_js);
+ json_engine_t je;
+ uint n_arg;
+ uint array_counters[JSON_DEPTH_LIMIT];
+
+ if ((null_value= args[0]->null_value))
+ return 0;
+
+ for (n_arg=1; n_arg < arg_count; n_arg++)
+ {
+ json_path_with_flags *c_path= paths + n_arg - 1;
+ if (!c_path->parsed)
+ {
+ String *s_p= args[n_arg]->val_str(tmp_paths+(n_arg-1));
+ if (s_p &&
+ json_path_setup(&c_path->p,s_p->charset(),(const uchar *) s_p->ptr(),
+ (const uchar *) s_p->ptr() + s_p->length()))
+ goto error;
+ c_path->parsed= c_path->constant;
+ }
+
+ json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
+ (const uchar *) js->ptr() + js->length());
+
+ c_path->cur_step= c_path->p.steps;
+
+ if (json_find_path(&je, &c_path->p, &c_path->cur_step, array_counters))
+ {
+ /* Path wasn't found. */
+ if (je.s.error)
+ goto error;
+
+ continue;
+ }
+
+ if (json_read_value(&je))
+ goto error;
+
+ if (json_value_scalar(&je))
+ {
+ int err;
+ char *v_end= (char *) je.value_end;
+ return (je.s.cs->cset->strtoll10)(je.s.cs, (const char *) je.value_begin,
+ &v_end, &err);
+ }
+ else
+ break;
+ }
+
+ /* Nothing was found. */
+ null_value= 1;
+ return 0;
+
+error:
+ /* TODO: launch error messages. */
+ null_value= 1;
+ return 0;
+}
+
+
+bool Item_func_json_contains::fix_fields(THD *thd, Item **ref)
+{
+ return alloc_tmp_paths(thd, arg_count-2, &paths, &tmp_paths) ||
+ Item_int_func::fix_fields(thd, ref);
+}
+
+
+void Item_func_json_contains::fix_length_and_dec()
+{
+ a2_constant= args[1]->const_item();
+ a2_parsed= FALSE;
+ mark_constant_paths(paths, args+2, arg_count-2);
+ Item_int_func::fix_length_and_dec();
+}
+
+
+void Item_func_json_contains::cleanup()
+{
+ if (tmp_paths)
+ {
+ for (uint i= arg_count-2; i>0; i--)
+ tmp_paths[i-1].free();
+ tmp_paths= 0;
+ }
+ Item_int_func::cleanup();
+}
+
+
+longlong Item_func_json_contains::val_int()
+{
+ String *js= args[0]->val_str(&tmp_js);
+ json_engine_t je;
+ uint n_arg;
+
+ if ((null_value= args[0]->null_value))
+ return 0;
+
+ if (!a2_parsed)
+ {
+ val= args[1]->val_str(&tmp_val);
+ a2_parsed= a2_constant;
+ }
+
+ if (val == 0)
+ {
+ null_value= 1;
+ return 0;
+ }
+
+ json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
+ (const uchar *) js->ptr() + js->length());
+
+ if (arg_count<3) /* No path specified. */
+ {
+ if (json_read_value(&je))
+ goto error;
+ String jv_str((const char *)je.value_begin,
+ je.value_end - je.value_begin, js->charset());
+ return val->eq(&jv_str, js->charset());
+ }
+
+ for (n_arg=2; n_arg < arg_count; n_arg++)
+ {
+ uint array_counters[JSON_DEPTH_LIMIT];
+ json_path_with_flags *c_path= paths + n_arg - 2;
+ if (!c_path->parsed)
+ {
+ String *s_p= args[n_arg]->val_str(tmp_paths+(n_arg-2));
+ if (s_p &&
+ json_path_setup(&c_path->p,s_p->charset(),(const uchar *) s_p->ptr(),
+ (const uchar *) s_p->ptr() + s_p->length()))
+ goto error;
+ c_path->parsed= c_path->constant;
+ }
+
+ json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
+ (const uchar *) js->ptr() + js->length());
+
+ c_path->cur_step= c_path->p.steps;
+ if (json_find_path(&je, &c_path->p, &c_path->cur_step, array_counters))
+ {
+ /* Path wasn't found. */
+ if (je.s.error)
+ goto error;
+ continue;
+ }
+
+ if (json_read_value(&je))
+ goto error;
+ String jv_str((const char *)je.value_begin,
+ je.value_end - je.value_begin, js->charset());
+ if (val->eq(&jv_str, js->charset()))
+ return 1;
+ }
+
+
+ return 0;
+
+error:
+ null_value= 1;
+ return 0;
+}
+
+
+bool Item_func_json_contains_path::fix_fields(THD *thd, Item **ref)
+{
+ return alloc_tmp_paths(thd, arg_count-2, &paths, &tmp_paths) ||
+ Item_int_func::fix_fields(thd, ref);
+}
+
+
+void Item_func_json_contains_path::fix_length_and_dec()
+{
+ ooa_constant= args[1]->const_item();
+ ooa_parsed= FALSE;
+ mark_constant_paths(paths, args+2, arg_count-2);
+ Item_int_func::fix_length_and_dec();
+}
+
+
+void Item_func_json_contains_path::cleanup()
+{
+ if (tmp_paths)
+ {
+ for (uint i= arg_count-2; i>0; i--)
+ tmp_paths[i-1].free();
+ tmp_paths= 0;
+ }
+ Item_int_func::cleanup();
+}
+
+
+longlong Item_func_json_contains_path::val_int()
+{
+ String *js= args[0]->val_str(&tmp_js);
+ json_engine_t je;
+ uint n_arg;
+ longlong result;
+
+ if ((null_value= args[0]->null_value))
+ return 0;
+
+ if (!ooa_parsed)
+ {
+ char buff[20];
+ String *res, tmp(buff, sizeof(buff), &my_charset_bin);
+ res= args[1]->val_str(&tmp);
+ mode_one=eq_ascii_string(res->charset(), "one",
+ res->ptr(), res->length());
+ if (!mode_one)
+ {
+ if (!eq_ascii_string(res->charset(), "all", res->ptr(), res->length()))
+ goto error;
+ }
+ ooa_parsed= ooa_constant;
+ }
+
+ result= !mode_one;
+ for (n_arg=2; n_arg < arg_count; n_arg++)
+ {
+ uint array_counters[JSON_DEPTH_LIMIT];
+ json_path_with_flags *c_path= paths + n_arg - 2;
+ if (!c_path->parsed)
+ {
+ String *s_p= args[n_arg]->val_str(tmp_paths+(n_arg-2));
+ if (s_p &&
+ json_path_setup(&c_path->p,s_p->charset(),(const uchar *) s_p->ptr(),
+ (const uchar *) s_p->ptr() + s_p->length()))
+ goto error;
+ c_path->parsed= c_path->constant;
+ }
+
+ json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
+ (const uchar *) js->ptr() + js->length());
+
+ c_path->cur_step= c_path->p.steps;
+ if (json_find_path(&je, &c_path->p, &c_path->cur_step, array_counters))
+ {
+ /* Path wasn't found. */
+ if (je.s.error)
+ goto error;
+
+ if (!mode_one)
+ {
+ result= 0;
+ break;
+ }
+ }
+ else if (mode_one)
+ {
+ result= 1;
+ break;
+ }
+ }
+
+
+ return result;
+
+error:
+ null_value= 1;
+ return 0;
+}
+
+
+static int append_json_value(String *str, Item *item, String *tmp_val)
+{
+ if (item->is_bool_type())
+ {
+ longlong v_int= item->val_int();
+ const char *t_f;
+ int t_f_len;
+
+ if (item->null_value)
+ goto append_null;
+
+ if (v_int)
+ {
+ t_f= "true";
+ t_f_len= 4;
+ }
+ else
+ {
+ t_f= "false";
+ t_f_len= 5;
+ }
+
+ return str->append(t_f, t_f_len);
+ }
+ {
+ String *sv= item->val_str(tmp_val);
+ if (item->null_value)
+ goto append_null;
+ if (item->result_type() == STRING_RESULT)
+ {
+ return str->append("\"", 1) ||
+ st_append_escaped(str, sv) ||
+ str->append("\"", 1);
+ }
+ return st_append_escaped(str, sv);
+ }
+
+append_null:
+ return str->append("null", 4);
+}
+
+
+static int append_json_keyname(String *str, Item *item, String *tmp_val)
+{
+ String *sv= item->val_str(tmp_val);
+ if (item->null_value)
+ goto append_null;
+
+ return str->append("\"", 1) ||
+ st_append_escaped(str, sv) ||
+ str->append("\": ", 3);
+
+append_null:
+ return str->append("\"\": ", 4);
+}
+
+
+void Item_func_json_array::fix_length_and_dec()
+{
+ ulonglong char_length= 4;
+ uint n_arg;
+
+ if (agg_arg_charsets_for_string_result(collation, args, arg_count))
+ return;
+
+ for (n_arg=0 ; n_arg < arg_count ; n_arg++)
+ char_length+= args[n_arg]->max_char_length() + 2;
+
+ fix_char_length_ulonglong(char_length);
+ tmp_val.set_charset(collation.collation);
+}
+
+
+String *Item_func_json_array::val_str(String *str)
+{
+ DBUG_ASSERT(fixed == 1);
+ uint n_arg;
+
+ str->length(0);
+
+ if (str->append("[", 1) ||
+ ((arg_count > 0) && append_json_value(str, args[0],&tmp_val)))
+ goto err_return;
+
+ for (n_arg=1; n_arg < arg_count; n_arg++)
+ {
+ if (str->append(", ", 2) ||
+ append_json_value(str, args[n_arg], &tmp_val))
+ goto err_return;
+ }
+
+ if (str->append("]", 1))
+ goto err_return;
+
+ return str;
+
+err_return:
+ /*TODO: Launch out of memory error. */
+ null_value= 1;
+ return NULL;
+}
+
+
+void Item_func_json_array_append::fix_length_and_dec()
+{
+ uint n_arg;
+ ulonglong char_length;
+
+ collation.set(args[0]->collation);
+ char_length= args[0]->max_char_length();
+
+ for (n_arg= 1; n_arg < arg_count; n_arg+= 2)
+ {
+ paths[n_arg-1].set_constant_flag(args[n_arg]->const_item());
+ char_length+= args[n_arg+1]->max_char_length() + 4;
+ }
+
+ fix_char_length_ulonglong(char_length);
+}
+
+
+String *Item_func_json_array_append::val_str(String *str)
+{
+ json_engine_t je;
+ String *js= args[0]->val_str(&tmp_js);
+ uint n_arg, n_path, str_rest_len;
+ const uchar *ar_end;
+
+ DBUG_ASSERT(fixed == 1);
+
+ if ((null_value= args[0]->null_value))
+ return 0;
+
+ for (n_arg=1, n_path=0; n_arg < arg_count; n_arg+=2, n_path++)
+ {
+ uint array_counters[JSON_DEPTH_LIMIT];
+ json_path_with_flags *c_path= paths + n_path;
+ if (!c_path->parsed)
+ {
+ String *s_p= args[n_arg]->val_str(tmp_paths+n_path);
+ if (s_p &&
+ json_path_setup(&c_path->p,s_p->charset(),(const uchar *) s_p->ptr(),
+ (const uchar *) s_p->ptr() + s_p->length()))
+ goto error;
+ c_path->parsed= c_path->constant;
+ }
+ if (args[n_arg]->null_value)
+ {
+ null_value= 1;
+ return 0;
+ }
+
+ json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
+ (const uchar *) js->ptr() + js->length());
+
+ c_path->cur_step= c_path->p.steps;
+
+ if (json_find_path(&je, &c_path->p, &c_path->cur_step, array_counters))
+ {
+ if (je.s.error)
+ goto error;
+ null_value= 1;
+ return 0;
+ }
+
+ if (json_read_value(&je))
+ goto error;
+
+ if (je.value_type != JSON_VALUE_ARRAY)
+ {
+ /* Must be an array. */
+ goto error;
+ }
+
+ if (json_skip_level(&je))
+ goto error;
+
+ str->length(0);
+ str->set_charset(js->charset());
+ if (str->reserve(js->length() + 8, 1024))
+ goto error; /* Out of memory. */
+ ar_end= je.s.c_str - je.sav_c_len;
+ str_rest_len= js->length() - (ar_end - (const uchar *) js->ptr());
+ str->q_append(js->ptr(), ar_end-(const uchar *) js->ptr());
+ str->append(", ", 2);
+ if (append_json_value(str, args[n_arg+1], &tmp_val))
+ goto error; /* Out of memory. */
+
+ if (str->reserve(str_rest_len, 1024))
+ goto error; /* Out of memory. */
+ str->q_append((const char *) ar_end, str_rest_len);
+ }
+
+ return str;
+
+error:
+ null_value= 1;
+ return 0;
+}
+
+
+String *Item_func_json_object::val_str(String *str)
+{
+ DBUG_ASSERT(fixed == 1);
+ uint n_arg;
+
+ str->length(0);
+
+ if (str->append("{", 1) ||
+ (arg_count > 0 &&
+ (append_json_keyname(str, args[0], &tmp_val) ||
+ append_json_value(str, args[1], &tmp_val))))
+ goto err_return;
+
+ for (n_arg=2; n_arg < arg_count; n_arg+=2)
+ {
+ if (str->append(", ", 2) ||
+ append_json_keyname(str, args[n_arg], &tmp_val) ||
+ append_json_value(str, args[n_arg+1], &tmp_val))
+ goto err_return;
+ }
+
+ if (str->append("}", 1))
+ goto err_return;
+
+ return str;
+
+err_return:
+ /*TODO: Launch out of memory error. */
+ null_value= 1;
+ return NULL;
+}
+
+
+String *Item_func_json_merge::val_str(String *str)
+{
+ DBUG_ASSERT(fixed == 1);
+ uint n_arg;
+
+ str->length(0);
+
+ if (str->append("[", 1) ||
+ ((arg_count > 0) && append_json_value(str, args[0], &tmp_val)))
+ goto err_return;
+
+ for (n_arg=1; n_arg < arg_count; n_arg++)
+ {
+ if (str->append(", ", 2) ||
+ append_json_value(str, args[n_arg], &tmp_val))
+ goto err_return;
+ }
+
+ if (str->append("]", 1))
+ goto err_return;
+
+ return str;
+
+err_return:
+ /*TODO: Launch out of memory error. */
+ null_value= 1;
+ return NULL;
+}
+
+
+longlong Item_func_json_length::val_int()
+{
+ String *js= args[0]->val_str(&tmp_js);
+ json_engine_t je;
+ uint length= 0;
+
+ if ((null_value= args[0]->null_value))
+ return 0;
+
+
+ json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
+ (const uchar *) js->ptr() + js->length());
+
+ do
+ {
+ if (je.state == JST_VALUE)
+ length++;
+ } while (json_scan_next(&je) == 0);
+
+ if (je.s.error)
+ {
+ null_value= 1;
+ return 0;
+ }
+
+ return length;
+
+}
+
+
+longlong Item_func_json_depth::val_int()
+{
+ String *js= args[0]->val_str(&tmp_js);
+ json_engine_t je;
+ uint depth= 0;
+ bool inc_depth= TRUE;
+
+ if ((null_value= args[0]->null_value))
+ return 0;
+
+
+ json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
+ (const uchar *) js->ptr() + js->length());
+
+ do
+ {
+ switch (je.state)
+ {
+ case JST_VALUE:
+ if (inc_depth)
+ {
+ depth++;
+ inc_depth= FALSE;
+ }
+ break;
+ case JST_OBJ_START:
+ case JST_ARRAY_START:
+ inc_depth= TRUE;
+ break;
+ default:
+ break;
+ }
+ } while (json_scan_next(&je) == 0);
+
+ if (je.s.error)
+ {
+ null_value= 1;
+ return 0;
+ }
+
+ return depth;
+}
+
+
+void Item_func_json_type::fix_length_and_dec()
+{
+ collation.set(&my_charset_utf8_general_ci);
+ max_length= 12;
+}
+
+
+String *Item_func_json_type::val_str(String *str)
+{
+ String *js= args[0]->val_str(&tmp_js);
+ json_engine_t je;
+ const char *type;
+
+ if ((null_value= args[0]->null_value))
+ return 0;
+
+
+ json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
+ (const uchar *) js->ptr() + js->length());
+
+ if (json_read_value(&je))
+ goto error;
+
+ switch (je.value_type)
+ {
+ case JSON_VALUE_OBJECT:
+ type= "OBJECT";
+ break;
+ case JSON_VALUE_ARRAY:
+ type= "ARRAY";
+ break;
+ case JSON_VALUE_STRING:
+ type= "STRING";
+ break;
+ case JSON_VALUE_NUMBER:
+ type= "NUMBER";
+ break;
+ case JSON_VALUE_TRUE:
+ case JSON_VALUE_FALSE:
+ type= "BOOLEAN";
+ break;
+ default:
+ type= "NULL";
+ break;
+ }
+
+ str->set(type, strlen(type), &my_charset_utf8_general_ci);
+ return str;
+
+error:
+ null_value= 1;
+ return 0;
+}
+
+
diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h
new file mode 100644
index 00000000000..54da67b5ab9
--- /dev/null
+++ b/sql/item_jsonfunc.h
@@ -0,0 +1,304 @@
+#ifndef ITEM_JSONFUNC_INCLUDED
+#define ITEM_JSONFUNC_INCLUDED
+
+/* Copyright (c) 2016, MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+
+/* This file defines all JSON functions */
+
+
+#include <json_lib.h>
+#include "item_cmpfunc.h" // Item_bool_func
+#include "item_strfunc.h" // Item_str_func
+
+
+class json_path_with_flags
+{
+public:
+ json_path_t p;
+ bool constant;
+ bool parsed;
+ json_path_step_t *cur_step;
+ void set_constant_flag(bool s_constant)
+ {
+ constant= s_constant;
+ parsed= FALSE;
+ }
+};
+
+
+class Item_func_json_valid: public Item_int_func
+{
+protected:
+ String tmp_value;
+
+public:
+ Item_func_json_valid(THD *thd, Item *json) : Item_int_func(thd, json) {}
+ longlong val_int();
+ const char *func_name() const { return "json_valid"; }
+ void fix_length_and_dec()
+ {
+ Item_int_func::fix_length_and_dec();
+ maybe_null= 1;
+ }
+ bool is_bool_type() { return true; }
+ Item *get_copy(THD *thd, MEM_ROOT *mem_root)
+ { return get_item_copy<Item_func_json_valid>(thd, mem_root, this); }
+};
+
+
+class Item_func_json_exists: public Item_int_func
+{
+protected:
+ json_path_with_flags path;
+ String tmp_js, tmp_path;
+
+public:
+ Item_func_json_exists(THD *thd, Item *js, Item *path):
+ Item_int_func(thd, js, path) {}
+ const char *func_name() const { return "json_exists"; }
+ bool is_bool_type() { return true; }
+ void fix_length_and_dec();
+ Item *get_copy(THD *thd, MEM_ROOT *mem_root)
+ { return get_item_copy<Item_func_json_exists>(thd, mem_root, this); }
+ longlong val_int();
+};
+
+
+class Item_func_json_value: public Item_str_func
+{
+protected:
+ json_path_with_flags path;
+ String tmp_js, tmp_path;
+
+public:
+ Item_func_json_value(THD *thd, Item *js, Item *path):
+ Item_str_func(thd, js, path) {}
+ const char *func_name() const { return "json_value"; }
+ void fix_length_and_dec();
+ String *val_str(String *);
+ virtual bool check_and_get_value(json_engine_t *je, String *res, int *error);
+ Item *get_copy(THD *thd, MEM_ROOT *mem_root)
+ { return get_item_copy<Item_func_json_value>(thd, mem_root, this); }
+};
+
+
+class Item_func_json_query: public Item_func_json_value
+{
+public:
+ Item_func_json_query(THD *thd, Item *js, Item *path):
+ Item_func_json_value(thd, js, path) {}
+ const char *func_name() const { return "json_query"; }
+ bool check_and_get_value(json_engine_t *je, String *res, int *error);
+ Item *get_copy(THD *thd, MEM_ROOT *mem_root)
+ { return get_item_copy<Item_func_json_query>(thd, mem_root, this); }
+};
+
+
+class Item_func_json_quote: public Item_str_func
+{
+protected:
+ String tmp_s;
+
+public:
+ Item_func_json_quote(THD *thd, Item *s): Item_str_func(thd, s) {}
+ const char *func_name() const { return "json_quote"; }
+ void fix_length_and_dec();
+ String *val_str(String *);
+ Item *get_copy(THD *thd, MEM_ROOT *mem_root)
+ { return get_item_copy<Item_func_json_quote>(thd, mem_root, this); }
+};
+
+
+class Item_json_str_multipath: public Item_str_func
+{
+protected:
+ json_path_with_flags *paths;
+ String *tmp_paths;
+public:
+ Item_json_str_multipath(THD *thd, List<Item> &list):
+ Item_str_func(thd, list), tmp_paths(0) {}
+ bool fix_fields(THD *thd, Item **ref);
+ void cleanup();
+ virtual uint get_n_paths() const = 0;
+};
+
+
+class Item_func_json_extract: public Item_json_str_multipath
+{
+protected:
+ String tmp_js;
+public:
+ Item_func_json_extract(THD *thd, List<Item> &list):
+ Item_json_str_multipath(thd, list) {}
+ const char *func_name() const { return "json_extract"; }
+ void fix_length_and_dec();
+ String *val_str(String *);
+ longlong val_int();
+ uint get_n_paths() const { return arg_count - 1; }
+ Item *get_copy(THD *thd, MEM_ROOT *mem_root)
+ { return get_item_copy<Item_func_json_extract>(thd, mem_root, this); }
+};
+
+
+class Item_func_json_contains: public Item_int_func
+{
+protected:
+ String tmp_js;
+ json_path_with_flags *paths;
+ String *tmp_paths;
+ bool a2_constant, a2_parsed;
+ String tmp_val, *val;
+public:
+ Item_func_json_contains(THD *thd, List<Item> &list):
+ Item_int_func(thd, list), tmp_paths(0) {}
+ const char *func_name() const { return "json_contains"; }
+ bool fix_fields(THD *thd, Item **ref);
+ void fix_length_and_dec();
+ void cleanup();
+ longlong val_int();
+ Item *get_copy(THD *thd, MEM_ROOT *mem_root)
+ { return get_item_copy<Item_func_json_contains>(thd, mem_root, this); }
+};
+
+
+class Item_func_json_contains_path: public Item_int_func
+{
+protected:
+ String tmp_js;
+ json_path_with_flags *paths;
+ String *tmp_paths;
+ bool mode_one;
+ bool ooa_constant, ooa_parsed;
+
+public:
+ Item_func_json_contains_path(THD *thd, List<Item> &list):
+ Item_int_func(thd, list), tmp_paths(0) {}
+ const char *func_name() const { return "json_contains_path"; }
+ bool fix_fields(THD *thd, Item **ref);
+ void fix_length_and_dec();
+ void cleanup();
+ longlong val_int();
+ Item *get_copy(THD *thd, MEM_ROOT *mem_root)
+ { return get_item_copy<Item_func_json_contains_path>(thd, mem_root, this); }
+};
+
+
+class Item_func_json_array: public Item_str_func
+{
+protected:
+ String tmp_val;
+public:
+ Item_func_json_array(THD *thd):
+ Item_str_func(thd) {}
+ Item_func_json_array(THD *thd, List<Item> &list):
+ Item_str_func(thd, list) {}
+ String *val_str(String *);
+ void fix_length_and_dec();
+ const char *func_name() const { return "json_array"; }
+ Item *get_copy(THD *thd, MEM_ROOT *mem_root)
+ { return get_item_copy<Item_func_json_array>(thd, mem_root, this); }
+};
+
+
+class Item_func_json_array_append: public Item_json_str_multipath
+{
+protected:
+ String tmp_js;
+ String tmp_val;
+public:
+ Item_func_json_array_append(THD *thd, List<Item> &list):
+ Item_json_str_multipath(thd, list) {}
+ void fix_length_and_dec();
+ String *val_str(String *);
+ uint get_n_paths() const { return arg_count/2; }
+ const char *func_name() const { return "json_array_append"; }
+ Item *get_copy(THD *thd, MEM_ROOT *mem_root)
+ { return get_item_copy<Item_func_json_array_append>(thd, mem_root, this); }
+};
+
+
+class Item_func_json_object: public Item_func_json_array
+{
+public:
+ Item_func_json_object(THD *thd):
+ Item_func_json_array(thd) {}
+ Item_func_json_object(THD *thd, List<Item> &list):
+ Item_func_json_array(thd, list) {}
+ String *val_str(String *);
+ const char *func_name() const { return "json_object"; }
+ Item *get_copy(THD *thd, MEM_ROOT *mem_root)
+ { return get_item_copy<Item_func_json_object>(thd, mem_root, this); }
+};
+
+
+class Item_func_json_merge: public Item_func_json_array
+{
+protected:
+ String tmp_val;
+public:
+ Item_func_json_merge(THD *thd, List<Item> &list):
+ Item_func_json_array(thd, list) {}
+ String *val_str(String *);
+ const char *func_name() const { return "json_merge"; }
+ Item *get_copy(THD *thd, MEM_ROOT *mem_root)
+ { return get_item_copy<Item_func_json_merge>(thd, mem_root, this); }
+};
+
+
+class Item_func_json_length: public Item_int_func
+{
+protected:
+ String tmp_js;
+ String tmp_path;
+public:
+ Item_func_json_length(THD *thd, List<Item> &list):
+ Item_int_func(thd, list) {}
+ const char *func_name() const { return "json_length"; }
+ longlong val_int();
+ Item *get_copy(THD *thd, MEM_ROOT *mem_root)
+ { return get_item_copy<Item_func_json_length>(thd, mem_root, this); }
+};
+
+
+class Item_func_json_depth: public Item_int_func
+{
+protected:
+ String tmp_js;
+public:
+ Item_func_json_depth(THD *thd, Item *js): Item_int_func(thd, js) {}
+ const char *func_name() const { return "json_depth"; }
+ longlong val_int();
+ Item *get_copy(THD *thd, MEM_ROOT *mem_root)
+ { return get_item_copy<Item_func_json_depth>(thd, mem_root, this); }
+};
+
+
+class Item_func_json_type: public Item_str_func
+{
+protected:
+ String tmp_js;
+public:
+ Item_func_json_type(THD *thd, Item *js): Item_str_func(thd, js) {}
+ const char *func_name() const { return "json_type"; }
+ void fix_length_and_dec();
+ String *val_str(String *);
+ Item *get_copy(THD *thd, MEM_ROOT *mem_root)
+ { return get_item_copy<Item_func_json_type>(thd, mem_root, this); }
+};
+
+
+#endif /* ITEM_JSONFUNC_INCLUDED */
diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc
index cbbdeea0205..4d848a0f737 100644
--- a/sql/item_xmlfunc.cc
+++ b/sql/item_xmlfunc.cc
@@ -13,10 +13,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
-#ifdef __GNUC__
-#pragma implementation
-#endif
-
#include <my_global.h>
#include "sql_priv.h"
/*
@@ -407,19 +403,6 @@ public:
/*
- We need to distinguish a number from a boolean:
- a[1] and a[true] are different things in XPath.
-*/
-class Item_bool :public Item_int
-{
-public:
- Item_bool(THD *thd, int32 i): Item_int(thd, i) {}
- const char *func_name() const { return "xpath_bool"; }
- bool is_bool_type() { return true; }
-};
-
-
-/*
Converts its argument into a boolean value.
* a number is true if it is non-zero
* a node-set is true if and only if it is non-empty
@@ -1214,13 +1197,13 @@ my_xpath_keyword(MY_XPATH *x,
static Item *create_func_true(MY_XPATH *xpath, Item **args, uint nargs)
{
- return new (xpath->thd->mem_root) Item_bool(xpath->thd, 1);
+ return new (xpath->thd->mem_root) Item_bool(xpath->thd, "xpath_bool", 1);
}
static Item *create_func_false(MY_XPATH *xpath, Item **args, uint nargs)
{
- return new (xpath->thd->mem_root) Item_bool(xpath->thd, 0);
+ return new (xpath->thd->mem_root) Item_bool(xpath->thd, "xpath_bool", 0);
}
diff --git a/sql/item_xmlfunc.h b/sql/item_xmlfunc.h
index 3c58955c96a..3c071b897e2 100644
--- a/sql/item_xmlfunc.h
+++ b/sql/item_xmlfunc.h
@@ -21,11 +21,6 @@
/* This file defines all XML functions */
-#ifdef USE_PRAGMA_INTERFACE
-#pragma interface /* gcc class implementation */
-#endif
-
-
typedef struct my_xml_node_st MY_XML_NODE;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 6a03f58c3b1..e17a514a391 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -13869,13 +13869,13 @@ literal:
}
| FALSE_SYM
{
- $$= new (thd->mem_root) Item_int(thd, (char*) "FALSE",0,1);
+ $$= new (thd->mem_root) Item_bool(thd, (char*) "FALSE",0);
if ($$ == NULL)
MYSQL_YYABORT;
}
| TRUE_SYM
{
- $$= new (thd->mem_root) Item_int(thd, (char*) "TRUE",1,1);
+ $$= new (thd->mem_root) Item_bool(thd, (char*) "TRUE",1);
if ($$ == NULL)
MYSQL_YYABORT;
}