Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions mysql-test/main/json_normalize.result
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,152 @@ select concat_ws(' ', json_normalize(t1.text), json_normalize(t1.text)) from t1;
concat_ws(' ', json_normalize(t1.text), json_normalize(t1.text))
0.0E0 0.0E0
drop table t1;
#
# MDEV-28922 JSON_NORMALIZE handling of duplicate keys
#
SET @j = '{"x": 1, "y": 2, "z": 3, "b": 0, "c": 5, "b":3, "a": 4, "b": 1, "a": 3, "a": 2, "a": 1, "b": 2}';
SELECT @k := JSON_NORMALIZE(@j);
@k := JSON_NORMALIZE(@j)
{"a":1.0E0,"a":2.0E0,"a":3.0E0,"a":4.0E0,"b":0.0E0,"b":1.0E0,"b":2.0E0,"b":3.0E0,"c":5.0E0,"x":1.0E0,"y":2.0E0,"z":3.0E0}
SELECT JSON_EXTRACT(@j, '$.b') as j1, JSON_EXTRACT(@k, '$.b') as j2;
j1 j2
0 0.0E0
Primitives
SET @j='{"a": null, "a": true, "a": false, "a": 123, "a": "string"}';
SELECT JSON_NORMALIZE(@j);
JSON_NORMALIZE(@j)
{"a":"string","a":1.23E2,"a":true,"a":false,"a":null}
SET @j2='{"a": "string", "a": 123, "a": false, "a": true, "a": null}';
SELECT JSON_NORMALIZE(@j2);
JSON_NORMALIZE(@j2)
{"a":"string","a":1.23E2,"a":true,"a":false,"a":null}
SELECT JSON_EQUALS(@j, @j2) je;
je
1
Objects
SET @j='{
"a": {},
"a": {"x":1},
"a": {"x":1,"y":2},
"a": {"x":1,"y":2,"z":3}
}';
SELECT JSON_NORMALIZE(@j);
JSON_NORMALIZE(@j)
{"a":{},"a":{"x":1.0E0},"a":{"x":1.0E0,"y":2.0E0},"a":{"x":1.0E0,"y":2.0E0,"z":3.0E0}}
SET @j2='{
"a": {"x":1,"y":2,"z":3},
"a": {"x":1},
"a": {},
"a": {"x":1,"y":2}
}';
SELECT JSON_NORMALIZE(@j2);
JSON_NORMALIZE(@j2)
{"a":{},"a":{"x":1.0E0},"a":{"x":1.0E0,"y":2.0E0},"a":{"x":1.0E0,"y":2.0E0,"z":3.0E0}}
SELECT JSON_EQUALS(@j, @j2) as je;
je
1
Arrays
SET @j='{
"a": [],
"a": [1],
"a": [1,2],
"a": [1,2,3],
"a": [1,2,3,4]
}';
SELECT JSON_NORMALIZE(@j);
JSON_NORMALIZE(@j)
{"a":[],"a":[1.0E0],"a":[1.0E0,2.0E0],"a":[1.0E0,2.0E0,3.0E0],"a":[1.0E0,2.0E0,3.0E0,4.0E0]}
SET @j2='{
"a": [1,2,3],
"a": [],
"a": [1,2,3,4],
"a": [1],
"a": [1,2]
}';
SELECT JSON_NORMALIZE(@j2);
JSON_NORMALIZE(@j2)
{"a":[],"a":[1.0E0],"a":[1.0E0,2.0E0],"a":[1.0E0,2.0E0,3.0E0],"a":[1.0E0,2.0E0,3.0E0,4.0E0]}
SELECT JSON_EQUALS(@j, @j2) je;
je
1
Mixed Arrays
SET @j='{
"a": [],
"a": [null],
"a": [1,"x",true],
"a": [{"k":1}],
"a": [[1,2],[3,4]]
}';
SELECT JSON_NORMALIZE(@j);
JSON_NORMALIZE(@j)
{"a":[],"a":[{"k":1.0E0}],"a":[null],"a":[[1.0E0,2.0E0],[3.0E0,4.0E0]],"a":[1.0E0,"x",true]}
SET @j2='{
"a": [[1,2],[3,4]],
"a": [{"k":1}],
"a": [],
"a": [1,"x",true],
"a": [null]
}';
SELECT JSON_NORMALIZE(@j2);
JSON_NORMALIZE(@j2)
{"a":[],"a":[{"k":1.0E0}],"a":[null],"a":[[1.0E0,2.0E0],[3.0E0,4.0E0]],"a":[1.0E0,"x",true]}
SELECT JSON_EQUALS(@j, @j2) je;
je
1
Nested objects
SET @j='{
"a": {"x":{"y":1}},
"a": {"x":{"y":[1,2]}},
"a": {"x":{"y":{"z":3}}},
"a": {"x":{}}
}';
SELECT JSON_NORMALIZE(@j);
JSON_NORMALIZE(@j)
{"a":{"x":{}},"a":{"x":{"y":{"z":3.0E0}}},"a":{"x":{"y":[1.0E0,2.0E0]}},"a":{"x":{"y":1.0E0}}}
SET @j2='{
"a": {"x":{}},
"a": {"x":{"y":{"z":3}}},
"a": {"x":{"y":1}},
"a": {"x":{"y":[1,2]}}
}';
SELECT JSON_NORMALIZE(@j2);
JSON_NORMALIZE(@j2)
{"a":{"x":{}},"a":{"x":{"y":{"z":3.0E0}}},"a":{"x":{"y":[1.0E0,2.0E0]}},"a":{"x":{"y":1.0E0}}}
SELECT JSON_EQUALS(@j, @j2) je;
je
1
Everything mixed
SET @j='{
"a": null,
"a": 1,
"a": "abc",
"a": true,
"a": [],
"a": [1],
"a": [1,2],
"a": {},
"a": {"k":1},
"a": {"k":1,"m":2}
}';
SELECT JSON_NORMALIZE(@j);
JSON_NORMALIZE(@j)
{"a":{},"a":{"k":1.0E0},"a":{"k":1.0E0,"m":2.0E0},"a":[],"a":[1.0E0],"a":[1.0E0,2.0E0],"a":"abc","a":1.0E0,"a":true,"a":null}
SET @j2='{
"a": {"k":1},
"a": [],
"a": true,
"a": {"k":1,"m":2},
"a": "abc",
"a": null,
"a": [1,2],
"a": 1,
"a": {},
"a": [1]
}';
SELECT JSON_NORMALIZE(@j2);
JSON_NORMALIZE(@j2)
{"a":{},"a":{"k":1.0E0},"a":{"k":1.0E0,"m":2.0E0},"a":[],"a":[1.0E0],"a":[1.0E0,2.0E0],"a":"abc","a":1.0E0,"a":true,"a":null}
SELECT JSON_EQUALS(@j, @j2) je;
je
1
# End of 10.11 tests
126 changes: 126 additions & 0 deletions mysql-test/main/json_normalize.test
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,129 @@ select concat_ws(' ', t1.text, t1.text) from t1;
select concat_ws(' ', json_normalize(t1.text), json_normalize(t1.text)) from t1;

