@@ -2330,33 +2330,49 @@ bool Json_dom::seek(const Json_seekable_path &path,
2330
2330
}
2331
2331
2332
2332
2333
- bool Json_wrapper::seek_no_ellipsis (const Json_seekable_path &path,
2333
+ /* *
2334
+ Finds all of the JSON sub-documents which match the path expression.
2335
+ Puts the matches on an evolving vector of results. This is a
2336
+ fast-track method for paths which don't need duplicate elimination
2337
+ due to multiple ellipses or the combination of ellipses and
2338
+ auto-wrapping. Those paths can take advantage of the efficient
2339
+ positioning logic of json_binary::Value.
2340
+
2341
+ @param[in] wrapper the wrapper to search
2342
+ @param[in] path the (possibly wildcarded) address of the sub-documents
2343
+ @param[out] hits the result of the search
2344
+ @param[in] current_leg the 0-based index of the first path leg to look at.
2345
+ Should be the same as the depth at which the document in this
2346
+ wrapper is located. Usually called on the root document with the
2347
+ value 0, and then increased by one in recursive calls within the
2348
+ function itself.
2349
+ @param[in] last_leg the 0-based index of the leg just behind the last leg to
2350
+ look at. If equal to the length of the path, the entire path is
2351
+ used. If shorter than the length of the path, the search stops
2352
+ at one of the ancestors of the value pointed to by the full
2353
+ path.
2354
+ @param[in] auto_wrap true if a non-array should be wrapped as a
2355
+ single-element array before it is matched against an array path leg
2356
+ @param[in] only_need_one true if we can stop after finding one match
2357
+
2358
+ @returns false if there was no error, otherwise true on error
2359
+ */
2360
+ static bool seek_no_dup_elimination (const Json_wrapper &wrapper,
2361
+ const Json_seekable_path &path,
2334
2362
Json_wrapper_vector *hits,
2335
2363
size_t current_leg,
2336
2364
size_t last_leg,
2337
2365
bool auto_wrap,
2338
- bool only_need_one) const
2366
+ bool only_need_one)
2339
2367
{
2368
+ // DOMs are searched using Json_dom::seek() instead.
2369
+ DBUG_ASSERT (!wrapper.is_dom ());
2370
+
2340
2371
if (current_leg >= last_leg)
2341
- {
2342
- if (m_is_dom)
2343
- {
2344
- Json_wrapper clone (m_dom_value->clone ());
2345
- return clone.empty () || hits->push_back (std::move (clone));
2346
- }
2347
- return hits->push_back (*this );
2348
- }
2372
+ return hits->push_back (wrapper);
2349
2373
2350
2374
const Json_path_leg *path_leg= path.get_leg_at (current_leg);
2351
- const enum_json_type jtype= type ();
2352
-
2353
- // Handle auto-wrapping of non-arrays.
2354
- if (auto_wrap && jtype != enum_json_type::J_ARRAY && path_leg->is_autowrap ())
2355
- {
2356
- // recursion
2357
- return seek_no_ellipsis (path, hits, current_leg + 1 , last_leg,
2358
- auto_wrap, only_need_one);
2359
- }
2375
+ const enum_json_type jtype= wrapper.type ();
2360
2376
2361
2377
switch (path_leg->get_type ())
2362
2378
{
@@ -2366,12 +2382,13 @@ bool Json_wrapper::seek_no_ellipsis(const Json_seekable_path &path,
2366
2382
{
2367
2383
case enum_json_type::J_OBJECT:
2368
2384
{
2369
- Json_wrapper member= lookup (path_leg->get_member_name ());
2385
+ Json_wrapper member= wrapper. lookup (path_leg->get_member_name ());
2370
2386
2371
2387
if (member.type () != enum_json_type::J_ERROR)
2372
2388
{
2373
2389
// recursion
2374
- if (member.seek_no_ellipsis (path, hits, current_leg + 1 , last_leg,
2390
+ if (seek_no_dup_elimination (member, path, hits,
2391
+ current_leg + 1 , last_leg,
2375
2392
auto_wrap, only_need_one))
2376
2393
return true ; /* purecov: inspected */
2377
2394
}
@@ -2391,19 +2408,16 @@ bool Json_wrapper::seek_no_ellipsis(const Json_seekable_path &path,
2391
2408
{
2392
2409
case enum_json_type::J_OBJECT:
2393
2410
{
2394
- for (Json_wrapper_object_iterator iter= object_iterator ();
2411
+ for (Json_wrapper_object_iterator iter= wrapper. object_iterator ();
2395
2412
!iter.empty (); iter.next ())
2396
2413
{
2397
2414
if (is_seek_done (hits, only_need_one))
2398
2415
return false ;
2399
2416
2400
2417
// recursion
2401
- if (iter.elt ().second .seek_no_ellipsis (path,
2402
- hits,
2403
- current_leg + 1 ,
2404
- last_leg,
2405
- auto_wrap,
2406
- only_need_one))
2418
+ if (seek_no_dup_elimination (iter.elt ().second , path, hits,
2419
+ current_leg + 1 , last_leg,
2420
+ auto_wrap, only_need_one))
2407
2421
return true ; /* purecov: inspected */
2408
2422
}
2409
2423
return false ;
@@ -2419,95 +2433,155 @@ bool Json_wrapper::seek_no_ellipsis(const Json_seekable_path &path,
2419
2433
case jpl_array_cell:
2420
2434
if (jtype == enum_json_type::J_ARRAY)
2421
2435
{
2422
- Json_array_index idx= path_leg->first_array_index (length ());
2436
+ const Json_array_index idx= path_leg->first_array_index (wrapper. length ());
2423
2437
return idx.within_bounds () &&
2424
- (* this ) [idx.position ()]. seek_no_ellipsis (path, hits, current_leg + 1 ,
2425
- last_leg, auto_wrap ,
2426
- only_need_one);
2438
+ seek_no_dup_elimination (wrapper [idx.position ()], path, hits ,
2439
+ current_leg + 1 , last_leg ,
2440
+ auto_wrap, only_need_one);
2427
2441
}
2428
- return false ;
2442
+ return auto_wrap && path_leg->is_autowrap () &&
2443
+ seek_no_dup_elimination (wrapper, path, hits, current_leg + 1 , last_leg,
2444
+ auto_wrap, only_need_one);
2429
2445
2430
2446
case jpl_array_range:
2431
2447
case jpl_array_cell_wildcard:
2432
2448
if (jtype == enum_json_type::J_ARRAY)
2433
2449
{
2434
- auto range= path_leg->get_array_range (length ());
2450
+ const auto range= path_leg->get_array_range (wrapper. length ());
2435
2451
for (size_t idx= range.m_begin ; idx < range.m_end ; idx++)
2436
2452
{
2437
2453
if (is_seek_done (hits, only_need_one))
2438
2454
return false ;
2439
2455
2440
2456
// recursion
2441
- Json_wrapper cell= (*this )[idx];
2442
- if (cell.seek_no_ellipsis (path, hits, current_leg + 1 , last_leg,
2443
- auto_wrap, only_need_one))
2457
+ if (seek_no_dup_elimination (wrapper[idx], path, hits, current_leg + 1 ,
2458
+ last_leg, auto_wrap, only_need_one))
2444
2459
return true ; /* purecov: inspected */
2445
2460
}
2461
+ return false ;
2446
2462
}
2447
- return false ;
2463
+ return auto_wrap && path_leg->is_autowrap () &&
2464
+ seek_no_dup_elimination (wrapper, path, hits, current_leg + 1 , last_leg,
2465
+ auto_wrap, only_need_one);
2448
2466
2449
- default :
2450
- // should never be called on a path which contains an ellipsis
2451
- DBUG_ASSERT (false ); /* purecov: inspected */
2452
- return true ; /* purecov: inspected */
2467
+ case jpl_ellipsis:
2468
+ // recursion
2469
+ if (seek_no_dup_elimination (wrapper, path, hits, current_leg + 1 , last_leg,
2470
+ auto_wrap, only_need_one))
2471
+ return true ; /* purecov: inspected */
2472
+ if (jtype == enum_json_type::J_ARRAY)
2473
+ {
2474
+ const size_t length= wrapper.length ();
2475
+ for (size_t idx= 0 ; idx < length; ++idx)
2476
+ {
2477
+ if (is_seek_done (hits, only_need_one))
2478
+ return false ;
2479
+
2480
+ // recursion
2481
+ if (seek_no_dup_elimination (wrapper[idx], path, hits,
2482
+ current_leg, last_leg,
2483
+ auto_wrap, only_need_one))
2484
+ return true ; /* purecov: inspected */
2485
+ }
2486
+ }
2487
+ else if (jtype == enum_json_type::J_OBJECT)
2488
+ {
2489
+ for (Json_wrapper_object_iterator iter= wrapper.object_iterator ();
2490
+ !iter.empty (); iter.next ())
2491
+ {
2492
+ if (is_seek_done (hits, only_need_one))
2493
+ return false ;
2494
+
2495
+ // recursion
2496
+ if (seek_no_dup_elimination (iter.elt ().second , path, hits, current_leg,
2497
+ last_leg, auto_wrap, only_need_one))
2498
+ return true ; /* purecov: inspected */
2499
+ }
2500
+ }
2501
+ return false ;
2453
2502
} // end outer switch on leg type
2503
+
2504
+ DBUG_ASSERT (false ); /* purecov: deadcode */
2505
+ return true ; /* purecov: deadcode */
2454
2506
}
2455
2507
2456
2508
2457
- namespace
2458
- {
2509
+ /* *
2510
+ Should Json_wrapper::seek() delegate to Json_dom::seek() for this
2511
+ search?
2512
+
2513
+ @param wrapper the wrapper being searched
2514
+ @param path the path to search for
2515
+ @param auto_wrap true if array auto-wrapping is used
2459
2516
2460
- // / Does the path contain an ellipsis token?
2461
- bool contains_ellipsis (const Json_seekable_path &path)
2517
+ @retval true if Json_dom::seek() should be used
2518
+ @retval false if the search should use the Json_wrapper interface
2519
+ */
2520
+ static bool seek_as_dom (const Json_wrapper *wrapper,
2521
+ const Json_seekable_path &path,
2522
+ bool auto_wrap)
2462
2523
{
2463
- const size_t size= path.leg_count ();
2464
- for (size_t i= 0 ; i < size; i++)
2465
- if (path.get_leg_at (i)->get_type () == jpl_ellipsis)
2524
+ // If the wrapper contains a DOM, search the DOM directly.
2525
+ if (wrapper->is_dom ())
2526
+ return true ;
2527
+
2528
+ /*
2529
+ If the path requires duplicate elimination, Json_wrapper::seek()
2530
+ should convert the value to a DOM and seek using Json_dom::seek(),
2531
+ which handles duplicate elimination. Duplicate elimination is
2532
+ required if the path contains multiple ellipses, or if it contains
2533
+ an auto-wrapping array path leg after an ellipsis.
2534
+ */
2535
+ const size_t legs= path.leg_count ();
2536
+ bool has_ellipsis= false ;
2537
+ for (size_t i= 0 ; i < legs; ++i)
2538
+ {
2539
+ const Json_path_leg *leg= path.get_leg_at (i);
2540
+ if (has_ellipsis && (leg->get_type () == jpl_ellipsis ||
2541
+ (auto_wrap && leg->is_autowrap ())))
2466
2542
return true ;
2543
+ has_ellipsis|= (leg->get_type () == jpl_ellipsis);
2544
+ }
2545
+
2467
2546
return false ;
2468
2547
}
2469
2548
2470
- } // namespace
2471
-
2472
2549
2473
2550
bool Json_wrapper::seek (const Json_seekable_path &path,
2474
2551
Json_wrapper_vector *hits,
2475
2552
bool auto_wrap, bool only_need_one)
2476
2553
{
2477
- if (empty ())
2478
- {
2479
- /* purecov: begin inspected */
2480
- DBUG_ASSERT (false );
2481
- return false ;
2482
- /* purecov: end */
2483
- }
2484
-
2485
- // use fast-track code if the path doesn't have any ellipses
2486
- if (!contains_ellipsis (path))
2487
- {
2488
- return seek_no_ellipsis (path, hits, 0 , path.leg_count (),
2489
- auto_wrap, only_need_one);
2490
- }
2554
+ DBUG_ASSERT (!empty ());
2491
2555
2492
2556
/*
2493
- FIXME.
2557
+ If the wrapper wraps a DOM, let's call Json_dom::seek() directly,
2558
+ to avoid the overhead of going through the Json_wrapper interface.
2494
2559
2495
- Materialize the dom if the path contains ellipses. Duplicate
2496
- detection is difficult on binary values.
2497
- */
2498
- to_dom (current_thd);
2499
-
2500
- Json_dom_vector dhits (key_memory_JSON);
2501
- if (m_dom_value->seek (path, &dhits, auto_wrap, only_need_one))
2502
- return true ; /* purecov: inspected */
2503
- for (const Json_dom *dom : dhits)
2560
+ If ellipsis and auto-wrapping are used in a way that requires
2561
+ duplicate elimination, convert to DOM since duplicate detection is
2562
+ difficult on binary values.
2563
+ */
2564
+ if (seek_as_dom (this , path, auto_wrap))
2504
2565
{
2505
- Json_wrapper clone (dom->clone ());
2506
- if (clone.empty () || hits->push_back (std::move (clone)))
2566
+ Json_dom *dom= to_dom (current_thd);
2567
+ if (dom == nullptr )
2568
+ return true ; /* purecov: inspected */
2569
+
2570
+ Json_dom_vector dom_hits (key_memory_JSON);
2571
+ if (dom->seek (path, &dom_hits, auto_wrap, only_need_one))
2507
2572
return true ; /* purecov: inspected */
2573
+
2574
+ for (const Json_dom *hit : dom_hits)
2575
+ {
2576
+ if (hits->emplace_back (hit->clone ()) || hits->back ().empty ())
2577
+ return true ; /* purecov: inspected */
2578
+ }
2579
+
2580
+ return false ;
2508
2581
}
2509
2582
2510
- return false ;
2583
+ return seek_no_dup_elimination (*this , path, hits, 0 , path.leg_count (),
2584
+ auto_wrap, only_need_one);
2511
2585
}
2512
2586
2513
2587
@@ -3901,7 +3975,8 @@ bool Json_wrapper::attempt_binary_update(const Field_json *field,
3901
3975
3902
3976
// Find the parent of the value we want to modify.
3903
3977
Json_wrapper_vector hits (key_memory_JSON);
3904
- if (seek_no_ellipsis (path, &hits, 0 , path.leg_count () - 1 , false , true ))
3978
+ if (seek_no_dup_elimination (*this , path, &hits, 0 , path.leg_count () - 1 ,
3979
+ false , true ))
3905
3980
return true ; /* purecov: inspected */
3906
3981
3907
3982
if (hits.empty ())
@@ -4046,7 +4121,8 @@ bool Json_wrapper::binary_remove(const Field_json *field,
4046
4121
*found_path= false ;
4047
4122
4048
4123
Json_wrapper_vector hits (key_memory_JSON);
4049
- if (seek_no_ellipsis (path, &hits, 0 , path.leg_count () - 1 , false , true ))
4124
+ if (seek_no_dup_elimination (*this , path, &hits, 0 , path.leg_count () - 1 ,
4125
+ false , true ))
4050
4126
return true ; /* purecov: inspected */
4051
4127
4052
4128
DBUG_ASSERT (hits.size () <= 1 );
0 commit comments