@@ -440,14 +440,22 @@ jsonStatsGetPath(JsonStats jsdata, Datum *path, int pathlen, float4 *nullfrac)
440
440
}
441
441
442
442
/*
443
- * jsonPathStatsGetNextKeyStats
444
- * Enumerate all collected object keys .
443
+ * jsonPathStatsGetNextSubpathStats
444
+ * Iterate all collected subpaths of a given path .
445
445
*
446
- * This can be useful for estimation of selectivity of jsonpath '.*' operator.
446
+ * This function can be useful for estimation of selectivity of jsonpath
447
+ * '.*' and '.**' operators.
448
+ *
449
+ * The next found subpath is written into *pkeystats, which should be set to
450
+ * NULL before the first call.
451
+ *
452
+ * If keysOnly is true, emit only top-level object-key subpaths.
453
+ *
454
+ * Returns false on the end of iteration and true otherwise.
447
455
*/
448
456
bool
449
- jsonPathStatsGetNextKeyStats (JsonPathStats stats , JsonPathStats * pkeystats ,
450
- bool keysOnly )
457
+ jsonPathStatsGetNextSubpathStats (JsonPathStats stats , JsonPathStats * pkeystats ,
458
+ bool keysOnly )
451
459
{
452
460
JsonPathStats keystats = * pkeystats ;
453
461
int index =
@@ -457,53 +465,69 @@ jsonPathStatsGetNextKeyStats(JsonPathStats stats, JsonPathStats *pkeystats,
457
465
{
458
466
JsonbValue pathkey ;
459
467
JsonbValue * jbvpath ;
460
- Jsonb * jb = DatumGetJsonbP (stats -> data -> values [index ]);
468
+ Datum * pdatum = & stats -> data -> values [index ];
469
+ Jsonb * jb = DatumGetJsonbP (* pdatum );
470
+ const char * path ;
471
+ int pathlen ;
461
472
462
473
JsonValueInitStringWithLen (& pathkey , "path" , 4 );
463
474
jbvpath = findJsonbValueFromContainer (& jb -> root , JB_FOBJECT , & pathkey );
464
475
465
- if (jbvpath -> type != jbvString ||
466
- jbvpath -> val .string .len <= stats -> pathlen ||
467
- memcmp (jbvpath -> val .string .val , stats -> path , stats -> pathlen ))
476
+ if (jbvpath -> type != jbvString )
477
+ break ; /* invalid path stats */
478
+
479
+ path = jbvpath -> val .string .val ;
480
+ pathlen = jbvpath -> val .string .len ;
481
+
482
+ /* Break, if subpath does not start from a desired prefix */
483
+ if (pathlen <= stats -> pathlen ||
484
+ memcmp (path , stats -> path , stats -> pathlen ))
468
485
break ;
469
486
470
487
if (keysOnly )
471
488
{
472
- const char * c = & jbvpath -> val . string . val [stats -> pathlen ];
489
+ const char * c = & path [stats -> pathlen ];
473
490
474
491
if (* c == '[' )
475
492
{
476
- c ++ ;
477
- Assert (* c == '*' );
478
- c ++ ;
479
- Assert (* c == ']' );
493
+ Assert (c [1 ] == '*' && c [2 ] == ']' );
480
494
481
- if (keysOnly || jbvpath -> val .string .len > stats -> pathlen + 2 )
482
- continue ;
495
+ #if 0 /* TODO add separate flag for requesting top-level array accessors */
496
+ /* skip if it is not last key in the path */
497
+ if (pathlen > stats -> pathlen + 3 )
498
+ #endif
499
+ continue ; /* skip array accessors */
483
500
}
484
- else
501
+ else if ( * c == '.' )
485
502
{
486
- Assert (* c == '.' );
487
- c ++ ;
488
- Assert (* c == '"' );
503
+ /* find end of '."key"' */
504
+ const char * pathend = path + pathlen ;
505
+
506
+ if (++ c >= pathend || * c != '"' )
507
+ break ; /* invalid path */
489
508
490
- while (* ++ c != '"' )
491
- if (* c == '\\' )
509
+ while (++ c <= pathend && * c != '"' )
510
+ if (* c == '\\' ) /* handle escaped chars */
492
511
c ++ ;
493
512
494
- if (c - jbvpath -> val .string .val < jbvpath -> val .string .len - 1 )
513
+ if (c > pathend )
514
+ break ; /* invalid path */
515
+
516
+ /* skip if it is not last key in the path */
517
+ if (c < pathend )
495
518
continue ;
496
519
}
520
+ else
521
+ continue ; /* invalid path */
497
522
}
498
523
499
524
if (!keystats )
500
525
keystats = palloc (sizeof (* keystats ));
501
526
502
- keystats -> datum = & stats -> data -> values [ index ] ;
527
+ keystats -> datum = pdatum ;
503
528
keystats -> data = stats -> data ;
504
- keystats -> pathlen = jbvpath -> val .string .len ;
505
- keystats -> path = memcpy (palloc (keystats -> pathlen ),
506
- jbvpath -> val .string .val , keystats -> pathlen );
529
+ keystats -> pathlen = pathlen ;
530
+ keystats -> path = memcpy (palloc (pathlen ), path , pathlen );
507
531
keystats -> type = JsonPathStatsValues ;
508
532
509
533
* pkeystats = keystats ;
0 commit comments