@@ -242,15 +242,21 @@ JsonPathHash(const void *key, Size keysize)
242
242
* updated.
243
243
*/
244
244
static inline JsonPathAnlStats *
245
- jsonAnalyzeAddPath (JsonAnalyzeContext * ctx , JsonPath path )
245
+ jsonAnalyzeAddPath (JsonAnalyzeContext * ctx , JsonPath parent ,
246
+ const char * entry , int len )
246
247
{
247
- JsonPathAnlStats * stats ;
248
- bool found ;
248
+ JsonPathEntry path ;
249
+ JsonPathAnlStats * stats ;
250
+ bool found ;
249
251
250
- path -> hash = JsonPathHash (path , 0 );
252
+ /* Init path entry */
253
+ path .parent = parent ;
254
+ path .entry = entry ;
255
+ path .len = len ;
256
+ path .hash = JsonPathHash (& path , 0 );
251
257
252
258
/* XXX See if we already saw this path earlier. */
253
- stats = hash_search_with_hash_value (ctx -> pathshash , path , path -> hash ,
259
+ stats = hash_search_with_hash_value (ctx -> pathshash , & path , path . hash ,
254
260
HASH_ENTER , & found );
255
261
256
262
/*
@@ -430,8 +436,6 @@ jsonAnalyzeJson(JsonAnalyzeContext *ctx, Jsonb *jb, void *param)
430
436
JsonbIteratorToken tok ;
431
437
JsonPathAnlStats * target = (JsonPathAnlStats * ) param ;
432
438
JsonPathAnlStats * stats = ctx -> root ;
433
- JsonPath path = & stats -> path ;
434
- JsonPathEntry entry ;
435
439
bool scalar = false;
436
440
437
441
if ((!target || target == stats ) &&
@@ -445,37 +449,49 @@ jsonAnalyzeJson(JsonAnalyzeContext *ctx, Jsonb *jb, void *param)
445
449
switch (tok )
446
450
{
447
451
case WJB_BEGIN_OBJECT :
448
- entry .entry = NULL ;
449
- entry .len = -1 ;
450
- entry .parent = path ;
451
- path = & entry ;
452
-
453
- break ;
454
-
455
- case WJB_END_OBJECT :
456
- stats = (JsonPathAnlStats * )(path = path -> parent );
452
+ /*
453
+ * Read next token to see if the object is empty or not.
454
+ * If not, make stats for the first key. Subsequent WJB_KEYs
455
+ * and WJB_END_OBJECT will expect that stats will be pointing
456
+ * to the key of current object.
457
+ */
458
+ tok = JsonbIteratorNext (& it , & jv , true);
459
+
460
+ if (tok == WJB_END_OBJECT )
461
+ /* Empty object, simply skip stats initialization. */
462
+ break ;
463
+
464
+ if (tok != WJB_KEY )
465
+ elog (ERROR , "unexpected jsonb iterator token: %d" , tok );
466
+
467
+ stats = jsonAnalyzeAddPath (ctx , & stats -> path ,
468
+ jv .val .string .val ,
469
+ jv .val .string .len );
457
470
break ;
458
471
459
472
case WJB_BEGIN_ARRAY :
473
+ /* Make stats for non-scalar array and use it for all elements */
460
474
if (!(scalar = jv .val .array .rawScalar ))
461
- {
462
- entry .entry = NULL ;
463
- entry .len = -1 ;
464
- entry .parent = path ;
465
- path = & (stats = jsonAnalyzeAddPath (ctx , & entry ))-> path ;
466
- }
475
+ stats = jsonAnalyzeAddPath (ctx , & stats -> path , NULL , -1 );
467
476
break ;
468
477
469
478
case WJB_END_ARRAY :
470
- if (!scalar )
471
- stats = (JsonPathAnlStats * )(path = path -> parent );
479
+ if (scalar )
480
+ break ;
481
+ /* FALLTHROUGH */
482
+ case WJB_END_OBJECT :
483
+ /* Reset to parent stats */
484
+ stats = (JsonPathAnlStats * ) stats -> path .parent ;
472
485
break ;
473
486
474
487
case WJB_KEY :
475
- entry .entry = jv .val .string .val ;
476
- entry .len = jv .val .string .len ;
477
- entry .parent = path -> parent ;
478
- path = & (stats = jsonAnalyzeAddPath (ctx , & entry ))-> path ;
488
+ /*
489
+ * Stats should point to the previous key of current object,
490
+ * use its parent path as a base path.
491
+ */
492
+ stats = jsonAnalyzeAddPath (ctx , stats -> path .parent ,
493
+ jv .val .string .val ,
494
+ jv .val .string .len );
479
495
break ;
480
496
481
497
case WJB_VALUE :
0 commit comments