drop table t1;

--echo #
--echo # MDEV-28922 JSON_NORMALIZE handling of duplicate keys
--echo #

SET @j = '{"x": 1, "y": 2, "z": 3, "b": 0, "c": 5, "b":3, "a": 4, "b": 1, "a": 3, "a": 2, "a": 1, "b": 2}';
SELECT @k := JSON_NORMALIZE(@j);
SELECT JSON_EXTRACT(@j, '$.b') as j1, JSON_EXTRACT(@k, '$.b') as j2;

--echo Primitives

SET @j='{"a": null, "a": true, "a": false, "a": 123, "a": "string"}';
SELECT JSON_NORMALIZE(@j);

SET @j2='{"a": "string", "a": 123, "a": false, "a": true, "a": null}';
SELECT JSON_NORMALIZE(@j2);
SELECT JSON_EQUALS(@j, @j2) je;

--echo Objects
SET @j='{
"a": {},
"a": {"x":1},
"a": {"x":1,"y":2},
"a": {"x":1,"y":2,"z":3}
}';
SELECT JSON_NORMALIZE(@j);

SET @j2='{
"a": {"x":1,"y":2,"z":3},
"a": {"x":1},
"a": {},
"a": {"x":1,"y":2}
}';
SELECT JSON_NORMALIZE(@j2);
SELECT JSON_EQUALS(@j, @j2) as je;

--echo Arrays

SET @j='{
"a": [],
"a": [1],
"a": [1,2],
"a": [1,2,3],
"a": [1,2,3,4]
}';
SELECT JSON_NORMALIZE(@j);

SET @j2='{
"a": [1,2,3],
"a": [],
"a": [1,2,3,4],
"a": [1],
"a": [1,2]
}';
SELECT JSON_NORMALIZE(@j2);
SELECT JSON_EQUALS(@j, @j2) je;

--echo Mixed Arrays
SET @j='{
"a": [],
"a": [null],
"a": [1,"x",true],
"a": [{"k":1}],
"a": [[1,2],[3,4]]
}';
SELECT JSON_NORMALIZE(@j);

