Commit 50831b0f authored by Alexey Botchkov's avatar Alexey Botchkov

MDEV-11557 port MySQL-5.7 JSON tests to MariaDB.

        json_no_table.test ported.
parent e5398aca
......@@ -219,7 +219,7 @@ typedef struct st_json_engine_t
/* string constants. */
int stack[JSON_DEPTH_LIMIT]; /* Keeps the stack of nested JSON structures. */
int *stack_p; /* The 'stack' pointer. */
int stack_p; /* The 'stack' pointer. */
} json_engine_t;
......@@ -308,7 +308,7 @@ typedef const int *json_level_t;
*/
#define json_get_level(j) (j->stack_p)
int json_skip_to_level(json_engine_t *j, json_level_t level);
int json_skip_to_level(json_engine_t *j, int level);
/*
json_skip_level() works as above with just current structre.
......@@ -391,6 +391,27 @@ int json_append_ascii(CHARSET_INFO *json_cs,
uchar *json, uchar *json_end,
const uchar *ascii, const uchar *ascii_end);
/*
Scan the JSON and return paths met one-by-one.
json_get_path_start(&p)
while (json_get_path_next(&p))
{
handle_the_next_path();
}
*/
int json_get_path_start(json_engine_t *je, CHARSET_INFO *i_cs,
const uchar *str, const uchar *end,
json_path_t *p);
int json_get_path_next(json_engine_t *je, json_path_t *p);
int json_path_compare(const json_path_t *a, const json_path_t *b);
#ifdef __cplusplus
}
#endif
......
......@@ -182,6 +182,7 @@ my @DEFAULT_SUITES= qw(
innodb_fts-
innodb_gis-
innodb_zip-
json-
maria-
multi_source-
optimizer_unfixed_bugs-
......
......@@ -212,6 +212,12 @@ json_extract('1', '$')
select json_extract('[10, 20, [30, 40], 1, 10]', '$[1]');
json_extract('[10, 20, [30, 40], 1, 10]', '$[1]')
20
select json_extract('[10, 20, [30, 40], 1, 10]', '$[1]', '$[25]');
json_extract('[10, 20, [30, 40], 1, 10]', '$[1]', '$[25]')
[20]
select json_extract( '[{"a": [3, 4]}, {"b": 2}]', '$[0].a', '$[1].a');
json_extract( '[{"a": [3, 4]}, {"b": 2}]', '$[0].a', '$[1].a')
[[3, 4]]
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]}
......
This source diff could not be displayed because it is too large. You can view the blob instead.
########### suite/json/t/json_notable.test #
# Tests json columns functionality that does not need any tables #
# to be defined (no storage engine functionality) #
# #
# This test copies some tests originally in json.test #
######################################################################
# Some extra checks for comparisons between positive and negative zero.
# All should be equal.
SELECT CAST(0.0e0 AS JSON) = -0.0e0;
SELECT CAST(CAST(0 AS DECIMAL) AS JSON) = CAST(-0.0e0 AS DECIMAL);
SELECT CAST(0.0e0 AS JSON) = CAST(-0.0e0 AS DECIMAL);
SELECT CAST(CAST(0 AS DECIMAL) AS JSON) = -0.0e0;
SELECT CAST(CAST(0 AS SIGNED) AS JSON) = -0.0e0;
SELECT CAST(CAST(0 AS SIGNED) AS JSON) = CAST(-0.0e0 AS DECIMAL);
SELECT CAST(CAST(0 AS UNSIGNED) AS JSON) = -0.0e0;
SELECT CAST(CAST(0 AS UNSIGNED) AS JSON) = CAST(-0.0e0 AS DECIMAL);
# Test that CAST string argument isn't treated as ANY_JSON_ATOM
# in that a MySQL string needs to be parsed to JSON here; it is not
# auto-converted to a JSON string as in ANY_JSON_ATOM contexts.
select cast('"abc"' as json);
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
select cast('abc' as json);
--echo
--echo # String literal - valid JSON
select JSON_VALID('123'); # uint
select JSON_VALID('-123'); # int
select JSON_VALID('5000000000'); # uint64
select JSON_VALID('-5000000000'); # int64
select JSON_VALID('1.23'); # double
select JSON_VALID('"123"');
select JSON_VALID('true');
select JSON_VALID('false');
select JSON_VALID('null');
select JSON_VALID('{"address": "Trondheim"}');
--echo
--echo # String literal - not valid JSON
select JSON_VALID('12 3');
--echo
--echo # String literal not in UTF-8
set names 'ascii';
# auto-convert to utf-8
select JSON_VALID('123');
set names 'utf8';
--echo
--echo # Json expression
select JSON_VALID(cast('[123]' as JSON ));
--echo
--echo # Json expression NULL
select JSON_VALID(cast(NULL as JSON ));
--echo
--echo # Bare NULL
select JSON_VALID( NULL );
--echo
--echo # Function result - string
select JSON_VALID( UPPER('"abc"') );
set names 'latin1';
--echo
--echo # Function result - string
# auto-convert to utf-8
select JSON_VALID( UPPER('"abc"') );
set names 'utf8';
--echo
--echo # Function result - date, not valid as JSON without CAST
select JSON_VALID( CAST('2015-01-15' AS DATE) );
--echo
--echo # The date string doesn't parse as JSON text, so wrong:
select JSON_VALID( CAST(CAST('2015-01-15' AS DATE) as CHAR CHARACTER SET 'utf8') );
--echo # OK, though:
select JSON_VALID( CAST(CURDATE() as JSON) );
--echo
--echo # Function result - NULL
select JSON_VALID( UPPER(NULL) );
select JSON_VALID( UPPER(CAST(NULL as CHAR)) );
# examples from wl7909 spec
# returns 1
SELECT JSON_VALID( '{ "firstName" : "Fred", "lastName" : "Flintstone" }' );
# returns 1
SELECT JSON_VALID( '3' );
# returns NULL as IS JSON would
SELECT JSON_VALID( null );
--echo # ----------------------------------------------------------------------
--echo # Test of JSON_CONTAINS_PATH function.
--echo # ----------------------------------------------------------------------
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_contains_path();
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_contains_path('{ "a": true }' );
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_contains_path('{ "a": true }', 'all' );
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
select json_contains_path('{ "a": tru }', 'all', '$' );
--echo error ER_INVALID_JSON_PATH
select json_contains_path('{ "a": true }', 'all', '$[' );
--echo error ER_INVALID_JSON_PATH
select json_contains_path('{ "a": true }', 'all', '$a.***[3]' );
--echo error ER_JSON_BAD_ONE_OR_ALL_ARG
select json_contains_path('{ "a": true }', 'foo', '$.a' );
--echo error ER_INVALID_JSON_CHARSET
select json_contains_path('{}', 'all', cast('$' as binary));
select json_contains_path(null, 'all', '$.a' );
select json_contains_path('{ "a": true }', null, '$.a' );
select json_contains_path('{ "a": true }', 'all', null );
# degenerate path
select json_contains_path('{ "a": true }', 'all', '$' );
# positive, one path
select json_contains_path('{ "a": true }', 'all', '$.a' );
select json_contains_path('{ "a": true }', 'one', '$.a' );
# negative, one path
select json_contains_path('{ "a": true }', 'all', '$.b' );
select json_contains_path('{ "a": true }', 'one', '$.b' );
# all
select json_contains_path('{ "a": true }', 'all', '$.a', '$.b' );
select json_contains_path('{ "a": true }', 'all', '$.b', '$.a' );
select json_contains_path('{ "a": true }', 'ALL', '$.a', '$.b' );
select json_contains_path('{ "a": true }', 'aLl', '$.a', '$.b' );
# some
select json_contains_path('{ "a": true }', 'one', '$.a', '$.b' );
select json_contains_path('{ "a": true }', 'one', '$.b', '$.a' );
select json_contains_path('{ "a": true }', 'ONE', '$.a', '$.b' );
select json_contains_path('{ "a": true }', 'oNe', '$.a', '$.b' );
# some wildcards
select json_contains_path('{ "a": true, "b": [ 1, 2, { "c": [ 4, 5, { "d": [ 6, 7, 8, 9, 10 ]} ] } ] }', 'all', '$**[4]' );
select json_contains_path('{ "a": true, "b": [ 1, 2, { "c": [ 4, 5, { "d": [ 6, 7, 8, 9, 10 ]} ] } ] }', 'all', '$**[4]', '$**[5]' );
select json_contains_path('{ "a": true, "b": [ 1, 2, { "c": [ 4, 5, { "d": [ 6, 7, 8, 9, 10 ]} ] } ] }', 'all', '$**.c[2]' );
select json_contains_path('{ "a": true, "b": [ 1, 2, { "c": [ 4, 5, { "d": [ 6, 7, 8, 9, 10 ]} ] } ] }', 'all', '$**.c[3]' );
select json_contains_path('{"a":1, "b":2}', 'one', '$.*');
select json_contains_path('[1,2,3]', 'one', '$.*');
select json_contains_path('{}', 'one', '$[*]');
# combine ellipsis and wildcard
SELECT JSON_CONTAINS_PATH('[1, [[{"x": [{"a":{"b":{"c":42}}}]}]]]',
'one', '$**.a.*');
SELECT JSON_CONTAINS_PATH('[1, [[{"x": [{"a":{"b":{"c":42}}}]}]]]',
'all', '$**.a.*');
SELECT JSON_CONTAINS_PATH('[1,2,3]', 'one', '$**[*]');
SELECT JSON_CONTAINS_PATH('[1,2,3]', 'all', '$**[*]');
# 3 paths
select json_contains_path('{ "a": true, "b": [ 1, 2 ] }', 'all', '$**[1]', '$.b[0]', '$.c' );
select json_contains_path('{ "a": true, "b": [ 1, 2 ] }', 'all', '$.c', '$**[1]', '$.b[0]' );
select json_contains_path('{ "a": true, "b": [ 1, 2 ] }', 'all', '$.b[0]', '$.c', '$**[1]' );
select json_contains_path('{ "a": true, "b": [ 1, 2 ] }', 'one', '$**[1]', '$.b[0]', '$.c' );
select json_contains_path('{ "a": true, "b": [ 1, 2 ] }', 'one', '$.c', '$**[1]', '$.b[0]' );
select json_contains_path('{ "a": true, "b": [ 1, 2 ] }', 'one', '$.b[0]', '$.c', '$**[1]' );
# examples from the wl7909 spec
# returns 0 because there is no element at $.a.c
SELECT JSON_CONTAINS_PATH
(
'{ "a" : 123, "b" : [ 123, 456 ] }',
'all',
'$.a.c',
'$.b[1]'
);
# returns 1 because there is an element at $.b[1]
SELECT JSON_CONTAINS_PATH
(
'{ "a" : 123, "b" : [ 123, 456 ] }',
'one',
'$.a.c',
'$.b[1]'
);
# returns 0 because there is no element at the given path
SELECT JSON_CONTAINS_PATH
(
'{ "a" : 123, "b" : [ 123, 456 ] }',
'all',
'$.c'
);
# returns 1 because there is an element at $.b[1].c.d
SELECT JSON_CONTAINS_PATH
(
'{ "a" : 123, "b" : [ 123, { "c" : { "d" : true } } ] }',
'all',
'$.b[1].c.d'
);
select json_length( null );
select json_length( '1' );
--echo
--echo # invalid json text
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
select json_length( 'abc' );
select json_length( '"abc"' );
select json_length( 'true' );
select json_length( 'false' );
select json_length( 'null' );
select json_length( '{}' );
select json_length( '{ "a" : 100, "b" : 200 }' );
select json_length( '{ "a" : 100, "b" : [ 300, 400, 500 ] }' );
select json_length( '[]' );
select json_length( '[ null, "foo", true, 1.1 ]' );
select json_length( '[ null, "foo", true, { "a" : "b", "c" : "d" } ]' );
select json_length( '"foo"' );
select json_length( '1.2' );
# bad path expressions
--echo
--echo # invalid json path
--echo error ER_INVALID_JSON_PATH
select json_length( 'true', 'c$' );
--echo
--echo # invalid json path
--echo error ER_INVALID_JSON_PATH
select json_length( '{ "foo" : [ true, false ] }', '$.foo[bar]' );
--echo
--echo # wildcards not allowed in path expressions for this function
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_length( 'true', '$.*' );
--echo
--echo # wildcards not allowed in path expressions for this function
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_length( 'true', '$.foo**.bar' );
# json_length() with non-vacuous path expressions
# 1
select json_length( '[ 1, [ 2, 3, 4 ], 5 ]', '$[0]' );
# 3
select json_length( '[ 1, [ 2, 3, 4 ], 5 ]', '$[1]' );
# 1
select json_length( '[ 1, [ 2, 3, 4 ], 5 ]', '$[2]' );
# auto-wrapping: 1
select json_length( '[ 1, [ 2, 3, 4 ], 5 ]', '$[2][0]' ); # auto-wrap scalar
select json_length( '[ 1, [ 2, 3, 4 ], {"a": 1} ]', '$[2][0]' ); # ditto object
# non-existent path: null
select json_length( '[ 1, [ 2, 3, 4 ], 5 ]', '$[2][1]' );
# 3
select json_length( '[ 1, { "a": true, "b": false, "c": null }, 5 ]', '$[1]' );
# examples from the wl7909 spec
# returns 0
SELECT JSON_LENGTH
(
'{}'
);
# returns 1
SELECT JSON_LENGTH
(
'3'
);
# returns 2
SELECT JSON_LENGTH
(
'{ "a" : 123, "b" : [ 123, 456, 789 ] }'
);
# returns 3
SELECT JSON_LENGTH
(
'{ "a" : 123, "b" : [ 123, 456, 789 ] }',
'$.b'
);
# returns null because the path does not exist
SELECT JSON_LENGTH
(
'{ "a" : 123, "b" : [ 123, 456, 789 ] }',
'$.c'
);
--echo # ----------------------------------------------------------------------
--echo # Test of JSON_DEPTH function.
--echo # ----------------------------------------------------------------------
select json_depth(null);
select json_depth(cast(null as json));
#select i, json_depth(j) from t1;
select json_depth(cast('[]' as json)),
json_depth(cast('{}' as json)),
json_depth(cast('null' as json)),
json_depth(json_quote('foo'));
select json_depth(cast('[[2], 3, [[[4]]]]' as json));
select json_depth(cast('{"a": {"a1": [3]}, "b": {"b1": {"c": {"d": [5]}}}}' as json));
# examples from the wl7909 spec
# returns 1
SELECT JSON_DEPTH
(
'{}'
);
# returns 1
SELECT JSON_DEPTH
(
'[]'
);
# returns 1
SELECT JSON_DEPTH( '"abc"' );
# returns 1
SELECT JSON_DEPTH( CAST( '"abc"' AS JSON ) );
--echo error ER_INVALID_TYPE_FOR_JSON
SELECT JSON_DEPTH( 1 );
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
SELECT JSON_DEPTH( 'abc' );
# returns 1
SELECT JSON_DEPTH( CAST( 1 AS JSON ) );
# returns 2
SELECT JSON_DEPTH
(
'{ "a" : true, "b" : false, "c" : null }'
);
# returns 2
SELECT JSON_DEPTH
(
'[ "a", true, "b" , false, "c" , null ]'
);
# returns 2
SELECT JSON_DEPTH
(
'{ "a" : true, "b" : {}, "c" : null }'
);
# returns 2
SELECT JSON_DEPTH
(
'[ "a", true, "b" , {}, "c" , null ]'
);
# returns 3
SELECT JSON_DEPTH
(
'{ "a" : true, "b" : { "e" : false }, "c" : null }'
);
# returns 3
SELECT JSON_DEPTH
(
'[ "a", true, "b" , { "e" : false }, "c" , null ]'
);
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
SELECT JSON_DEPTH
(
'[ "a", true, "b" , { "e" : false }, "c" , null'
);
--echo # ----------------------------------------------------------------------
--echo # Test of JSON_REMOVE function.
--echo # ----------------------------------------------------------------------
# null args
select json_remove( null, '$[1]' );
select json_remove( null, '$[1]' ) is null;
select json_remove( '[ 1, { "a": true, "b": false, "c": null }, 5 ]', null );
select json_remove( '[ 1, { "a": true, "b": false, "c": null }, 5 ]', null ) is null;
select json_remove( '[ 1, { "a": true, "b": false, "c": null }, 5 ]', '$[1]', null );
select json_remove( '[ 1, { "a": true, "b": false, "c": null }, 5 ]', '$[1]', null ) is null;
# too few args
--echo
--echo # not enough args
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_remove();
--echo
--echo # not enough args
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_remove( '[ 1, { "a": true, "b": false, "c": null }, 5 ]' );
--echo
--echo # not enough args
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_remove( '$[1]' );
# malformed args
--echo
--echo # invalid json text
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
select json_remove( '[ 1, { "a": true, "b": false, "c": null }, 5 ', '$[1]', '$[2]' );
--echo
--echo # invalid json path
--echo error ER_INVALID_JSON_PATH
select json_remove( '[ 1, { "a": true, "b": false, "c": null }, 5 ]', '$[1', '$[2]' );
--echo
--echo # invalid json path
--echo error ER_INVALID_JSON_PATH
select json_remove( '[ 1, { "a": true, "b": false, "c": null }, 5 ]', '$[1]', '$[2' );
--echo
--echo # Vacuous path expression
--echo error ER_JSON_VACUOUS_PATH
select json_remove( '[ 1, 2, 3 ]', '$' );
--echo
--echo # Vacuous path expression
--echo error ER_JSON_VACUOUS_PATH
select json_remove( '[ 1, 2, 3 ]', '$', '$[2]' );
--echo
--echo # Vacuous path expression
--echo error ER_JSON_VACUOUS_PATH
select json_remove( '[ 1, 2, 3 ]', '$[1]', '$' );
# wildcard/ellipsis not allowed in paths
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_remove( '[ 1, 2, 3 ]', '$[*]' );
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_remove( '[ 1, 2, 3 ]', '$**[2]' );
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_remove( '[ 1, 2, 3 ]', '$[2]', '$[*]' );
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_remove( '[ 1, 2, 3 ]', '$[2]', '$**[2]' );
# simple matches
select json_remove( '[ 1, 2, 3 ]', '$[0]' );
select json_remove( '[ 1, 2, 3 ]', '$[1]' );
select json_remove( '[ 1, 2, 3 ]', '$[2]' );
select json_remove( '[ 1, 2, 3 ]', '$[3]' );
select json_remove( '[ 1, { "a": true, "b": false, "c": null }, 5 ]', '$[1]' );
# one match nested inside another
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_remove( '[ { "a": { "a": true } } ]', '$**.a' );
# multiple paths
select json_remove( '[ { "a": true }, { "b": false }, { "c": null }, { "a": null } ]', '$[0].a', '$[2].c' );
# ellipsis with matches at different levels
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_remove( '[ { "a": true }, { "b": [ { "c": { "a": true } } ] }, { "c": null }, { "a": null } ]', '$**.a' );
# nonsense path
select json_remove( '{"id": 123, "name": "systemQA", "array": [1, 2, 3]}', '$[0]' );
# examples from wl7909 spec
# returns the document {"a": "foo", "b": [true]}
SELECT JSON_REMOVE
(
'{"a" : "foo", "b" : [true, {"c" : 123}]}',
'$.b[ 1 ]'
);
# returns {"a": "foo", "b": [true, {}]} due to normalization
SELECT JSON_REMOVE
(
'{ "a" : "foo", "b" : [ true, { "c" : 123, "c" : 456 } ] }',
'$.b[ 1 ].c'
);
# returns {"a": "foo", "b": [true, {}]}
SELECT JSON_REMOVE
(
'{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }',
'$.b[ 1 ].c'
);
# returns the original document because the path doesn't identify an element
SELECT JSON_REMOVE
(
'{ "a" : "foo", "b" : [ true, { "c" : 123, "d" : 456 } ] }',
'$.b[ 1 ].e'
);
--echo # ----------------------------------------------------------------------
--echo # Test of JSON_MERGE function.
--echo # ----------------------------------------------------------------------
--echo
--echo # not enough args
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_merge();
--echo
--echo # not enough args
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_merge( '[ 1, 2, 3 ]' );
# null args result in NULL value
select json_merge( null, null );
select json_merge( null, '[ 1, 2, 3 ]' );
select json_merge( '[ 1, 2, 3 ]', null );
select json_merge( null, '[ 1, 2, 3 ]', '[ 4, 5, 6 ]' );
select json_merge( '[ 1, 2, 3 ]', null, '[ 4, 5, 6 ]' );
select json_merge( '[ 1, 2, 3 ]', '[ 4, 5, 6 ]', null );
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
select json_merge( '[1, 2]', '[3, 4' );
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
select json_merge( '[1, 2', '[3, 4]' );
# good json_merge() expressions
select json_merge( '1', '2' );
select json_merge( '1', '[2, 3]' );
select json_merge( '[1, 2]', '3' );
select json_merge( '1', '{ "a": 2 }' );
select json_merge( '{ "a": 2 }', '1' );
select json_merge( '[1, 2]', '[3, 4]' );
select json_merge( '{ "a": 2 }', '{ "b": 3}' );
select json_merge( '[1, 2]', '{ "a": 2 }' );
select json_merge( '{ "a": 2 }', '[1, 2]' );
select json_merge( '{"a": 1, "b": 2 }', '{"b": 3, "d": 4 }' );
select json_merge( '{"a": 1, "b": 2 }', '{"b": [3, 4], "d": 4 }' );
select json_merge( '{"a": 1, "b": [2, 3] }', '{"b": 4, "d": 4 }' );
select json_merge( '{"a": 1, "b": 2 }', '{"b": {"e": 7, "f": 8}, "d": 4 }' );
select json_merge( '{"b": {"e": 7, "f": 8}, "d": 4 }', '{"a": 1, "b": 2 }' );
select json_merge( '{"a": 1, "b": [2, 9] }', '{"b": [10, 11], "d": 4 }' );
select json_merge( '{"a": 1, "b": [2, 9] }', '{"b": {"e": 7, "f": 8}, "d": 4 }' );
select json_merge( '{"b": {"e": 7, "f": 8}, "d": 4 }', '{"a": 1, "b": [2, 9] }' );
select json_merge( '{"b": {"e": 7, "f": 8}, "d": 4 }', '{ "a": 1, "b": {"e": 20, "g": 21 } }' );
select json_merge( '1', '2', '3' );
select json_merge( '[1, 2 ]', '3', '[4, 5]' );
select json_merge
(
'{ "a": true, "b": { "c": 3, "d": 4 }, "e": [ 1, 2 ] }',
'{ "d": false, "b": { "g": 3, "d": 5 }, "f": [ 1, 2 ] }',
'{ "m": true, "b": { "h": 8, "d": 4 }, "e": [ 3, 4 ] }'
);
# examples from the wl7909 spec
# returns [{"a": "foo", "b": [true, {"c": 123}]}, 5, 6]
SELECT JSON_MERGE
(
'{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }',
'[ 5, 6]'
);
# returns {"a": "foo", "b": [true, {"c": 123}, false, 34]}
SELECT JSON_MERGE
(
'{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }',
'{ "b": [ false, 34 ] }'
);
# returns {"a": "foo", "b": [true, {"c": 123}, "bar"]}
SELECT JSON_MERGE
(
'{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }',
'{ "b": "bar" }'
);
# returns {"a": {"b": 1, "c": 1}}
SELECT JSON_MERGE
(
'{ "a" : { "b" : 1 } }',
'{ "a" : { "c" : 1 } }'
);
--echo # ----------------------------------------------------------------------
--echo # Test of JSON_TYPE function.
--echo # ----------------------------------------------------------------------
# negative test
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
select json_type('abc');
#select i, json_type(j) from t1;
select json_type('{"a": 2}');
select json_type('[1,2]');
select json_type('"scalar string"');
select json_type('true');
select json_type('false');
select json_type('null');
select json_type('1');
select json_type('-0');
select json_type('-0.0');
--echo error ER_INVALID_TYPE_FOR_JSON
select json_type(-1);
--echo error ER_INVALID_TYPE_FOR_JSON
select json_type(CAST(1 AS UNSIGNED));
select json_type('32767');
--echo error ER_INVALID_TYPE_FOR_JSON
select json_type(PI());
select json_type('3.14');
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
select json_type(CAST(CAST('2015-01-15' AS DATE) as CHAR CHARACTER SET 'utf8'));
--echo # ----------------------------------------------------------------------
--echo # Test of CAST(literal AS JSON)
--echo # ----------------------------------------------------------------------
select json_type(cast(cast('2014-11-25 18:00' as datetime) as json));
select json_type(cast(cast('2014-11-25' as date) as json));
select json_type(cast(cast('18:00:59' as time) as json));
# select json_type(cast(cast('2014-11-25 18:00' as timestamp) as json)); -- cast target type not supported
# select json_type(cast(cast('1999' as year) as json)); -- cast target type not supported
select json_type(cast(127 as json));
select json_type(cast(255 as json));
select json_type(cast(32767 as json));
select json_type(cast(65535 as json));
select json_type(cast(8388607 as json));
select json_type(cast(16777215 as json));
select json_type(cast(2147483647 as json));
select json_type(cast(4294967295 as json));
select json_type(cast(9223372036854775807 as json));
select json_type(cast(18446744073709551615 as json));
select json_type(cast(true as json));
select json_type(cast(b'10101' as json));
select json_type(cast(cast(3.14 as decimal(5,2)) as json));
select json_type(cast(3.14 as json));
select json_type(cast(3.14E30 as json));
# select json_type(cast(cast(3.14 as numeral(5,2)) as json)); -- cast target type not supported
# select json_type(cast(cast(3.14 as double) as json)); -- cast target type not supported
# select json_type(cast(cast(3.14 as float) as json)); -- cast target type not supported
# select json_type(cast(cast(b'10101' as bit(10)) as json)); -- cast target type not supported
# select json_type(cast(cast('10101abcde' as blob) as json)); -- cast target type not supported
select json_type(cast(cast('10101abcde' as binary) as json));
# select json_type(cast(cast('a' as enum('a','b','c')) as json)); -- cast target type not supported
# select json_type(cast(cast('a,c' as set('a','b','c')) as json)); -- cast target type not supported
select json_type(cast(ST_GeomFromText('POINT(1 1)') as json));
select json_type(cast(ST_GeomFromText('LINESTRING(0 0,1 1,2 2)') as json));
select json_type(cast(ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),
(5 5,7 5,7 7,5 7, 5 5))') as json));
select json_type(cast(null as json));
select json_type(cast(null as json)) is null; # check that it is an SQL NULL
select json_type(null) is null; # is an SQL NULL
#
# same, but now show the printable value:
#
select cast(cast('2014-11-25 18:00' as datetime) as json);
select cast(cast('2014-11-25' as date) as json);
select cast(cast('18:00:59' as time) as json);
# select cast(cast('2014-11-25 18:00' as timestamp) as json); -- cast target type not supported
# select cast(cast('1999' as year) as json); -- cast target type not supported
select cast(127 as json);
select cast(255 as json);
select cast(32767 as json);
select cast(65535 as json);
select cast(8388607 as json);
select cast(16777215 as json);
select cast(2147483647 as json);
select cast(4294967295 as json);
select cast(9223372036854775807 as json);
select cast(18446744073709551615 as json);
select cast(true as json);
select cast(b'10101' as json);
select cast(cast(3.14 as decimal(5,2)) as json);
select cast(3.14 as json);
select cast(3.14e0 as json);
# select cast(cast(3.14 as numeral(5,2)) as json); -- cast target type not supported
# select cast(cast(3.14 as double) as json); -- cast target type not supported
# select cast(cast(3.14 as float) as json); -- cast target type not supported
# select cast(cast(b'10101' as bit(10) as json); -- cast target type not supported
# select cast(cast('10101abcde' as blob) as json); -- cast target type not supported
select cast(cast('10101abcde' as binary) as json);
# select cast(cast('a' as enum('a','b','c') as json); -- cast target type not supported
# select cast(cast('a,c' as set('a','b','c') as json); -- cast target type not supported
select cast(ST_GeomFromText('POINT(1 1)') as json);
select cast(ST_GeomFromText('LINESTRING(0 0,1 1,2 2)') as json);
select cast(ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),
(5 5,7 5,7 7,5 7, 5 5))') as json);
select cast(null as json);
select cast(null as json) is null; # check that it is an SQL NULL
--echo # ----------------------------------------------------------------------
--echo # Test of JSON_KEYS function.
--echo # ----------------------------------------------------------------------
# should all give NULL:
select json_keys(NULL);
select json_keys(NULL, '$.b');
select json_keys(NULL, NULL);
select json_keys('{"a": 1, "b": {"e": "foo", "b": 3}}', '$.a');
select json_keys('{"a": 1, "b": {"e": "foo", "b": 3}}', NULL);
# non NULL results
select json_keys('{"a": 1, "b": {"e": "foo", "b": 3}}');
select json_keys('{"a": 1, "b": {"e": "foo", "b": 3}}', '$.b');
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_keys('{"a": 1, "b": {"e": "foo", "b": 3}}', '$.*.b');
# Examples from the specification
--echo # returns [ "a", "b" ]
SELECT JSON_KEYS('{ "a" : "foo", "b" : [ true, { "c" : "123" } ] }');
--echo # returns []
SELECT JSON_KEYS('{ "a" : "foo", "b" : [ true, { "c" : {} } ] }',
'$.b[1].c');
--echo # returns NULL
SELECT JSON_KEYS('{ "a" : "foo", "b" : [ true, { "c" : {} } ] }',
'$.a.b[2]');
--echo error ER_INVALID_JSON_PATH
SELECT JSON_KEYS('{"a":1}', '1010');
--echo error ER_INVALID_JSON_PATH
SELECT JSON_KEYS('{"a":1}', '1010') IS NULL;
# examples from the wl7909 spec
# returns [ "a", "b" ]
SELECT JSON_KEYS
(
'{ "a" : "foo", "b" : [ true, { "c" : "123" } ] }'
);
# returns []
SELECT JSON_KEYS
(
'{ "a" : "foo", "b" : [ true, { "c" : {} } ] }',
'$.b[1].c'
);
# returns NULL
SELECT JSON_KEYS
(
'{ "a" : "foo", "b" : [ true, { "c" : {} } ] }',
'$.a.b[2]'
);
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
SELECT JSON_KEYS();
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
SELECT JSON_KEYS('{}', '$', '$');
--echo # ----------------------------------------------------------------------
--echo # CAST(<json> AS CHAR). See also 'json_conversions.test' for other
--echo # conversion tests.
--echo # ----------------------------------------------------------------------
select cast(json_keys('{"a": 1}') as char);
select cast(cast(1 as json) as char);
select cast(json_keys(NULL) as char);
#select cast(j as char) from keys1;
--echo # ----------------------------------------------------------------------
--echo # Path matching with double-quotes
--echo # ----------------------------------------------------------------------
# matches
select json_extract( '{ "one potato" : 1 }', '$."one potato"' );
# matches
select json_extract( '{ "a.b" : 1 }', '$."a.b"' );
# doesn't match
select json_extract( '{ "\\"a\\"": 1}', '$."a"' );
# matches
select json_extract( '{ "\\"a\\"": 1}', '$."\\"a\\""' );
# matches
select json_extract( '{ "a": 1}', '$."a"' );
# matches
select json_extract( '{ "a": 1}', '$.a' );
# examples from functional spec section on Path Syntax
# [3, 2]
select json_extract( '{ "a": [ [ 3, 2 ], [ { "c" : "d" }, 1 ] ], "b": { "c" : 6 }, "one potato": 7, "b.c" : 8 }', '$.a[0]' );
# 2
select json_extract( '{ "a": [ [ 3, 2 ], [ { "c" : "d" }, 1 ] ], "b": { "c" : 6 }, "one potato": 7, "b.c" : 8 }', '$.a[0][1]' );
# [ { "c": "d" }, 1 ]
select json_extract( '{ "a": [ [ 3, 2 ], [ { "c" : "d" }, 1 ] ], "b": { "c" : 6 }, "one potato": 7, "b.c" : 8 }', '$.a[1]' );
# { "c": "d" }
select json_extract( '{ "a": [ [ 3, 2 ], [ { "c" : "d" }, 1 ] ], "b": { "c" : 6 }, "one potato": 7, "b.c" : 8 }', '$.a[1][0]' );
# "d"
select json_extract( '{ "a": [ [ 3, 2 ], [ { "c" : "d" }, 1 ] ], "b": { "c" : 6 }, "one potato": 7, "b.c" : 8 }', '$.a[1][0].c' );
# 7
select json_extract( '{ "a": [ [ 3, 2 ], [ { "c" : "d" }, 1 ] ], "b": { "c" : 6 }, "one potato": 7, "b.c" : 8 }', '$."one potato"' );
# 6
select json_extract( '{ "a": [ [ 3, 2 ], [ { "c" : "d" }, 1 ] ], "b": { "c" : 6 }, "one potato": 7, "b.c" : 8 }', '$.b.c' );
# 8
select json_extract( '{ "a": [ [ 3, 2 ], [ { "c" : "d" }, 1 ] ], "b": { "c" : 6 }, "one potato": 7, "b.c" : 8 }', '$."b.c"' );
--echo # ----------------------------------------------------------------------
--echo # Test of JSON_EXTRACT function.
--echo # ----------------------------------------------------------------------
# errors
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_extract(NULL);
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_extract('$.b');
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_extract('{"a": 1, "b": {"e": "foo", "b": 3}}');
# Confused argument order
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
select json_extract('$.a', '{"a": 1, "b": {"e": "foo", "b": 3}}');
# NULLs
select json_extract(NULL, '$.b');
select json_extract(NULL, NULL);
# non-NULLs
select json_extract('{"a": 1, "b": {"e": "foo", "b": 3}}', '$.a');
select json_extract('{"a": 1, "b": {"e": "foo", "b": 3}}', '$.*');
select json_extract('{"a": 1, "b": {"e": "foo", "b": 3}}', '$.a', '$.b.e');
select json_extract('{"a": 1, "b": [1,2,3]}', '$.b[2]');
# one path is NULL
select json_extract('{"a": 1, "b": {"e": "foo", "b": 3}}', '$.a', NULL);
# Examples from the specification
--echo # returns a JSON value containing just the string "123"
SELECT JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : "123" } ] }',
'$.b[ 1 ].c');
--echo # returns a JSON value containing just the number 123
SELECT JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }',
'$.b[ 1 ].c');
--echo # raises an error because the document is not valid
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
SELECT JSON_EXTRACT('{ "a" : [ }',
'$.b[ 1 ].c');
--echo # raises an error because the path is invalid
--echo error ER_INVALID_JSON_PATH
SELECT JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }',
'$.b[ 1 ].');
--echo # returns a JSON value containing the number 123 (because of
--echo # auto-wrapping the scalar)
SELECT JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }',
'$.b[ 1 ].c[ 0 ]');
--echo # returns a JSON value containing the object because of auto-wrapping
SELECT JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : {"not array": 4} } ] }',
'$.b[ 1 ].c[ 0 ]');
--echo # returns null because the path, although valid, does not identify a value
SELECT JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }',
'$.b[ 1 ].c[ 1 ]');
--echo # returns a JSON value containing the number 123 (due to normalization)
SELECT JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : 123, "c" : 456 } ] }',
'$.b[ 1 ].c');
--echo # returns a JSON array [ "foo", true ]
SELECT JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : 123, "c" : 456 } ] }',
'$.a', '$.b[0]');
--echo # returns a JSON array [ true ]
SELECT JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : 123, "c" : 456 } ] }',
'$.d', '$.b[0]');
# some examples verifying ellipsis behavior
# should have same result
select json_extract( '[1]', '$[0][0]' );
select json_extract( '[1]', '$**[0]' );
# should have same result
select json_extract( '{ "a": 1 }', '$.a[0]' );
select json_extract( '{ "a": 1 }', '$**[0]' );
# should have same result
select json_extract( '{ "a": 1 }', '$[0].a' );
select json_extract( '{ "a": 1 }', '$**.a' );
# should have same result
select json_extract( '{ "a": 1 }', '$[0].a[0]' );
select json_extract( '{ "a": 1 }', '$**[0]' );
# should have the same result
select json_extract( '{ "a": 1 }', '$[0].a' );
select json_extract( '{ "a": 1 }', '$**.a' );
select json_extract( '{ "a": 1 }', '$[0][0].a' );
select json_extract( '{ "a": 1 }', '$[0][0][0].a' );
# should have the same result
SELECT JSON_EXTRACT('[1, [[{"x": [{"a":{"b":{"c":42}}}]}]]]', '$**.a.*');
SELECT JSON_EXTRACT('[1, [[{"x": [{"a":{"b":{"c":42}}}]}]]]',
'$[1][0][0].x[0].a.*');
# examples from the wl7909 spec
# returns a JSON value containing just the string "123"
SELECT JSON_EXTRACT
(
'{ "a" : "foo", "b" : [ true, { "c" : "123" } ] }',
'$.b[ 1 ].c'
);
# returns a JSON value containing just the number 123
SELECT JSON_EXTRACT
(
'{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }',
'$.b[ 1 ].c'
);
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
SELECT JSON_EXTRACT
(
'{ "a" : [ }',
'$.b[ 1 ].c'
);
--echo error ER_INVALID_JSON_PATH
SELECT JSON_EXTRACT
(
'{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }',
'$.b[ 1 ].'
);
# returns a JSON value containing the number 123 (because of auto-wrapping)
SELECT JSON_EXTRACT
(
'{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }',
'$.b[ 1 ].c[ 0 ]'
);
# returns null because the path, although valid, does not identify a value
SELECT JSON_EXTRACT
(
'{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }',
'$.b[ 1 ].c[ 1 ]'
);
# returns a JSON value containing the number 123 (due to normalization)
SELECT JSON_EXTRACT
(
'{ "a" : "foo", "b" : [ true, { "c" : 123, "c" : 456 } ] }',
'$.b[ 1 ].c'
);
# returns a JSON array ["foo", true]
SELECT JSON_EXTRACT
(
'{ "a" : "foo", "b" : [ true, { "c" : 123, "c" : 456 } ] }',
'$.a', '$.b[0]'
);
# returns a the 'true' literal
SELECT JSON_EXTRACT
(
'{ "a" : "foo", "b" : [ true, { "c" : 123, "c" : 456 } ] }',
'$.d', '$.b[0]'
);
# should return NULL
select json_extract( '[ { "a": 1 }, { "a": 2 } ]', '$[*].b' ) jdoc;
# should return NULL
select json_extract( '[ { "a": 1 }, { "a": 2 } ]', '$[0].b' ) jdoc;
# should return 1
select json_extract( '[ { "a": 1 }, { "a": 2 } ]', '$[0].a' ) jdoc;
# should return [1, 2]
select json_extract( '[ { "a": 1 }, { "a": 2 } ]', '$[*].a' ) jdoc;
# should return [1]
select json_extract( '[ { "a": 1 }, { "b": 2 } ]', '$[*].a' ) jdoc;
# should return [3, 4]
select json_extract( '[ { "a": [3,4] }, { "b": 2 } ]', '$[0].a' ) jdoc;
# should return [[3, 4]]
select json_extract( '[ { "a": [3,4] }, { "b": 2 } ]', '$[*].a' ) jdoc;
# should return [[3, 4]]
select json_extract( '[ { "a": [3,4] }, { "b": 2 } ]', '$[0].a', '$[1].a' ) jdoc;
--echo # ----------------------------------------------------------------------
--echo # Test of JSON_ARRAY_APPEND function.
--echo # ----------------------------------------------------------------------
# NULLs
select json_array_append(NULL, '$.b', cast(1 as json));
select json_array_append('[1,2,3]', NULL, cast(1 as json));
select json_array_append('[1,2,3]', '$', NULL);
# wrong # args
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_array_append(NULL);
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_array_append(NULL, NULL);
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_array_append(NULL, NULL, NULL, NULL);
# auto-wrap
SELECT JSON_ARRAY_APPEND(cast('1' as json), '$', 3);
SELECT JSON_ARRAY_APPEND(cast('{"a": 3}' as json), '$', 3);
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_array_append(cast('{"a": {"b": [3]}}' as json), '$**[0]', 6);
# Examples from the specification
--echo # Auto-wrapping, since because the paths identify scalars.
--echo # should return {"a": "foo", "b": ["bar", 4], "c": ["wibble", "grape"]}
SELECT JSON_ARRAY_APPEND('{"a": "foo", "b": "bar", "c": "wibble"}',
'$.b', cast(4 as json),
'$.c', cast('"grape"' as json));
--echo # should return {"a": "foo", "b": [1, 2, 3, 4],
--echo # "c": ["apple", "pear", "grape"]}
SELECT JSON_ARRAY_APPEND('{"a" : "foo","b": [1, 2, 3], "c": ["apple", "pear"]}',
'$.b', cast(4 as json),
'$.c', cast('"grape"' as json));
# without CAST: cf. not required for ANY_JSON_ATOM arguments in specification
SELECT JSON_ARRAY_APPEND('{"a" : "foo","b": [1, 2, 3], "c": ["apple", "pear"]}',
'$.b', 4,
'$.c', 'grape');
# wild cards, multiple pairs
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_array_append( '[[], [], []]', '$[*]', 3, '$[*]', 4);
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_array_append( '[[], "not array", []]', '$[*]', 3, '$[*]', 4);
# examples from wl7909 spec
# should return {"a": "foo", "b": ["bar", 4], "c": ["wibble", "grape"]} due to autowrapping
SELECT JSON_ARRAY_APPEND
(
'{ "a" : "foo", "b" : "bar", "c" : "wibble" }',
'$.b', 4,
'$.c', "grape"
);
# should return {"a": "foo", "b": [1, 2, 3, 4], "c": ["apple", "pear", "grape"]}
SELECT JSON_ARRAY_APPEND
(
'{ "a" : "foo", "b" : [ 1, 2, 3 ], "c" : [ "apple", "pear" ] }',
'$.b', 4,
'$.c', "grape"
);
--echo # ----------------------------------------------------------------------
--echo # Bug#21373874 ASSERTION `PARENT' FAILED
--echo # ----------------------------------------------------------------------
select json_array_append('{"a":1}', '$[0]', 100);
select json_array_append('3', '$[0]', 100);
select json_array_append('3', '$[0][0][0][0]', 100);
--echo # ----------------------------------------------------------------------
--echo # Test of JSON_INSERT function.
--echo # ----------------------------------------------------------------------
# NULLs
select json_insert(NULL, '$.b', cast(1 as json));
select json_insert('[1,2,3]', NULL, cast(1 as json));
select json_insert('[1,2,3]', '$[3]', NULL);
# wrong # args
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_insert(NULL);
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_insert(NULL, NULL);
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_insert(NULL, NULL, NULL, NULL);
# positive test cases
select json_insert('[1,2,3]', '$[2]', 4);
select json_insert('[1,2,3]', '$[3]', 4);
select json_insert('[1,2,3]', '$[10]', 4);
select json_insert('{"c":4}', '$.c', 4);
select json_insert('{"c":4}', '$.a', 4);
select json_insert('1', '$', 4);
select json_insert('1', '$[0]', 4);
select json_insert('1', '$[1]', 4);
select json_insert('1', '$[10]', '4', '$[11]', 5);
select json_insert('[1,2,3]', '$[2][0]', 4);
select json_insert('[1,2,3]', '$[2][2]', 4);
select json_insert('{"a": 3}', '$.a[0]', 4);
select json_insert('{"a": 3}', '$.a[1]', 4, '$.a[2]', '5');
# wild card & auto-wrap (scalars)
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_insert(cast('{"a": [1], "b": 2}' as json), '$.*[1]', 6);
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_insert(cast('{"a": 1, "b": 2}' as json), '$.*[1]', 6);
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_insert(cast('{"a": {"b": 3}}' as json), '$.a.*[1]', 6);
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_insert(cast('{"a": {"b": [3]}}' as json), '$.a.*[1]', 6);
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_insert(cast('{"a": {"b": 3}}' as json), '$**[1]', 6);
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_insert(cast('{"a": {"b": [3]}}' as json), '$**[1]', 6);
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_insert(cast('[1]' as json), '$[*][1]', 6);
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_insert(cast('[1]' as json), '$**[1]', 6);
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_insert(cast('[1, [2], 3]' as json), '$[*][1]', 6);
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_insert(cast('[1, [2], 3]' as json), '$**[1]', 6);
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_insert(cast('[[1]]' as json), '$[*][1]', 6);
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_insert(cast('[[1]]' as json), '$**[1]', 6);
# auto-wrap object
select json_insert(cast('{"a": 3}' as json), '$[1]', 6);
# Examples from the specification
# returns the original document because the path does exist
SELECT JSON_INSERT('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.a', true);
# inserts a number, returns '{ "a" : "foo", "b" : [ 1, 2, 3 ], "c" : 123 }
SELECT JSON_INSERT('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.c', 123);
# inserts a string, returns '{ "a" : "foo", "b" : [ 1, 2, 3 ], "c" : "123" }
SELECT JSON_INSERT('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.c', '123');
# returns '{ "a" : [ "foo", true ], "b" : [ 1, 2, 3 ] }'
SELECT JSON_INSERT('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.a[1]', true);
# should return { "a" : "foo", "b": true }
SELECT JSON_INSERT('{ "a" : "foo"}', '$.b', true, '$.b', false);
# examples from the wl7909 spec
# returns the original document because the path does exist
SELECT JSON_INSERT
(
'{ "a" : "foo", "b" : [ 1, 2, 3 ] }',
'$.a',
true
);
# inserts a number, returns '{"a": "foo", "b": [1, 2, 3], "c": 123}
SELECT JSON_INSERT
(
'{ "a" : "foo", "b" : [ 1, 2, 3 ] }',
'$.c',
123
);
# inserts a string, returns '{"a": "foo", "b": [1, 2, 3], "c": "123"}
SELECT JSON_INSERT
(
'{ "a" : "foo", "b" : [ 1, 2, 3 ] }',
'$.c',
'123'
);
# returns '{"a": ["foo", true], "b": [1, 2, 3]}'
SELECT JSON_INSERT
(
'{ "a" : "foo", "b" : [ 1, 2, 3 ] }',
'$.a[1]',
true
);
# returns {"a": "foo", "b": true}
SELECT JSON_INSERT
(
'{ "a" : "foo"}',
'$.b', true,
'$.b', false
);
--echo # ----------------------------------------------------------------------
--echo # Test of JSON_ARRAY_INSERT function.
--echo # ----------------------------------------------------------------------
# NULLs
select json_array_insert(NULL, '$.b[1]', 1);
select json_array_insert('[1,2,3]', NULL, 1);
select json_array_insert('[1,2,3]', '$[3]', NULL);
# wrong # args
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_array_insert(NULL);
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_array_insert(NULL, NULL);
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_array_insert(NULL, NULL, NULL, NULL);
# path does not indicate a cell position
--echo error ER_INVALID_JSON_PATH_ARRAY_CELL
select json_array_insert('true', '$', 1);
--echo error ER_INVALID_JSON_PATH_ARRAY_CELL
select json_array_insert('true', '$.a', 1);
--echo error ER_INVALID_JSON_PATH_ARRAY_CELL
select json_array_insert('true', '$.a[1].b', 1);
# nop if there is no array at the path's parent
select json_array_insert( 'true', '$[0]', false );
select json_array_insert( 'true', '$[1]', false );
select json_array_insert( '{ "a": true }', '$.a[0]', false );
select json_array_insert( '{ "a": true }', '$.a[1]', false );
# positive tests
select json_array_insert( '[]', '$[0]', false );
select json_array_insert( '[]', '$[1]', false );
select json_array_insert( '[true]', '$[0]', false );
select json_array_insert( '[true]', '$[1]', false );
select json_array_insert( '[true]', '$[2]', false );
select json_array_insert( '{ "a": [] }', '$.a[0]', false );
select json_array_insert( '{ "a": [] }', '$.a[1]', false );
select json_array_insert( '{ "a": [true] }', '$.a[0]', false );
select json_array_insert( '{ "a": [true] }', '$.a[1]', false );
select json_array_insert( '{ "a": [true] }', '$.a[2]', false );
# insert into the middle of an array
select json_array_insert( '[1, 2, 3, 4]', '$[0]', false );
select json_array_insert( '[1, 2, 3, 4]', '$[1]', false );
select json_array_insert( '[1, 2, 3, 4]', '$[2]', false );
select json_array_insert( '[1, 2, 3, 4]', '$[3]', false );
select json_array_insert( '[1, 2, 3, 4]', '$[4]', false );
select json_array_insert( '[1, 2, 3, 4]', '$[5]', false );
select json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.a[0]', false );
select json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.a[1]', false );
select json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.a[2]', false );
select json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.a[3]', false );
select json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.a[4]', false );
select json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.a[5]', false );
# nop
select json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.b[0]', false );
select json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.b[1]', false );
# no auto-wrapping
select json_array_insert( '"a"', '$[0]', true );
select json_array_insert( '[ "a" ]', '$[0][0]', true );
select json_array_insert( '"a"', '$[1]', true );
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_insert('[]', '$.a.*[1]', 6);
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_insert('[]', '$**[1]', 6);
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_insert('[]', '$[*][1]', 6);
# multiple paths,
select json_array_insert( '[ 1, 2, 3 ]', '$[1]', true, '$[1]', false );
select json_array_insert( '[ 1, 2, 3 ]', '$[1]',
cast( '[ "a", "b", "c", "d" ]' as json ), '$[1][2]', false );
# test an error while evaluating the document expression
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
SELECT JSON_ARRAY_INSERT(JSON_EXTRACT('[1', '$'), '$[0]', 1);
# error in reading new value
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
select json_array_insert( '[ 1, 2, 3 ]', '$[1]', json_extract( '[', '$' ) );
--echo # ----------------------------------------------------------------------
--echo # Test of JSON_SET function.
--echo # ----------------------------------------------------------------------
# NULLs
select json_set(NULL, '$.b', cast(1 as json));
select json_set('[1,2,3]', NULL, cast(1 as json));
select json_set('[1,2,3]', '$[3]', NULL);
# wrong # args
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_set(NULL);
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_set(NULL, NULL);
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_set(NULL, NULL, NULL, NULL);
# Detect errors in nested function calls.
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
SELECT JSON_SET('{}', '$.name', JSON_EXTRACT('', '$'));
# positive test cases
select json_set('[1,2,3]', '$[2]', 4);
select json_set('[1,2,3]', '$[3]', 4);
select json_set('[1,2,3]', '$[10]', 4);
select json_set('{"c":4}', '$.c', 5);
select json_set('{"c":4}', '$.a', 5);
select json_set('1', '$', 4);
select json_set('1', '$[0]', 4);
select json_set('1', '$[1]', 4);
select json_set('1', '$[10]', '4', '$[11]', 5);
select json_set('[1,2,3]', '$[2][0]', 4);
select json_set('[1,2,3]', '$[2][2]', 4);
select json_set('{"a": 3}', '$.a[0]', 4);
select json_set('{"a": 3}', '$.a[1]', 4, '$.a[2]', '5');
# auto-wrap plus ellipsis with nested hits should give: {"a": [{"b": [3, 6]}, 6]}
--echo error ER_INVALID_JSON_PATH_WILDCARD
select json_set(cast('{"a": {"b": [3]}}' as json), '$**[1]', 6);
# Examples from the specification: Include when missing functions are
# available.
# returns { "a" : {}, "b" : [ 1, 2, 3 ] }
SELECT JSON_SET('{ "a" : "foo", "b" : [ 1, 2, 3 ] }',
'$.a',
JSON_OBJECT());
# # returns { "a" : "foo", "b" : [ 1, 2, 3 ], "c" : [ true, false ] }
# SELECT JSON_SET('{ "a" : "foo", "b" : [ 1, 2, 3 ] }',
# '$.c',
# JSON_ARRAY( true, false ));
# # returns { "a" : "foo", "b" : [ 1, 2, 3 ], "c" : [ true, false ] }
# SELECT JSON_SET('{ "a" : "foo", "b" : [ 1, 2, 3 ] }',
# '$.c',
# JSON_ARRAY( CAST( 'true' AS JSON ), CAST( 'false' AS JSON ) ));
# # returns [ 1, null, null, 2 ]
# SELECT JSON_SET('1', '$[3]', 2);
# should return { "a": { "b": false, "c": true } }
SELECT JSON_SET('{ "a" : "foo"}', '$.a',
JSON_OBJECT( 'b', false ), '$.a.c', true);
# returns { "a" : {}, "b" : [ 1, 2, 3 ] }
select json_set('{ "a" : "foo", "b" : [ 1, 2, 3 ] }',
'$.a',
cast('{}' as json));
# returns { "a" : "foo", "b" : [ 1, 2, 3 ], "c" : [ true, false ] }
select json_set('{ "a" : "foo", "b" : [ 1, 2, 3 ] }',
'$.c',
cast('[true, false]' as json));
# returns [ 1, null, null, 2 ]
select json_set('1', '$[3]', 2);
# should return { "a": { "b": false, "c": true } }
select json_set('{ "a" : "foo"}', '$.a',
cast('{"b": false}' as json), '$.a.c', true);
# examples from wl7909 spec
# returns {"a": {}, "b": [1, 2, 3]}
SELECT JSON_SET
(
'{ "a" : "foo", "b" : [ 1, 2, 3 ] }',
'$.a',
JSON_OBJECT()
);
# returns {"a": "foo", "b": [1, 2, 3], "c": [true, false]}
SELECT JSON_SET
(
'{ "a" : "foo", "b" : [ 1, 2, 3 ] }',
'$.c',
JSON_ARRAY( true, false )
);
# returns {"a": "foo", "b": [1, 2, 3], "c": [true, false]}
SELECT JSON_SET
(
'{ "a" : "foo", "b" : [ 1, 2, 3 ] }',
'$.c',
JSON_ARRAY( CAST( 'true' AS JSON ), CAST( 'false' AS JSON ) )
);
# returns [1, 2]
SELECT JSON_SET
(
'1',
'$[3]',
2
);
# returns {"a": {"b": false, "c": true}}
SELECT JSON_SET
(
'{ "a" : "foo"}',
'$.a', JSON_OBJECT( 'b', false ),
'$.a.c', true
);
--echo # ----------------------------------------------------------------------
--echo # Test of JSON_REPLACE function.
--echo # ----------------------------------------------------------------------
# NULLs
select json_replace(NULL, '$.b', cast(1 as json));
select json_replace('[1,2,3]', NULL, cast(1 as json));
select json_replace('[1,2,3]', '$[2]', NULL);
# wrong # args
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_replace(NULL);
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_replace(NULL, NULL);
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_replace(NULL, NULL, NULL, NULL);
# positive test cases
select json_replace('[1,2,3]', '$[2]', 4);
select json_replace('[1,2,3]', '$[3]', 4);
select json_replace('[1,2,3]', '$[10]', 4);
select json_replace('{"c":4}', '$.c', 5);
select json_replace('{"c":4}', '$.a', 5);
select json_replace('1', '$', 4);
select json_replace('1', '$[0]', 4);
select json_replace('1', '$[1]', 4);
select json_replace('1', '$[10]', '4', '$[11]', 5);
select json_replace('[1,2,3]', '$[2][0]', 4);
select json_replace('[1,2,3]', '$[2][2]', 4);
select json_replace('{"a": 3}', '$.a[0]', 4);
select json_replace('{"a": 3}', '$.a[1]', 4, '$.a[2]', '5');
# Examples from the specification
# returns the original document because the path doesn't exist
SELECT JSON_REPLACE('{ "a" : "foo", "b" : [ 1, 2, 3 ] }',
'$.c',
true);
# returns '{ "a" : true, "b" : [ 1, 2, 3 ] }'
SELECT JSON_REPLACE('{ "a" : "foo", "b" : [ 1, 2, 3 ] }',
'$.a[0]',
true);
# returns the original document because the path doesn't exist
SELECT JSON_REPLACE('{ "a" : "foo", "b" : [ 1, 2, 3 ] }',
'$.b[5]',
true);
--echo # ----------------------------------------------------------------------
--echo # Test of JSON_ARRAY function.
--echo # ----------------------------------------------------------------------
# NULLs
select json_array(NULL, '$.b', cast(1 as json));
select json_array('[1,2,3]', NULL, cast(1 as json));
select json_array('[1,2,3]', '$[3]', NULL);
# positive test cases
select json_array();
select json_array(3.14);
select json_array('[1,2,3]');
select json_array(cast('[1,2,3]' as json));
select json_array(1,2,3);
select json_array(b'0', b'1', b'10');
# returns the empty array: []
SELECT JSON_ARRAY();
--echo # ----------------------------------------------------------------------
--echo # Test of JSON_OBJECT function.
--echo # ----------------------------------------------------------------------
# odd number of args
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_object( 'a' );
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_object( 'a', 1, 'b' );
# null arg
--echo error ER_JSON_DOCUMENT_NULL_KEY
select json_object( null, 1 );
# positive tests
select json_object();
select json_object( 'a', null );
select json_object( 'a', 1 );
select json_object( 'a', 1, 'b', 'foo' );
select json_object( 'a', 1, 'b', 'foo', 'c', cast( '{ "d": "wibble" }' as json ) );
select json_object( 'a', true, 'b', false, 'c', cast( 'null' as json) );
select json_valid( json_object( '"a"', 1 ) );
# long key
select json_object( REPEAT('a', 64 * 1024), 1 );
# non-string keyNames are cast to CHAR
select json_object(json_array(), json_array());
select json_object( cast(json_array() as char), json_array());
select json_object( 1, json_array());
select json_object( cast(1 as char), json_array());
# returns the empty object: {}
SELECT JSON_OBJECT();
--echo # ----------------------------------------------------------------------
--echo # Test of JSON_SEARCH function.
--echo # ----------------------------------------------------------------------
# wrong number of args
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_search();
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_search( '{ "a": true }' );
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_search( '{ "a": true }', 'one' );
# null args
select json_search( null, 'one', 'foo' );
select json_search( '{ "a": "foo" }', null, 'foo' );
# FIXME. what should happen here?
#select json_search( '{ "a": "foo" }', 'one', null );
select json_search( '{ "a": "foo" }', 'one', 'foo', null, null );
select json_search( '{ "a": "foo" }', 'one', 'foo', null, '$.a', null );
# bad values for the oneOrAll arg
--echo error ER_JSON_BAD_ONE_OR_ALL_ARG
select json_search( '{ "a": "foo" }', 'twof', 'foo' );
--echo error ER_JSON_BAD_ONE_OR_ALL_ARG
select json_search( '{ "a": "foo" }', 'two', 'foo' );
# bad escape arg
--error ER_WRONG_ARGUMENTS
select json_search( '{ "a": "foo" }', 'one', 'foo', 'ab' );
# bad path args
--echo error ER_INVALID_JSON_PATH
select json_search( '{ "a": "foo" }', 'one', 'foo', null, '$a' );
--echo error ER_INVALID_JSON_PATH
select json_search( '{ "a": "foo" }', 'all', 'foo', null, '$.a', '$b' );
--error ER_BAD_FIELD_ERROR
select json_search(a, b, c);
# simple tests for search without path arguments
select json_search( '{ "a": "foobar" }', 'one', 'foo%' );
select json_search( '{ "a": "foobar", "b": "focus", "c": [ "arm", "foot", "shoulder" ] }', 'one', 'foo%' );
select json_search( '{ "a": "foobar", "b": "focus", "c": [ "arm", "foot", "shoulder" ] }', 'all', 'foo%' );
select json_search( '{ "a": "foobar", "b": "focus", "c": [ "arm", "foot", "shoulder" ] }', 'all', 'f__us' );
select json_search( '{ "a": [ "foolish", "folly", "foolhardy" ], "b" : "fool" }', 'all', 'foo%', null, '$.a' );
select json_search( '{ "a": [ "foolish", "folly", "foolhardy" ], "b" : "fool" }', 'all', 'foo%', null, '$.a', '$.b' );
select json_search( '{ "a": [ "foolish", "folly", "foolhardy" ], "b" : "fool" }', 'one', 'foo%', null, '$.a', '$.b' );
select json_search( '{ "a": [ "foolish", "folly", "foolhardy" ], "b" : "fool" }', 'ALL', 'foo%', null, '$.a' );
select json_search( '{ "a": [ "foolish", "folly", "foolhardy" ], "b" : "fool" }', 'aLl', 'foo%', null, '$.a', '$.b' );
select json_search( '{ "a": [ "foolish", "folly", "foolhardy" ], "b" : "fool" }', 'ONE', 'foo%', null, '$.a', '$.b' );
# wildcards in the path expression
select json_search
(
'[ { "a": { "b": { "c": "fool" } } }, { "b": { "c": "shoulder" } }, { "c": { "c": "food"} } ]',
'all',
'foo%',
null,
'$**.c'
);
select json_search
(
'[ { "a": { "b": { "c": "showtime" } } }, { "b": { "c": "shoulder" } }, { "c": { "c": "shoe"} } ]',
'all',
'sho%',
null,
'$**.c'
);
select json_search
(
'[ { "a": { "b": { "c": "showtime" } } }, { "b": { "c": "shoulder" } }, { "c": { "c": "shoe"} } ]',
'all',
'sho%e',
null,
'$**.c'
);
select json_search
(
'[ { "a": { "b": { "c": "showtime" } } }, { "b": { "c": "shoulder" } }, { "c": { "c": "shoe"} } ]',
'all',
'sho%',
null,
'$[*].c'
);
select json_search
(
'[ { "a": { "b": { "c": "showtime" } } }, [ { "b": { "c": "shout" } }, { "c": { "c": "shoe"} } ] ]',
'all',
'sho%',
null,
'$[1]**.c'
);
# escape character
select json_search( '[ "footbar", "foo%bar" ]', 'all', 'foo%bar' );
select json_search( '[ "footbar", "foo%bar" ]', 'all', 'foo\%bar' );
select json_search( '[ "footbar", "foo%bar" ]', 'all', 'foo|%bar', '|' );
select json_search( '[ "footbar", "foo%bar" ]', 'all', 'foo|%bar', '|', '$[0]' );
select json_search( '[ "footbar", "foo%bar" ]', 'all', 'foo|%bar', '|', '$[0]', '$[1]' );
select json_search( '[ "footbar", "foo%bar" ]', 'all', 'foo|%bar', '|', '$[0]', '$[1]', '$[2]' );
select json_search( '[ "footbar", "foo%bar" ]', 'all', 'foo\%bar', null );
select json_search( '[ "footbar", "foo%bar" ]', 'all', 'foo\%bar', null, '$[0]' );
select json_search( '[ "footbar", "foo%bar" ]', 'all', 'foo\%bar', null, '$[1]' );
select json_search( '[ "footbar", "foo%bar" ]', 'all', 'foo|%bar', '|', '$[0]' );
select json_search( '[ "footbar", "foo%bar" ]', 'all', 'foo|%bar', '|', '$[1]' );
# search is case-sensitive
select json_search( '[ "abc", "ABC" ]', 'all', 'aBc' );
select json_search( '[ "abc", "ABC" ]', 'all', 'abc' );
select json_search( '[ "abc", "ABC" ]', 'all', 'ABC' );
# only matches strings, not numerics
select json_search( '[ 10, "10", 1.0, "1.0" ]', 'all', '1%' );
# examples from the wl7909 spec
# returns null because numeric values don't match string values
SELECT JSON_SEARCH
(
'{ "a" : 123, "b" : [ 123, 456 ] }',
'one',
'123'
);
# returns "$.b[2]"
SELECT JSON_SEARCH
(
'{ "a" : "123", "b" : [ 123, "789", "123", "456", "123" ] }',
'one',
'123',
null,
'$.b'
);
# could return either "$.a" or "$.b.key"
SELECT JSON_SEARCH
(
'{ "a" : "123", "b" : { "key" : "123" } }',
'one',
'123'
);
# returns "$.b.key"
SELECT JSON_SEARCH
(
'{ "a" : "1243", "b" : { "key" : "1234" } }',
'one',
'123%'
);
# returns "$.b.c"
SELECT JSON_SEARCH
(
'{ "a" : "1243", "b" : { "key" : "1234", "c": "directorysub%directoryabc" } }',
'one',
'dir%torysub@%dir%',
'@'
);
# returns null because the path doesn't exist
SELECT JSON_SEARCH
(
'{ "a" : "1243", "b" : { "key" : "1234" } }',
'one',
'123%',
null,
'$.c'
);
# returns $."one potato"
SELECT JSON_UNQUOTE
(
JSON_SEARCH
(
'{ "onepotato": "foot", "one potato": "food" , "one \\"potato": "fool" }',
'all',
'food'
)
);
select json_type(case (null is null) when 1 then
cast('null' as json) else
cast('[1,2,3]' as json) end);
select json_type(case (null is not null) when 1 then
cast('null' as json) else
cast('[1,2,3]' as json) end);
select json_type( if(null is null,
cast('null' as json),
cast('[1,2,3]' as json)) );
select json_type( if(null is not null,
cast('null' as json),
cast('[1,2,3]' as json)));
select cast(json_extract(cast(concat('[', cast('["A",2]' as json), ']') as json),
'$[0][1]') as char) = 2;
--echo # ----------------------------------------------------------------------
--echo # Test of aggregate function MAX, MIN.
--echo # ----------------------------------------------------------------------
select max(cast('[1,2,3]' as json));
--echo # ----------------------------------------------------------------------
--echo # Test of JSON_QUOTE, JSON_UNQUOTE
--echo # ----------------------------------------------------------------------
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_quote();
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_quote('abc', 'def');
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_quote(NULL, 'def');
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_quote('abc', NULL);
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_unquote();
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_unquote('"abc"', '"def"');
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_unquote(NULL, 'def');
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select json_unquote('"abc"', NULL);
select json_quote(NULL);
select json_unquote(NULL);
select json_quote('abc');
select json_quote(convert('abc' using ascii));
select json_quote(convert('abc' using latin1));
select json_quote(convert('abc' using utf8));
select json_quote(convert('abc' using utf8mb4));
select json_unquote('abc'); # should do nothing
select json_unquote('"abc"');
select json_unquote(convert('"abc"' using ascii));
select json_unquote(convert('"abc"' using latin1));
select json_unquote(convert('"abc"' using utf8));
select json_unquote(convert('"abc"' using utf8mb4));
select json_quote('"');
select json_unquote('"'); # should do nothing
--echo error ER_INCORRECT_TYPE
select json_quote(123); # integer not allowed
--echo error ER_INCORRECT_TYPE
select json_unquote(123); # integer not allowed
select json_unquote('""'); # empty string
select char_length(json_unquote('""')); # verify empty string
select json_unquote('"" '); # unchanged: no final "
select json_unquote(cast(json_quote('abc') as json)); # round trip
# No change in this JSON string: it is an object
select cast('{"abc": "foo"}' as json);
select json_unquote(cast('{"abc": "foo"}' as json));
# This is a JSON string, so it is actually unquoted
select json_extract(cast('{"abc": "foo"}' as json), '$.abc');
select json_unquote(json_extract(cast('{"abc": "foo"}' as json), '$.abc'));
# Bug fix: thse should be the same
select json_unquote('["a", "b", "c"]');
select json_unquote(cast('["a", "b", "c"]' as json));
select charset(json_unquote('"abc"'));
select json_quote(convert(X'e68891' using utf8)); # chinese "I" (wo3)
select json_quote(convert(X'e68891' using utf8mb4)); # chinese "I" (wo3)
select cast(json_quote(convert(X'e68891' using utf8)) as json);
select json_unquote(convert(X'e68891' using utf8)); # chinese "I" (wo3)
select json_quote(json_quote(json_quote('abc'))); # deep quote
select json_unquote(json_unquote(json_unquote( # long round trip of it
json_quote(json_quote(json_quote('abc'))))));
# DATE/TIME will lose their quotes, too:
select cast(cast('2015-01-15 23:24:25' as datetime) as json);
select json_unquote(cast(cast('2015-01-15 23:24:25' as datetime) as json));
# as well as opaque values:
select cast(st_geomfromtext('point(1 1)') as json);
select json_unquote(cast(st_geomfromtext('point(1 1)') as json));
# examples from the wl7909 spec
# returns the SQL string literal abc
SELECT JSON_UNQUOTE( '"abc"' );
# returns the SQL string literal "abc
SELECT JSON_UNQUOTE( '"abc' );
--echo error ER_INCORRECT_TYPE
SELECT JSON_UNQUOTE( 123 );
# returns the SQL string literal abc
SELECT JSON_UNQUOTE
( CAST( CAST( '"abc"' AS JSON ) AS CHAR ) );
# returns 1
SELECT JSON_UNQUOTE
(
CAST(
JSON_EXTRACT( '{ "userName" : "fred" }', '$.userName' )
AS CHAR
)
) = 'fred';
# returns 0
SELECT
CAST(
JSON_EXTRACT( '{ "userName" : "fred" }', '$.userName' )
AS CHAR
) = 'fred';
# returns "abc"
SELECT JSON_QUOTE( 'abc' );
--echo error ER_INCORRECT_TYPE
SELECT JSON_QUOTE( 123 );
# returns the JSON document consisting of the string scalar "123"
SELECT CAST( JSON_QUOTE( '123' ) AS JSON );
--echo # ----------------------------------------------------------------------
--echo # Test of JSON_CONTAINS
--echo # ----------------------------------------------------------------------
--echo # should give NULL
select json_contains(NULL, NULL);
select json_contains(cast('{"a": 1, "b": 2}' as json), NULL);
select json_contains(NULL, cast('null' as json));
select json_contains(cast('[1]' as json), cast('[1]' as json), NULL);
--echo # should give 0:
select json_contains(cast(3.14 as json), cast(3 as json));
--echo # should give 0: not at top level
select json_contains(cast('{"a": {"b": 7}}' as json), cast('{"b": 7}' as json));
--echo # but path argument will fix it:
select json_contains(cast('{"a": {"b": 7}}' as json), cast('{"b": 7}' as json), '$.a');
--echo # but arrays "introspect"
select json_contains(cast('[1,[2.0, 3.0]]' as json), cast('[2.0]' as json));
select json_contains(cast('[1, 2, [3, [4, 5]], 6, 7]' as json), cast('5' as json));
--echo # should give 0: just a key
select json_contains(cast('{"a": 1, "b": 2}' as json), cast('"a"' as json));
--echo # should give 0: one candidate element doesn't match
select json_contains(cast('[1]' as json), cast('[1,2]' as json));
--echo # should all give 1
select json_contains(cast('null' as json), cast('null' as json));
--echo # simple object subset
select json_contains(cast('{"a": 1, "b": 2}' as json), cast( '{"a": 1}' as json));
--echo # simple vector subset
select json_contains(cast('[1, 2, 3]' as json), cast('[1, 3]' as json));
--echo # auto-wrap, should give 1
select json_contains(cast('[1, 2, 3]' as json), cast(3 as json));
--echo # ok even with nested cast off elements
select json_contains(cast('{"person": {"id": 1, "country": "norway"}}' as json),
cast('{"person": {"country": "norway"}}' as json));
--echo # vector reordering and duplicates is ok
select json_contains(cast('[1,3,5]' as json), cast('[5,3,1,5]' as json));
--echo # ok even with more elts in candidate than in doc
select json_contains(cast('[{"b": 4, "a":7}]' as json), cast('[{"a":7},{"b":4}]' as json));
select json_contains(cast('[{"b": 4, "a":7}, 5]' as json), cast('[5, {"a":7, "b":4}]' as json));
--echo # ok even with mixed number types that compare equal
select json_contains(cast('[{"b": 4, "a":7}, 5.0]' as json), cast('[5, {"a":7.0E0, "b":4}]' as json));
# Bug discovered by Rick: used to give 1 (true).
select json_contains( '{"customer": "cust3"}', '{"customer": "cust1"}' );
SELECT JSON_CONTAINS('[null,1,[2,3],true,false]', '[null,1,[3],false]');
SELECT JSON_CONTAINS('[null,1,[2,3],true,false]', '[null,1,[4],false]');
SELECT JSON_CONTAINS('[true,false]', '[[true]]');
SELECT JSON_CONTAINS('[1,2]', '[[1]]');
SELECT JSON_CONTAINS('[1,2]', '1', '$.abc');
SELECT JSON_CONTAINS('{}', '{}');
SELECT JSON_CONTAINS('{}', '{"a":1}');
SELECT JSON_CONTAINS('{"a":1}', '{"a":1,"b":2}');
# examples from the wl7909 spec
# returns 1
SELECT JSON_CONTAINS
(
CAST('[1, 4, 6]' AS JSON),
CAST('[1, 6]' AS JSON)
);
# returns 1; even with nested cast off elements
SELECT JSON_CONTAINS
(
CAST('{"person": {"id": 1, "country": "norway"}}' AS JSON),
CAST('{"person": {"country": "norway"}}' AS JSON)
);
# returns 1; reordering and duplicates are ok
SELECT JSON_CONTAINS
(
CAST('[1,3,5]' AS JSON),
CAST('[5,3,1,5]' AS JSON)
);
# return 0; no type conversion is performed
SELECT JSON_CONTAINS
(
CAST('[3.14]' AS JSON),
CAST('[3]' AS JSON)
);
# returns 1, due to auto-wrapping
SELECT JSON_CONTAINS
(
CAST('[1, 2, 3]' AS JSON),
CAST(3 AS JSON)
);
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
SELECT JSON_CONTAINS();
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
SELECT JSON_CONTAINS('[1]');
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
SELECT JSON_CONTAINS('[1]', '[1]', '$', '$[0]');
--echo # ----------------------------------------------------------------------
--echo # Wrong collation from JSON_QUOTE caused problems: Set it in
--echo # Item_func_json_quote::fix_length_and_dec. Bug found by Knut.
--echo # Similar issue for JSON_UNQUOTE and JSON_TYPE.
--echo # ----------------------------------------------------------------------
select json_object("a", ifnull(json_quote('test'), cast('null' as json)));
select cast(concat('[', json_quote('ab'), ']') as json);
select cast(concat('[', json_unquote('"12"'), ']') as json);
select cast(concat('["', json_type(cast(1 as json)), '"]') as json);
--echo #
--echo # Bug#20912438: ITEM_TYPE_HOLDER::DISPLAY_LENGTH(ITEM*): ASSERTION `0' FAILED
--echo #
(SELECT JSON_KEYS('{ "key80": "2015-04-20 11:53:55"}')) UNION ALL
(SELECT JSON_KEYS('{ "key80": "2015-04-20 11:53:55" }') LIMIT 0);
SELECT CAST(1 AS JSON) UNION ALL SELECT CAST(1 AS JSON);
# Exercise NULL handling and error handling in Item_copy_json::copy().
SELECT COUNT(*), CAST(NULL AS JSON);
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
SELECT COUNT(*), JSON_EXTRACT('not valid json!', '$');
--echo # ----------------------------------------------------------------------
--echo # Bug report from John E.
--echo # Crash in Item_copy_json::~Item_copy_json
--echo # ----------------------------------------------------------------------
EXPLAIN SELECT COUNT(*), JSON_KEYS('{}');
select json_search( '{ "a": "foo" }', 'one', 'foo', 'a' );
select json_search( '{ "a": "foo" }', 'one', 'foo', null );
select json_search( '{ "a": "foo" }', 'one', 'foo', convert(x'f8' using latin1) );
# bad escape arg
--error ER_WRONG_ARGUMENTS
select json_search( '{ "a": "foo" }', 'one', 'foo', 'ab' );
--echo # ----------------------------------------------------------------------
--echo # Wrong results when Json_path_cache primed is accessed
--echo # during the prepare-phase.
--echo #----------------------------------------------------------------------
select json_remove( '[ 1, { "a": true, "b": false, "c": null }, 5 ]', null ) is null;
prepare stmt1 from 'select json_remove( ''[ 1, { "a": true, "b": false, "c": null }, 5 ]'', null ) is null';
execute stmt1;
--echo error ER_INVALID_JSON_PATH
select json_remove( '[ 1, { "a": true, "b": false, "c": null }, 5 ]', '$.' ) is null;
--echo error ER_INVALID_JSON_PATH
prepare stmt1 from 'select json_remove( ''[ 1, { "a": true, "b": false, "c": null }, 5 ]'', ''$.'' ) is null';
--echo # ----------------------------------------------------------------------
--echo # Bug#20987329 VALUE OF PREPARED STATEMENT PLACEHOLDER FOR PARAMETER
--echo # IN JSON_EXTRACT IS STICKY
--echo #----------------------------------------------------------------------
# should get different results with different parameter values
# json_extract()
# json_contains()
prepare json_stmt1 FROM 'select json_contains( ''{ "keyA": [1, 2, 3], "keyB": [4, 5, 6] }'', ''[2]'', ? )';
set @mypath = '$.keyA';
execute json_stmt1 USING @mypath;
set @mypath = '$.keyB';
execute json_stmt1 USING @mypath;
# json_contains_path()
prepare json_stmt2 FROM 'select json_contains_path( ''{ "keyA": [1, 2, 3] }'', ''all'', ? )';
set @mypath = '$.keyA';
execute json_stmt2 USING @mypath;
set @mypath = '$.keyB';
execute json_stmt2 USING @mypath;
# json_length()
prepare json_stmt3 FROM 'select json_length( ''{ "keyA": [1, 2, 3], "keyB": [1, 2, 3, 4] }'', ? )';
set @mypath = '$.keyA';
execute json_stmt3 USING @mypath;
set @mypath = '$.keyB';
execute json_stmt3 USING @mypath;
# json_keys()
prepare json_stmt4 FROM 'select json_keys( ''[ { "keyA": true }, { "keyB": false } ]'', ? )';
set @mypath = '$[0]';
execute json_stmt4 USING @mypath;
set @mypath = '$[1]';
execute json_stmt4 USING @mypath;
# json_array_append()
prepare json_stmt5 FROM 'select json_array_append( ''{ "keyA": [1, 2], "keyB": [3, 4] }'', ?, 5 )';
set @mypath = '$.keyA';
execute json_stmt5 USING @mypath;
set @mypath = '$.keyB';
execute json_stmt5 USING @mypath;
# json_insert()
prepare json_stmt6 FROM 'select json_insert( ''{ "keyA": [1, 2], "keyB": [3, 4] }'', ?, 5 )';
set @mypath = '$.keyA[2]';
execute json_stmt6 USING @mypath;
set @mypath = '$.keyB[2]';
execute json_stmt6 USING @mypath;
# json_set()
prepare json_stmt7 FROM 'select json_set( ''{ "keyA": [1, 2], "keyB": [3, 4] }'', ?, 5 )';
set @mypath = '$.keyA[2]';
execute json_stmt7 USING @mypath;
set @mypath = '$.keyB[2]';
execute json_stmt7 USING @mypath;
# json_replace()
prepare json_stmt8 FROM 'select json_replace( ''{ "keyA": [1, 2], "keyB": [3, 4] }'', ?, 5 )';
set @mypath = '$.keyA[1]';
execute json_stmt8 USING @mypath;
set @mypath = '$.keyB[1]';
execute json_stmt8 USING @mypath;
# json_search()
prepare json_stmt9 FROM 'select json_search( ''{ "keyA": [ "foot" ], "keyB": [ "food" ] }'', ''all'', ''foo%'', null, ? )';
set @mypath = '$.keyA';
execute json_stmt9 USING @mypath;
set @mypath = '$.keyB';
execute json_stmt9 USING @mypath;
# json_remove()
prepare json_stmt10 FROM 'select json_remove( ''{ "keyA": [ "foot" ], "keyB": [ "food" ] }'', ? )';
set @mypath = '$.keyA';
execute json_stmt10 USING @mypath;
set @mypath = '$.keyB';
execute json_stmt10 USING @mypath;
# similar caching problem for the oneOrAll args
prepare json_stmt11 FROM 'select json_contains_path( ''{ "keyA": true }'', ?, ''$.keyA'', ''$.keyB'' )';
set @mypath = 'one';
execute json_stmt11 USING @mypath;
set @mypath = 'all';
execute json_stmt11 USING @mypath;
prepare json_stmt12 FROM 'select json_search( ''{ "keyA": [ "foot" ], "keyB": [ "food" ] }'', ?, ''foo%'' )';
set @mypath = 'one';
execute json_stmt12 USING @mypath;
set @mypath = 'all';
execute json_stmt12 USING @mypath;
--echo #
--echo # Bug#21128632 JSON_QUOTE(JSON_TYPE(...)) GIVES ERROR 3139 ER_INVALID_JSON_CHARSET
--echo #
select json_quote( json_type( json_object() ) );
select json_quote( json_type( cast('{}' as json) ) );
--echo #
--echo # Bug#21148020 OUTPUT FROM JSON_TYPE() IS TRUNCATED
--echo # WHEN EXECUTED IN A VIEW OR JOIN
--echo #
SELECT JSON_TYPE(JSON_OBJECT());
CREATE VIEW v1 AS SELECT JSON_TYPE(JSON_OBJECT());
SELECT * FROM v1;
drop view v1;
# SELECT JSON_TYPE(CAST(CAST('2015-05-25 11:23:55' AS DATETIME) AS JSON));
# CREATE VIEW v2 AS SELECT JSON_TYPE(CAST(CAST('2015-05-25 11:23:55' AS
# DATETIME) AS JSON));
# SELECT * FROM v2;
# drop view v2;
--echo #
--echo # Bug#21198333 SIG 6 IN ITEM_CACHE_JSON::CACHE_VALUE AT SQL/ITEM.CC:9470
--echo #
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
SELECT MIN(JSON_EXTRACT('not json', '$'));
--echo #
--echo # Bug#21200657 DATA FROM DERIVED TABLE BASED
--echo # ON JSN_QUOTE()/JSN_UNQUOTE() CALL IS TRUNCATED
--echo #
SELECT JSON_QUOTE('This is a string that should not be truncated') AS field1;
SELECT JSON_UNQUOTE(JSON_QUOTE('This is a string that should not be truncated')) AS field1;
SELECT * FROM (SELECT JSON_QUOTE('This is a string that should not be truncated') AS field1) AS DERIVED_TABLE;
SELECT * FROM (SELECT JSON_UNQUOTE("This is a string that should not be truncated") AS field1) AS DERIVED_TABLE;
SELECT * FROM (SELECT JSON_UNQUOTE(JSON_QUOTE('This is a string that should not be truncated')) AS field1) AS DERIVED_TABLE;
--echo #
--echo # Bug#21296173 JSON_OBJECT('KEY', BOOLEAN_LITERAL) USES VALUES 0, 1
--echo # FOR BOOL WHEN USED VIA VIEW
--echo #
SELECT JSON_OBJECT('key1', false, 'key2', true);
SELECT JSON_ARRAY('key1', false, 'key2', true);
CREATE VIEW v1 AS SELECT JSON_OBJECT('key1', false, 'key2', true);
SELECT * FROM v1;
CREATE VIEW v2 AS SELECT JSON_ARRAY('key1', false, 'key2', true);
SELECT * FROM v2;
drop view v1;
drop view v2;
--echo #
--echo # Bug#21293089 JSON_CONTAINS() RETURNS WRONG RESULT WITH EMPTY JSON ARRAY
--echo #
SELECT JSON_CONTAINS('[]', '{"a" : 1}');
SELECT JSON_CONTAINS('[]', '[1, 2, 3, 4, 5]');
SELECT JSON_CONTAINS('[]', '[1, 2, 3, 4, {"a" : 1}]');
SELECT JSON_CONTAINS('[]', '{"a" : [1, 2, 3, 4, 5]}');
SELECT JSON_CONTAINS('[]', '[]');
--echo #
--echo # Bug#21377136 STACK OVERFLOW IN RAPIDJSON::GENERICREADER
--echo #
--echo error ER_JSON_DOCUMENT_TOO_DEEP
SELECT JSON_VALID(REPEAT('[', 100000));
--echo error ER_JSON_DOCUMENT_TOO_DEEP
SELECT JSON_VALID(REPEAT('{"a":', 100000));
--echo error ER_JSON_DOCUMENT_TOO_DEEP
SELECT JSON_VALID(REPEAT('{"a":[', 100000));
--echo error ER_JSON_DOCUMENT_TOO_DEEP
SELECT JSON_VALID(REPEAT('[{"a":', 100000));
--echo #
--echo # Bug#21381806 JSON: ASSERTION FAILED: ARG->NULL_VALUE
--echo #
SELECT JSON_SET(CASE WHEN 1 THEN NULL ELSE NULL END, '{}', '{}');
SELECT JSON_VALID(CASE WHEN 1 THEN NULL ELSE NULL END);
SELECT JSON_ARRAY(CASE WHEN 1 THEN NULL ELSE NULL END);
--echo #
--echo # Bug#21384048 ASSERTION FAILED: N >= 0 && N <= 308
--echo # IN RAPIDJSON::INTERNAL::FASTPATH
--echo #
SELECT JSON_EXTRACT('-1E-36181012216111515851075235238', '$');
SELECT JSON_EXTRACT('1E-36181012216111515851075235238', '$');
SELECT JSON_EXTRACT('1E-325', '$');
SELECT JSON_EXTRACT('1E-324', '$');
SELECT JSON_EXTRACT('1E-323', '$');
SELECT JSON_EXTRACT('1E+308', '$');
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
SELECT JSON_EXTRACT('1E+309', '$');
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
SELECT JSON_EXTRACT('1E+36181012216111515851075235238', '$');
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
SELECT JSON_EXTRACT('-1E+36181012216111515851075235238', '$');
--echo #
--echo # Bug#21383284: ASSERTION IN SELECT_LEX::SETUP_CONDS
--echo #
--error ER_WRONG_ARGUMENTS
SELECT 1 FROM dual WHERE JSON_SEARCH('{}', 'one', 'foo', 'too-long-escape');
--echo error ER_INVALID_JSON_TEXT_IN_PARAM
SELECT 1 FROM dual WHERE JSON_SEARCH('{}', 'one', 'foo', JSON_EXTRACT('', '$'));
--echo #
--echo # Bug#21442624 INCORRECT RESULT FROM JSON_SET WITH AUTO-WRAPPING
--echo #
SELECT JSON_SET('1', '$', 100);
SELECT JSON_SET('1', '$[0]', 100);
SELECT JSON_SET('1', '$[0][0]', 100);
SELECT JSON_SET('1', '$[0][0][0]', 100);
SELECT JSON_SET('[]', '$', 100);
SELECT JSON_SET('[]', '$[0]', 100);
SELECT JSON_SET('[]', '$[0][0]', 100);
SELECT JSON_SET('[]', '$[0][0][0]', 100);
SELECT JSON_SET('[1]', '$', 100);
SELECT JSON_SET('[1]', '$[0]', 100);
SELECT JSON_SET('[1]', '$[0][0]', 100);
SELECT JSON_SET('[1]', '$[0][0][0]', 100);
SELECT JSON_SET('[[1]]', '$', 100);
SELECT JSON_SET('[[1]]', '$[0]', 100);
SELECT JSON_SET('[[1]]', '$[0][0]', 100);
SELECT JSON_SET('[[1]]', '$[0][0][0]', 100);
SELECT JSON_SET('[[[1]]]', '$', 100);
SELECT JSON_SET('[[[1]]]', '$[0]', 100);
SELECT JSON_SET('[[[1]]]', '$[0][0]', 100);
SELECT JSON_SET('[[[1]]]', '$[0][0][0]', 100);
SELECT JSON_REPLACE('1', '$', 100);
SELECT JSON_REPLACE('1', '$[0]', 100);
SELECT JSON_REPLACE('1', '$[0][0]', 100);
SELECT JSON_REPLACE('1', '$[0][0][0]', 100);
SELECT JSON_REPLACE('[]', '$', 100);
SELECT JSON_REPLACE('[]', '$[0]', 100);
SELECT JSON_REPLACE('[]', '$[0][0]', 100);
SELECT JSON_REPLACE('[]', '$[0][0][0]', 100);
SELECT JSON_REPLACE('[1]', '$', 100);
SELECT JSON_REPLACE('[1]', '$[0]', 100);
SELECT JSON_REPLACE('[1]', '$[0][0]', 100);
SELECT JSON_REPLACE('[1]', '$[0][0][0]', 100);
SELECT JSON_REPLACE('[[1]]', '$', 100);
SELECT JSON_REPLACE('[[1]]', '$[0]', 100);
SELECT JSON_REPLACE('[[1]]', '$[0][0]', 100);
SELECT JSON_REPLACE('[[1]]', '$[0][0][0]', 100);
SELECT JSON_REPLACE('[[[1]]]', '$', 100);
SELECT JSON_REPLACE('[[[1]]]', '$[0]', 100);
SELECT JSON_REPLACE('[[[1]]]', '$[0][0]', 100);
SELECT JSON_REPLACE('[[[1]]]', '$[0][0][0]', 100);
--echo #
--echo # Bug#21828321: JSON FUNCS CALL DBUG_ABORT OR EXIT() ON WINDOWS!
--echo #
# LEAST and GREATEST treat JSON arguments as strings for now. They used to hit
# an assertion if used in a JSON context and all arguments were JSON values, or
# a mix of NULLs and JSON values.
SELECT JSON_ARRAY(LEAST(NULL, NULL), GREATEST(NULL, NULL), LEAST(j1, NULL),
GREATEST(NULL, j2), LEAST(j1, j2), GREATEST(j1, j2)) AS j
FROM (SELECT CAST('1' AS JSON) AS j1, CAST('2' AS JSON) AS j2) t;
......@@ -78,6 +78,8 @@ select json_extract('[10, 20, [30, 40]]', '$[2][*]');
select json_extract('[10, 20, [{"a":3}, 30, 40]]', '$[2][*]');
select json_extract('1', '$');
select json_extract('[10, 20, [30, 40], 1, 10]', '$[1]');
select json_extract('[10, 20, [30, 40], 1, 10]', '$[1]', '$[25]');
select json_extract( '[{"a": [3, 4]}, {"b": 2}]', '$[0].a', '$[1].a');
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);
......
......@@ -168,6 +168,7 @@ void report_json_error_ex(String *js, json_engine_t *je,
#define NO_WILDCARD_ALLOWED 1
#define SHOULD_END_WITH_ARRAY 2
#define TRIVIAL_PATH_NOT_ALLOWED 3
#define report_path_error(js, je, n_param) \
report_path_error_ex(js, je, func_name(), n_param,\
......@@ -205,6 +206,11 @@ static void report_path_error_ex(String *ps, json_path_t *p,
code= ER_JSON_PATH_NO_WILDCARD;
break;
case TRIVIAL_PATH_NOT_ALLOWED:
code= ER_JSON_PATH_EMPTY;
break;
default:
return;
}
......@@ -547,22 +553,43 @@ void Item_func_json_extract::fix_length_and_dec()
}
static bool path_exact(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;
}
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_extract::val_str(String *str)
{
String *js= args[0]->val_str(&tmp_js);
json_engine_t je;
bool multiple_values_found= FALSE;
json_engine_t je, sav_je;
json_path_t p;
const uchar *value;
const char *first_value= NULL;
uint n_arg, v_len, first_len;
uint array_counters[JSON_DEPTH_LIMIT];
int not_first_value= 0;
uint n_arg, v_len;
int possible_multiple_values;
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;
......@@ -572,76 +599,66 @@ String *Item_func_json_extract::val_str(String *str)
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()))
{
report_path_error(s_p, &c_path->p, n_arg);
goto return_null;
}
c_path->parsed= c_path->constant;
}
}
if (args[n_arg]->null_value)
goto return_null;
possible_multiple_values= arg_count > 2 ||
(paths[0].p.types_used & (JSON_PATH_WILD | JSON_PATH_DOUBLE_WILD));
json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
(const uchar *) js->ptr() + js->length());
str->set_charset(js->charset());
str->length(0);
c_path->cur_step= c_path->p.steps;
if (possible_multiple_values && str->append("[", 1))
goto error;
while (!json_find_path(&je, &c_path->p, &c_path->cur_step, array_counters))
{
if (json_read_value(&je))
goto error;
json_get_path_start(&je, js->charset(),(const uchar *) js->ptr(),
(const uchar *) js->ptr() + js->length(), &p);
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;
}
while (json_get_path_next(&je, &p) == 0)
{
if (!path_exact(paths, arg_count-1, &p))
continue;
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;
}
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. */
}
value= je.value_begin;
}
if (multiple_values_found &&
(str->append(", ", 2) ||
str->append((const char *) value, v_len)))
goto error; /* Out of memory. */
if (json_value_scalar(&je))
v_len= je.value_end - value;
else
{
if (possible_multiple_values)
sav_je= je;
if (json_skip_level(&je))
goto error;
v_len= je.s.c_str - value;
if (possible_multiple_values)
je= sav_je;
}
if (json_scan_next(&je))
break;
if ((not_first_value && str->append(", ", 2)) ||
str->append((const char *) value, v_len))
goto error; /* Out of memory. */
}
not_first_value= 1;
if (!possible_multiple_values)
break;
}
if (je.s.error)
goto error;
if (first_value == NULL)
if (!not_first_value)
{
/* Nothing was found. */
goto return_null;
}
if (multiple_values_found ?
str->append("]") :
str->append(first_value, first_len))
if (possible_multiple_values && str->append("]"))
goto error; /* Out of memory. */
return str;
......@@ -796,12 +813,14 @@ static int check_contains(json_engine_t *js, json_engine_t *value)
{
while (json_scan_next(js) == 0 && js->state != JST_ARRAY_END)
{
json_level_t c_level;
int c_level, v_scalar;
DBUG_ASSERT(js->state == JST_VALUE);
if (json_read_value(js))
return FALSE;
c_level= json_value_scalar(js) ? NULL : json_get_level(js);
if (!(v_scalar= json_value_scalar(js)))
c_level= json_get_level(js);
if (check_contains(js, value))
{
if (json_skip_level(js))
......@@ -809,7 +828,7 @@ static int check_contains(json_engine_t *js, json_engine_t *value)
return TRUE;
}
if (value->s.error || js->s.error ||
(c_level && json_skip_to_level(js, c_level)))
(!v_scalar && json_skip_to_level(js, c_level)))
return FALSE;
}
return FALSE;
......@@ -955,6 +974,8 @@ longlong Item_func_json_contains::val_int()
bool Item_func_json_contains_path::fix_fields(THD *thd, Item **ref)
{
return alloc_tmp_paths(thd, arg_count-2, &paths, &tmp_paths) ||
(p_found= (bool *) alloc_root(thd->mem_root,
(arg_count-2)*sizeof(bool))) == NULL ||
Item_int_func::fix_fields(thd, ref);
}
......@@ -1010,6 +1031,7 @@ static int parse_one_or_all(const Item_func *f, Item *ooa_arg,
}
#ifdef DUMMY
longlong Item_func_json_contains_path::val_int()
{
String *js= args[0]->val_str(&tmp_js);
......@@ -1076,6 +1098,87 @@ longlong Item_func_json_contains_path::val_int()
null_value= 1;
return 0;
}
#endif /*DUMMY*/
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;
json_path_t p;
int n_found;
if ((null_value= args[0]->null_value))
return 0;
if (parse_one_or_all(this, args[1], &ooa_parsed, ooa_constant, &mode_one))
goto null_return;;
for (n_arg=2; n_arg < arg_count; n_arg++)
{
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()))
{
report_path_error(s_p, &c_path->p, n_arg);
goto null_return;
}
c_path->parsed= c_path->constant;
}
if (args[n_arg]->null_value)
goto null_return;
}
json_get_path_start(&je, js->charset(),(const uchar *) js->ptr(),
(const uchar *) js->ptr() + js->length(), &p);
if (!mode_one)
{
bzero(p_found, (arg_count-2) * sizeof(bool));
n_found= arg_count - 2;
}
result= 0;
while (json_get_path_next(&je, &p) == 0)
{
int n_path= arg_count - 2;
json_path_with_flags *c_path= paths;
for (; n_path > 0; n_path--, c_path++)
{
if (json_path_compare(&c_path->p, &p) >= 0)
{
if (mode_one)
{
result= 1;
break;
}
/* mode_all */
if (p_found[n_path-1])
continue; /* already found */
if (--n_found == 0)
{
result= 1;
break;
}
p_found[n_path-1]= TRUE;
}
}
}
if (je.s.error == 0)
return result;
report_json_error(js, &je, 0);
null_return:
null_value= 1;
return 0;
}
static int append_json_value(String *str, Item *item, String *tmp_val)
......@@ -1626,10 +1729,10 @@ longlong Item_func_json_length::val_int()
{
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()))
path_setup_nwc(&path.p, s_p->charset(), (const uchar *) s_p->ptr(),
(const uchar *) s_p->ptr() + s_p->length()))
{
report_path_error(s_p, &path.p, 2);
report_path_error(s_p, &path.p, 1);
goto null_return;
}
path.parsed= path.constant;
......@@ -2040,7 +2143,7 @@ String *Item_func_json_remove::val_str(String *str)
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++)
for (n_arg=1, n_path=0; n_arg < arg_count; n_arg++, n_path++)
{
uint array_counters[JSON_DEPTH_LIMIT];
json_path_with_flags *c_path= paths + n_path;
......@@ -2064,7 +2167,11 @@ String *Item_func_json_remove::val_str(String *str)
/* We search to the last step. */
c_path->p.last_step--;
if (c_path->p.last_step < c_path->p.steps)
{
c_path->p.s.error= TRIVIAL_PATH_NOT_ALLOWED;
report_path_error(s_p, &c_path->p, n_arg);
goto null_return;
}
}
c_path->parsed= c_path->constant;
}
......@@ -2371,60 +2478,6 @@ static int append_json_path(String *str, const json_path_t *p)
}
static int json_path_compare(const json_path_t *a, const json_path_t *b)
{
const json_path_step_t *sa= a->steps + 1;
const json_path_step_t *sb= b->steps + 1;
if (a->last_step - sa > b->last_step - sb)
return -2;
while (sa <= a->last_step)
{
if (sb > b->last_step)
return -2;
if (!((sa->type & sb->type) & JSON_PATH_KEY_OR_ARRAY))
goto step_failed;
if (sa->type & JSON_PATH_ARRAY)
{
if (!(sa->type & JSON_PATH_WILD) && sa->n_item != sb->n_item)
goto step_failed;
}
else /* JSON_PATH_KEY */
{
if (!(sa->type & JSON_PATH_WILD) &&
(sa->key_end - sa->key != sb->key_end - sb->key ||
memcmp(sa->key, sb->key, sa->key_end - sa->key) != 0))
goto step_failed;
}
sb++;
sa++;
continue;
step_failed:
if (!(sa->type & JSON_PATH_DOUBLE_WILD))
return -1;
sb++;
}
return sb <= b->last_step;
}
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);
......@@ -2462,75 +2515,38 @@ String *Item_func_json_search::val_str(String *str)
goto null_return;
}
json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
(const uchar *) js->ptr() + js->length());
p.last_step= p.steps;
p.steps[0].type= JSON_PATH_ARRAY_WILD;
p.steps[0].n_item= 0;
json_get_path_start(&je, js->charset(),(const uchar *) js->ptr(),
(const uchar *) js->ptr() + js->length(), &p);
do
while (json_get_path_next(&je, &p) == 0)
{
switch (je.state)
if (json_value_scalar(&je))
{
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 js_error;
/* Now we have je.state == JST_VALUE, so let's handle it. */
case JST_VALUE:
if (json_read_value(&je))
goto js_error;
if (json_value_scalar(&je))
if ((arg_count < 5 || path_ok(paths, arg_count - 4, &p)) &&
compare_json_value_wild(&je, s_str) != 0)
{
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)
{
++n_path_found;
if (n_path_found == 1)
{
sav_path= p;
sav_path.last_step= sav_path.steps + (p.last_step - p.steps);
}
else
sav_path= p;
sav_path.last_step= sav_path.steps + (p.last_step - p.steps);
}
else
{
if (n_path_found == 2)
{
if (n_path_found == 2)
{
if (str->append("[", 1) ||
append_json_path(str, &sav_path))
if (str->append("[", 1) ||
append_json_path(str, &sav_path))
goto js_error;
}
if (str->append(", ", 2) || append_json_path(str, &p))
goto js_error;
}
if (mode_one)
goto end;
if (str->append(", ", 2) || append_json_path(str, &p))
goto js_error;
}
if (p.last_step->type & JSON_PATH_ARRAY)
p.last_step->n_item++;
if (mode_one)
goto end;
}
else
{
p.last_step++;
p.last_step->type= (enum json_path_step_types) je.value_type;
p.last_step->n_item= 0;
}
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 js_error;
......
......@@ -197,6 +197,7 @@ class Item_func_json_contains_path: public Item_int_func
String *tmp_paths;
bool mode_one;
bool ooa_constant, ooa_parsed;
bool *p_found;
public:
Item_func_json_contains_path(THD *thd, List<Item> &list):
......
......@@ -7446,3 +7446,5 @@ ER_GEOJSON_TOO_FEW_POINTS
eng "Incorrect GeoJSON format - too few points for linestring specified."
ER_GEOJSON_NOT_CLOSED
eng "Incorrect GeoJSON format - polygon not closed."
ER_JSON_PATH_EMPTY
eng "Path expression '$' is not allowed in argument %d to function '%s'."
#include <my_global.h>
#include <string.h>
#include <m_ctype.h>
......@@ -126,9 +127,9 @@ static int syntax_error(json_engine_t *j)
static int mark_object(json_engine_t *j)
{
j->state= JST_OBJ_START;
if ((++j->stack_p) - j->stack < JSON_DEPTH_LIMIT)
if (++j->stack_p < JSON_DEPTH_LIMIT)
{
*j->stack_p= JST_OBJ_CONT;
j->stack[j->stack_p]= JST_OBJ_CONT;
return 0;
}
j->s.error= JE_DEPTH;
......@@ -142,9 +143,9 @@ static int read_obj(json_engine_t *j)
j->state= JST_OBJ_START;
j->value_type= JSON_VALUE_OBJECT;
j->value= j->value_begin;
if ((++j->stack_p) - j->stack < JSON_DEPTH_LIMIT)
if (++j->stack_p < JSON_DEPTH_LIMIT)
{
*j->stack_p= JST_OBJ_CONT;
j->stack[j->stack_p]= JST_OBJ_CONT;
return 0;
}
j->s.error= JE_DEPTH;
......@@ -156,9 +157,9 @@ static int read_obj(json_engine_t *j)
static int mark_array(json_engine_t *j)
{
j->state= JST_ARRAY_START;
if ((++j->stack_p) - j->stack < JSON_DEPTH_LIMIT)
if (++j->stack_p < JSON_DEPTH_LIMIT)
{
*j->stack_p= JST_ARRAY_CONT;
j->stack[j->stack_p]= JST_ARRAY_CONT;
j->value= j->value_begin;
return 0;
}
......@@ -172,9 +173,9 @@ static int read_array(json_engine_t *j)
j->state= JST_ARRAY_START;
j->value_type= JSON_VALUE_ARRAY;
j->value= j->value_begin;
if ((++j->stack_p) - j->stack < JSON_DEPTH_LIMIT)
if (++j->stack_p < JSON_DEPTH_LIMIT)
{
*j->stack_p= JST_ARRAY_CONT;
j->stack[j->stack_p]= JST_ARRAY_CONT;
return 0;
}
j->s.error= JE_DEPTH;
......@@ -376,7 +377,7 @@ static int skip_str_constant(json_engine_t *j)
return j->s.error= json_eos(&j->s) ? JE_EOS : JE_BAD_CHR;
}
j->state= *j->stack_p;
j->state= j->stack[j->stack_p];
return 0;
}
......@@ -397,7 +398,7 @@ static int read_strn(json_engine_t *j)
if (skip_str_constant(j))
return 1;
j->state= *j->stack_p;
j->state= j->stack[j->stack_p];
j->value_len= (j->s.c_str - j->value) - 1;
return 0;
}
......@@ -469,7 +470,7 @@ static int json_num_states[NS_NUM_STATES][N_NUM_CLASSES]=
/*GO*/ { NS_GO1, JE_SYN, NS_Z, NS_INT, JE_SYN, JE_SYN, JE_SYN, JE_BAD_CHR },
/*GO1*/ { JE_SYN, JE_SYN, NS_Z1, NS_INT, JE_SYN, JE_SYN, JE_SYN, JE_BAD_CHR },
/*ZERO*/ { JE_SYN, JE_SYN, JE_SYN, JE_SYN, NS_FRAC, JE_SYN, NS_OK, JE_BAD_CHR },
/*ZE1*/ { JE_SYN, JE_SYN, JE_SYN, JE_SYN, NS_FRAC, JE_SYN, JE_SYN, JE_BAD_CHR },
/*ZE1*/ { JE_SYN, JE_SYN, JE_SYN, JE_SYN, NS_FRAC, JE_SYN, NS_OK, JE_BAD_CHR },
/*INT*/ { JE_SYN, JE_SYN, NS_INT, NS_INT, NS_FRAC, NS_EX, NS_OK, JE_BAD_CHR },
/*FRAC*/ { JE_SYN, JE_SYN, NS_FRAC, NS_FRAC,JE_SYN, NS_EX, NS_OK, JE_BAD_CHR },
/*EX*/ { NS_EX1, NS_EX1, NS_EX1, NS_EX1, JE_SYN, JE_SYN, JE_SYN, JE_BAD_CHR },
......@@ -517,7 +518,7 @@ static int skip_num_constant(json_engine_t *j)
break;
}
j->state= *j->stack_p;
j->state= j->stack[j->stack_p];
return 0;
}
......@@ -570,7 +571,7 @@ static int v_false(json_engine_t *j)
{
if (skip_string_verbatim(&j->s, "alse"))
return 1;
j->state= *j->stack_p;
j->state= j->stack[j->stack_p];
return json_scan_next(j);
}
......@@ -580,7 +581,7 @@ static int v_null(json_engine_t *j)
{
if (skip_string_verbatim(&j->s, "ull"))
return 1;
j->state= *j->stack_p;
j->state= j->stack[j->stack_p];
return json_scan_next(j);
}
......@@ -590,7 +591,7 @@ static int v_true(json_engine_t *j)
{
if (skip_string_verbatim(&j->s, "rue"))
return 1;
j->state= *j->stack_p;
j->state= j->stack[j->stack_p];
return json_scan_next(j);
}
......@@ -600,7 +601,7 @@ static int read_false(json_engine_t *j)
{
j->value_type= JSON_VALUE_FALSE;
j->value= j->value_begin;
j->state= *j->stack_p;
j->state= j->stack[j->stack_p];
j->value_len= 5;
return skip_string_verbatim(&j->s, "alse");
}
......@@ -611,7 +612,7 @@ static int read_null(json_engine_t *j)
{
j->value_type= JSON_VALUE_NULL;
j->value= j->value_begin;
j->state= *j->stack_p;
j->state= j->stack[j->stack_p];
j->value_len= 4;
return skip_string_verbatim(&j->s, "ull");
}
......@@ -622,7 +623,7 @@ static int read_true(json_engine_t *j)
{
j->value_type= JSON_VALUE_TRUE;
j->value= j->value_begin;
j->state= *j->stack_p;
j->state= j->stack[j->stack_p];
j->value_len= 4;
return skip_string_verbatim(&j->s, "rue");
}
......@@ -791,7 +792,7 @@ int json_scan_start(json_engine_t *je,
{
json_string_setup(&je->s, i_cs, str, end);
je->stack[0]= JST_DONE;
je->stack_p= je->stack;
je->stack_p= 0;
je->state= JST_VALUE;
return 0;
}
......@@ -839,7 +840,7 @@ static int skip_key(json_engine_t *j)
run our 'state machine' accordingly.
*/
static int struct_end_eos(json_engine_t *j)
{ return json_actions[*j->stack_p][C_EOS](j); }
{ return json_actions[j->stack[j->stack_p]][C_EOS](j); }
/*
......@@ -849,7 +850,7 @@ static int struct_end_eos(json_engine_t *j)
run our 'state machine' accordingly.
*/
static int struct_end_cb(json_engine_t *j)
{ return json_actions[*j->stack_p][C_RCURB](j); }
{ return json_actions[j->stack[j->stack_p]][C_RCURB](j); }
/*
......@@ -859,7 +860,7 @@ static int struct_end_cb(json_engine_t *j)
run our 'state machine' accordingly.
*/
static int struct_end_qb(json_engine_t *j)
{ return json_actions[*j->stack_p][C_RSQRB](j); }
{ return json_actions[j->stack[j->stack_p]][C_RSQRB](j); }
/*
......@@ -869,7 +870,7 @@ static int struct_end_qb(json_engine_t *j)
run our 'state machine' accordingly.
*/
static int struct_end_cm(json_engine_t *j)
{ return json_actions[*j->stack_p][C_COMMA](j); }
{ return json_actions[j->stack[j->stack_p]][C_COMMA](j); }
int json_read_keyname_chr(json_engine_t *j)
......@@ -1107,8 +1108,6 @@ int json_path_setup(json_path_t *p,
continue;
case PS_KWD:
case PS_AWD:
if (p->last_step->type & JSON_PATH_DOUBLE_WILD)
return p->s.error= JE_SYN;
p->last_step->type|= JSON_PATH_WILD;
p->types_used|= JSON_PATH_WILD;
continue;
......@@ -1158,7 +1157,7 @@ int json_path_setup(json_path_t *p,
}
int json_skip_to_level(json_engine_t *j, json_level_t level)
int json_skip_to_level(json_engine_t *j, int level)
{
do {
if (j->stack_p < level)
......@@ -1595,3 +1594,118 @@ int json_escape(CHARSET_INFO *str_cs,
return json - json_start;
}
int json_get_path_start(json_engine_t *je, CHARSET_INFO *i_cs,
const uchar *str, const uchar *end,
json_path_t *p)
{
json_scan_start(je, i_cs, str, end);
p->last_step= p->steps - 1;
return 0;
}
int json_get_path_next(json_engine_t *je, json_path_t *p)
{
if (p->last_step < p->steps)
{
if (json_read_value(je))
return 1;
p->last_step= p->steps;
p->steps[0].type= JSON_PATH_ARRAY_WILD;
p->steps[0].n_item= 0;
return 0;
}
else
{
if (json_value_scalar(je))
{
if (p->last_step->type & JSON_PATH_ARRAY)
p->last_step->n_item++;
}
else
{
p->last_step++;
p->last_step->type= (enum json_path_step_types) je->value_type;
p->last_step->n_item= 0;
}
if (json_scan_next(je))
return 1;
}
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)
return 1;
/* Now we have je.state == JST_VALUE, so let's handle it. */
case JST_VALUE:
if (json_read_value(je))
return 1;
return 0;
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);
return 1;
}
int json_path_compare(const json_path_t *a, const json_path_t *b)
{
const json_path_step_t *sa= a->steps + 1;
const json_path_step_t *sb= b->steps + 1;
if (a->last_step - sa > b->last_step - sb)
return -2;
while (sa <= a->last_step)
{
if (sb > b->last_step)
return -2;
if (!((sa->type & sb->type) & JSON_PATH_KEY_OR_ARRAY))
goto step_failed;
if (sa->type & JSON_PATH_ARRAY)
{
if (!(sa->type & JSON_PATH_WILD) && sa->n_item != sb->n_item)
goto step_failed;
}
else /* JSON_PATH_KEY */
{
if (!(sa->type & JSON_PATH_WILD) &&
(sa->key_end - sa->key != sb->key_end - sb->key ||
memcmp(sa->key, sb->key, sa->key_end - sa->key) != 0))
goto step_failed;
}
sb++;
sa++;
continue;
step_failed:
if (!(sa->type & JSON_PATH_DOUBLE_WILD))
return -1;
sb++;
}
return sb <= b->last_step;
}
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