diff options
author | Alexey Botchkov <holyfoot@askmonty.org> | 2016-10-19 14:10:03 +0400 |
---|---|---|
committer | Alexey Botchkov <holyfoot@askmonty.org> | 2016-10-19 14:10:03 +0400 |
commit | 27025221fe2ea17aa737ad2ad31011407c00dcc9 (patch) | |
tree | 0f5352944d26aceb427320756c90bde3b00f13a3 /sql | |
parent | 8303aded294ce905bbc513e7ee42623d5f1fdb50 (diff) | |
download | mariadb-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.txt | 2 | ||||
-rw-r--r-- | sql/item.h | 15 | ||||
-rw-r--r-- | sql/item_create.cc | 474 | ||||
-rw-r--r-- | sql/item_jsonfunc.cc | 1109 | ||||
-rw-r--r-- | sql/item_jsonfunc.h | 304 | ||||
-rw-r--r-- | sql/item_xmlfunc.cc | 21 | ||||
-rw-r--r-- | sql/item_xmlfunc.h | 5 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 4 |
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; } |