Skip to content

Commit 3a17727

Browse files
author
Alexey Botchkov
committed
MDEV-11573 JSON_LENGTH returns incorrect results.
Item_func_json_length fixed.
1 parent 4d10273 commit 3a17727

File tree

4 files changed

+77
-11
lines changed

4 files changed

+77
-11
lines changed

mysql-test/r/func_json.result

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,12 @@ json_length('{}')
425425
select json_length('[1, 2, {"a": 3}]');
426426
json_length('[1, 2, {"a": 3}]')
427427
3
428+
select json_length('{"a": 1, "b": {"c": 30}}', '$.b');
429+
json_length('{"a": 1, "b": {"c": 30}}', '$.b')
430+
1
431+
select json_length('{"a": 1, "b": {"c": 30}}');
432+
json_length('{"a": 1, "b": {"c": 30}}')
433+
2
428434
create table json (j INT);
429435
show create table json;
430436
Table Create Table

mysql-test/t/func_json.test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ select json_depth('[10, {"a": 20}]');
170170
select json_length('');
171171
select json_length('{}');
172172
select json_length('[1, 2, {"a": 3}]');
173+
select json_length('{"a": 1, "b": {"c": 30}}', '$.b');
174+
select json_length('{"a": 1, "b": {"c": 30}}');
173175

174176
create table json (j INT);
175177
show create table json;

sql/item_jsonfunc.cc

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,29 +1599,85 @@ String *Item_func_json_merge::val_str(String *str)
15991599
}
16001600

16011601

1602+
void Item_func_json_length::fix_length_and_dec()
1603+
{
1604+
if (arg_count > 1)
1605+
path.set_constant_flag(args[1]->const_item());
1606+
}
1607+
1608+
16021609
longlong Item_func_json_length::val_int()
16031610
{
16041611
String *js= args[0]->val_str(&tmp_js);
16051612
json_engine_t je;
16061613
uint length= 0;
1614+
uint array_counters[JSON_DEPTH_LIMIT];
16071615

16081616
if ((null_value= args[0]->null_value))
16091617
return 0;
16101618

1611-
16121619
json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
16131620
(const uchar *) js->ptr() + js->length());
16141621

1615-
do
1622+
if (arg_count > 1)
16161623
{
1617-
if (je.state == JST_VALUE)
1624+
/* Path specified - let's apply it. */
1625+
if (!path.parsed)
1626+
{
1627+
String *s_p= args[1]->val_str(&tmp_path);
1628+
if (s_p &&
1629+
json_path_setup(&path.p, s_p->charset(), (const uchar *) s_p->ptr(),
1630+
(const uchar *) s_p->ptr() + s_p->length()))
1631+
{
1632+
report_path_error(s_p, &path.p, 2);
1633+
goto null_return;
1634+
}
1635+
path.parsed= path.constant;
1636+
}
1637+
if (args[1]->null_value)
1638+
goto null_return;
1639+
1640+
path.cur_step= path.p.steps;
1641+
if (json_find_path(&je, &path.p, &path.cur_step, array_counters))
1642+
{
1643+
if (je.s.error)
1644+
goto err_return;
1645+
goto null_return;
1646+
}
1647+
}
1648+
1649+
1650+
if (json_read_value(&je))
1651+
goto err_return;
1652+
1653+
if (json_value_scalar(&je))
1654+
return 1;
1655+
1656+
while (json_scan_next(&je) == 0 &&
1657+
je.state != JST_OBJ_END && je.state != JST_ARRAY_END)
1658+
{
1659+
switch (je.state)
1660+
{
1661+
case JST_VALUE:
1662+
case JST_KEY:
16181663
length++;
1619-
} while (json_scan_next(&je) == 0);
1664+
break;
1665+
case JST_OBJ_START:
1666+
case JST_ARRAY_START:
1667+
if (json_skip_level(&je))
1668+
goto err_return;
1669+
break;
1670+
default:
1671+
break;
1672+
};
1673+
}
16201674

16211675
if (!je.s.error)
1622-
return length - 1;
1676+
return length;
16231677

1678+
err_return:
16241679
report_json_error(js, &je, 0);
1680+
null_return:
16251681
null_value= 1;
16261682
return 0;
16271683
}

sql/item_jsonfunc.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ class Item_func_json_exists: public Item_int_func
6767
String tmp_js, tmp_path;
6868

6969
public:
70-
Item_func_json_exists(THD *thd, Item *js, Item *path):
71-
Item_int_func(thd, js, path) {}
70+
Item_func_json_exists(THD *thd, Item *js, Item *i_path):
71+
Item_int_func(thd, js, i_path) {}
7272
const char *func_name() const { return "json_exists"; }
7373
bool is_bool_type() { return true; }
7474
void fix_length_and_dec();
@@ -85,8 +85,8 @@ class Item_func_json_value: public Item_str_func
8585
String tmp_js, tmp_path;
8686

8787
public:
88-
Item_func_json_value(THD *thd, Item *js, Item *path):
89-
Item_str_func(thd, js, path) {}
88+
Item_func_json_value(THD *thd, Item *js, Item *i_path):
89+
Item_str_func(thd, js, i_path) {}
9090
const char *func_name() const { return "json_value"; }
9191
void fix_length_and_dec();
9292
String *val_str(String *);
@@ -99,8 +99,8 @@ class Item_func_json_value: public Item_str_func
9999
class Item_func_json_query: public Item_func_json_value
100100
{
101101
public:
102-
Item_func_json_query(THD *thd, Item *js, Item *path):
103-
Item_func_json_value(thd, js, path) {}
102+
Item_func_json_query(THD *thd, Item *js, Item *i_path):
103+
Item_func_json_value(thd, js, i_path) {}
104104
const char *func_name() const { return "json_query"; }
105105
bool check_and_get_value(json_engine_t *je, String *res, int *error);
106106
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
@@ -291,12 +291,14 @@ class Item_func_json_merge: public Item_func_json_array
291291
class Item_func_json_length: public Item_int_func
292292
{
293293
protected:
294+
json_path_with_flags path;
294295
String tmp_js;
295296
String tmp_path;
296297
public:
297298
Item_func_json_length(THD *thd, List<Item> &list):
298299
Item_int_func(thd, list) {}
299300
const char *func_name() const { return "json_length"; }
301+
void fix_length_and_dec();
300302
longlong val_int();
301303
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
302304
{ return get_item_copy<Item_func_json_length>(thd, mem_root, this); }

0 commit comments

Comments
 (0)