Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
ebe5ebba
Commit
ebe5ebba
authored
Nov 15, 2016
by
Alexey Botchkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MDEV-9143 JSON_xxx functions.
The rest of mysql/json functions implemented. CAST AS JSON implemented.
parent
1122c1f0
Changes
15
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
1619 additions
and
59 deletions
+1619
-59
include/json_lib.h
include/json_lib.h
+7
-0
mysql-test/r/dyncol.result
mysql-test/r/dyncol.result
+16
-16
mysql-test/r/func_json.result
mysql-test/r/func_json.result
+93
-0
mysql-test/t/dyncol.test
mysql-test/t/dyncol.test
+8
-8
mysql-test/t/func_json.test
mysql-test/t/func_json.test
+43
-0
sql/item.h
sql/item.h
+12
-0
sql/item_cmpfunc.cc
sql/item_cmpfunc.cc
+27
-15
sql/item_create.cc
sql/item_create.cc
+302
-0
sql/item_func.h
sql/item_func.h
+1
-1
sql/item_jsonfunc.cc
sql/item_jsonfunc.cc
+971
-14
sql/item_jsonfunc.h
sql/item_jsonfunc.h
+129
-0
sql/lex.h
sql/lex.h
+1
-0
sql/sql_yacc.yy
sql/sql_yacc.yy
+4
-3
storage/connect/mysql-test/connect/disabled.def
storage/connect/mysql-test/connect/disabled.def
+1
-0
strings/json_lib.c
strings/json_lib.c
+4
-2
No files found.
include/json_lib.h
View file @
ebe5ebba
...
...
@@ -226,6 +226,13 @@ int json_scan_next(json_engine_t *j);
int
json_read_keyname_chr
(
json_engine_t
*
j
);
/*
Check if the name of the current JSON key matches
the step of the path.
*/
int
json_key_matches
(
json_engine_t
*
je
,
json_string_t
*
k
);
/*
json_read_value() function parses the JSON value syntax,
so that we can handle the value of a key or an array item.
...
...
mysql-test/r/dyncol.result
View file @
ebe5ebba
...
...
@@ -1731,36 +1731,36 @@ column_json(column_create(1, "val", 2, column_create(3, "val2")))
# Time encoding
#
select hex(column_create("t", "800:46:06.23434" AS time)) as hex,
column_json(column_create("t", "800:46:06.23434" AS time)) as js
on
;
hex js
on
column_json(column_create("t", "800:46:06.23434" AS time)) as js;
hex js
04010001000000070074649363B82003 {"t":"800:46:06.234340"}
select hex(column_create(1, "800:46:06.23434" AS time)) as hex,
column_json(column_create(1, "800:46:06.23434" AS time)) as js
on
;
hex js
on
column_json(column_create(1, "800:46:06.23434" AS time)) as js;
hex js
000100010007649363B82003 {"1":"800:46:06.234340"}
select hex(column_create("t", "800:46:06" AS time)) as hex,
column_json(column_create("t", "800:46:06" AS time)) as js
on
;
hex js
on
column_json(column_create("t", "800:46:06" AS time)) as js;
hex js
04010001000000070074860B32 {"t":"800:46:06"}
select hex(column_create(1, "800:46:06" AS time)) as hex,
column_json(column_create(1, "800:46:06" AS time)) as js
on
;
hex js
on
column_json(column_create(1, "800:46:06" AS time)) as js;
hex js
000100010007000060B82003 {"1":"800:46:06"}
select hex(column_create("t", "2012-12-21 10:46:06.23434" AS datetime)) as hex,
column_json(column_create("t", "2012-12-21 10:46:06.23434" AS datetime)) as js
on
;
hex js
on
column_json(column_create("t", "2012-12-21 10:46:06.23434" AS datetime)) as js;
hex js
0401000100000005007495B90F649363B80A00 {"t":"2012-12-21 10:46:06.234340"}
select hex(column_create(1, "2012-12-21 10:46:06.23434" AS datetime)) as hex,
column_json(column_create(1, "2012-12-21 10:46:06.23434" AS datetime)) as js
on
;
hex js
on
column_json(column_create(1, "2012-12-21 10:46:06.23434" AS datetime)) as js;
hex js
00010001000595B90F649363B80A00 {"1":"2012-12-21 10:46:06.234340"}
select hex(column_create("t", "2012-12-21 10:46:06" AS datetime)) as hex,
column_json(column_create("t", "2012-12-21 10:46:06" AS datetime)) as js
on
;
hex js
on
column_json(column_create("t", "2012-12-21 10:46:06" AS datetime)) as js;
hex js
0401000100000005007495B90F86AB00 {"t":"2012-12-21 10:46:06"}
select hex(column_create(1, "2012-12-21 10:46:06" AS datetime)) as hex,
column_json(column_create(1, "2012-12-21 10:46:06" AS datetime)) as js
on
;
hex js
on
column_json(column_create(1, "2012-12-21 10:46:06" AS datetime)) as js;
hex js
00010001000595B90F000060B80A00 {"1":"2012-12-21 10:46:06"}
#
# MDEV-4849: Out of memory error and valgrind warnings on COLUMN_ADD
...
...
mysql-test/r/func_json.result
View file @
ebe5ebba
...
...
@@ -46,6 +46,18 @@ json_array_append('["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_ARRAY_INSERT('["a", {"b": [1, 2]}, [3, 4]]', '$[1]', 'x');
JSON_ARRAY_INSERT('["a", {"b": [1, 2]}, [3, 4]]', '$[1]', 'x')
["a", "x", {"b": [1, 2]}, [3, 4]]
SELECT JSON_ARRAY_INSERT('["a", {"b": [1, 2]}, [3, 4]]', '$[2]', 'x');
JSON_ARRAY_INSERT('["a", {"b": [1, 2]}, [3, 4]]', '$[2]', 'x')
["a", {"b": [1, 2]}, "x", [3, 4]]
SELECT JSON_ARRAY_INSERT('["a", {"b": [1, 2]}, [3, 4]]', '$[3]', 'x');
JSON_ARRAY_INSERT('["a", {"b": [1, 2]}, [3, 4]]', '$[3]', 'x')
["a", {"b": [1, 2]}, [3, 4], "x"]
SELECT JSON_ARRAY_INSERT('["a", {"b": [1, 2]}, [3, 4]]', '$[4]', 'x');
JSON_ARRAY_INSERT('["a", {"b": [1, 2]}, [3, 4]]', '$[4]', 'x')
["a", {"b": [1, 2]}, [3, 4], "x"]
select json_contains('{"k1":123, "k2":345}', '123', '$.k1');
json_contains('{"k1":123, "k2":345}', '123', '$.k1')
1
...
...
@@ -91,6 +103,44 @@ json_extract('{"key1":5, "key2":[2,3]}', "$.key1", "$.key2")
select json_extract('{"key0":true, "key1":"qwe"}', "$.key1");
json_extract('{"key0":true, "key1":"qwe"}', "$.key1")
qwe
select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.k1', 'word');
json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.k1', 'word')
{"a":1, "b":{"c":1, "k1":"word"}, "d":[1, 2]}
select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.d[3]', 3);
json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.d[3]', 3)
{"a":1, "b":{"c":1}, "d":[1, 2, 3]}
select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.a[2]', 2);
json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.a[2]', 2)
{"a":[1, 2], "b":{"c":1}, "d":[1, 2]}
select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.c', 'word');
json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.c', 'word')
{"a":1, "b":{"c":1}, "d":[1, 2]}
select json_set('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]');
json_set('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]')
{ "a": 10, "b": [2, 3], "c":"[true, false]"}
select json_replace('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]');
json_replace('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]')
{ "a": 10, "b": [2, 3]}
select json_replace('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.b', '[true, false]');
json_replace('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.b', '[true, false]')
{ "a": 10, "b": "[true, false]"}
set @j = '["a", ["b", "c"], "d"]';
select json_remove(@j, '$[0]');
json_remove(@j, '$[0]')
[ ["b", "c"], "d"]
select json_remove(@j, '$[1]');
json_remove(@j, '$[1]')
["a" "d"]
select json_remove(@j, '$[2]');
json_remove(@j, '$[2]')
["a", ["b", "c"]]
set @j = '{"a": 1, "b": [2, 3]}';
select json_remove(@j, '$.b');
json_remove(@j, '$.b')
{"a": 1}
select json_remove(@j, '$.a');
json_remove(@j, '$.a')
{"b": [2, 3]}
select json_object("ki", 1, "mi", "ya");
json_object("ki", 1, "mi", "ya")
{"ki": 1, "mi": "ya"}
...
...
@@ -121,3 +171,46 @@ BOOLEAN
select json_type('123');
json_type('123')
NUMBER
select json_keys('{"a":{"c":1, "d":2}, "b":2}');
json_keys('{"a":{"c":1, "d":2}, "b":2}')
["a", "b"]
select json_keys('{"a":{"c":1, "d":2}, "b":2}', "$.a");
json_keys('{"a":{"c":1, "d":2}, "b":2}', "$.a")
["c", "d"]
select json_keys('{"a":{"c":1, "d":2}, "b":2}', "$.b");
json_keys('{"a":{"c":1, "d":2}, "b":2}', "$.b")
NULL
SET @j = '["abc", [{"k": "10"}, "def"], {"x":"abc"}, {"y":"bcd"}]';
select json_search(@j, 'one', 'abc');
json_search(@j, 'one', 'abc')
"$[0]"
select json_search(@j, 'all', 'abc');
json_search(@j, 'all', 'abc')
["$[0]", "$[2].x"]
select json_search(@j, 'all', 'abc', NULL, '$[2]');
json_search(@j, 'all', 'abc', NULL, '$[2]')
"$[2].x"
select json_search(@j, 'all', 'abc', NULL, '$');
json_search(@j, 'all', 'abc', NULL, '$')
["$[0]", "$[2].x"]
select json_search(@j, 'all', '10', NULL, '$');
json_search(@j, 'all', '10', NULL, '$')
"$[1][0].k"
select json_search(@j, 'all', '10', NULL, '$[*]');
json_search(@j, 'all', '10', NULL, '$[*]')
"$[1][0].k"
select json_search(@j, 'all', '10', NULL, '$[*][0].k');
json_search(@j, 'all', '10', NULL, '$[*][0].k')
"$[1][0].k"
select json_unquote('"abc"');
json_unquote('"abc"')
abc
select json_object("a", json_object("b", "abcd"));
json_object("a", json_object("b", "abcd"))
{"a": {"b": "abcd"}}
select json_object("a", '{"b": "abcd"}');
json_object("a", '{"b": "abcd"}')
{"a": "{\"b\": \"abcd\"}"}
select json_object("a", cast('{"b": "abcd"}' as json));
json_object("a", cast('{"b": "abcd"}' as json))
{"a": {"b": "abcd"}}
mysql-test/t/dyncol.test
View file @
ebe5ebba
...
...
@@ -805,24 +805,24 @@ select column_json(column_create(1, "val", 2, column_create(3, "val2")));
--
echo
# Time encoding
--
echo
#
select
hex
(
column_create
(
"t"
,
"800:46:06.23434"
AS
time
))
as
hex
,
column_json
(
column_create
(
"t"
,
"800:46:06.23434"
AS
time
))
as
js
on
;
column_json
(
column_create
(
"t"
,
"800:46:06.23434"
AS
time
))
as
js
;
select
hex
(
column_create
(
1
,
"800:46:06.23434"
AS
time
))
as
hex
,
column_json
(
column_create
(
1
,
"800:46:06.23434"
AS
time
))
as
js
on
;
column_json
(
column_create
(
1
,
"800:46:06.23434"
AS
time
))
as
js
;
select
hex
(
column_create
(
"t"
,
"800:46:06"
AS
time
))
as
hex
,
column_json
(
column_create
(
"t"
,
"800:46:06"
AS
time
))
as
js
on
;
column_json
(
column_create
(
"t"
,
"800:46:06"
AS
time
))
as
js
;
select
hex
(
column_create
(
1
,
"800:46:06"
AS
time
))
as
hex
,
column_json
(
column_create
(
1
,
"800:46:06"
AS
time
))
as
js
on
;
column_json
(
column_create
(
1
,
"800:46:06"
AS
time
))
as
js
;
select
hex
(
column_create
(
"t"
,
"2012-12-21 10:46:06.23434"
AS
datetime
))
as
hex
,
column_json
(
column_create
(
"t"
,
"2012-12-21 10:46:06.23434"
AS
datetime
))
as
js
on
;
column_json
(
column_create
(
"t"
,
"2012-12-21 10:46:06.23434"
AS
datetime
))
as
js
;
select
hex
(
column_create
(
1
,
"2012-12-21 10:46:06.23434"
AS
datetime
))
as
hex
,
column_json
(
column_create
(
1
,
"2012-12-21 10:46:06.23434"
AS
datetime
))
as
js
on
;
column_json
(
column_create
(
1
,
"2012-12-21 10:46:06.23434"
AS
datetime
))
as
js
;
select
hex
(
column_create
(
"t"
,
"2012-12-21 10:46:06"
AS
datetime
))
as
hex
,
column_json
(
column_create
(
"t"
,
"2012-12-21 10:46:06"
AS
datetime
))
as
js
on
;
column_json
(
column_create
(
"t"
,
"2012-12-21 10:46:06"
AS
datetime
))
as
js
;
select
hex
(
column_create
(
1
,
"2012-12-21 10:46:06"
AS
datetime
))
as
hex
,
column_json
(
column_create
(
1
,
"2012-12-21 10:46:06"
AS
datetime
))
as
js
on
;
column_json
(
column_create
(
1
,
"2012-12-21 10:46:06"
AS
datetime
))
as
js
;
--
echo
#
--
echo
# MDEV-4849: Out of memory error and valgrind warnings on COLUMN_ADD
...
...
mysql-test/t/func_json.test
View file @
ebe5ebba
...
...
@@ -19,6 +19,11 @@ 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_ARRAY_INSERT
(
'["a", {"b": [1, 2]}, [3, 4]]'
,
'$[1]'
,
'x'
);
SELECT
JSON_ARRAY_INSERT
(
'["a", {"b": [1, 2]}, [3, 4]]'
,
'$[2]'
,
'x'
);
SELECT
JSON_ARRAY_INSERT
(
'["a", {"b": [1, 2]}, [3, 4]]'
,
'$[3]'
,
'x'
);
SELECT
JSON_ARRAY_INSERT
(
'["a", {"b": [1, 2]}, [3, 4]]'
,
'$[4]'
,
'x'
);
select
json_contains
(
'{"k1":123, "k2":345}'
,
'123'
,
'$.k1'
);
select
json_contains
(
'"you"'
,
'"you"'
);
select
json_contains
(
'"youth"'
,
'"you"'
);
...
...
@@ -37,6 +42,24 @@ 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_insert
(
'{"a":1, "b":{"c":1}, "d":[1, 2]}'
,
'$.b.k1'
,
'word'
);
select
json_insert
(
'{"a":1, "b":{"c":1}, "d":[1, 2]}'
,
'$.d[3]'
,
3
);
select
json_insert
(
'{"a":1, "b":{"c":1}, "d":[1, 2]}'
,
'$.a[2]'
,
2
);
select
json_insert
(
'{"a":1, "b":{"c":1}, "d":[1, 2]}'
,
'$.b.c'
,
'word'
);
select
json_set
(
'{ "a": 1, "b": [2, 3]}'
,
'$.a'
,
10
,
'$.c'
,
'[true, false]'
);
select
json_replace
(
'{ "a": 1, "b": [2, 3]}'
,
'$.a'
,
10
,
'$.c'
,
'[true, false]'
);
select
json_replace
(
'{ "a": 1, "b": [2, 3]}'
,
'$.a'
,
10
,
'$.b'
,
'[true, false]'
);
set
@
j
=
'["a", ["b", "c"], "d"]'
;
select
json_remove
(
@
j
,
'$[0]'
);
select
json_remove
(
@
j
,
'$[1]'
);
select
json_remove
(
@
j
,
'$[2]'
);
set
@
j
=
'{"a": 1, "b": [2, 3]}'
;
select
json_remove
(
@
j
,
'$.b'
);
select
json_remove
(
@
j
,
'$.a'
);
select
json_object
(
"ki"
,
1
,
"mi"
,
"ya"
);
select
json_exists
(
'{"key1":"xxxx", "key2":[1, 2, 3]}'
,
"$.key2"
);
...
...
@@ -52,3 +75,23 @@ select json_type('[123, "k2", 345]');
select
json_type
(
"true"
);
select
json_type
(
'123'
);
select
json_keys
(
'{"a":{"c":1, "d":2}, "b":2}'
);
select
json_keys
(
'{"a":{"c":1, "d":2}, "b":2}'
,
"$.a"
);
select
json_keys
(
'{"a":{"c":1, "d":2}, "b":2}'
,
"$.b"
);
SET
@
j
=
'["abc", [{"k": "10"}, "def"], {"x":"abc"}, {"y":"bcd"}]'
;
select
json_search
(
@
j
,
'one'
,
'abc'
);
select
json_search
(
@
j
,
'all'
,
'abc'
);
select
json_search
(
@
j
,
'all'
,
'abc'
,
NULL
,
'$[2]'
);
select
json_search
(
@
j
,
'all'
,
'abc'
,
NULL
,
'$'
);
select
json_search
(
@
j
,
'all'
,
'10'
,
NULL
,
'$'
);
select
json_search
(
@
j
,
'all'
,
'10'
,
NULL
,
'$[*]'
);
select
json_search
(
@
j
,
'all'
,
'10'
,
NULL
,
'$[*][0].k'
);
select
json_unquote
(
'"abc"'
);
select
json_object
(
"a"
,
json_object
(
"b"
,
"abcd"
));
select
json_object
(
"a"
,
'{"b": "abcd"}'
);
select
json_object
(
"a"
,
cast
(
'{"b": "abcd"}'
as
json
));
sql/item.h
View file @
ebe5ebba
...
...
@@ -1457,6 +1457,7 @@ class Item: public Value_source,
virtual
void
set_result_field
(
Field
*
field
)
{}
virtual
bool
is_result_field
()
{
return
0
;
}
virtual
bool
is_bool_type
()
{
return
false
;
}
virtual
bool
is_json_type
()
{
return
false
;
}
/* This is to handle printing of default values */
virtual
bool
need_parentheses_in_default
()
{
return
false
;
}
virtual
void
save_in_result_field
(
bool
no_conversions
)
{}
...
...
@@ -5763,4 +5764,15 @@ class Item_iterator_row: public Item_iterator
void
close
()
{}
};
/*
It's used in ::fix_fields() methods of LIKE and JSON_SEARCH
functions to handle the ESCAPE parameter.
This parameter is quite non-standard so the specific function.
*/
bool
fix_escape_item
(
THD
*
thd
,
Item
*
escape_item
,
String
*
tmp_str
,
bool
escape_used_in_parsing
,
CHARSET_INFO
*
cmp_cs
,
int
*
escape
);
#endif
/* SQL_ITEM_INCLUDED */
sql/item_cmpfunc.cc
View file @
ebe5ebba
...
...
@@ -5124,13 +5124,10 @@ bool Item_func_like::with_sargable_pattern() const
}
bool
Item_func_like
::
fix_fields
(
THD
*
thd
,
Item
**
ref
)
bool
fix_escape_item
(
THD
*
thd
,
Item
*
escape_item
,
String
*
tmp_str
,
bool
escape_used_in_parsing
,
CHARSET_INFO
*
cmp_cs
,
int
*
escape
)
{
DBUG_ASSERT
(
fixed
==
0
);
if
(
Item_bool_func2
::
fix_fields
(
thd
,
ref
)
||
escape_item
->
fix_fields
(
thd
,
&
escape_item
))
return
TRUE
;
if
(
!
escape_item
->
const_during_execution
())
{
my_error
(
ER_WRONG_ARGUMENTS
,
MYF
(
0
),
"ESCAPE"
);
...
...
@@ -5140,7 +5137,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
if
(
escape_item
->
const_item
())
{
/* If we are on execution stage */
String
*
escape_str
=
escape_item
->
val_str
(
&
cmp_value1
);
String
*
escape_str
=
escape_item
->
val_str
(
tmp_str
);
if
(
escape_str
)
{
const
char
*
escape_str_ptr
=
escape_str
->
ptr
();
...
...
@@ -5153,7 +5150,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
return
TRUE
;
}
if
(
use_mb
(
cmp_c
ollation
.
collation
))
if
(
use_mb
(
cmp_c
s
))
{
CHARSET_INFO
*
cs
=
escape_str
->
charset
();
my_wc_t
wc
;
...
...
@@ -5161,7 +5158,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
(
const
uchar
*
)
escape_str_ptr
,
(
const
uchar
*
)
escape_str_ptr
+
escape_str
->
length
());
escape
=
(
int
)
(
rc
>
0
?
wc
:
'\\'
);
*
escape
=
(
int
)
(
rc
>
0
?
wc
:
'\\'
);
}
else
{
...
...
@@ -5170,25 +5167,40 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
code instead of Unicode code as "escape" argument.
Convert to "cs" if charset of escape differs.
*/
CHARSET_INFO
*
cs
=
cmp_collation
.
collation
;
uint32
unused
;
if
(
escape_str
->
needs_conversion
(
escape_str
->
length
(),
escape_str
->
charset
(),
cs
,
&
unused
))
escape_str
->
charset
(),
cmp_cs
,
&
unused
))
{
char
ch
;
uint
errors
;
uint32
cnvlen
=
copy_and_convert
(
&
ch
,
1
,
cs
,
escape_str_ptr
,
uint32
cnvlen
=
copy_and_convert
(
&
ch
,
1
,
c
mp_c
s
,
escape_str_ptr
,
escape_str
->
length
(),
escape_str
->
charset
(),
&
errors
);
escape
=
cnvlen
?
ch
:
'\\'
;
*
escape
=
cnvlen
?
ch
:
'\\'
;
}
else
escape
=
escape_str_ptr
?
*
escape_str_ptr
:
'\\'
;
*
escape
=
escape_str_ptr
?
*
escape_str_ptr
:
'\\'
;
}
}
else
escape
=
'\\'
;
*
escape
=
'\\'
;
}
return
FALSE
;
}
bool
Item_func_like
::
fix_fields
(
THD
*
thd
,
Item
**
ref
)
{
DBUG_ASSERT
(
fixed
==
0
);
if
(
Item_bool_func2
::
fix_fields
(
thd
,
ref
)
||
escape_item
->
fix_fields
(
thd
,
&
escape_item
)
||
fix_escape_item
(
thd
,
escape_item
,
&
cmp_value1
,
escape_used_in_parsing
,
cmp_collation
.
collation
,
&
escape
))
return
TRUE
;
if
(
escape_item
->
const_item
())
{
/*
We could also do boyer-more for non-const items, but as we would have to
recompute the tables for each row it's not worth it.
...
...
sql/item_create.cc
View file @
ebe5ebba
...
...
@@ -1786,6 +1786,19 @@ class Create_func_json_query : public Create_func_arg2
};
class
Create_func_json_keys
:
public
Create_native_func
{
public:
virtual
Item
*
create_native
(
THD
*
thd
,
LEX_STRING
name
,
List
<
Item
>
*
item_list
);
static
Create_func_json_keys
s_singleton
;
protected:
Create_func_json_keys
()
{}
virtual
~
Create_func_json_keys
()
{}
};
class
Create_func_json_contains
:
public
Create_native_func
{
public:
...
...
@@ -1825,6 +1838,19 @@ class Create_func_json_extract : public Create_native_func
};
class
Create_func_json_search
:
public
Create_native_func
{
public:
virtual
Item
*
create_native
(
THD
*
thd
,
LEX_STRING
name
,
List
<
Item
>
*
item_list
);
static
Create_func_json_search
s_singleton
;
protected:
Create_func_json_search
()
{}
virtual
~
Create_func_json_search
()
{}
};
class
Create_func_json_array
:
public
Create_native_func
{
public:
...
...
@@ -1851,6 +1877,71 @@ class Create_func_json_array_append : public Create_native_func
};
class
Create_func_json_array_insert
:
public
Create_native_func
{
public:
virtual
Item
*
create_native
(
THD
*
thd
,
LEX_STRING
name
,
List
<
Item
>
*
item_list
);
static
Create_func_json_array_insert
s_singleton
;
protected:
Create_func_json_array_insert
()
{}
virtual
~
Create_func_json_array_insert
()
{}
};
class
Create_func_json_insert
:
public
Create_native_func
{
public:
virtual
Item
*
create_native
(
THD
*
thd
,
LEX_STRING
name
,
List
<
Item
>
*
item_list
);
static
Create_func_json_insert
s_singleton
;
protected:
Create_func_json_insert
()
{}
virtual
~
Create_func_json_insert
()
{}
};
class
Create_func_json_set
:
public
Create_native_func
{
public:
virtual
Item
*
create_native
(
THD
*
thd
,
LEX_STRING
name
,
List
<
Item
>
*
item_list
);
static
Create_func_json_set
s_singleton
;
protected:
Create_func_json_set
()
{}
virtual
~
Create_func_json_set
()
{}
};
class
Create_func_json_replace
:
public
Create_native_func
{
public:
virtual
Item
*
create_native
(
THD
*
thd
,
LEX_STRING
name
,
List
<
Item
>
*
item_list
);
static
Create_func_json_replace
s_singleton
;
protected:
Create_func_json_replace
()
{}
virtual
~
Create_func_json_replace
()
{}
};
class
Create_func_json_remove
:
public
Create_native_func
{
public:
virtual
Item
*
create_native
(
THD
*
thd
,
LEX_STRING
name
,
List
<
Item
>
*
item_list
);
static
Create_func_json_remove
s_singleton
;
protected:
Create_func_json_remove
()
{}
virtual
~
Create_func_json_remove
()
{}
};
class
Create_func_json_object
:
public
Create_native_func
{
public:
...
...
@@ -1903,6 +1994,19 @@ class Create_func_json_quote : public Create_func_arg1
};
class
Create_func_json_unquote
:
public
Create_func_arg1
{
public:
virtual
Item
*
create_1_arg
(
THD
*
thd
,
Item
*
arg1
);
static
Create_func_json_unquote
s_singleton
;
protected:
Create_func_json_unquote
()
{}
virtual
~
Create_func_json_unquote
()
{}
};
class
Create_func_last_day
:
public
Create_func_arg1
{
public:
...
...
@@ -4830,6 +4934,15 @@ Create_func_json_quote::create_1_arg(THD *thd, Item *arg1)
}
Create_func_json_unquote
Create_func_json_unquote
::
s_singleton
;
Item
*
Create_func_json_unquote
::
create_1_arg
(
THD
*
thd
,
Item
*
arg1
)
{
return
new
(
thd
->
mem_root
)
Item_func_json_unquote
(
thd
,
arg1
);
}
Create_func_last_day
Create_func_last_day
::
s_singleton
;
Item
*
...
...
@@ -4885,6 +4998,134 @@ Create_func_json_array_append::create_native(THD *thd, LEX_STRING name,
}
Create_func_json_array_insert
Create_func_json_array_insert
::
s_singleton
;
Item
*
Create_func_json_array_insert
::
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_insert
(
thd
,
*
item_list
);
}
return
func
;
}
Create_func_json_insert
Create_func_json_insert
::
s_singleton
;
Item
*
Create_func_json_insert
::
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_insert
(
true
,
false
,
thd
,
*
item_list
);
}
return
func
;
}
Create_func_json_set
Create_func_json_set
::
s_singleton
;
Item
*
Create_func_json_set
::
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_insert
(
true
,
true
,
thd
,
*
item_list
);
}
return
func
;
}
Create_func_json_replace
Create_func_json_replace
::
s_singleton
;
Item
*
Create_func_json_replace
::
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_insert
(
false
,
true
,
thd
,
*
item_list
);
}
return
func
;
}
Create_func_json_remove
Create_func_json_remove
::
s_singleton
;
Item
*
Create_func_json_remove
::
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_remove
(
thd
,
*
item_list
);
}
return
func
;
}
Create_func_json_object
Create_func_json_object
::
s_singleton
;
Item
*
...
...
@@ -4990,6 +5231,31 @@ Create_func_json_contains::create_native(THD *thd, LEX_STRING name,
}
Create_func_json_keys
Create_func_json_keys
::
s_singleton
;
Item
*
Create_func_json_keys
::
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
<
1
||
arg_count
>
2
/* json_doc, [path]...*/
)
{
my_error
(
ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
,
MYF
(
0
),
name
.
str
);
}
else
{
func
=
new
(
thd
->
mem_root
)
Item_func_json_keys
(
thd
,
*
item_list
);
}
return
func
;
}
Create_func_json_contains_path
Create_func_json_contains_path
::
s_singleton
;
Item
*
...
...
@@ -5040,6 +5306,31 @@ Create_func_json_extract::create_native(THD *thd, LEX_STRING name,
}
Create_func_json_search
Create_func_json_search
::
s_singleton
;
Item
*
Create_func_json_search
::
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, search_str, [escape_char[, path]...*/
)
{
my_error
(
ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
,
MYF
(
0
),
name
.
str
);
}
else
{
func
=
new
(
thd
->
mem_root
)
Item_func_json_search
(
thd
,
*
item_list
);
}
return
func
;
}
Create_func_last_insert_id
Create_func_last_insert_id
::
s_singleton
;
Item
*
...
...
@@ -6313,17 +6604,25 @@ static Native_func_registry func_array[] =
{
{
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_ARRAY_INSERT"
)
},
BUILDER
(
Create_func_json_array_insert
)},
{
{
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_INSERT"
)
},
BUILDER
(
Create_func_json_insert
)},
{
{
C_STRING_WITH_LEN
(
"JSON_KEYS"
)
},
BUILDER
(
Create_func_json_keys
)},
{
{
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_REMOVE"
)
},
BUILDER
(
Create_func_json_remove
)},
{
{
C_STRING_WITH_LEN
(
"JSON_REPLACE"
)
},
BUILDER
(
Create_func_json_replace
)},
{
{
C_STRING_WITH_LEN
(
"JSON_SET"
)
},
BUILDER
(
Create_func_json_set
)},
{
{
C_STRING_WITH_LEN
(
"JSON_SEARCH"
)
},
BUILDER
(
Create_func_json_search
)},
{
{
C_STRING_WITH_LEN
(
"JSON_TYPE"
)
},
BUILDER
(
Create_func_json_type
)},
{
{
C_STRING_WITH_LEN
(
"JSON_UNQUOTE"
)
},
BUILDER
(
Create_func_json_unquote
)},
{
{
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
)},
...
...
@@ -6716,6 +7015,9 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type,
res
=
new
(
thd
->
mem_root
)
Item_char_typecast
(
thd
,
a
,
len
,
real_cs
);
break
;
}
case
ITEM_CAST_JSON
:
res
=
new
(
thd
->
mem_root
)
Item_json_typecast
(
thd
,
a
);
break
;
default:
{
DBUG_ASSERT
(
0
);
...
...
sql/item_func.h
View file @
ebe5ebba
...
...
@@ -2197,7 +2197,7 @@ enum Cast_target
{
ITEM_CAST_BINARY
,
ITEM_CAST_SIGNED_INT
,
ITEM_CAST_UNSIGNED_INT
,
ITEM_CAST_DATE
,
ITEM_CAST_TIME
,
ITEM_CAST_DATETIME
,
ITEM_CAST_CHAR
,
ITEM_CAST_DECIMAL
,
ITEM_CAST_DOUBLE
ITEM_CAST_DECIMAL
,
ITEM_CAST_DOUBLE
,
ITEM_CAST_JSON
};
...
...
sql/item_jsonfunc.cc
View file @
ebe5ebba
...
...
@@ -48,6 +48,45 @@ static bool eq_ascii_string(const CHARSET_INFO *cs,
}
static
bool
append_simple
(
String
*
s
,
const
char
*
a
,
uint
a_len
)
{
if
(
!
s
->
realloc_with_extra_if_needed
(
s
->
length
()
+
a_len
))
{
s
->
q_append
(
a
,
a_len
);
return
FALSE
;
}
return
TRUE
;
}
static
inline
bool
append_simple
(
String
*
s
,
const
uchar
*
a
,
uint
a_len
)
{
return
append_simple
(
s
,
(
const
char
*
)
a
,
a_len
);
}
/*
Appends JSON string to the String object taking charsets in
consideration.
static int st_append_json(String *s,
CHARSET_INFO *json_cs, const uchar *js, uint js_len)
{
int str_len= js_len * s->charset()->mbmaxlen;
if (!s->reserve(str_len, 1024) &&
(str_len= json_unescape(json_cs, js, js + js_len,
s->charset(), (uchar *) s->end(), (uchar *) s->end() + str_len)) > 0)
{
s->length(s->length() + str_len);
return 0;
}
return js_len;
}
*/
/*
Appends arbitrary String to the JSON string taking charsets in
consideration.
...
...
@@ -278,6 +317,50 @@ String *Item_func_json_quote::val_str(String *str)
}
void
Item_func_json_unquote
::
fix_length_and_dec
()
{
collation
.
set
(
&
my_charset_utf8_general_ci
);
max_length
=
args
[
0
]
->
max_length
;
}
String
*
Item_func_json_unquote
::
val_str
(
String
*
str
)
{
String
*
js
=
args
[
0
]
->
val_str
(
&
tmp_s
);
json_engine_t
je
;
int
c_len
;
if
((
null_value
=
args
[
0
]
->
null_value
))
return
NULL
;
json_scan_start
(
&
je
,
js
->
charset
(),(
const
uchar
*
)
js
->
ptr
(),
(
const
uchar
*
)
js
->
ptr
()
+
js
->
length
());
if
(
json_read_value
(
&
je
))
goto
error
;
if
(
je
.
value_type
!=
JSON_VALUE_STRING
)
return
js
;
str
->
length
(
0
);
str
->
set_charset
(
&
my_charset_utf8_general_ci
);
if
(
str
->
realloc_with_extra_if_needed
(
je
.
value_len
)
||
(
c_len
=
json_unescape
(
js
->
charset
(),
je
.
value
,
je
.
value
+
je
.
value_len
,
&
my_charset_utf8_general_ci
,
(
uchar
*
)
str
->
ptr
(),
(
uchar
*
)
(
str
->
ptr
()
+
je
.
value_len
)))
<
0
)
goto
error
;
str
->
length
(
c_len
);
return
str
;
error:
null_value
=
1
;
return
0
;
}
static
int
alloc_tmp_paths
(
THD
*
thd
,
uint
n_paths
,
json_path_with_flags
**
paths
,
String
**
tmp_paths
)
{
...
...
@@ -642,6 +725,27 @@ void Item_func_json_contains_path::cleanup()
}
static
int
parse_one_or_all
(
Item
*
ooa_arg
,
bool
*
ooa_parsed
,
bool
ooa_constant
,
bool
*
mode_one
)
{
if
(
!*
ooa_parsed
)
{
char
buff
[
20
];
String
*
res
,
tmp
(
buff
,
sizeof
(
buff
),
&
my_charset_bin
);
res
=
ooa_arg
->
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
()))
return
TRUE
;
}
*
ooa_parsed
=
ooa_constant
;
}
return
FALSE
;
}
longlong
Item_func_json_contains_path
::
val_int
()
{
String
*
js
=
args
[
0
]
->
val_str
(
&
tmp_js
);
...
...
@@ -652,20 +756,8 @@ longlong Item_func_json_contains_path::val_int()
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
()))
if
(
parse_one_or_all
(
args
[
1
],
&
ooa_parsed
,
ooa_constant
,
&
mode_one
))
goto
error
;
}
ooa_parsed
=
ooa_constant
;
}
result
=
!
mode_one
;
for
(
n_arg
=
2
;
n_arg
<
arg_count
;
n_arg
++
)
...
...
@@ -742,6 +834,9 @@ static int append_json_value(String *str, Item *item, String *tmp_val)
String
*
sv
=
item
->
val_str
(
tmp_val
);
if
(
item
->
null_value
)
goto
append_null
;
if
(
item
->
is_json_type
())
return
str
->
append
(
sv
->
ptr
(),
sv
->
length
());
if
(
item
->
result_type
()
==
STRING_RESULT
)
{
return
str
->
append
(
"
\"
"
,
1
)
||
...
...
@@ -915,6 +1010,117 @@ String *Item_func_json_array_append::val_str(String *str)
}
String
*
Item_func_json_array_insert
::
val_str
(
String
*
str
)
{
json_engine_t
je
;
String
*
js
=
args
[
0
]
->
val_str
(
&
tmp_js
);
uint
n_arg
,
n_path
;
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
;
const
char
*
item_pos
;
uint
n_item
;
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
())
||
c_path
->
p
.
last_step
-
1
>
c_path
->
p
.
steps
||
c_path
->
p
.
last_step
->
type
!=
JSON_PATH_ARRAY
))
goto
error
;
c_path
->
parsed
=
c_path
->
constant
;
c_path
->
p
.
last_step
--
;
}
if
(
args
[
n_arg
]
->
null_value
)
goto
null_return
;
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
;
/* Can't find the array to insert. */
goto
null_return
;
}
if
(
json_read_value
(
&
je
))
goto
error
;
if
(
je
.
value_type
!=
JSON_VALUE_ARRAY
)
{
/* Must be an array. */
goto
null_return
;
}
item_pos
=
0
;
n_item
=
0
;
while
(
json_scan_next
(
&
je
)
==
0
&&
je
.
state
!=
JST_ARRAY_END
&&
item_pos
==
0
)
{
switch
(
je
.
state
)
{
case
JST_VALUE
:
if
(
n_item
==
c_path
->
p
.
last_step
[
1
].
n_item
)
{
item_pos
=
(
const
char
*
)
je
.
s
.
c_str
;
break
;
}
n_item
++
;
break
;
case
JST_OBJ_START
:
case
JST_ARRAY_START
:
if
(
json_skip_level
(
&
je
))
break
;
break
;
default:
break
;
}
}
str
->
length
(
0
);
str
->
set_charset
(
js
->
charset
());
if
(
!
item_pos
)
item_pos
=
(
const
char
*
)
(
je
.
s
.
c_str
-
je
.
sav_c_len
);
if
(
append_simple
(
str
,
js
->
ptr
(),
item_pos
-
js
->
ptr
())
||
((
je
.
state
==
JST_ARRAY_END
)
?
(
n_item
>
0
&&
str
->
append
(
", "
,
2
))
:
str
->
append
(
" "
,
1
))
||
append_json_value
(
str
,
args
[
n_arg
+
1
],
&
tmp_val
)
||
(
je
.
state
!=
JST_ARRAY_END
&&
str
->
append
(
","
,
1
))
||
append_simple
(
str
,
item_pos
,
js
->
end
()
-
item_pos
))
goto
error
;
/* Out of memory. */
{
String
*
tmp_str
=
str
;
str
=
&
tmp_js
;
js
=
tmp_str
;
}
}
return
js
;
null_return:
error:
null_value
=
1
;
return
0
;
}
String
*
Item_func_json_object
::
val_str
(
String
*
str
)
{
DBUG_ASSERT
(
fixed
==
1
);
...
...
@@ -1107,3 +1313,754 @@ String *Item_func_json_type::val_str(String *str)
}
void
Item_func_json_insert
::
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_insert
::
val_str
(
String
*
str
)
{
json_engine_t
je
;
String
*
js
=
args
[
0
]
->
val_str
(
&
tmp_js
);
uint
n_arg
,
n_path
;
json_string_t
key_name
;
DBUG_ASSERT
(
fixed
==
1
);
if
((
null_value
=
args
[
0
]
->
null_value
))
return
0
;
str
->
set_charset
(
js
->
charset
());
json_string_set_cs
(
&
key_name
,
js
->
charset
());
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
;
const
char
*
v_to
;
const
json_path_step_t
*
lp
;
if
(
!
c_path
->
parsed
)
{
String
*
s_p
=
args
[
n_arg
]
->
val_str
(
tmp_paths
+
n_path
);
if
(
s_p
)
{
if
(
json_path_setup
(
&
c_path
->
p
,
s_p
->
charset
(),
(
const
uchar
*
)
s_p
->
ptr
(),
(
const
uchar
*
)
s_p
->
ptr
()
+
s_p
->
length
()))
goto
error
;
/* We search to the last step. */
c_path
->
p
.
last_step
--
;
}
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
(
c_path
->
p
.
last_step
>=
c_path
->
p
.
steps
&&
json_find_path
(
&
je
,
&
c_path
->
p
,
&
c_path
->
cur_step
,
array_counters
))
{
if
(
je
.
s
.
error
)
goto
error
;
}
if
(
json_read_value
(
&
je
))
goto
error
;
lp
=
c_path
->
p
.
last_step
+
1
;
if
(
lp
->
type
==
JSON_PATH_ARRAY
)
{
uint
n_item
=
0
;
if
(
je
.
value_type
!=
JSON_VALUE_ARRAY
)
{
const
uchar
*
v_from
=
je
.
value_begin
;
if
(
!
mode_insert
)
continue
;
str
->
length
(
0
);
/* Wrap the value as an array. */
if
(
append_simple
(
str
,
js
->
ptr
(),
(
const
char
*
)
v_from
-
js
->
ptr
())
||
str
->
append
(
"["
,
1
))
goto
error
;
/* Out of memory. */
if
(
je
.
value_type
==
JSON_VALUE_OBJECT
)
{
if
(
json_skip_level
(
&
je
))
goto
error
;
}
if
(
append_simple
(
str
,
v_from
,
je
.
s
.
c_str
-
v_from
)
||
str
->
append
(
", "
,
2
)
||
append_json_value
(
str
,
args
[
n_arg
+
1
],
&
tmp_val
)
||
str
->
append
(
"]"
,
1
)
||
append_simple
(
str
,
je
.
s
.
c_str
,
js
->
end
()
-
(
const
char
*
)
je
.
s
.
c_str
))
goto
error
;
/* Out of memory. */
goto
continue_point
;
}
while
(
json_scan_next
(
&
je
)
==
0
&&
je
.
state
!=
JST_ARRAY_END
)
{
switch
(
je
.
state
)
{
case
JST_VALUE
:
if
(
n_item
==
lp
->
n_item
)
goto
v_found
;
n_item
++
;
if
(
json_skip_array_item
(
&
je
))
goto
error
;
break
;
default:
break
;
}
}
if
(
je
.
s
.
error
)
goto
error
;
if
(
!
mode_insert
)
continue
;
v_to
=
(
const
char
*
)
(
je
.
s
.
c_str
-
je
.
sav_c_len
);
str
->
length
(
0
);
if
(
append_simple
(
str
,
js
->
ptr
(),
v_to
-
js
->
ptr
())
||
str
->
append
(
", "
,
2
)
||
append_json_value
(
str
,
args
[
n_arg
+
1
],
&
tmp_val
)
||
append_simple
(
str
,
v_to
,
js
->
end
()
-
v_to
))
goto
error
;
/* Out of memory. */
}
else
/*JSON_PATH_KEY*/
{
if
(
je
.
value_type
!=
JSON_VALUE_OBJECT
)
continue
;
while
(
json_scan_next
(
&
je
)
==
0
&&
je
.
state
!=
JST_OBJ_END
)
{
switch
(
je
.
state
)
{
case
JST_KEY
:
json_string_set_str
(
&
key_name
,
lp
->
key
,
lp
->
key_end
);
if
(
json_key_matches
(
&
je
,
&
key_name
))
goto
v_found
;
if
(
json_skip_key
(
&
je
))
goto
error
;
break
;
default:
break
;
}
}
if
(
je
.
s
.
error
)
goto
error
;
if
(
!
mode_insert
)
continue
;
v_to
=
(
const
char
*
)
(
je
.
s
.
c_str
-
je
.
sav_c_len
);
str
->
length
(
0
);
if
(
append_simple
(
str
,
js
->
ptr
(),
v_to
-
js
->
ptr
())
||
str
->
append
(
",
\"
"
,
3
)
||
append_simple
(
str
,
lp
->
key
,
lp
->
key_end
-
lp
->
key
)
||
str
->
append
(
"
\"
:"
,
2
)
||
append_json_value
(
str
,
args
[
n_arg
+
1
],
&
tmp_val
)
||
append_simple
(
str
,
v_to
,
js
->
end
()
-
v_to
))
goto
error
;
/* Out of memory. */
}
goto
continue_point
;
v_found:
if
(
!
mode_replace
)
continue
;
if
(
json_read_value
(
&
je
))
goto
error
;
v_to
=
(
const
char
*
)
je
.
value_begin
;
str
->
length
(
0
);
if
(
!
json_value_scalar
(
&
je
))
{
if
(
json_skip_level
(
&
je
))
goto
error
;
}
if
(
append_simple
(
str
,
js
->
ptr
(),
v_to
-
js
->
ptr
())
||
append_json_value
(
str
,
args
[
n_arg
+
1
],
&
tmp_val
)
||
append_simple
(
str
,
je
.
s
.
c_str
,
js
->
end
()
-
(
const
char
*
)
je
.
s
.
c_str
))
goto
error
;
/* Out of memory. */
continue_point:
{
String
*
tmp
=
str
;
str
=
&
tmp_js
;
js
=
tmp
;
}
}
return
js
;
error:
null_value
=
1
;
return
0
;
}
void
Item_func_json_remove
::
fix_length_and_dec
()
{
collation
.
set
(
args
[
0
]
->
collation
);
max_length
=
args
[
0
]
->
max_length
;
mark_constant_paths
(
paths
,
args
+
1
,
arg_count
-
1
);
}
String
*
Item_func_json_remove
::
val_str
(
String
*
str
)
{
json_engine_t
je
;
String
*
js
=
args
[
0
]
->
val_str
(
&
tmp_js
);
uint
n_arg
,
n_path
;
json_string_t
key_name
;
DBUG_ASSERT
(
fixed
==
1
);
if
(
args
[
0
]
->
null_value
)
goto
null_return
;
str
->
set_charset
(
js
->
charset
());
json_string_set_cs
(
&
key_name
,
js
->
charset
());
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
;
const
char
*
rem_start
,
*
rem_end
;
const
json_path_step_t
*
lp
;
uint
n_item
=
0
;
if
(
!
c_path
->
parsed
)
{
String
*
s_p
=
args
[
n_arg
]
->
val_str
(
tmp_paths
+
n_path
);
if
(
s_p
)
{
if
(
json_path_setup
(
&
c_path
->
p
,
s_p
->
charset
(),
(
const
uchar
*
)
s_p
->
ptr
(),
(
const
uchar
*
)
s_p
->
ptr
()
+
s_p
->
length
()))
goto
error
;
/* We search to the last step. */
c_path
->
p
.
last_step
--
;
if
(
c_path
->
p
.
last_step
<
c_path
->
p
.
steps
)
goto
null_return
;
}
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
;
}
if
(
json_read_value
(
&
je
))
goto
error
;
lp
=
c_path
->
p
.
last_step
+
1
;
if
(
lp
->
type
==
JSON_PATH_ARRAY
)
{
if
(
je
.
value_type
!=
JSON_VALUE_ARRAY
)
continue
;
while
(
json_scan_next
(
&
je
)
==
0
&&
je
.
state
!=
JST_ARRAY_END
)
{
switch
(
je
.
state
)
{
case
JST_VALUE
:
if
(
n_item
==
lp
->
n_item
)
{
rem_start
=
(
const
char
*
)
(
je
.
s
.
c_str
-
(
n_item
?
je
.
sav_c_len
:
0
));
goto
v_found
;
}
n_item
++
;
if
(
json_skip_array_item
(
&
je
))
goto
error
;
break
;
default:
break
;
}
}
if
(
je
.
s
.
error
)
goto
error
;
continue
;
}
else
/*JSON_PATH_KEY*/
{
if
(
je
.
value_type
!=
JSON_VALUE_OBJECT
)
continue
;
while
(
json_scan_next
(
&
je
)
==
0
&&
je
.
state
!=
JST_OBJ_END
)
{
switch
(
je
.
state
)
{
case
JST_KEY
:
if
(
n_item
==
0
)
rem_start
=
(
const
char
*
)
(
je
.
s
.
c_str
-
je
.
sav_c_len
);
json_string_set_str
(
&
key_name
,
lp
->
key
,
lp
->
key_end
);
if
(
json_key_matches
(
&
je
,
&
key_name
))
{
goto
v_found
;
}
if
(
json_skip_key
(
&
je
))
goto
error
;
rem_start
=
(
const
char
*
)
je
.
s
.
c_str
;
n_item
++
;
break
;
default:
break
;
}
}
if
(
je
.
s
.
error
)
goto
error
;
continue
;
}
v_found:
if
(
json_skip_key
(
&
je
)
||
json_scan_next
(
&
je
))
goto
error
;
rem_end
=
(
je
.
state
==
JST_VALUE
)
?
(
const
char
*
)
je
.
s
.
c_str
:
(
const
char
*
)
(
je
.
s
.
c_str
-
je
.
sav_c_len
);
str
->
length
(
0
);
if
(
append_simple
(
str
,
js
->
ptr
(),
rem_start
-
js
->
ptr
())
||
append_simple
(
str
,
rem_end
,
js
->
end
()
-
rem_end
))
goto
error
;
/* Out of memory. */
{
String
*
tmp
=
str
;
str
=
&
tmp_js
;
js
=
tmp
;
}
}
return
js
;
null_return:
error:
null_value
=
1
;
return
0
;
}
void
Item_func_json_keys
::
fix_length_and_dec
()
{
collation
.
set
(
args
[
0
]
->
collation
);
max_length
=
args
[
0
]
->
max_length
;
if
(
arg_count
>
1
)
path
.
set_constant_flag
(
args
[
1
]
->
const_item
());
}
String
*
Item_func_json_keys
::
val_str
(
String
*
str
)
{
json_engine_t
je
;
String
*
js
=
args
[
0
]
->
val_str
(
&
tmp_js
);
uint
n_keys
=
0
;
uint
array_counters
[
JSON_DEPTH_LIMIT
];
if
((
args
[
0
]
->
null_value
))
goto
null_return
;
json_scan_start
(
&
je
,
js
->
charset
(),(
const
uchar
*
)
js
->
ptr
(),
(
const
uchar
*
)
js
->
ptr
()
+
js
->
length
());
if
(
arg_count
<
2
)
goto
skip_search
;
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
(
args
[
1
]
->
null_value
)
goto
null_return
;
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
;
goto
null_return
;
}
skip_search:
if
(
json_read_value
(
&
je
))
goto
err_return
;
if
(
je
.
value_type
!=
JSON_VALUE_OBJECT
)
goto
null_return
;
str
->
length
(
0
);
if
(
str
->
append
(
"["
,
1
))
goto
err_return
;
/* Out of memory. */
/* Parse the OBJECT collecting the keys. */
while
(
json_scan_next
(
&
je
)
==
0
&&
je
.
state
!=
JST_OBJ_END
)
{
const
uchar
*
key_start
,
*
key_end
;
switch
(
je
.
state
)
{
case
JST_KEY
:
key_start
=
je
.
s
.
c_str
;
while
(
json_read_keyname_chr
(
&
je
)
==
0
)
{
key_end
=
je
.
s
.
c_str
;
}
if
(
je
.
s
.
error
||
(
n_keys
>
0
&&
str
->
append
(
", "
,
2
))
||
str
->
append
(
"
\"
"
,
1
)
||
append_simple
(
str
,
key_start
,
key_end
-
key_start
)
||
str
->
append
(
"
\"
"
,
1
))
goto
err_return
;
n_keys
++
;
break
;
case
JST_OBJ_START
:
case
JST_ARRAY_START
:
if
(
json_skip_level
(
&
je
))
break
;
break
;
default:
break
;
}
}
if
(
je
.
s
.
error
||
str
->
append
(
"]"
,
1
))
goto
err_return
;
null_value
=
0
;
return
str
;
null_return:
err_return:
null_value
=
1
;
return
0
;
}
bool
Item_func_json_search
::
fix_fields
(
THD
*
thd
,
Item
**
ref
)
{
if
(
Item_json_str_multipath
::
fix_fields
(
thd
,
ref
))
return
TRUE
;
if
(
arg_count
<
4
)
return
FALSE
;
return
fix_escape_item
(
thd
,
args
[
3
],
&
tmp_js
,
true
,
args
[
0
]
->
collation
.
collation
,
&
escape
);
}
static
const
uint
SQR_MAX_BLOB_WIDTH
=
sqrt
(
MAX_BLOB_WIDTH
);
void
Item_func_json_search
::
fix_length_and_dec
()
{
collation
.
set
(
args
[
0
]
->
collation
);
/*
It's rather difficult to estimate the length of the result.
I belive arglen^2 is the reasonable upper limit.
*/
if
(
args
[
0
]
->
max_length
>
SQR_MAX_BLOB_WIDTH
)
max_length
=
MAX_BLOB_WIDTH
;
else
{
max_length
=
args
[
0
]
->
max_length
;
max_length
*=
max_length
;
}
ooa_constant
=
args
[
1
]
->
const_item
();
ooa_parsed
=
FALSE
;
if
(
arg_count
>
4
)
mark_constant_paths
(
paths
,
args
+
4
,
arg_count
-
4
);
}
int
Item_func_json_search
::
compare_json_value_wild
(
json_engine_t
*
je
,
const
String
*
cmp_str
)
{
return
my_wildcmp
(
collation
.
collation
,
(
const
char
*
)
je
->
value
,
(
const
char
*
)
(
je
->
value
+
je
->
value_len
),
cmp_str
->
ptr
(),
cmp_str
->
end
(),
escape
,
wild_one
,
wild_many
)
?
0
:
1
;
}
static
int
append_json_path
(
String
*
str
,
const
json_path_t
*
p
)
{
const
json_path_step_t
*
c
;
if
(
str
->
append
(
"
\"
$"
,
2
))
return
TRUE
;
for
(
c
=
p
->
steps
+
1
;
c
<=
p
->
last_step
;
c
++
)
{
if
(
c
->
type
==
JSON_PATH_KEY
)
{
if
(
str
->
append
(
"."
,
1
)
||
append_simple
(
str
,
c
->
key
,
c
->
key_end
-
c
->
key
))
return
TRUE
;
}
else
/*JSON_PATH_ARRAY*/
{
if
(
str
->
append
(
"["
,
1
)
||
str
->
append_ulonglong
(
c
->
n_item
)
||
str
->
append
(
"]"
,
1
))
return
TRUE
;
}
}
return
str
->
append
(
"
\"
"
,
1
);
}
static
int
json_path_compare
(
const
json_path_t
*
a
,
const
json_path_t
*
b
)
{
uint
i
,
a_len
=
a
->
last_step
-
a
->
steps
,
b_len
=
b
->
last_step
-
b
->
steps
;
if
(
a_len
>
b_len
)
return
-
2
;
for
(
i
=
0
;
i
<=
a_len
;
i
++
)
{
const
json_path_step_t
*
sa
=
a
->
steps
+
i
;
const
json_path_step_t
*
sb
=
b
->
steps
+
i
;
if
(
sa
->
type
!=
sb
->
type
)
return
-
1
;
if
(
sa
->
type
==
JSON_PATH_ARRAY
)
{
if
(
!
sa
->
wild
&&
sa
->
n_item
!=
sb
->
n_item
)
return
-
1
;
}
else
/* JSON_PATH_KEY */
{
if
(
!
sa
->
wild
&&
(
sa
->
key_end
-
sa
->
key
!=
sb
->
key_end
-
sb
->
key
||
memcmp
(
sa
->
key
,
sb
->
key
,
sa
->
key_end
-
sa
->
key
)
!=
0
))
return
-
1
;
}
}
return
b_len
>
a_len
;
}
static
bool
path_ok
(
const
json_path_with_flags
*
paths_list
,
int
n_paths
,
const
json_path_t
*
p
)
{
for
(;
n_paths
>
0
;
n_paths
--
,
paths_list
++
)
{
if
(
json_path_compare
(
&
paths_list
->
p
,
p
)
>=
0
)
return
TRUE
;
}
return
FALSE
;
}
String
*
Item_func_json_search
::
val_str
(
String
*
str
)
{
String
*
js
=
args
[
0
]
->
val_str
(
&
tmp_js
);
String
*
s_str
=
args
[
2
]
->
val_str
(
&
tmp_js
);
json_engine_t
je
;
json_path_t
p
,
sav_path
;
uint
n_arg
;
if
(
args
[
0
]
->
null_value
||
args
[
2
]
->
null_value
)
goto
null_return
;
if
(
parse_one_or_all
(
args
[
1
],
&
ooa_parsed
,
ooa_constant
,
&
mode_one
))
goto
error
;
if
(
args
[
1
]
->
null_value
)
goto
null_return
;
n_path_found
=
0
;
str
->
set_charset
(
js
->
charset
());
str
->
length
(
0
);
for
(
n_arg
=
4
;
n_arg
<
arg_count
;
n_arg
++
)
{
json_path_with_flags
*
c_path
=
paths
+
n_arg
-
4
;
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
());
p
.
last_step
=
p
.
steps
;
p
.
steps
[
0
].
wild
=
0
;
p
.
steps
[
0
].
type
=
JSON_PATH_ARRAY
;
p
.
steps
[
0
].
n_item
=
0
;
do
{
switch
(
je
.
state
)
{
case
JST_KEY
:
p
.
last_step
->
key
=
je
.
s
.
c_str
;
while
(
json_read_keyname_chr
(
&
je
)
==
0
)
p
.
last_step
->
key_end
=
je
.
s
.
c_str
;
if
(
je
.
s
.
error
)
goto
error
;
/* Now we have je.state == JST_VALUE, so let's handle it. */
case
JST_VALUE
:
if
(
json_read_value
(
&
je
))
goto
error
;
if
(
json_value_scalar
(
&
je
))
{
if
((
arg_count
<
5
||
path_ok
(
paths
,
n_arg
-
4
,
&
p
))
&&
compare_json_value_wild
(
&
je
,
s_str
)
!=
0
)
{
++
n_path_found
;
if
(
n_path_found
==
1
)
{
sav_path
=
p
;
sav_path
.
last_step
=
sav_path
.
steps
+
(
p
.
last_step
-
p
.
steps
);
}
else
{
if
(
n_path_found
==
2
)
{
if
(
str
->
append
(
"["
,
1
)
||
append_json_path
(
str
,
&
sav_path
))
goto
error
;
}
if
(
str
->
append
(
", "
,
2
)
||
append_json_path
(
str
,
&
p
))
goto
error
;
}
if
(
mode_one
)
goto
end
;
}
if
(
p
.
last_step
->
type
==
JSON_PATH_ARRAY
)
p
.
last_step
->
n_item
++
;
}
else
{
p
.
last_step
++
;
if
(
je
.
value_type
==
JSON_VALUE_ARRAY
)
{
p
.
last_step
->
type
=
JSON_PATH_ARRAY
;
p
.
last_step
->
n_item
=
0
;
}
else
/*JSON_VALUE_OBJECT*/
p
.
last_step
->
type
=
JSON_PATH_KEY
;
}
break
;
case
JST_OBJ_END
:
case
JST_ARRAY_END
:
p
.
last_step
--
;
if
(
p
.
last_step
->
type
==
JSON_PATH_ARRAY
)
p
.
last_step
->
n_item
++
;
break
;
default:
break
;
}
}
while
(
json_scan_next
(
&
je
)
==
0
);
if
(
je
.
s
.
error
)
goto
error
;
end:
if
(
n_path_found
==
0
)
goto
null_return
;
if
(
n_path_found
==
1
)
{
if
(
append_json_path
(
str
,
&
sav_path
))
goto
error
;
}
else
{
if
(
str
->
append
(
"]"
,
1
))
goto
error
;
}
return
str
;
null_return:
error:
/* TODO: launch error messages. */
null_value
=
1
;
return
0
;
}
void
Item_json_typecast
::
fix_length_and_dec
()
{
maybe_null
=
args
[
0
]
->
maybe_null
;
max_length
=
args
[
0
]
->
max_length
;
}
sql/item_jsonfunc.h
View file @
ebe5ebba
...
...
@@ -123,6 +123,21 @@ class Item_func_json_quote: public Item_str_func
};
class
Item_func_json_unquote
:
public
Item_str_func
{
protected:
String
tmp_s
;
public:
Item_func_json_unquote
(
THD
*
thd
,
Item
*
s
)
:
Item_str_func
(
thd
,
s
)
{}
const
char
*
func_name
()
const
{
return
"json_unquote"
;
}
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_unquote
>
(
thd
,
mem_root
,
this
);
}
};
class
Item_json_str_multipath
:
public
Item_str_func
{
protected:
...
...
@@ -134,6 +149,7 @@ class Item_json_str_multipath: public Item_str_func
bool
fix_fields
(
THD
*
thd
,
Item
**
ref
);
void
cleanup
();
virtual
uint
get_n_paths
()
const
=
0
;
bool
is_json_type
()
{
return
true
;
}
};
...
...
@@ -207,6 +223,7 @@ class Item_func_json_array: public Item_str_func
Item_func_json_array
(
THD
*
thd
,
List
<
Item
>
&
list
)
:
Item_str_func
(
thd
,
list
)
{}
String
*
val_str
(
String
*
);
bool
is_json_type
()
{
return
true
;
}
void
fix_length_and_dec
();
const
char
*
func_name
()
const
{
return
"json_array"
;
}
Item
*
get_copy
(
THD
*
thd
,
MEM_ROOT
*
mem_root
)
...
...
@@ -231,6 +248,18 @@ class Item_func_json_array_append: public Item_json_str_multipath
};
class
Item_func_json_array_insert
:
public
Item_func_json_array_append
{
public:
Item_func_json_array_insert
(
THD
*
thd
,
List
<
Item
>
&
list
)
:
Item_func_json_array_append
(
thd
,
list
)
{}
String
*
val_str
(
String
*
);
const
char
*
func_name
()
const
{
return
"json_array_insert"
;
}
Item
*
get_copy
(
THD
*
thd
,
MEM_ROOT
*
mem_root
)
{
return
get_item_copy
<
Item_func_json_array_insert
>
(
thd
,
mem_root
,
this
);
}
};
class
Item_func_json_object
:
public
Item_func_json_array
{
public:
...
...
@@ -239,6 +268,7 @@ class Item_func_json_object: public Item_func_json_array
Item_func_json_object
(
THD
*
thd
,
List
<
Item
>
&
list
)
:
Item_func_json_array
(
thd
,
list
)
{}
String
*
val_str
(
String
*
);
bool
is_json_type
()
{
return
true
;
}
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
);
}
...
...
@@ -253,6 +283,7 @@ class Item_func_json_merge: public Item_func_json_array
Item_func_json_merge
(
THD
*
thd
,
List
<
Item
>
&
list
)
:
Item_func_json_array
(
thd
,
list
)
{}
String
*
val_str
(
String
*
);
bool
is_json_type
()
{
return
true
;
}
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
);
}
...
...
@@ -301,4 +332,102 @@ class Item_func_json_type: public Item_str_func
};
class
Item_func_json_insert
:
public
Item_json_str_multipath
{
protected:
String
tmp_js
;
String
tmp_val
;
bool
mode_insert
,
mode_replace
;
public:
Item_func_json_insert
(
bool
i_mode
,
bool
r_mode
,
THD
*
thd
,
List
<
Item
>
&
list
)
:
Item_json_str_multipath
(
thd
,
list
),
mode_insert
(
i_mode
),
mode_replace
(
r_mode
)
{}
void
fix_length_and_dec
();
String
*
val_str
(
String
*
);
uint
get_n_paths
()
const
{
return
arg_count
/
2
;
}
const
char
*
func_name
()
const
{
return
mode_insert
?
(
mode_replace
?
"json_set"
:
"json_insert"
)
:
"json_update"
;
}
Item
*
get_copy
(
THD
*
thd
,
MEM_ROOT
*
mem_root
)
{
return
get_item_copy
<
Item_func_json_insert
>
(
thd
,
mem_root
,
this
);
}
};
class
Item_func_json_remove
:
public
Item_json_str_multipath
{
protected:
String
tmp_js
;
public:
Item_func_json_remove
(
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
-
1
;
}
const
char
*
func_name
()
const
{
return
"json_remove"
;
}
Item
*
get_copy
(
THD
*
thd
,
MEM_ROOT
*
mem_root
)
{
return
get_item_copy
<
Item_func_json_remove
>
(
thd
,
mem_root
,
this
);
}
};
class
Item_func_json_keys
:
public
Item_str_func
{
protected:
json_path_with_flags
path
;
String
tmp_js
,
tmp_path
;
public:
Item_func_json_keys
(
THD
*
thd
,
List
<
Item
>
&
list
)
:
Item_str_func
(
thd
,
list
)
{}
const
char
*
func_name
()
const
{
return
"json_keys"
;
}
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_keys
>
(
thd
,
mem_root
,
this
);
}
};
class
Item_func_json_search
:
public
Item_json_str_multipath
{
protected:
String
tmp_js
;
bool
mode_one
;
bool
ooa_constant
,
ooa_parsed
;
int
escape
;
int
n_path_found
;
json_path_t
sav_path
;
int
compare_json_value_wild
(
json_engine_t
*
je
,
const
String
*
cmp_str
);
public:
Item_func_json_search
(
THD
*
thd
,
List
<
Item
>
&
list
)
:
Item_json_str_multipath
(
thd
,
list
)
{}
const
char
*
func_name
()
const
{
return
"json_search"
;
}
bool
fix_fields
(
THD
*
thd
,
Item
**
ref
);
void
fix_length_and_dec
();
String
*
val_str
(
String
*
);
uint
get_n_paths
()
const
{
return
arg_count
>
4
?
arg_count
-
4
:
0
;
}
Item
*
get_copy
(
THD
*
thd
,
MEM_ROOT
*
mem_root
)
{
return
get_item_copy
<
Item_func_json_search
>
(
thd
,
mem_root
,
this
);
}
};
class
Item_json_typecast
:
public
Item_str_func
{
public:
Item_json_typecast
(
THD
*
thd
,
Item
*
a
)
:
Item_str_func
(
thd
,
a
)
{}
const
char
*
func_name
()
const
{
return
"cast_as_json"
;
}
bool
is_json_type
()
{
return
true
;
}
void
fix_length_and_dec
();
String
*
val_str
(
String
*
str
)
{
return
args
[
0
]
->
val_str
(
str
);
}
Item
*
get_copy
(
THD
*
thd
,
MEM_ROOT
*
mem_root
)
{
return
get_item_copy
<
Item_json_typecast
>
(
thd
,
mem_root
,
this
);
}
};
#endif
/* ITEM_JSONFUNC_INCLUDED */
sql/lex.h
View file @
ebe5ebba
...
...
@@ -309,6 +309,7 @@ static SYMBOL symbols[] = {
{
"ITERATE"
,
SYM
(
ITERATE_SYM
)},
{
"INVOKER"
,
SYM
(
INVOKER_SYM
)},
{
"JOIN"
,
SYM
(
JOIN_SYM
)},
{
"JSON"
,
SYM
(
JSON_SYM
)},
{
"KEY"
,
SYM
(
KEY_SYM
)},
{
"KEYS"
,
SYM
(
KEYS
)},
{
"KEY_BLOCK_SIZE"
,
SYM
(
KEY_BLOCK_SIZE
)},
...
...
sql/sql_yacc.yy
View file @
ebe5ebba
...
...
@@ -1324,6 +1324,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token ISSUER_SYM
%token ITERATE_SYM
%token JOIN_SYM /* SQL-2003-R */
%token JSON_SYM
%token KEYS
%token KEY_BLOCK_SIZE
%token KEY_SYM /* SQL-2003-N */
...
...
@@ -10709,6 +10710,7 @@ cast_type:
}
| cast_type_numeric { $$= $1; Lex->charset= NULL; }
| cast_type_temporal { $$= $1; Lex->charset= NULL; }
| JSON_SYM { $$.set(ITEM_CAST_JSON); }
;
cast_type_numeric:
...
...
@@ -13226,11 +13228,10 @@ opt_extended_describe:
opt_format_json:
/* empty */ {}
| FORMAT_SYM '=' JSON_SYM { Lex->explain_json= true; }
| FORMAT_SYM '=' ident_or_text
{
if (!my_strcasecmp(system_charset_info, $3.str, "JSON"))
Lex->explain_json= true;
else if (!my_strcasecmp(system_charset_info, $3.str, "TRADITIONAL"))
if (!my_strcasecmp(system_charset_info, $3.str, "TRADITIONAL"))
DBUG_ASSERT(Lex->explain_json==false);
else
my_yyabort_error((ER_UNKNOWN_EXPLAIN_FORMAT, MYF(0), $3.str));
...
...
storage/connect/mysql-test/connect/disabled.def
View file @
ebe5ebba
...
...
@@ -13,5 +13,6 @@ 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 : TABLE_TYPE = JSON conflicts with the SQL syntax
json_udf : conflicts with the server JSON functions
json_udf_bin : conflicts with the server JSON functions
strings/json_lib.c
View file @
ebe5ebba
...
...
@@ -1174,7 +1174,7 @@ static int handle_match(json_engine_t *je, json_path_t *p,
Check if the name of the current JSON key matches
the step of the path.
*/
static
int
json_key_matches
(
json_engine_t
*
je
,
json_string_t
*
k
)
int
json_key_matches
(
json_engine_t
*
je
,
json_string_t
*
k
)
{
while
(
json_read_keyname_chr
(
je
)
==
0
)
{
...
...
@@ -1409,6 +1409,8 @@ int json_unescape(CHARSET_INFO *json_cs,
CHARSET_INFO
*
res_cs
,
uchar
*
res
,
uchar
*
res_end
)
{
json_string_t
s
;
const
uchar
*
res_b
=
res
;
json_string_setup
(
&
s
,
json_cs
,
json_str
,
json_end
);
while
(
json_read_string_const_chr
(
&
s
)
==
0
)
{
...
...
@@ -1434,7 +1436,7 @@ int json_unescape(CHARSET_INFO *json_cs,
return
-
1
;
}
return
s
.
error
?
1
:
0
;
return
s
.
error
==
JE_EOS
?
res
-
res_b
:
-
1
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment