Commit 27025221 authored by Alexey Botchkov's avatar Alexey Botchkov

MDEV-9143 JSON_xxx functions.

        strings/json_lib.c added as a JSON library.
        SQL frunction added with sql/item_jsonfunc.h/cc
parent 8303aded
......@@ -356,6 +356,7 @@ IF(WITH_UNIT_TESTS)
ADD_SUBDIRECTORY(unittest/examples)
ADD_SUBDIRECTORY(unittest/mysys)
ADD_SUBDIRECTORY(unittest/my_decimal)
ADD_SUBDIRECTORY(unittest/json_lib)
IF(NOT WITHOUT_SERVER)
ADD_SUBDIRECTORY(unittest/sql)
ENDIF()
......
......@@ -61,6 +61,7 @@ SET(HEADERS
my_compiler.h
handler_state.h
handler_ername.h
json_lib.h
)
INSTALL(FILES ${HEADERS} DESTINATION ${INSTALL_INCLUDEDIR} COMPONENT Development)
......
This diff is collapsed.
......@@ -50,7 +50,8 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
../sql/item.cc ../sql/item_create.cc ../sql/item_func.cc
../sql/item_geofunc.cc ../sql/item_row.cc ../sql/item_strfunc.cc
../sql/item_subselect.cc ../sql/item_sum.cc ../sql/item_timefunc.cc
../sql/item_xmlfunc.cc ../sql/key.cc ../sql/lock.cc ../sql/log.cc
../sql/item_xmlfunc.cc ../sql/item_jsonfunc.cc
../sql/key.cc ../sql/lock.cc ../sql/log.cc
../sql/log_event.cc ../sql/mf_iocache.cc ../sql/my_decimal.cc
../sql/net_serv.cc ../sql/opt_range.cc ../sql/opt_sum.cc
../sql/parse_file.cc ../sql/procedure.cc ../sql/protocol.cc
......
select json_valid('[1, 2]');
json_valid('[1, 2]')
1
select json_valid('"string"}');
json_valid('"string"}')
0
select json_valid('{"key1":1, "key2":[2,3]}');
json_valid('{"key1":1, "key2":[2,3]}')
1
select json_valid('[false, true, null]');
json_valid('[false, true, null]')
1
select json_value('{"key1":123}', '$.key2');
json_value('{"key1":123}', '$.key2')
NULL
select json_value('{"key1":123}', '$.key1');
json_value('{"key1":123}', '$.key1')
123
select json_value('{"key1":[1,2,3]}', '$.key1');
json_value('{"key1":[1,2,3]}', '$.key1')
NULL
select json_value('{"key1": [1,2,3], "key1":123}', '$.key1');
json_value('{"key1": [1,2,3], "key1":123}', '$.key1')
123
select json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key2');
json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key2')
NULL
select json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key1');
json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key1')
{"a":1, "b":[1,2]}
select json_query('{"key1": 1}', '$.key1');
json_query('{"key1": 1}', '$.key1')
NULL
select json_query('{"key1":123, "key1": [1,2,3]}', '$.key1');
json_query('{"key1":123, "key1": [1,2,3]}', '$.key1')
[1,2,3]
select json_array(1);
json_array(1)
[1]
select json_array(1, "text", false, null);
json_array(1, "text", false, null)
[1, "text", false, null]
select json_array_append('["a", "b"]', '$', FALSE);
json_array_append('["a", "b"]', '$', FALSE)
["a", "b", false]
select json_array_append('{"k1":1, "k2":["a", "b"]}', '$.k2', 2);
json_array_append('{"k1":1, "k2":["a", "b"]}', '$.k2', 2)
{"k1":1, "k2":["a", "b", 2]}
select json_contains('{"k1":123, "k2":345}', '123', '$.k1');
json_contains('{"k1":123, "k2":345}', '123', '$.k1')
1
select json_contains('"you"', '"you"');
json_contains('"you"', '"you"')
1
select json_contains('"youth"', '"you"');
json_contains('"youth"', '"you"')
0
select json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[1]");
json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[1]")
1
select json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[10]");
json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[10]")
0
select json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.ma");
json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.ma")
0
select json_contains_path('{"key1":1, "key2":[2,3]}', "one", "$.key1");
json_contains_path('{"key1":1, "key2":[2,3]}', "one", "$.key1")
1
select json_contains_path('{"key1":1, "key2":[2,3]}', "one", "$.key1", "$.ma");
json_contains_path('{"key1":1, "key2":[2,3]}', "one", "$.key1", "$.ma")
1
select json_contains_path('{"key1":1, "key2":[2,3]}', "aLl", "$.key1", "$.ma");
json_contains_path('{"key1":1, "key2":[2,3]}', "aLl", "$.key1", "$.ma")
0
select json_contains_path('{"key1":1, "key2":[2,3]}', "aLl", "$.key1", "$.key2");
json_contains_path('{"key1":1, "key2":[2,3]}', "aLl", "$.key1", "$.key2")
1
select json_extract('{"key1":"asd", "key2":[2,3]}', "$.key1");
json_extract('{"key1":"asd", "key2":[2,3]}', "$.key1")
asd
select json_extract('{"key1":"asd", "key2":[2,3]}', "$.keyX", "$.keyY");
json_extract('{"key1":"asd", "key2":[2,3]}', "$.keyX", "$.keyY")
NULL
select json_extract('{"key1":"asd", "key2":[2,3]}', "$.key1", "$.key2");
json_extract('{"key1":"asd", "key2":[2,3]}', "$.key1", "$.key2")
["asd", [2,3]]
select json_extract('{"key1":5, "key2":[2,3]}', "$.key1", "$.key2");
json_extract('{"key1":5, "key2":[2,3]}', "$.key1", "$.key2")
[5, [2,3]]
select json_extract('{"key0":true, "key1":"qwe"}', "$.key1");
json_extract('{"key0":true, "key1":"qwe"}', "$.key1")
qwe
select json_object("ki", 1, "mi", "ya");
json_object("ki", 1, "mi", "ya")
{"ki": 1, "mi": "ya"}
select json_exists('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2");
json_exists('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2")
1
select json_exists('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[1]");
json_exists('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[1]")
1
select json_exists('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[10]");
json_exists('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[10]")
0
select json_quote('"string"');
json_quote('"string"')
\"string\"
select json_merge('string', 123);
json_merge('string', 123)
["string", 123]
select json_type('{"k1":123, "k2":345}');
json_type('{"k1":123, "k2":345}')
OBJECT
select json_type('[123, "k2", 345]');
json_type('[123, "k2", 345]')
ARRAY
select json_type("true");
json_type("true")
BOOLEAN
select json_type('123');
json_type('123')
NUMBER
......@@ -369,7 +369,7 @@ select (NOT FALSE) AND FALSE, NOT (FALSE AND FALSE), NOT FALSE AND FALSE;
0 1 0
Testing that NOT is associative
select NOT NOT TRUE, NOT NOT NOT FALSE;
NOT NOT TRUE NOT NOT NOT FALSE
TRUE NOT NOT NOT FALSE
1 1
Testing that IS has precedence over NOT
select (NOT NULL) IS TRUE, NOT (NULL IS TRUE), NOT NULL IS TRUE;
......
select json_valid('[1, 2]');
select json_valid('"string"}');
select json_valid('{"key1":1, "key2":[2,3]}');
select json_valid('[false, true, null]');
select json_value('{"key1":123}', '$.key2');
select json_value('{"key1":123}', '$.key1');
select json_value('{"key1":[1,2,3]}', '$.key1');
select json_value('{"key1": [1,2,3], "key1":123}', '$.key1');
select json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key2');
select json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key1');
select json_query('{"key1": 1}', '$.key1');
select json_query('{"key1":123, "key1": [1,2,3]}', '$.key1');
select json_array(1);
select json_array(1, "text", false, null);
select json_array_append('["a", "b"]', '$', FALSE);
select json_array_append('{"k1":1, "k2":["a", "b"]}', '$.k2', 2);
select json_contains('{"k1":123, "k2":345}', '123', '$.k1');
select json_contains('"you"', '"you"');
select json_contains('"youth"', '"you"');
select json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[1]");
select json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.key2[10]");
select json_contains_path('{"key1":1, "key2":[2,3]}', "oNE", "$.ma");
select json_contains_path('{"key1":1, "key2":[2,3]}', "one", "$.key1");
select json_contains_path('{"key1":1, "key2":[2,3]}', "one", "$.key1", "$.ma");
select json_contains_path('{"key1":1, "key2":[2,3]}', "aLl", "$.key1", "$.ma");
select json_contains_path('{"key1":1, "key2":[2,3]}', "aLl", "$.key1", "$.key2");
select json_extract('{"key1":"asd", "key2":[2,3]}', "$.key1");
select json_extract('{"key1":"asd", "key2":[2,3]}', "$.keyX", "$.keyY");
select json_extract('{"key1":"asd", "key2":[2,3]}', "$.key1", "$.key2");
select json_extract('{"key1":5, "key2":[2,3]}', "$.key1", "$.key2");
select json_extract('{"key0":true, "key1":"qwe"}', "$.key1");
select json_object("ki", 1, "mi", "ya");
select json_exists('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2");
select json_exists('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[1]");
select json_exists('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[10]");
select json_quote('"string"');
select json_merge('string', 123);
select json_type('{"k1":123, "k2":345}');
select json_type('[123, "k2", 345]');
select json_type("true");
select json_type('123');
......@@ -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
......
......@@ -2997,6 +2997,20 @@ class Item_int :public Item_num
};
/*
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 @@ class Item_int_with_ref :public Item_int
#include "item_timefunc.h"
#include "item_subselect.h"
#include "item_xmlfunc.h"
#include "item_jsonfunc.h"
#include "item_create.h"
#endif
......
This diff is collapsed.
This diff is collapsed.
#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 */
......@@ -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"
/*
......@@ -406,19 +402,6 @@ class Item_nodeset_func_elementbyindex :public Item_nodeset_func
};
/*
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
......@@ -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);
}
......
......@@ -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;
......
......@@ -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;
}
......
......@@ -13,3 +13,5 @@ jdbc : Variable settings depend on machine configuration
jdbc_new : Variable settings depend on machine configuration
jdbc_oracle : Variable settings depend on machine configuration
jdbc_postgresql : Variable settings depend on machine configuration
json_udf : conflicts with the server JSON functions
json_udf_bin : conflicts with the server JSON functions
......@@ -23,7 +23,7 @@ SET(STRINGS_SOURCES bchange.c bmove_upp.c ctype-big5.c ctype-bin.c ctype-cp932.c
str2int.c str_alloc.c strcend.c strend.c strfill.c strmake.c strmov.c strnmov.c
strxmov.c strxnmov.c xml.c
strmov_overlapp.c
my_strchr.c strcont.c strappend.c)
my_strchr.c strcont.c strappend.c json_lib.c)
IF(NOT HAVE_STRNLEN)
# OSX below 10.7 did not have strnlen
......
......@@ -1190,10 +1190,13 @@ my_lengthsp_mb2(CHARSET_INFO *cs __attribute__((unused)),
#endif /* HAVE_CHARSET_mb2*/
/*
Next part is actually HAVE_CHARSET_utf16-specific,
but the JSON functions needed my_utf16_uni()
so the #ifdef was moved lower.
*/
#ifdef HAVE_CHARSET_utf16
/*
D800..DB7F - Non-provate surrogate high (896 pages)
DB80..DBFF - Private surrogate high (128 pages)
......@@ -1260,7 +1263,12 @@ static inline int my_weight_mb2_utf16mb2_general_ci(uchar b0, uchar b1)
#undef IS_MB2_CHAR
#undef IS_MB4_CHAR
static int
/*
These two functions are used in JSON library, so made exportable
and unconditionally compiled into the library.
*/
/*static*/ int
my_utf16_uni(CHARSET_INFO *cs __attribute__((unused)),
my_wc_t *pwc, const uchar *s, const uchar *e)
{
......@@ -1293,7 +1301,7 @@ my_utf16_uni(CHARSET_INFO *cs __attribute__((unused)),
}
static int
/*static*/ int
my_uni_utf16(CHARSET_INFO *cs __attribute__((unused)),
my_wc_t wc, uchar *s, uchar *e)
{
......@@ -1323,6 +1331,9 @@ my_uni_utf16(CHARSET_INFO *cs __attribute__((unused)),
}
#ifdef HAVE_CHARSET_utf16
static inline void
my_tolower_utf16(MY_UNICASE_INFO *uni_plane, my_wc_t *wc)
{
......
This diff is collapsed.
# Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
#
# 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_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/sql
${CMAKE_SOURCE_DIR}/regex
${CMAKE_SOURCE_DIR}/extra/yassl/include
${CMAKE_SOURCE_DIR}/unittest/mytap)
#
MY_ADD_TESTS(json_lib LINK_LIBRARIES strings dbug)
/* Copyright (c) 2016, MariaDB Corp. All rights reserved.
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_config.h"
#include "config.h"
#include <tap.h>
#include <my_global.h>
#include <my_sys.h>
#include <json_lib.h>
/* The character set used for JSON all over this test. */
static CHARSET_INFO *ci;
#define s_e(j) j, j + strlen((const char *) j)
struct st_parse_result
{
int n_keys;
int n_values;
int n_arrays;
int n_objects;
int n_steps;
int error;
uchar keyname_csum;
};
static void parse_json(const uchar *j, struct st_parse_result *result)
{
json_engine_t je;
bzero(result, sizeof(*result));
if (json_scan_start(&je, ci, s_e(j)))
return;
do
{
result->n_steps++;
switch (je.state)
{
case JST_KEY:
result->n_keys++;
while (json_read_keyname_chr(&je) == 0)
{
result->keyname_csum^= je.s.c_next;
}
if (je.s.error)
return;
break;
case JST_VALUE:
result->n_values++;
break;
case JST_OBJ_START:
result->n_objects++;
break;
case JST_ARRAY_START:
result->n_arrays++;
break;
default:
break;
};
} while (json_scan_next(&je) == 0);
result->error= je.s.error;
}
static const uchar *js0= (const uchar *) "123";
static const uchar *js1= (const uchar *) "[123, \"text\"]";
static const uchar *js2= (const uchar *) "{\"key1\":123, \"key2\":\"text\"}";
static const uchar *js3= (const uchar *) "{\"key1\":{\"ikey1\":321},"
"\"key2\":[\"text\", 321]}";
/*
Test json_lib functions to parse JSON.
*/
static void
test_json_parsing()
{
struct st_parse_result r;
parse_json(js0, &r);
ok(r.n_steps == 1 && r.n_values == 1, "simple value");
parse_json(js1, &r);
ok(r.n_steps == 5 && r.n_values == 3 && r.n_arrays == 1, "array");
parse_json(js2, &r);
ok(r.n_steps == 5 && r.n_keys == 2 && r.n_objects == 1 && r.keyname_csum == 3,
"object");
parse_json(js3, &r);
ok(r.n_steps == 12 && r.n_keys == 3 && r.n_objects == 2 &&
r.n_arrays == 1 && r.keyname_csum == 44,
"complex json");
}
static const uchar *p0= (const uchar *) "$.key1[12].*[*]";
/*
Test json_lib functions to parse JSON path.
*/
static void
test_path_parsing()
{
json_path_t p;
if (json_path_setup(&p, ci, s_e(p0)))
return;
ok(p.last_step - p.steps == 4 &&
p.steps[0].type == JSON_PATH_ARRAY && p.steps[0].wild == 1 &&
p.steps[1].type == JSON_PATH_KEY && p.steps[1].wild == 0 &&
p.steps[2].type == JSON_PATH_ARRAY && p.steps[2].n_item == 12 &&
p.steps[3].type == JSON_PATH_KEY && p.steps[3].wild == 1 &&
p.steps[4].type == JSON_PATH_ARRAY && p.steps[4].wild == 1,
"path");
}
static const uchar *fj0=(const uchar *) "[{\"k0\":123, \"k1\":123, \"k1\":123},"
" {\"k3\":321, \"k4\":\"text\"},"
" {\"k1\":[\"text\"], \"k2\":123}]";
static const uchar *fp0= (const uchar *) "$[*].k1";
/*
Test json_lib functions to search through JSON.
*/
static void
test_search()
{
json_engine_t je;
json_path_t p;
json_path_step_t *cur_step;
int n_matches, scal_values;
uint array_counters[JSON_DEPTH_LIMIT];
if (json_scan_start(&je, ci, s_e(fj0)) ||
json_path_setup(&p, ci, s_e(fp0)))
return;
cur_step= p.steps;
n_matches= scal_values= 0;
while (json_find_path(&je, &p, &cur_step, array_counters) == 0)
{
n_matches++;
if (json_read_value(&je))
return;
if (json_value_scalar(&je))
{
scal_values++;
if (json_scan_next(&je))
return;
}
else
{
if (json_skip_level(&je) || json_scan_next(&je))
return;
}
}
ok(n_matches == 3, "search");
}
int main()
{
ci= &my_charset_utf8_general_ci;
plan(6);
diag("Testing json_lib functions.");
test_json_parsing();
test_path_parsing();
test_search();
return exit_status();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment