Skip to content

Commit f08d729

Browse files
committed
Bug#25418534: JSON_EXTRACT USING WILDCARDS TAKES FOREVER
Patch #7: Accessing the JSON path legs requires going through virtual accessor functions, due to the different storage of path legs in Json_path and Json_path_clone. The former stores the path legs in an array of Json_path_leg objects, whereas the latter stores them in an array of pointers. This patch makes both of the classes store the path legs in an array of pointers. Json_path, which is the owner of the path leg instances, additionally has a MEM_ROOT in which the Json_path_leg objects live. Now that the path legs are stored the same way in the two classes, it is possible to iterate over them without using virtual function calls. Iterators are provided through begin() and end() to facilitate iteration using standard mechanisms. The seek functions find_child_doms() and seek_no_dup_elimination() are changed to take begin and end iterators for iterating over the paths. Microbenchmarks (64-bit, Intel Core i7-4770 3.4 GHz, GCC 6.3): BM_JsonDomSearchEllipsis 17634 [+21.0%] BM_JsonDomSearchEllipsis_OnlyOne 123 [ +5.7%] BM_JsonDomSearchKey 116 [ 0.0%] BM_JsonBinarySearchEllipsis 64065 [+10.8%] BM_JsonBinarySearchEllipsis_OnlyOne 89 [+14.6%] BM_JsonBinarySearchKey 77 [ +7.8%] Change-Id: I864d55a2f07d5f4bda330fee03cdcf0bb0d4f3e6
1 parent 5ed6fc6 commit f08d729

File tree

7 files changed

+185
-190
lines changed

7 files changed

+185
-190
lines changed

sql/item_json_func.cc

+6-9
Original file line numberDiff line numberDiff line change
@@ -2038,8 +2038,8 @@ bool wrapped_top_level_item(Json_path *path MY_ATTRIBUTE((unused)),
20382038
return false;
20392039

20402040
#ifndef DBUG_OFF
2041-
for (size_t i= 0; i < path->leg_count(); i++)
2042-
DBUG_ASSERT(path->get_leg_at(i)->is_autowrap());
2041+
for (const Json_path_leg *leg : *path)
2042+
DBUG_ASSERT(leg->is_autowrap());
20432043
#endif
20442044

20452045
return true;
@@ -2365,9 +2365,8 @@ bool Item_func_json_array_insert::val_json(Json_wrapper *wr)
23652365
m_path.set(current_path);
23662366

23672367
// the path must end in a cell identifier
2368-
size_t leg_count= m_path.leg_count();
2369-
if ((leg_count == 0) ||
2370-
(m_path.get_leg_at(leg_count - 1)->get_type() != jpl_array_cell))
2368+
if (m_path.leg_count() == 0 ||
2369+
m_path.last_leg()->get_type() != jpl_array_cell)
23712370
{
23722371
my_error(ER_INVALID_JSON_PATH_ARRAY_CELL, MYF(0));
23732372
return error_json();
@@ -2466,10 +2465,8 @@ static bool clone_without_autowrapping(Json_path *source_path,
24662465
Json_wrapper_vector hits(key_memory_JSON);
24672466

24682467
target_path->clear();
2469-
size_t leg_count= source_path->leg_count();
2470-
for (size_t leg_idx= 0; leg_idx < leg_count; leg_idx++)
2468+
for (const Json_path_leg *path_leg : *source_path)
24712469
{
2472-
const Json_path_leg *path_leg= source_path->get_leg_at(leg_idx);
24732470
if (path_leg->is_autowrap())
24742471
{
24752472
/*
@@ -3429,7 +3426,7 @@ bool Item_func_json_remove::val_json(Json_wrapper *wr)
34293426
}
34303427
else
34313428
{
3432-
const Json_path_leg *last_leg= path.get_leg_at(path.leg_count() - 1);
3429+
const Json_path_leg *last_leg= path.last_leg();
34333430
path.pop();
34343431
hits.clear();
34353432
if (dom->seek(path, &hits, false, true))

sql/json_diff.cc

+12-11
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,17 @@ Json_wrapper Json_diff::value() const
3737
member names. Auto-wrapping is not performed.
3838
3939
@param dom the root of the DOM
40-
@param path the path to seek for
41-
@param path_legs the number of path legs to use
40+
@param first_leg the first path leg
41+
@param last_leg the last path leg (exclusive)
4242
@return the JSON DOM at the given path, or `nullptr` if the path is not found
4343
*/
44-
static Json_dom *seek_exact_path(Json_dom *dom, const Json_seekable_path &path,
45-
size_t path_legs)
44+
static Json_dom *seek_exact_path(Json_dom *dom,
45+
const Json_path_iterator &first_leg,
46+
const Json_path_iterator &last_leg)
4647
{
47-
for (size_t i= 0; i < path_legs; ++i)
48+
for (auto it= first_leg; it != last_leg; ++it)
4849
{
49-
const auto leg= path.get_leg_at(i);
50+
const Json_path_leg *leg= *it;
5051
const auto leg_type= leg->get_type();
5152
DBUG_ASSERT(leg_type == jpl_member || leg_type == jpl_array_cell);
5253
switch (dom->json_type())
@@ -164,7 +165,7 @@ enum_json_diff_status apply_json_diffs(Field_json *field,
164165
case enum_json_diff_operation::REPLACE:
165166
{
166167
DBUG_ASSERT(path.leg_count() > 0);
167-
Json_dom *old= seek_exact_path(dom, path, path.leg_count());
168+
Json_dom *old= seek_exact_path(dom, path.begin(), path.end());
168169
if (old == nullptr)
169170
return enum_json_diff_status::REJECTED;
170171
DBUG_ASSERT(old->parent() != nullptr);
@@ -174,10 +175,10 @@ enum_json_diff_status apply_json_diffs(Field_json *field,
174175
case enum_json_diff_operation::INSERT:
175176
{
176177
DBUG_ASSERT(path.leg_count() > 0);
177-
Json_dom *parent= seek_exact_path(dom, path, path.leg_count() - 1);
178+
Json_dom *parent= seek_exact_path(dom, path.begin(), path.end() - 1);
178179
if (parent == nullptr)
179180
return enum_json_diff_status::REJECTED;
180-
const Json_path_leg *last_leg= path.get_leg_at(path.leg_count() - 1);
181+
const Json_path_leg *last_leg= path.last_leg();
181182
if (parent->json_type() == enum_json_type::J_OBJECT &&
182183
last_leg->get_type() == jpl_member)
183184
{
@@ -202,10 +203,10 @@ enum_json_diff_status apply_json_diffs(Field_json *field,
202203
case enum_json_diff_operation::REMOVE:
203204
{
204205
DBUG_ASSERT(path.leg_count() > 0);
205-
Json_dom *parent= seek_exact_path(dom, path, path.leg_count() - 1);
206+
Json_dom *parent= seek_exact_path(dom, path.begin(), path.end() - 1);
206207
if (parent == nullptr)
207208
return enum_json_diff_status::REJECTED;
208-
const Json_path_leg *last_leg= path.get_leg_at(path.leg_count() - 1);
209+
const Json_path_leg *last_leg= path.last_leg();
209210
if (parent->json_type() == enum_json_type::J_OBJECT)
210211
{
211212
auto object= down_cast<Json_object*>(parent);

sql/json_diff.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ class Json_diff final
9292
std::unique_ptr<Json_dom> value)
9393
: m_path(), m_operation(operation), m_value(std::move(value))
9494
{
95-
for (size_t i= 0; i < path.leg_count(); ++i)
96-
m_path.append(*path.get_leg_at(i));
95+
for (const Json_path_leg *leg : path)
96+
m_path.append(*leg);
9797
}
9898

9999
/// Get the path that is changed by this diff.

0 commit comments

Comments
 (0)