diff --git a/include/json_lib.h b/include/json_lib.h index ddba571ac59..cdfcffad38a 100644 --- a/include/json_lib.h +++ b/include/json_lib.h @@ -409,7 +409,12 @@ int json_get_path_start(json_engine_t *je, CHARSET_INFO *i_cs, 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); +int json_path_parts_compare( + const json_path_step_t *a, const json_path_step_t *a_end, + const json_path_step_t *b, const json_path_step_t *b_end, + enum json_value_types vt); +int json_path_compare(const json_path_t *a, const json_path_t *b, + enum json_value_types vt); #ifdef __cplusplus diff --git a/mysql-test/r/func_json.result b/mysql-test/r/func_json.result index 67a5dd20883..bfee73c2eef 100644 --- a/mysql-test/r/func_json.result +++ b/mysql-test/r/func_json.result @@ -57,7 +57,7 @@ json_array_append('["a", "b"]', '$', FALSE) ["a", "b", false] select json_array_append('{"k1":1, "k2":["a", "b"]}', '$.k2', 2); json_array_append('{"k1":1, "k2":["a", "b"]}', '$.k2', 2) -{"k1":1, "k2":["a", "b", 2]} +{"k1": 1, "k2": ["a", "b", 2]} select json_array_append('["a", ["b", "c"], "d"]', '$[0]', 2); json_array_append('["a", ["b", "c"], "d"]', '$[0]', 2) [["a", 2], ["b", "c"], "d"] @@ -190,10 +190,10 @@ json_extract('{"key1":"asd", "key2":[2,3]}', "$.keyX", "$.keyY") NULL select json_extract('{"key1":"asd", "key2":[2,3]}', "$.key1", "$.key2"); json_extract('{"key1":"asd", "key2":[2,3]}', "$.key1", "$.key2") -["asd", [2,3]] +["asd", [2, 3]] select json_extract('{"key1":5, "key2":[2,3]}', "$.key1", "$.key2"); json_extract('{"key1":5, "key2":[2,3]}', "$.key1", "$.key2") -[5, [2,3]] +[5, [2, 3]] select json_extract('{"key0":true, "key1":"qwe"}', "$.key1"); json_extract('{"key0":true, "key1":"qwe"}', "$.key1") "qwe" @@ -205,7 +205,7 @@ json_extract('[10, 20, [30, 40]]', '$[2][*]') [30, 40] select json_extract('[10, 20, [{"a":3}, 30, 40]]', '$[2][*]'); json_extract('[10, 20, [{"a":3}, 30, 40]]', '$[2][*]') -[{"a":3}, 30, 40] +[{"a": 3}, 30, 40] select json_extract('1', '$'); json_extract('1', '$') 1 @@ -220,29 +220,29 @@ 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]} +{"a": 1, "b": {"c": 1, "k1": "word"}, "d": [1, 2]} select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.d[3]', 3); json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.d[3]', 3) -{"a":1, "b":{"c":1}, "d":[1, 2, 3]} +{"a": 1, "b": {"c": 1}, "d": [1, 2, 3]} select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.a[2]', 2); json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.a[2]', 2) -{"a":[1, 2], "b":{"c":1}, "d":[1, 2]} +{"a": [1, 2], "b": {"c": 1}, "d": [1, 2]} select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.c', 'word'); json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.c', 'word') -{"a":1, "b":{"c":1}, "d":[1, 2]} +{"a": 1, "b": {"c": 1}, "d": [1, 2]} select json_set('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]'); json_set('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]') -{ "a": 10, "b": [2, 3], "c":"[true, false]"} +{"a": 10, "b": [2, 3], "c": "[true, false]"} select json_replace('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]'); json_replace('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]') -{ "a": 10, "b": [2, 3]} +{"a": 10, "b": [2, 3]} select json_replace('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.b', '[true, false]'); json_replace('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.b', '[true, false]') -{ "a": 10, "b": "[true, false]"} +{"a": 10, "b": "[true, false]"} set @j = '["a", ["b", "c"], "d"]'; select json_remove(@j, '$[0]'); json_remove(@j, '$[0]') -[ ["b", "c"], "d"] +[["b", "c"], "d"] select json_remove(@j, '$[1]'); json_remove(@j, '$[1]') ["a", "d"] @@ -323,7 +323,7 @@ Warnings: Warning 4038 Syntax error in JSON text in argument 1 to function 'json_merge' at position 1 select json_merge('{"a":"b"}','{"c":"d"}'); json_merge('{"a":"b"}','{"c":"d"}') -{"a":"b", "c":"d"} +{"a": "b", "c": "d"} SELECT JSON_MERGE('[1, 2]', '{"id": 47}'); JSON_MERGE('[1, 2]', '{"id": 47}') [1, 2, {"id": 47}] @@ -485,15 +485,13 @@ json_set('{"a":12}', '$[0]', 100) 100 select json_set('{"a":12}', '$[0].a', 100); json_set('{"a":12}', '$[0].a', 100) -{"a":100} +{"a": 100} select json_set('{"a":12}', '$[0][0].a', 100); json_set('{"a":12}', '$[0][0].a', 100) -{"a":100} +{"a": 100} select json_set('{"a":12}', '$[0][1].a', 100); json_set('{"a":12}', '$[0][1].a', 100) -NULL -Warnings: -Warning 4037 Unexpected end of JSON text in argument 1 to function 'json_set' +{"a": 12} select json_value('{"\\"key1":123}', '$."\\"key1"'); json_value('{"\\"key1":123}', '$."\\"key1"') 123 @@ -503,3 +501,54 @@ json_value('{"\\"key1\\"":123}', '$."\\"key1\\""') select json_value('{"key 1":123}', '$."key 1"'); json_value('{"key 1":123}', '$."key 1"') 123 +select json_contains_path('{"a":[{"c":[1,{"a":[0,1,2]},3]}], "b":[1,2,3]}', 'one', "$**.a[2]"); +json_contains_path('{"a":[{"c":[1,{"a":[0,1,2]},3]}], "b":[1,2,3]}', 'one', "$**.a[2]") +1 +select json_contains_path('{"a":[{"c":[1,{"a":[0,1,2]},3]}], "b":[1,2,3]}', 'one', "$**.a[3]"); +json_contains_path('{"a":[{"c":[1,{"a":[0,1,2]},3]}], "b":[1,2,3]}', 'one', "$**.a[3]") +0 +select json_extract( '[1]', '$[0][0]' ); +json_extract( '[1]', '$[0][0]' ) +1 +select json_extract( '[1]', '$[1][0]' ); +json_extract( '[1]', '$[1][0]' ) +NULL +select json_extract( '[1]', '$**[0]' ); +json_extract( '[1]', '$**[0]' ) +[1] +select json_extract( '[1]', '$**[0][0]' ); +json_extract( '[1]', '$**[0][0]' ) +[1] +select json_insert('1', '$[0]', 4); +json_insert('1', '$[0]', 4) +1 +select json_replace('1', '$[0]', 4); +json_replace('1', '$[0]', 4) +4 +select json_set('1', '$[0]', 4); +json_set('1', '$[0]', 4) +4 +select json_set('1', '$[1]', 4); +json_set('1', '$[1]', 4) +[1, 4] +select json_replace('1', '$[1]', 4); +json_replace('1', '$[1]', 4) +1 +SELECT json_insert('[]', '$[0][0]', 100); +json_insert('[]', '$[0][0]', 100) +[] +SELECT json_insert('1', '$[0][0]', 100); +json_insert('1', '$[0][0]', 100) +1 +SELECT json_replace('1', '$[0][0]', 100); +json_replace('1', '$[0][0]', 100) +100 +SELECT json_replace('[]', '$[0][0]', 100); +json_replace('[]', '$[0][0]', 100) +[] +SELECT json_set('[]', '$[0][0]', 100); +json_set('[]', '$[0][0]', 100) +[] +SELECT json_set('[]', '$[0][0][0]', 100); +json_set('[]', '$[0][0][0]', 100) +[] diff --git a/mysql-test/suite/json/r/json_no_table.result b/mysql-test/suite/json/r/json_no_table.result index 3660a37814c..3201d0fc432 100644 --- a/mysql-test/suite/json/r/json_no_table.result +++ b/mysql-test/suite/json/r/json_no_table.result @@ -710,19 +710,19 @@ Warnings: Warning 4044 Wildcards in JSON path not allowed in argument 3 to function 'json_remove' select json_remove( '[ 1, 2, 3 ]', '$[0]' ); json_remove( '[ 1, 2, 3 ]', '$[0]' ) -[ 2, 3 ] +[2, 3] select json_remove( '[ 1, 2, 3 ]', '$[1]' ); json_remove( '[ 1, 2, 3 ]', '$[1]' ) -[ 1, 3 ] +[1, 3] select json_remove( '[ 1, 2, 3 ]', '$[2]' ); json_remove( '[ 1, 2, 3 ]', '$[2]' ) -[ 1, 2] +[1, 2] select json_remove( '[ 1, 2, 3 ]', '$[3]' ); json_remove( '[ 1, 2, 3 ]', '$[3]' ) -[ 1, 2, 3 ] +[1, 2, 3] select json_remove( '[ 1, { "a": true, "b": false, "c": null }, 5 ]', '$[1]' ); json_remove( '[ 1, { "a": true, "b": false, "c": null }, 5 ]', '$[1]' ) -[ 1, 5 ] +[1, 5] error ER_INVALID_JSON_PATH_WILDCARD select json_remove( '[ { "a": { "a": true } } ]', '$**.a' ); json_remove( '[ { "a": { "a": true } } ]', '$**.a' ) @@ -731,7 +731,7 @@ Warnings: Warning 4044 Wildcards in JSON path not allowed in argument 2 to function 'json_remove' select json_remove( '[ { "a": true }, { "b": false }, { "c": null }, { "a": null } ]', '$[0].a', '$[2].c' ); json_remove( '[ { "a": true }, { "b": false }, { "c": null }, { "a": null } ]', '$[0].a', '$[2].c' ) -[ { }, { "b": false }, { }, { "a": null } ] +[{}, {"b": false}, {}, {"a": null}] error ER_INVALID_JSON_PATH_WILDCARD select json_remove( '[ { "a": true }, { "b": [ { "c": { "a": true } } ] }, { "c": null }, { "a": null } ]', '$**.a' ); json_remove( '[ { "a": true }, { "b": [ { "c": { "a": true } } ] }, { "c": null }, { "a": null } ]', '$**.a' ) @@ -751,7 +751,7 @@ JSON_REMOVE '{"a" : "foo", "b" : [true, {"c" : 123}]}', '$.b[ 1 ]' ) -{"a" : "foo", "b" : [true, {"c" : 123}]} +{"a": "foo", "b": [true]} SELECT JSON_REMOVE ( '{ "a" : "foo", "b" : [ true, { "c" : 123, "c" : 456 } ] }', @@ -762,9 +762,7 @@ JSON_REMOVE '{ "a" : "foo", "b" : [ true, { "c" : 123, "c" : 456 } ] }', '$.b[ 1 ].c' ) -NULL -Warnings: -Warning 4037 Unexpected end of JSON text in argument 1 to function 'json_remove' +{"a": "foo", "b": [true, {"c": 456}]} SELECT JSON_REMOVE ( '{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }', @@ -775,9 +773,7 @@ JSON_REMOVE '{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }', '$.b[ 1 ].c' ) -NULL -Warnings: -Warning 4037 Unexpected end of JSON text in argument 1 to function 'json_remove' +{"a": "foo", "b": [true, {}]} SELECT JSON_REMOVE ( '{ "a" : "foo", "b" : [ true, { "c" : 123, "d" : 456 } ] }', @@ -788,9 +784,7 @@ JSON_REMOVE '{ "a" : "foo", "b" : [ true, { "c" : 123, "d" : 456 } ] }', '$.b[ 1 ].e' ) -NULL -Warnings: -Warning 4037 Unexpected end of JSON text in argument 1 to function 'json_remove' +{"a": "foo", "b": [true, {"c": 123, "d": 456}]} # ---------------------------------------------------------------------- # Test of JSON_MERGE function. # ---------------------------------------------------------------------- @@ -823,7 +817,9 @@ NULL error ER_INVALID_JSON_TEXT_IN_PARAM select json_merge( '[1, 2]', '[3, 4' ); json_merge( '[1, 2]', '[3, 4' ) -[1, 2, 3, 4 +NULL +Warnings: +Warning 4037 Unexpected end of JSON text in argument 1 to function 'json_merge' error ER_INVALID_JSON_TEXT_IN_PARAM select json_merge( '[1, 2', '[3, 4]' ); json_merge( '[1, 2', '[3, 4]' ) @@ -841,55 +837,55 @@ json_merge( '[1, 2]', '3' ) [1, 2, 3] select json_merge( '1', '{ "a": 2 }' ); json_merge( '1', '{ "a": 2 }' ) -[1, { "a": 2 }] +[1, {"a": 2}] select json_merge( '{ "a": 2 }', '1' ); json_merge( '{ "a": 2 }', '1' ) -[{ "a": 2 }, 1] +[{"a": 2}, 1] select json_merge( '[1, 2]', '[3, 4]' ); json_merge( '[1, 2]', '[3, 4]' ) [1, 2, 3, 4] select json_merge( '{ "a": 2 }', '{ "b": 3}' ); json_merge( '{ "a": 2 }', '{ "b": 3}' ) -{ "a": 2 , "b": 3} +{"a": 2, "b": 3} select json_merge( '[1, 2]', '{ "a": 2 }' ); json_merge( '[1, 2]', '{ "a": 2 }' ) -[1, 2, { "a": 2 }] +[1, 2, {"a": 2}] select json_merge( '{ "a": 2 }', '[1, 2]' ); json_merge( '{ "a": 2 }', '[1, 2]' ) -[{ "a": 2 }, 1, 2] +[{"a": 2}, 1, 2] select json_merge( '{"a": 1, "b": 2 }', '{"b": 3, "d": 4 }' ); json_merge( '{"a": 1, "b": 2 }', '{"b": 3, "d": 4 }' ) -{"a": 1, "b": 2 , "b": 3, "d": 4 } +{"a": 1, "b": 2, "b": 3, "d": 4} select json_merge( '{"a": 1, "b": 2 }', '{"b": [3, 4], "d": 4 }' ); json_merge( '{"a": 1, "b": 2 }', '{"b": [3, 4], "d": 4 }' ) -{"a": 1, "b": 2 , "b": [3, 4], "d": 4 } +{"a": 1, "b": 2, "b": [3, 4], "d": 4} select json_merge( '{"a": 1, "b": [2, 3] }', '{"b": 4, "d": 4 }' ); json_merge( '{"a": 1, "b": [2, 3] }', '{"b": 4, "d": 4 }' ) -{"a": 1, "b": [2, 3] , "b": 4, "d": 4 } +{"a": 1, "b": [2, 3], "b": 4, "d": 4} select json_merge( '{"a": 1, "b": 2 }', '{"b": {"e": 7, "f": 8}, "d": 4 }' ); json_merge( '{"a": 1, "b": 2 }', '{"b": {"e": 7, "f": 8}, "d": 4 }' ) -{"a": 1, "b": 2 , "b": {"e": 7, "f": 8}, "d": 4 } +{"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 }' ); json_merge( '{"b": {"e": 7, "f": 8}, "d": 4 }', '{"a": 1, "b": 2 }' ) -{"b": {"e": 7, "f": 8}, "d": 4 , "a": 1, "b": 2 } +{"b": {"e": 7, "f": 8}, "d": 4, "a": 1, "b": 2} select json_merge( '{"a": 1, "b": [2, 9] }', '{"b": [10, 11], "d": 4 }' ); json_merge( '{"a": 1, "b": [2, 9] }', '{"b": [10, 11], "d": 4 }' ) -{"a": 1, "b": [2, 9] , "b": [10, 11], "d": 4 } +{"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 }' ); json_merge( '{"a": 1, "b": [2, 9] }', '{"b": {"e": 7, "f": 8}, "d": 4 }' ) -{"a": 1, "b": [2, 9] , "b": {"e": 7, "f": 8}, "d": 4 } +{"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] }' ); json_merge( '{"b": {"e": 7, "f": 8}, "d": 4 }', '{"a": 1, "b": [2, 9] }' ) -{"b": {"e": 7, "f": 8}, "d": 4 , "a": 1, "b": [2, 9] } +{"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 } }' ); json_merge( '{"b": {"e": 7, "f": 8}, "d": 4 }', '{ "a": 1, "b": {"e": 20, "g": 21 } }' ) -{"b": {"e": 7, "f": 8}, "d": 4 , "a": 1, "b": {"e": 20, "g": 21 } } +{"b": {"e": 7, "f": 8}, "d": 4, "a": 1, "b": {"e": 20, "g": 21}} select json_merge( '1', '2', '3' ); json_merge( '1', '2', '3' ) [1, 2, 3] select json_merge( '[1, 2 ]', '3', '[4, 5]' ); json_merge( '[1, 2 ]', '3', '[4, 5]' ) -[1, 2 , 3, 4, 5] +[1, 2, 3, 4, 5] select json_merge ( '{ "a": true, "b": { "c": 3, "d": 4 }, "e": [ 1, 2 ] }', @@ -902,7 +898,7 @@ json_merge '{ "d": false, "b": { "g": 3, "d": 5 }, "f": [ 1, 2 ] }', '{ "m": true, "b": { "h": 8, "d": 4 }, "e": [ 3, 4 ] }' ) -{ "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 ] } +{"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]} SELECT JSON_MERGE ( '{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }', @@ -913,7 +909,7 @@ JSON_MERGE '{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }', '[ 5, 6]' ) -[{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }, 5, 6] +[{"a": "foo", "b": [true, {"c": 123}]}, 5, 6] SELECT JSON_MERGE ( '{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }', @@ -924,7 +920,7 @@ JSON_MERGE '{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }', '{ "b": [ false, 34 ] }' ) -{ "a" : "foo", "b" : [ true, { "c" : 123 } ] , "b": [ false, 34 ] } +{"a": "foo", "b": [true, {"c": 123}], "b": [false, 34]} SELECT JSON_MERGE ( '{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }', @@ -935,7 +931,7 @@ JSON_MERGE '{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }', '{ "b": "bar" }' ) -{ "a" : "foo", "b" : [ true, { "c" : 123 } ] , "b": "bar" } +{"a": "foo", "b": [true, {"c": 123}], "b": "bar"} SELECT JSON_MERGE ( '{ "a" : { "b" : 1 } }', @@ -946,7 +942,7 @@ JSON_MERGE '{ "a" : { "b" : 1 } }', '{ "a" : { "c" : 1 } }' ) -{ "a" : { "b" : 1 } , "a" : { "c" : 1 } } +{"a": {"b": 1}, "a": {"c": 1}} # ---------------------------------------------------------------------- # Test of JSON_TYPE function. # ---------------------------------------------------------------------- @@ -1296,16 +1292,16 @@ json_extract( '{ "a": 1}', '$.a' ) 1 select json_extract( '{ "a": [ [ 3, 2 ], [ { "c" : "d" }, 1 ] ], "b": { "c" : 6 }, "one potato": 7, "b.c" : 8 }', '$.a[0]' ); json_extract( '{ "a": [ [ 3, 2 ], [ { "c" : "d" }, 1 ] ], "b": { "c" : 6 }, "one potato": 7, "b.c" : 8 }', '$.a[0]' ) -[ 3, 2 ] +[3, 2] select json_extract( '{ "a": [ [ 3, 2 ], [ { "c" : "d" }, 1 ] ], "b": { "c" : 6 }, "one potato": 7, "b.c" : 8 }', '$.a[0][1]' ); json_extract( '{ "a": [ [ 3, 2 ], [ { "c" : "d" }, 1 ] ], "b": { "c" : 6 }, "one potato": 7, "b.c" : 8 }', '$.a[0][1]' ) 2 select json_extract( '{ "a": [ [ 3, 2 ], [ { "c" : "d" }, 1 ] ], "b": { "c" : 6 }, "one potato": 7, "b.c" : 8 }', '$.a[1]' ); json_extract( '{ "a": [ [ 3, 2 ], [ { "c" : "d" }, 1 ] ], "b": { "c" : 6 }, "one potato": 7, "b.c" : 8 }', '$.a[1]' ) -[ { "c" : "d" }, 1 ] +[{"c": "d"}, 1] select json_extract( '{ "a": [ [ 3, 2 ], [ { "c" : "d" }, 1 ] ], "b": { "c" : 6 }, "one potato": 7, "b.c" : 8 }', '$.a[1][0]' ); json_extract( '{ "a": [ [ 3, 2 ], [ { "c" : "d" }, 1 ] ], "b": { "c" : 6 }, "one potato": 7, "b.c" : 8 }', '$.a[1][0]' ) -{ "c" : "d" } +{"c": "d"} select json_extract( '{ "a": [ [ 3, 2 ], [ { "c" : "d" }, 1 ] ], "b": { "c" : 6 }, "one potato": 7, "b.c" : 8 }', '$.a[1][0].c' ); json_extract( '{ "a": [ [ 3, 2 ], [ { "c" : "d" }, 1 ] ], "b": { "c" : 6 }, "one potato": 7, "b.c" : 8 }', '$.a[1][0].c' ) "d" @@ -1359,13 +1355,13 @@ SELECT JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : "123" } ] }', '$.b[ 1 ].c'); JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : "123" } ] }', '$.b[ 1 ].c') -NULL +"123" # returns a JSON value containing just the number 123 SELECT JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }', '$.b[ 1 ].c'); JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }', '$.b[ 1 ].c') -NULL +123 # raises an error because the document is not valid error ER_INVALID_JSON_TEXT_IN_PARAM SELECT JSON_EXTRACT('{ "a" : [ }', @@ -1390,13 +1386,13 @@ SELECT JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }', '$.b[ 1 ].c[ 0 ]'); JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }', '$.b[ 1 ].c[ 0 ]') -NULL +123 # 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 ]'); JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : {"not array": 4} } ] }', '$.b[ 1 ].c[ 0 ]') -NULL +{"not array": 4} # 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 ]'); @@ -1408,7 +1404,7 @@ SELECT JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : 123, "c" : 456 } ] }', '$.b[ 1 ].c'); JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : 123, "c" : 456 } ] }', '$.b[ 1 ].c') -NULL +123 # returns a JSON array [ "foo", true ] SELECT JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : 123, "c" : 456 } ] }', '$.a', '$.b[0]'); @@ -1423,48 +1419,48 @@ JSON_EXTRACT('{ "a" : "foo", "b" : [ true, { "c" : 123, "c" : 456 } ] }', [true] select json_extract( '[1]', '$[0][0]' ); json_extract( '[1]', '$[0][0]' ) -NULL +1 select json_extract( '[1]', '$**[0]' ); json_extract( '[1]', '$**[0]' ) [1] select json_extract( '{ "a": 1 }', '$.a[0]' ); json_extract( '{ "a": 1 }', '$.a[0]' ) -NULL +1 select json_extract( '{ "a": 1 }', '$**[0]' ); json_extract( '{ "a": 1 }', '$**[0]' ) -NULL +[{"a": 1}, 1] select json_extract( '{ "a": 1 }', '$[0].a' ); json_extract( '{ "a": 1 }', '$[0].a' ) -NULL +1 select json_extract( '{ "a": 1 }', '$**.a' ); json_extract( '{ "a": 1 }', '$**.a' ) [1] select json_extract( '{ "a": 1 }', '$[0].a[0]' ); json_extract( '{ "a": 1 }', '$[0].a[0]' ) -NULL +1 select json_extract( '{ "a": 1 }', '$**[0]' ); json_extract( '{ "a": 1 }', '$**[0]' ) -NULL +[{"a": 1}, 1] select json_extract( '{ "a": 1 }', '$[0].a' ); json_extract( '{ "a": 1 }', '$[0].a' ) -NULL +1 select json_extract( '{ "a": 1 }', '$**.a' ); json_extract( '{ "a": 1 }', '$**.a' ) [1] select json_extract( '{ "a": 1 }', '$[0][0].a' ); json_extract( '{ "a": 1 }', '$[0][0].a' ) -NULL +1 select json_extract( '{ "a": 1 }', '$[0][0][0].a' ); json_extract( '{ "a": 1 }', '$[0][0][0].a' ) -NULL +1 SELECT JSON_EXTRACT('[1, [[{"x": [{"a":{"b":{"c":42}}}]}]]]', '$**.a.*'); JSON_EXTRACT('[1, [[{"x": [{"a":{"b":{"c":42}}}]}]]]', '$**.a.*') -[{"c":42}] +[{"c": 42}] SELECT JSON_EXTRACT('[1, [[{"x": [{"a":{"b":{"c":42}}}]}]]]', '$[1][0][0].x[0].a.*'); JSON_EXTRACT('[1, [[{"x": [{"a":{"b":{"c":42}}}]}]]]', '$[1][0][0].x[0].a.*') -[{"c":42}] +[{"c": 42}] SELECT JSON_EXTRACT ( '{ "a" : "foo", "b" : [ true, { "c" : "123" } ] }', @@ -1475,7 +1471,7 @@ JSON_EXTRACT '{ "a" : "foo", "b" : [ true, { "c" : "123" } ] }', '$.b[ 1 ].c' ) -NULL +"123" SELECT JSON_EXTRACT ( '{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }', @@ -1486,7 +1482,7 @@ JSON_EXTRACT '{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }', '$.b[ 1 ].c' ) -NULL +123 error ER_INVALID_JSON_TEXT_IN_PARAM SELECT JSON_EXTRACT ( @@ -1525,7 +1521,7 @@ JSON_EXTRACT '{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }', '$.b[ 1 ].c[ 0 ]' ) -NULL +123 SELECT JSON_EXTRACT ( '{ "a" : "foo", "b" : [ true, { "c" : 123 } ] }', @@ -1547,7 +1543,7 @@ JSON_EXTRACT '{ "a" : "foo", "b" : [ true, { "c" : 123, "c" : 456 } ] }', '$.b[ 1 ].c' ) -NULL +123 SELECT JSON_EXTRACT ( '{ "a" : "foo", "b" : [ true, { "c" : 123, "c" : 456 } ] }', @@ -1587,13 +1583,13 @@ jdoc [1] select json_extract( '[ { "a": [3,4] }, { "b": 2 } ]', '$[0].a' ) jdoc; jdoc -[3,4] +[3, 4] select json_extract( '[ { "a": [3,4] }, { "b": 2 } ]', '$[*].a' ) jdoc; jdoc -[[3,4]] +[[3, 4]] select json_extract( '[ { "a": [3,4] }, { "b": 2 } ]', '$[0].a', '$[1].a' ) jdoc; jdoc -[[3,4]] +[[3, 4]] # ---------------------------------------------------------------------- # Test of JSON_ARRAY_APPEND function. # ---------------------------------------------------------------------- @@ -1605,7 +1601,7 @@ json_array_append('[1,2,3]', NULL, cast(1 as json)) NULL select json_array_append('[1,2,3]', '$', NULL); json_array_append('[1,2,3]', '$', NULL) -[1,2,3, null] +[1, 2, 3, null] select json_array_append(NULL); ERROR 42000: Incorrect parameter count in the call to native function 'json_array_append' select json_array_append(NULL, NULL); @@ -1641,14 +1637,14 @@ SELECT JSON_ARRAY_APPEND('{"a" : "foo","b": [1, 2, 3], "c": ["apple", "pear"]}', JSON_ARRAY_APPEND('{"a" : "foo","b": [1, 2, 3], "c": ["apple", "pear"]}', '$.b', cast(4 as json), '$.c', cast('"grape"' as json)) -{"a" : "foo","b": [1, 2, 3, 4], "c": ["apple", "pear", "grape"]} +{"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'); JSON_ARRAY_APPEND('{"a" : "foo","b": [1, 2, 3], "c": ["apple", "pear"]}', '$.b', 4, '$.c', 'grape') -{"a" : "foo","b": [1, 2, 3, 4], "c": ["apple", "pear", "grape"]} +{"a": "foo", "b": [1, 2, 3, 4], "c": ["apple", "pear", "grape"]} error ER_INVALID_JSON_PATH_WILDCARD select json_array_append( '[[], [], []]', '$[*]', 3, '$[*]', 4); json_array_append( '[[], [], []]', '$[*]', 3, '$[*]', 4) @@ -1673,7 +1669,7 @@ JSON_ARRAY_APPEND '$.b', 4, '$.c', "grape" ) -{ "a" : "foo", "b" : ["bar", 4], "c" : ["wibble", "grape"] } +{"a": "foo", "b": ["bar", 4], "c": ["wibble", "grape"]} SELECT JSON_ARRAY_APPEND ( '{ "a" : "foo", "b" : [ 1, 2, 3 ], "c" : [ "apple", "pear" ] }', @@ -1686,13 +1682,13 @@ JSON_ARRAY_APPEND '$.b', 4, '$.c', "grape" ) -{ "a" : "foo", "b" : [ 1, 2, 3 , 4], "c" : [ "apple", "pear" , "grape"] } +{"a": "foo", "b": [1, 2, 3, 4], "c": ["apple", "pear", "grape"]} # ---------------------------------------------------------------------- # Bug#21373874 ASSERTION `PARENT' FAILED # ---------------------------------------------------------------------- select json_array_append('{"a":1}', '$[0]', 100); json_array_append('{"a":1}', '$[0]', 100) -[{"a":1}, 100] +[{"a": 1}, 100] select json_array_append('3', '$[0]', 100); json_array_append('3', '$[0]', 100) [3, 100] @@ -1710,7 +1706,7 @@ json_insert('[1,2,3]', NULL, cast(1 as json)) NULL select json_insert('[1,2,3]', '$[3]', NULL); json_insert('[1,2,3]', '$[3]', NULL) -[1,2,3, null] +[1, 2, 3, null] select json_insert(NULL); ERROR 42000: Incorrect parameter count in the call to native function 'json_insert' select json_insert(NULL, NULL); @@ -1719,25 +1715,25 @@ select json_insert(NULL, NULL, NULL, NULL); ERROR 42000: Incorrect parameter count in the call to native function 'json_insert' select json_insert('[1,2,3]', '$[2]', 4); json_insert('[1,2,3]', '$[2]', 4) -[1,2,3] +[1, 2, 3] select json_insert('[1,2,3]', '$[3]', 4); json_insert('[1,2,3]', '$[3]', 4) -[1,2,3, 4] +[1, 2, 3, 4] select json_insert('[1,2,3]', '$[10]', 4); json_insert('[1,2,3]', '$[10]', 4) -[1,2,3, 4] +[1, 2, 3, 4] select json_insert('{"c":4}', '$.c', 4); json_insert('{"c":4}', '$.c', 4) -{"c":4} +{"c": 4} select json_insert('{"c":4}', '$.a', 4); json_insert('{"c":4}', '$.a', 4) -{"c":4, "a":4} +{"c": 4, "a": 4} select json_insert('1', '$', 4); json_insert('1', '$', 4) 1 select json_insert('1', '$[0]', 4); json_insert('1', '$[0]', 4) -[1, 4] +1 select json_insert('1', '$[1]', 4); json_insert('1', '$[1]', 4) [1, 4] @@ -1746,13 +1742,13 @@ json_insert('1', '$[10]', '4', '$[11]', 5) [1, "4", 5] select json_insert('[1,2,3]', '$[2][0]', 4); json_insert('[1,2,3]', '$[2][0]', 4) -[1,2,[3, 4]] +[1, 2, 3] select json_insert('[1,2,3]', '$[2][2]', 4); json_insert('[1,2,3]', '$[2][2]', 4) -[1,2,[3, 4]] +[1, 2, [3, 4]] select json_insert('{"a": 3}', '$.a[0]', 4); json_insert('{"a": 3}', '$.a[0]', 4) -{"a": [3, 4]} +{"a": 3} select json_insert('{"a": 3}', '$.a[1]', 4, '$.a[2]', '5'); json_insert('{"a": 3}', '$.a[1]', 4, '$.a[2]', '5') {"a": [3, 4, "5"]} @@ -1833,19 +1829,19 @@ json_insert(cast('{"a": 3}' as json), '$[1]', 6) [{"a": 3}, 6] SELECT JSON_INSERT('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.a', true); JSON_INSERT('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.a', true) -{ "a" : "foo", "b" : [ 1, 2, 3 ] } +{"a": "foo", "b": [1, 2, 3]} SELECT JSON_INSERT('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.c', 123); JSON_INSERT('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.c', 123) -{ "a" : "foo", "b" : [ 1, 2, 3 ] , "c":123} +{"a": "foo", "b": [1, 2, 3], "c": 123} SELECT JSON_INSERT('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.c', '123'); JSON_INSERT('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.c', '123') -{ "a" : "foo", "b" : [ 1, 2, 3 ] , "c":"123"} +{"a": "foo", "b": [1, 2, 3], "c": "123"} SELECT JSON_INSERT('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.a[1]', true); JSON_INSERT('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.a[1]', true) -{ "a" : ["foo", true], "b" : [ 1, 2, 3 ] } +{"a": ["foo", true], "b": [1, 2, 3]} SELECT JSON_INSERT('{ "a" : "foo"}', '$.b', true, '$.b', false); JSON_INSERT('{ "a" : "foo"}', '$.b', true, '$.b', false) -{ "a" : "foo", "b":true} +{"a": "foo", "b": true} SELECT JSON_INSERT ( '{ "a" : "foo", "b" : [ 1, 2, 3 ] }', @@ -1858,7 +1854,7 @@ JSON_INSERT '$.a', true ) -{ "a" : "foo", "b" : [ 1, 2, 3 ] } +{"a": "foo", "b": [1, 2, 3]} SELECT JSON_INSERT ( '{ "a" : "foo", "b" : [ 1, 2, 3 ] }', @@ -1871,7 +1867,7 @@ JSON_INSERT '$.c', 123 ) -{ "a" : "foo", "b" : [ 1, 2, 3 ] , "c":123} +{"a": "foo", "b": [1, 2, 3], "c": 123} SELECT JSON_INSERT ( '{ "a" : "foo", "b" : [ 1, 2, 3 ] }', @@ -1884,7 +1880,7 @@ JSON_INSERT '$.c', '123' ) -{ "a" : "foo", "b" : [ 1, 2, 3 ] , "c":"123"} +{"a": "foo", "b": [1, 2, 3], "c": "123"} SELECT JSON_INSERT ( '{ "a" : "foo", "b" : [ 1, 2, 3 ] }', @@ -1897,7 +1893,7 @@ JSON_INSERT '$.a[1]', true ) -{ "a" : ["foo", true], "b" : [ 1, 2, 3 ] } +{"a": ["foo", true], "b": [1, 2, 3]} SELECT JSON_INSERT ( '{ "a" : "foo"}', @@ -1910,7 +1906,7 @@ JSON_INSERT '$.b', true, '$.b', false ) -{ "a" : "foo", "b":true} +{"a": "foo", "b": true} # ---------------------------------------------------------------------- # Test of JSON_ARRAY_INSERT function. # ---------------------------------------------------------------------- @@ -1922,7 +1918,7 @@ json_array_insert('[1,2,3]', NULL, 1) NULL select json_array_insert('[1,2,3]', '$[3]', NULL); json_array_insert('[1,2,3]', '$[3]', NULL) -[1,2,3, null] +[1, 2, 3, null] select json_array_insert(NULL); ERROR 42000: Incorrect parameter count in the call to native function 'json_array_insert' select json_array_insert(NULL, NULL); @@ -1949,10 +1945,10 @@ json_array_insert( 'true', '$[1]', false ) true select json_array_insert( '{ "a": true }', '$.a[0]', false ); json_array_insert( '{ "a": true }', '$.a[0]', false ) -{ "a": true } +{"a": true} select json_array_insert( '{ "a": true }', '$.a[1]', false ); json_array_insert( '{ "a": true }', '$.a[1]', false ) -{ "a": true } +{"a": true} select json_array_insert( '[]', '$[0]', false ); json_array_insert( '[]', '$[0]', false ) [false] @@ -1970,19 +1966,19 @@ json_array_insert( '[true]', '$[2]', false ) [true, false] select json_array_insert( '{ "a": [] }', '$.a[0]', false ); json_array_insert( '{ "a": [] }', '$.a[0]', false ) -{ "a": [false] } +{"a": [false]} select json_array_insert( '{ "a": [] }', '$.a[1]', false ); json_array_insert( '{ "a": [] }', '$.a[1]', false ) -{ "a": [false] } +{"a": [false]} select json_array_insert( '{ "a": [true] }', '$.a[0]', false ); json_array_insert( '{ "a": [true] }', '$.a[0]', false ) -{ "a": [false, true] } +{"a": [false, true]} select json_array_insert( '{ "a": [true] }', '$.a[1]', false ); json_array_insert( '{ "a": [true] }', '$.a[1]', false ) -{ "a": [true, false] } +{"a": [true, false]} select json_array_insert( '{ "a": [true] }', '$.a[2]', false ); json_array_insert( '{ "a": [true] }', '$.a[2]', false ) -{ "a": [true, false] } +{"a": [true, false]} select json_array_insert( '[1, 2, 3, 4]', '$[0]', false ); json_array_insert( '[1, 2, 3, 4]', '$[0]', false ) [false, 1, 2, 3, 4] @@ -2003,34 +1999,34 @@ json_array_insert( '[1, 2, 3, 4]', '$[5]', false ) [1, 2, 3, 4, false] select json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.a[0]', false ); json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.a[0]', false ) -{ "a": [false, 1, 2, 3, 4] } +{"a": [false, 1, 2, 3, 4]} select json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.a[1]', false ); json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.a[1]', false ) -{ "a": [1, false, 2, 3, 4] } +{"a": [1, false, 2, 3, 4]} select json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.a[2]', false ); json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.a[2]', false ) -{ "a": [1, 2, false, 3, 4] } +{"a": [1, 2, false, 3, 4]} select json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.a[3]', false ); json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.a[3]', false ) -{ "a": [1, 2, 3, false, 4] } +{"a": [1, 2, 3, false, 4]} select json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.a[4]', false ); json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.a[4]', false ) -{ "a": [1, 2, 3, 4, false] } +{"a": [1, 2, 3, 4, false]} select json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.a[5]', false ); json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.a[5]', false ) -{ "a": [1, 2, 3, 4, false] } +{"a": [1, 2, 3, 4, false]} select json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.b[0]', false ); json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.b[0]', false ) -{ "a": [1, 2, 3, 4] } +{"a": [1, 2, 3, 4]} select json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.b[1]', false ); json_array_insert( '{ "a": [1, 2, 3, 4] }', '$.b[1]', false ) -{ "a": [1, 2, 3, 4] } +{"a": [1, 2, 3, 4]} select json_array_insert( '"a"', '$[0]', true ); json_array_insert( '"a"', '$[0]', true ) "a" select json_array_insert( '[ "a" ]', '$[0][0]', true ); json_array_insert( '[ "a" ]', '$[0][0]', true ) -[ "a" ] +["a"] select json_array_insert( '"a"', '$[1]', true ); json_array_insert( '"a"', '$[1]', true ) "a" @@ -2054,12 +2050,12 @@ Warnings: Warning 4044 Wildcards in JSON path not allowed in argument 2 to function 'json_insert' select json_array_insert( '[ 1, 2, 3 ]', '$[1]', true, '$[1]', false ); json_array_insert( '[ 1, 2, 3 ]', '$[1]', true, '$[1]', false ) -[ 1, false, true, 2, 3 ] +[1, false, true, 2, 3] select json_array_insert( '[ 1, 2, 3 ]', '$[1]', cast( '[ "a", "b", "c", "d" ]' as json ), '$[1][2]', false ); json_array_insert( '[ 1, 2, 3 ]', '$[1]', cast( '[ "a", "b", "c", "d" ]' as json ), '$[1][2]', false ) -[ 1, [ "a", "b", false, "c", "d" ], 2, 3 ] +[1, ["a", "b", false, "c", "d"], 2, 3] error ER_INVALID_JSON_TEXT_IN_PARAM SELECT JSON_ARRAY_INSERT(JSON_EXTRACT('[1', '$'), '$[0]', 1); JSON_ARRAY_INSERT(JSON_EXTRACT('[1', '$'), '$[0]', 1) @@ -2069,7 +2065,7 @@ Warning 4037 Unexpected end of JSON text in argument 1 to function 'json_extract error ER_INVALID_JSON_TEXT_IN_PARAM select json_array_insert( '[ 1, 2, 3 ]', '$[1]', json_extract( '[', '$' ) ); json_array_insert( '[ 1, 2, 3 ]', '$[1]', json_extract( '[', '$' ) ) -[ 1, null, 2, 3 ] +[1, null, 2, 3] Warnings: Warning 4037 Unexpected end of JSON text in argument 1 to function 'json_extract' # ---------------------------------------------------------------------- @@ -2083,7 +2079,7 @@ json_set('[1,2,3]', NULL, cast(1 as json)) NULL select json_set('[1,2,3]', '$[3]', NULL); json_set('[1,2,3]', '$[3]', NULL) -[1,2,3, null] +[1, 2, 3, null] select json_set(NULL); ERROR 42000: Incorrect parameter count in the call to native function 'json_set' select json_set(NULL, NULL); @@ -2093,24 +2089,25 @@ ERROR 42000: Incorrect parameter count in the call to native function 'json_set' error ER_INVALID_JSON_TEXT_IN_PARAM SELECT JSON_SET('{}', '$.name', JSON_EXTRACT('', '$')); JSON_SET('{}', '$.name', JSON_EXTRACT('', '$')) -{, "name":null} +NULL Warnings: Warning 4037 Unexpected end of JSON text in argument 1 to function 'json_extract' +Warning 4038 Syntax error in JSON text in argument 1 to function 'json_set' at position 2 select json_set('[1,2,3]', '$[2]', 4); json_set('[1,2,3]', '$[2]', 4) -[1,2,4] +[1, 2, 4] select json_set('[1,2,3]', '$[3]', 4); json_set('[1,2,3]', '$[3]', 4) -[1,2,3, 4] +[1, 2, 3, 4] select json_set('[1,2,3]', '$[10]', 4); json_set('[1,2,3]', '$[10]', 4) -[1,2,3, 4] +[1, 2, 3, 4] select json_set('{"c":4}', '$.c', 5); json_set('{"c":4}', '$.c', 5) -{"c":5} +{"c": 5} select json_set('{"c":4}', '$.a', 5); json_set('{"c":4}', '$.a', 5) -{"c":4, "a":5} +{"c": 4, "a": 5} select json_set('1', '$', 4); json_set('1', '$', 4) 4 @@ -2125,10 +2122,10 @@ json_set('1', '$[10]', '4', '$[11]', 5) [1, "4", 5] select json_set('[1,2,3]', '$[2][0]', 4); json_set('[1,2,3]', '$[2][0]', 4) -[1,2,4] +[1, 2, 4] select json_set('[1,2,3]', '$[2][2]', 4); json_set('[1,2,3]', '$[2][2]', 4) -[1,2,[3, 4]] +[1, 2, [3, 4]] select json_set('{"a": 3}', '$.a[0]', 4); json_set('{"a": 3}', '$.a[0]', 4) {"a": 4} @@ -2147,26 +2144,26 @@ JSON_OBJECT()); JSON_SET('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.a', JSON_OBJECT()) -{ "a" : {}, "b" : [ 1, 2, 3 ] } +{"a": {}, "b": [1, 2, 3]} SELECT JSON_SET('{ "a" : "foo"}', '$.a', JSON_OBJECT( 'b', false ), '$.a.c', true); JSON_SET('{ "a" : "foo"}', '$.a', JSON_OBJECT( 'b', false ), '$.a.c', true) -{ "a" : {"b": false, "c":true}} +{"a": {"b": false, "c": true}} select json_set('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.a', cast('{}' as json)); json_set('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.a', cast('{}' as json)) -{ "a" : {}, "b" : [ 1, 2, 3 ] } +{"a": {}, "b": [1, 2, 3]} select json_set('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.c', cast('[true, false]' as json)); json_set('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.c', cast('[true, false]' as json)) -{ "a" : "foo", "b" : [ 1, 2, 3 ] , "c":[true, false]} +{"a": "foo", "b": [1, 2, 3], "c": [true, false]} select json_set('1', '$[3]', 2); json_set('1', '$[3]', 2) [1, 2] @@ -2174,7 +2171,7 @@ select json_set('{ "a" : "foo"}', '$.a', cast('{"b": false}' as json), '$.a.c', true); json_set('{ "a" : "foo"}', '$.a', cast('{"b": false}' as json), '$.a.c', true) -{ "a" : {"b": false, "c":true}} +{"a": {"b": false, "c": true}} SELECT JSON_SET ( '{ "a" : "foo", "b" : [ 1, 2, 3 ] }', @@ -2187,7 +2184,7 @@ JSON_SET '$.a', JSON_OBJECT() ) -{ "a" : {}, "b" : [ 1, 2, 3 ] } +{"a": {}, "b": [1, 2, 3]} SELECT JSON_SET ( '{ "a" : "foo", "b" : [ 1, 2, 3 ] }', @@ -2200,7 +2197,7 @@ JSON_SET '$.c', JSON_ARRAY( true, false ) ) -{ "a" : "foo", "b" : [ 1, 2, 3 ] , "c":[true, false]} +{"a": "foo", "b": [1, 2, 3], "c": [true, false]} SELECT JSON_SET ( '{ "a" : "foo", "b" : [ 1, 2, 3 ] }', @@ -2213,7 +2210,7 @@ JSON_SET '$.c', JSON_ARRAY( CAST( 'true' AS JSON ), CAST( 'false' AS JSON ) ) ) -{ "a" : "foo", "b" : [ 1, 2, 3 ] , "c":[true, false]} +{"a": "foo", "b": [1, 2, 3], "c": [true, false]} SELECT JSON_SET ( '1', @@ -2239,7 +2236,7 @@ JSON_SET '$.a', JSON_OBJECT( 'b', false ), '$.a.c', true ) -{ "a" : {"b": false, "c":true}} +{"a": {"b": false, "c": true}} # ---------------------------------------------------------------------- # Test of JSON_REPLACE function. # ---------------------------------------------------------------------- @@ -2251,7 +2248,7 @@ json_replace('[1,2,3]', NULL, cast(1 as json)) NULL select json_replace('[1,2,3]', '$[2]', NULL); json_replace('[1,2,3]', '$[2]', NULL) -[1,2,null] +[1, 2, null] select json_replace(NULL); ERROR 42000: Incorrect parameter count in the call to native function 'json_replace' select json_replace(NULL, NULL); @@ -2260,19 +2257,19 @@ select json_replace(NULL, NULL, NULL, NULL); ERROR 42000: Incorrect parameter count in the call to native function 'json_replace' select json_replace('[1,2,3]', '$[2]', 4); json_replace('[1,2,3]', '$[2]', 4) -[1,2,4] +[1, 2, 4] select json_replace('[1,2,3]', '$[3]', 4); json_replace('[1,2,3]', '$[3]', 4) -[1,2,3] +[1, 2, 3] select json_replace('[1,2,3]', '$[10]', 4); json_replace('[1,2,3]', '$[10]', 4) -[1,2,3] +[1, 2, 3] select json_replace('{"c":4}', '$.c', 5); json_replace('{"c":4}', '$.c', 5) -{"c":5} +{"c": 5} select json_replace('{"c":4}', '$.a', 5); json_replace('{"c":4}', '$.a', 5) -{"c":4} +{"c": 4} select json_replace('1', '$', 4); json_replace('1', '$', 4) 4 @@ -2287,10 +2284,10 @@ json_replace('1', '$[10]', '4', '$[11]', 5) 1 select json_replace('[1,2,3]', '$[2][0]', 4); json_replace('[1,2,3]', '$[2][0]', 4) -[1,2,4] +[1, 2, 4] select json_replace('[1,2,3]', '$[2][2]', 4); json_replace('[1,2,3]', '$[2][2]', 4) -[1,2,3] +[1, 2, 3] select json_replace('{"a": 3}', '$.a[0]', 4); json_replace('{"a": 3}', '$.a[0]', 4) {"a": 4} @@ -2303,21 +2300,21 @@ true); JSON_REPLACE('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.c', true) -{ "a" : "foo", "b" : [ 1, 2, 3 ] } +{"a": "foo", "b": [1, 2, 3]} SELECT JSON_REPLACE('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.a[0]', true); JSON_REPLACE('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.a[0]', true) -{ "a" : true, "b" : [ 1, 2, 3 ] } +{"a": true, "b": [1, 2, 3]} SELECT JSON_REPLACE('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.b[5]', true); JSON_REPLACE('{ "a" : "foo", "b" : [ 1, 2, 3 ] }', '$.b[5]', true) -{ "a" : "foo", "b" : [ 1, 2, 3 ] } +{"a": "foo", "b": [1, 2, 3]} # ---------------------------------------------------------------------- # Test of JSON_ARRAY function. # ---------------------------------------------------------------------- @@ -3231,38 +3228,38 @@ prepare json_stmt5 FROM 'select json_array_append( ''{ "keyA": [1, 2], "keyB": [ set @mypath = '$.keyA'; execute json_stmt5 USING @mypath; json_array_append( '{ "keyA": [1, 2], "keyB": [3, 4] }', ?, 5 ) -{ "keyA": [1, 2, 5], "keyB": [3, 4] } +{"keyA": [1, 2, 5], "keyB": [3, 4]} set @mypath = '$.keyB'; execute json_stmt5 USING @mypath; json_array_append( '{ "keyA": [1, 2], "keyB": [3, 4] }', ?, 5 ) -{ "keyA": [1, 2], "keyB": [3, 4, 5] } +{"keyA": [1, 2], "keyB": [3, 4, 5]} prepare json_stmt6 FROM 'select json_insert( ''{ "keyA": [1, 2], "keyB": [3, 4] }'', ?, 5 )'; set @mypath = '$.keyA[2]'; execute json_stmt6 USING @mypath; json_insert( '{ "keyA": [1, 2], "keyB": [3, 4] }', ?, 5 ) -{ "keyA": [1, 2, 5], "keyB": [3, 4] } +{"keyA": [1, 2, 5], "keyB": [3, 4]} set @mypath = '$.keyB[2]'; execute json_stmt6 USING @mypath; json_insert( '{ "keyA": [1, 2], "keyB": [3, 4] }', ?, 5 ) -{ "keyA": [1, 2], "keyB": [3, 4, 5] } +{"keyA": [1, 2], "keyB": [3, 4, 5]} prepare json_stmt7 FROM 'select json_set( ''{ "keyA": [1, 2], "keyB": [3, 4] }'', ?, 5 )'; set @mypath = '$.keyA[2]'; execute json_stmt7 USING @mypath; json_set( '{ "keyA": [1, 2], "keyB": [3, 4] }', ?, 5 ) -{ "keyA": [1, 2, 5], "keyB": [3, 4] } +{"keyA": [1, 2, 5], "keyB": [3, 4]} set @mypath = '$.keyB[2]'; execute json_stmt7 USING @mypath; json_set( '{ "keyA": [1, 2], "keyB": [3, 4] }', ?, 5 ) -{ "keyA": [1, 2], "keyB": [3, 4, 5] } +{"keyA": [1, 2], "keyB": [3, 4, 5]} prepare json_stmt8 FROM 'select json_replace( ''{ "keyA": [1, 2], "keyB": [3, 4] }'', ?, 5 )'; set @mypath = '$.keyA[1]'; execute json_stmt8 USING @mypath; json_replace( '{ "keyA": [1, 2], "keyB": [3, 4] }', ?, 5 ) -{ "keyA": [1, 5], "keyB": [3, 4] } +{"keyA": [1, 5], "keyB": [3, 4]} set @mypath = '$.keyB[1]'; execute json_stmt8 USING @mypath; json_replace( '{ "keyA": [1, 2], "keyB": [3, 4] }', ?, 5 ) -{ "keyA": [1, 2], "keyB": [3, 5] } +{"keyA": [1, 2], "keyB": [3, 5]} prepare json_stmt9 FROM 'select json_search( ''{ "keyA": [ "foot" ], "keyB": [ "food" ] }'', ''all'', ''foo%'', null, ? )'; set @mypath = '$.keyA'; execute json_stmt9 USING @mypath; @@ -3276,11 +3273,11 @@ prepare json_stmt10 FROM 'select json_remove( ''{ "keyA": [ "foot" ], "keyB": [ set @mypath = '$.keyA'; execute json_stmt10 USING @mypath; json_remove( '{ "keyA": [ "foot" ], "keyB": [ "food" ] }', ? ) -{ "keyB": [ "food" ] } +{"keyB": ["food"]} set @mypath = '$.keyB'; execute json_stmt10 USING @mypath; json_remove( '{ "keyA": [ "foot" ], "keyB": [ "food" ] }', ? ) -{ "keyA": [ "foot" ]} +{"keyA": ["foot"]} prepare json_stmt11 FROM 'select json_contains_path( ''{ "keyA": true }'', ?, ''$.keyA'', ''$.keyB'' )'; set @mypath = 'one'; execute json_stmt11 USING @mypath; @@ -3502,14 +3499,10 @@ JSON_SET('[]', '$[0]', 100) [100] SELECT JSON_SET('[]', '$[0][0]', 100); JSON_SET('[]', '$[0][0]', 100) -NULL -Warnings: -Warning 4037 Unexpected end of JSON text in argument 1 to function 'json_set' +[] SELECT JSON_SET('[]', '$[0][0][0]', 100); JSON_SET('[]', '$[0][0][0]', 100) -NULL -Warnings: -Warning 4037 Unexpected end of JSON text in argument 1 to function 'json_set' +[] SELECT JSON_SET('[1]', '$', 100); JSON_SET('[1]', '$', 100) 100 @@ -3566,14 +3559,10 @@ JSON_REPLACE('[]', '$[0]', 100) [] SELECT JSON_REPLACE('[]', '$[0][0]', 100); JSON_REPLACE('[]', '$[0][0]', 100) -NULL -Warnings: -Warning 4037 Unexpected end of JSON text in argument 1 to function 'json_update' +[] SELECT JSON_REPLACE('[]', '$[0][0][0]', 100); JSON_REPLACE('[]', '$[0][0][0]', 100) -NULL -Warnings: -Warning 4037 Unexpected end of JSON text in argument 1 to function 'json_update' +[] SELECT JSON_REPLACE('[1]', '$', 100); JSON_REPLACE('[1]', '$', 100) 100 diff --git a/mysql-test/t/func_json.test b/mysql-test/t/func_json.test index 546b5db77e3..2ed5282abc0 100644 --- a/mysql-test/t/func_json.test +++ b/mysql-test/t/func_json.test @@ -200,3 +200,23 @@ select json_set('{"a":12}', '$[0][1].a', 100); select json_value('{"\\"key1":123}', '$."\\"key1"'); select json_value('{"\\"key1\\"":123}', '$."\\"key1\\""'); select json_value('{"key 1":123}', '$."key 1"'); + +select json_contains_path('{"a":[{"c":[1,{"a":[0,1,2]},3]}], "b":[1,2,3]}', 'one', "$**.a[2]"); +select json_contains_path('{"a":[{"c":[1,{"a":[0,1,2]},3]}], "b":[1,2,3]}', 'one', "$**.a[3]"); + +select json_extract( '[1]', '$[0][0]' ); +select json_extract( '[1]', '$[1][0]' ); +select json_extract( '[1]', '$**[0]' ); +select json_extract( '[1]', '$**[0][0]' ); + +select json_insert('1', '$[0]', 4); +select json_replace('1', '$[0]', 4); +select json_set('1', '$[0]', 4); +select json_set('1', '$[1]', 4); +select json_replace('1', '$[1]', 4); +SELECT json_insert('[]', '$[0][0]', 100); +SELECT json_insert('1', '$[0][0]', 100); +SELECT json_replace('1', '$[0][0]', 100); +SELECT json_replace('[]', '$[0][0]', 100); +SELECT json_set('[]', '$[0][0]', 100); +SELECT json_set('[]', '$[0][0][0]', 100); diff --git a/sql/item_create.cc b/sql/item_create.cc index add8da67810..d2be36e105f 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -1762,6 +1762,46 @@ protected: }; +class Create_func_json_compact : public Create_func_arg1 +{ +public: + virtual Item *create_1_arg(THD *thd, Item *arg1); + + static Create_func_json_compact s_singleton; + +protected: + Create_func_json_compact() {} + virtual ~Create_func_json_compact() {} +}; + + +class Create_func_json_loose : public Create_func_arg1 +{ +public: + virtual Item *create_1_arg(THD *thd, Item *arg1); + + static Create_func_json_loose s_singleton; + +protected: + Create_func_json_loose() {} + virtual ~Create_func_json_loose() {} +}; + + +class Create_func_json_detailed : public Create_func_arg2 +{ +public: + virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2); + + static Create_func_json_detailed s_singleton; + +protected: + Create_func_json_detailed() {} + virtual ~Create_func_json_detailed() {} +}; + + + class Create_func_json_type : public Create_func_arg1 { public: @@ -5003,6 +5043,35 @@ Create_func_json_exists::create_2_arg(THD *thd, Item *arg1, Item *arg2) } +Create_func_json_detailed Create_func_json_detailed::s_singleton; + +Item* +Create_func_json_detailed::create_2_arg(THD *thd, Item *arg1, Item *arg2) +{ + return new (thd->mem_root) Item_func_json_format(thd, arg1, arg2); +} + + +Create_func_json_loose Create_func_json_loose::s_singleton; + +Item* +Create_func_json_loose::create_1_arg(THD *thd, Item *arg1) +{ + return new (thd->mem_root) Item_func_json_format(thd, arg1, + Item_func_json_format::LOOSE); +} + + +Create_func_json_compact Create_func_json_compact::s_singleton; + +Item* +Create_func_json_compact::create_1_arg(THD *thd, Item *arg1) +{ + return new (thd->mem_root) Item_func_json_format(thd, arg1, + Item_func_json_format::COMPACT); +} + + Create_func_json_valid Create_func_json_valid::s_singleton; Item* @@ -6728,14 +6797,17 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("JSON_ARRAY") }, BUILDER(Create_func_json_array)}, { { C_STRING_WITH_LEN("JSON_ARRAY_APPEND") }, BUILDER(Create_func_json_array_append)}, { { C_STRING_WITH_LEN("JSON_ARRAY_INSERT") }, BUILDER(Create_func_json_array_insert)}, + { { C_STRING_WITH_LEN("JSON_COMPACT") }, BUILDER(Create_func_json_compact)}, { { C_STRING_WITH_LEN("JSON_CONTAINS") }, BUILDER(Create_func_json_contains)}, { { C_STRING_WITH_LEN("JSON_CONTAINS_PATH") }, BUILDER(Create_func_json_contains_path)}, { { C_STRING_WITH_LEN("JSON_DEPTH") }, BUILDER(Create_func_json_depth)}, + { { C_STRING_WITH_LEN("JSON_DETAILED") }, BUILDER(Create_func_json_detailed)}, { { C_STRING_WITH_LEN("JSON_EXISTS") }, BUILDER(Create_func_json_exists)}, { { C_STRING_WITH_LEN("JSON_EXTRACT") }, BUILDER(Create_func_json_extract)}, { { C_STRING_WITH_LEN("JSON_INSERT") }, BUILDER(Create_func_json_insert)}, { { C_STRING_WITH_LEN("JSON_KEYS") }, BUILDER(Create_func_json_keys)}, { { C_STRING_WITH_LEN("JSON_LENGTH") }, BUILDER(Create_func_json_length)}, + { { C_STRING_WITH_LEN("JSON_LOOSE") }, BUILDER(Create_func_json_loose)}, { { C_STRING_WITH_LEN("JSON_MERGE") }, BUILDER(Create_func_json_merge)}, { { C_STRING_WITH_LEN("JSON_QUERY") }, BUILDER(Create_func_json_query)}, { { C_STRING_WITH_LEN("JSON_QUOTE") }, BUILDER(Create_func_json_quote)}, diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index d1f82bc94da..73b0e6b0870 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -113,6 +113,100 @@ static int st_append_escaped(String *s, const String *a) } +static int json_nice(json_engine_t *je, String *nice_js, + Item_func_json_format::formats mode) +{ + int depth= 0; + const char *comma, *colon; + uint comma_len, colon_len; + int first_value= 1; + + DBUG_ASSERT(je->s.cs == nice_js->charset()); + + if (mode == Item_func_json_format::LOOSE) + { + comma= ", "; + comma_len= 2; + colon= "\": "; + colon_len= 3; + } + else + { + comma= ","; + comma_len= 1; + colon= "\":"; + colon_len= 2; + } + + do + { + switch (je->state) + { + case JST_KEY: + { + const uchar *key_start= je->s.c_str; + const uchar *key_end; + + while (json_read_keyname_chr(je) == 0) + key_end= je->s.c_str; + + if (je->s.error) + goto error; + + if (!first_value) + nice_js->append(comma, comma_len); + + nice_js->append("\"", 1); + append_simple(nice_js, key_start, key_end - key_start); + nice_js->append(colon, colon_len); + } + /* now we have key value to handle, so no 'break'. */ + DBUG_ASSERT(je->state == JST_VALUE); + goto handle_value; + + case JST_VALUE: + if (!first_value) + nice_js->append(comma, comma_len); + +handle_value: + if (json_read_value(je)) + goto error; + if (json_value_scalar(je)) + { + if (append_simple(nice_js, je->value_begin, + je->value_end - je->value_begin)) + goto error; + + first_value= 0; + } + else + { + nice_js->append((je->value_type == JSON_VALUE_OBJECT) ? "{" : "[", 1); + first_value= 1; + depth++; + } + + break; + + case JST_OBJ_END: + case JST_ARRAY_END: + depth--; + nice_js->append((je->state == JST_OBJ_END) ? "}": "]", 1); + first_value= 0; + break; + + default: + break; + }; + } while (json_scan_next(je) == 0); + + return je->s.error; + +error: + return 1; +} + + #define report_json_error(js, je, n_param) \ report_json_error_ex(js, je, func_name(), n_param, \ Sql_condition::WARN_LEVEL_WARN) @@ -554,11 +648,11 @@ 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) + const json_path_t *p, enum json_value_types vt) { for (; n_paths > 0; n_paths--, paths_list++) { - if (json_path_compare(&paths_list->p, p) == 0) + if (json_path_compare(&paths_list->p, p, vt) == 0) return TRUE; } return FALSE; @@ -566,11 +660,11 @@ static bool path_exact(const json_path_with_flags *paths_list, int n_paths, static bool path_ok(const json_path_with_flags *paths_list, int n_paths, - const json_path_t *p) + const json_path_t *p, enum json_value_types vt) { for (; n_paths > 0; n_paths--, paths_list++) { - if (json_path_compare(&paths_list->p, p) >= 0) + if (json_path_compare(&paths_list->p, p, vt) >= 0) return TRUE; } return FALSE; @@ -624,7 +718,7 @@ String *Item_func_json_extract::val_str(String *str) while (json_get_path_next(&je, &p) == 0) { - if (!path_exact(paths, arg_count-1, &p)) + if (!path_exact(paths, arg_count-1, &p, je.value_type)) continue; value= je.value_begin; @@ -661,10 +755,18 @@ String *Item_func_json_extract::val_str(String *str) goto return_null; } - if (possible_multiple_values && str->append("]")) + if (possible_multiple_values && str->append("]", 1)) goto error; /* Out of memory. */ - return str; + js= str; + json_scan_start(&je, js->charset(),(const uchar *) js->ptr(), + (const uchar *) js->ptr() + js->length()); + tmp_js.length(0); + tmp_js.set_charset(js->charset()); + if (json_nice(&je, &tmp_js, Item_func_json_format::LOOSE)) + goto error; + + return &tmp_js; error: report_json_error(js, &je, 0); @@ -1153,7 +1255,7 @@ longlong Item_func_json_contains_path::val_int() 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 (json_path_compare(&c_path->p, &p, je.value_type) >= 0) { if (mode_one) { @@ -1424,7 +1526,14 @@ String *Item_func_json_array_append::val_str(String *str) } } - return js; + json_scan_start(&je, js->charset(),(const uchar *) js->ptr(), + (const uchar *) js->ptr() + js->length()); + str->length(0); + str->set_charset(js->charset()); + if (json_nice(&je, str, Item_func_json_format::LOOSE)) + goto js_error; + + return str; js_error: report_json_error(js, &je, 0); @@ -1558,7 +1667,14 @@ String *Item_func_json_array_insert::val_str(String *str) } } - return js; + json_scan_start(&je, js->charset(),(const uchar *) js->ptr(), + (const uchar *) js->ptr() + js->length()); + str->length(0); + str->set_charset(js->charset()); + if (json_nice(&je, str, Item_func_json_format::LOOSE)) + goto js_error; + + return str; js_error: report_json_error(js, &je, 0); @@ -1690,8 +1806,15 @@ String *Item_func_json_merge::val_str(String *str) } } + json_scan_start(&je1, js1->charset(),(const uchar *) js1->ptr(), + (const uchar *) js1->ptr() + js1->length()); + str->length(0); + str->set_charset(js1->charset()); + if (json_nice(&je1, str, Item_func_json_format::LOOSE)) + goto error_return; + null_value= 0; - return js1; + return str; error_return: if (je1.s.error) @@ -1970,6 +2093,7 @@ String *Item_func_json_insert::val_str(String *str) { if (je.s.error) goto js_error; + continue; } if (json_read_value(&je)) @@ -1986,7 +2110,16 @@ String *Item_func_json_insert::val_str(String *str) int do_array_autowrap; if (mode_insert) - do_array_autowrap= !mode_replace || lp->n_item; + { + if (mode_replace) + do_array_autowrap= lp->n_item > 0; + else + { + if (lp->n_item == 0) + continue; + do_array_autowrap= 1; + } + } else { if (lp->n_item) @@ -2124,7 +2257,14 @@ continue_point: } } - return js; + json_scan_start(&je, js->charset(),(const uchar *) js->ptr(), + (const uchar *) js->ptr() + js->length()); + str->length(0); + str->set_charset(js->charset()); + if (json_nice(&je, str, Item_func_json_format::LOOSE)) + goto js_error; + + return str; js_error: report_json_error(js, &je, 0); @@ -2300,7 +2440,14 @@ v_found: } } - return js; + json_scan_start(&je, js->charset(),(const uchar *) js->ptr(), + (const uchar *) js->ptr() + js->length()); + str->length(0); + str->set_charset(js->charset()); + if (json_nice(&je, str, Item_func_json_format::LOOSE)) + goto js_error; + + return str; js_error: report_json_error(js, &je, 0); @@ -2540,7 +2687,7 @@ String *Item_func_json_search::val_str(String *str) { if (json_value_scalar(&je)) { - if ((arg_count < 5 || path_ok(paths, arg_count - 4, &p)) && + if ((arg_count < 5 || path_ok(paths, arg_count - 4, &p, je.value_type)) && compare_json_value_wild(&je, s_str) != 0) { ++n_path_found; @@ -2609,3 +2756,52 @@ String *Item_json_typecast::val_str(String *str) return vs; } + +const char *Item_func_json_format::func_name() const +{ + switch (fmt) + { + case COMPACT: + return "json_compact"; + case LOOSE: + return "json_loose"; + case DETAILED: + return "json_detailed"; + default: + DBUG_ASSERT(0); + }; + + return ""; +} + + +void Item_func_json_format::fix_length_and_dec() +{ + decimals= 0; + max_length= args[0]->max_length; +} + + +String *Item_func_json_format::val_str(String *str) +{ + String *js= args[0]->val_str(&tmp_js); + json_engine_t je; + if ((null_value= args[0]->null_value)) + return 0; + + json_scan_start(&je, js->charset(), (const uchar *) js->ptr(), + (const uchar *) js->ptr()+js->length()); + + str->length(0); + str->set_charset(js->charset()); + if (json_nice(&je, str, fmt)) + { + null_value= 1; + report_json_error(js, &je, 0); + return 0; + } + + return str; +} + + diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index 2ce94985a00..941123041d2 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -427,4 +427,30 @@ public: }; +class Item_func_json_format: public Item_str_func +{ +public: + enum formats + { + NONE, + COMPACT, + LOOSE, + DETAILED + }; +protected: + formats fmt; + String tmp_js; +public: + Item_func_json_format(THD *thd, Item *js, formats format): + Item_str_func(thd, js), fmt(format) {} + Item_func_json_format(THD *thd, Item *js, Item *tabsize): + Item_str_func(thd, js, tabsize), fmt(DETAILED) {} + const char *func_name() const; + void fix_length_and_dec(); + String *val_str(String *str); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy(thd, mem_root, this); } +}; + + #endif /* ITEM_JSONFUNC_INCLUDED */ diff --git a/strings/json_lib.c b/strings/json_lib.c index 20dc1b3d718..cc3a8adf0aa 100644 --- a/strings/json_lib.c +++ b/strings/json_lib.c @@ -1001,6 +1001,7 @@ enum json_path_states { PS_LAX, /* Parse the 'lax' keyword. */ PS_PT, /* New path's step begins. */ PS_AR, /* Parse array step. */ + PS_SAR, /* space after the '['. */ PS_AWD, /* Array wildcard. */ PS_Z, /* '0' (as an array item number). */ PS_INT, /* Parse integer (as an array item number). */ @@ -1041,7 +1042,10 @@ static int json_path_transitions[N_PATH_STATES][N_PATH_CLASSES]= JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_NOT_JSON_CHR, JE_BAD_CHR}, /* AR */ { JE_EOS, JE_SYN, PS_AWD, JE_SYN, PS_PT, JE_SYN, PS_Z, - PS_INT, JE_SYN, JE_SYN, PS_AR, JE_SYN, JE_SYN, JE_SYN, + PS_INT, JE_SYN, JE_SYN, PS_SAR, JE_SYN, JE_SYN, JE_SYN, + JE_NOT_JSON_CHR, JE_BAD_CHR}, +/* SAR */ { JE_EOS, JE_SYN, PS_AWD, JE_SYN, PS_PT, JE_SYN, PS_Z, + PS_INT, JE_SYN, JE_SYN, PS_SAR, JE_SYN, JE_SYN, JE_SYN, JE_NOT_JSON_CHR, JE_BAD_CHR}, /* AWD */ { JE_EOS, JE_SYN, JE_SYN, JE_SYN, PS_PT, JE_SYN, JE_SYN, JE_SYN, JE_SYN, JE_SYN, PS_AS, JE_SYN, JE_SYN, JE_SYN, @@ -1722,45 +1726,103 @@ 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) +int json_path_parts_compare( + const json_path_step_t *a, const json_path_step_t *a_end, + const json_path_step_t *b, const json_path_step_t *b_end, + enum json_value_types vt) { - const json_path_step_t *sa= a->steps + 1; - const json_path_step_t *sb= b->steps + 1; + int res, res2; - if (a->last_step - sa > b->last_step - sb) - return -2; - - while (sa <= a->last_step) + while (a <= a_end) { - 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 (b > b_end) { - if (!(sa->type & JSON_PATH_WILD) && sa->n_item != sb->n_item) + while (vt != JSON_VALUE_ARRAY && + (a->type & JSON_PATH_ARRAY_WILD) == JSON_PATH_ARRAY && + a->n_item == 0) + { + if (++a > a_end) + return 0; + } + return -2; + } + + DBUG_ASSERT((b->type & (JSON_PATH_WILD | JSON_PATH_DOUBLE_WILD)) == 0); + + + if (a->type & JSON_PATH_ARRAY) + { + if (b->type & JSON_PATH_ARRAY) + { + if ((a->type & JSON_PATH_WILD) || a->n_item == b->n_item) + goto step_fits; goto step_failed; + } + if (a->n_item == 0) + goto step_fits_autowrap; + 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)) + if (!(b->type & JSON_PATH_KEY)) goto step_failed; + + if (!(a->type & JSON_PATH_WILD) && + (a->key_end - a->key != b->key_end - b->key || + memcmp(a->key, b->key, a->key_end - a->key) != 0)) + goto step_failed; + + goto step_fits; } - sb++; - sa++; +step_failed: + if (!(a->type & JSON_PATH_DOUBLE_WILD)) + return -1; + b++; continue; -step_failed: - if (!(sa->type & JSON_PATH_DOUBLE_WILD)) - return -1; - sb++; +step_fits: + b++; + if (!(a->type & JSON_PATH_DOUBLE_WILD)) + { + a++; + continue; + } + + /* Double wild handling needs recursions. */ + res= json_path_parts_compare(a+1, a_end, b, b_end, vt); + if (res == 0) + return 0; + + res2= json_path_parts_compare(a, a_end, b, b_end, vt); + + return (res2 >= 0) ? res2 : res; + +step_fits_autowrap: + if (!(a->type & JSON_PATH_DOUBLE_WILD)) + { + a++; + continue; + } + + /* Double wild handling needs recursions. */ + res= json_path_parts_compare(a+1, a_end, b+1, b_end, vt); + if (res == 0) + return 0; + + res2= json_path_parts_compare(a, a_end, b+1, b_end, vt); + + return (res2 >= 0) ? res2 : res; + } - return sb <= b->last_step; + return b <= b_end; } +int json_path_compare(const json_path_t *a, const json_path_t *b, + enum json_value_types vt) +{ + return json_path_parts_compare(a->steps+1, a->last_step, + b->steps+1, b->last_step, vt); +} +