SET @j2='{
"a": [[1,2],[3,4]],
"a": [{"k":1}],
"a": [],
"a": [1,"x",true],
"a": [null]
}';
SELECT JSON_NORMALIZE(@j2);
SELECT JSON_EQUALS(@j, @j2) je;

--echo Nested objects
SET @j='{
"a": {"x":{"y":1}},
"a": {"x":{"y":[1,2]}},
"a": {"x":{"y":{"z":3}}},
"a": {"x":{}}
}';
SELECT JSON_NORMALIZE(@j);

SET @j2='{
"a": {"x":{}},
"a": {"x":{"y":{"z":3}}},
"a": {"x":{"y":1}},
"a": {"x":{"y":[1,2]}}
}';
SELECT JSON_NORMALIZE(@j2);
SELECT JSON_EQUALS(@j, @j2) je;

--echo Everything mixed
SET @j='{
"a": null,
"a": 1,
"a": "abc",
"a": true,
"a": [],
"a": [1],
"a": [1,2],
"a": {},
"a": {"k":1},
"a": {"k":1,"m":2}
}';
SELECT JSON_NORMALIZE(@j);

SET @j2='{
"a": {"k":1},
"a": [],
"a": true,
"a": {"k":1,"m":2},
"a": "abc",
"a": null,
"a": [1,2],
"a": 1,
"a": {},
"a": [1]
}';
SELECT JSON_NORMALIZE(@j2);
SELECT JSON_EQUALS(@j, @j2) je;

--echo # End of 10.11 tests
87 changes: 84 additions & 3 deletions strings/json_normalize.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,12 +308,93 @@ json_norm_value_string_init(struct json_norm_value *val,
}


static int json_norm_kv_comp(const void *a_, const void *b_);

static int json_norm_value_comp(const struct json_norm_value *a,
const struct json_norm_value *b)
{
if (a->type != b->type)
return (int) a->type - b->type;

switch (a->type)
{
case JSON_VALUE_OBJECT:
{
const DYNAMIC_ARRAY *ao= &a->value.object.kv_pairs;
const DYNAMIC_ARRAY *bo= &b->value.object.kv_pairs;
int ret;
if (ao->elements != bo->elements)
return ao->elements < bo->elements ? -1 : 1;

for (size_t i= 0; i < ao->elements; ++i)
{
const struct json_norm_kv *akv=
dynamic_element(ao, i, struct json_norm_kv*);
const struct json_norm_kv *bkv=
dynamic_element(bo, i, struct json_norm_kv*);
if ((ret= json_norm_kv_comp(akv, bkv)))
return ret;
}
return 0;
}
case JSON_VALUE_ARRAY:
{
const DYNAMIC_ARRAY *aa= &a->value.array.values;
const DYNAMIC_ARRAY *ba= &b->value.array.values;
int ret;

if (aa->elements != ba->elements)
return aa->elements < ba->elements ? -1 : 1;

for (size_t i= 0; i < aa->elements; ++i)
{
const struct json_norm_value *aval=
dynamic_element(aa, i, struct json_norm_value*);
const struct json_norm_value *bval=
dynamic_element(ba, i, struct json_norm_value*);
if ((ret= json_norm_value_comp(aval, bval)))
return ret;
}
return 0;
}
case JSON_VALUE_STRING:
{
const LEX_STRING *as= &a->value.string;
const LEX_STRING *bs= &b->value.string;
if (as->length != bs->length)
return as->length < bs->length ? -1 : 1;

return my_strnncoll(&my_charset_utf8mb4_bin,
(const uchar *)as->str, as->length,
(const uchar *)bs->str, bs->length);
}
case JSON_VALUE_NUMBER:
{
const DYNAMIC_STRING *anum= &a->value.number;
const DYNAMIC_STRING *bnum= &b->value.number;
if (anum->length != bnum->length)
return anum->length < bnum->length ? -1 : 1;
return strncmp(anum->str, bnum->str, anum->length);
}
case JSON_VALUE_NULL:
case JSON_VALUE_TRUE:
case JSON_VALUE_FALSE:
case JSON_VALUE_UNINITIALIZED:
default:
return 0;
}
}


static int json_norm_kv_comp(const void *a_, const void *b_)
{
const struct json_norm_kv *a= a_, *b= b_;
return my_strnncoll(&my_charset_utf8mb4_bin,
(const uchar *)a->key.str, a->key.length,
(const uchar *)b->key.str, b->key.length);
int ret;
if (!(ret= my_strnncoll(&my_charset_utf8mb4_bin,
(const uchar *)a->key.str, a->key.length,
(const uchar *)b->key.str, b->key.length)))
return json_norm_value_comp(&a->value, &b->value);
return ret;
}
Comment thread
grooverdan marked this conversation as resolved.


Expand Down