@@ -305,19 +305,24 @@ makePathItem(PathItemType type, PathItem *parent)
305305typedef struct ExtractedJsonPath
306306{
307307 PathItem * path ;
308+ List * filters ;
308309 bool indirect ;
309310 bool type ;
310311} ExtractedJsonPath ;
311312
312313static bool
313314recursiveExtractJsonPath (JsonPathItem * jpi ,
314315 bool lax , bool not , bool indirect , bool unwrap ,
315- PathItem * parent , List * * paths );
316+ PathItem * parent , List * * paths , List * filters );
317+
318+ static ExtractedNode *
319+ recursiveExtractJsonPathExpr (JsonPathItem * jpi , bool lax , bool not ,
320+ PathItem * path );
316321
317322static bool
318323recursiveExtractJsonPath2 (JsonPathItem * jpi ,
319324 bool lax , bool not , bool indirect , bool unwrap ,
320- PathItem * parent , List * * paths )
325+ PathItem * parent , List * * paths , List * filters )
321326{
322327 JsonPathItem next ;
323328 PathItem * path ;
@@ -373,6 +378,24 @@ recursiveExtractJsonPath2(JsonPathItem *jpi,
373378 indirect = true;
374379 break ;
375380
381+ case jpiFilter :
382+ {
383+ JsonPathItem arg ;
384+ ExtractedNode * expr ;
385+
386+ if (not )
387+ return false;
388+
389+ jspGetArg (jpi , & arg );
390+ expr = recursiveExtractJsonPathExpr (& arg , lax , not , parent );
391+
392+ if (expr )
393+ filters = lappend (list_copy (filters ), expr );
394+
395+ path = parent ;
396+ break ;
397+ }
398+
376399 default :
377400 /* elog(ERROR,"Wrong state: %d", jpi->type); */
378401 return false;
@@ -384,6 +407,7 @@ recursiveExtractJsonPath2(JsonPathItem *jpi,
384407 ExtractedJsonPath * ejp = palloc (sizeof (* ejp ));
385408
386409 ejp -> path = path ;
410+ ejp -> filters = filters ;
387411 ejp -> indirect = indirect ;
388412 ejp -> type = jspHasNext (jpi ) && next .type == jpiType ;
389413
@@ -394,6 +418,7 @@ recursiveExtractJsonPath2(JsonPathItem *jpi,
394418 {
395419 ejp = palloc (sizeof (* ejp ));
396420 ejp -> path = makePathItem (iAnyArray , path );
421+ ejp -> filters = filters ;
397422 ejp -> indirect = indirect ;
398423 ejp -> type = false;
399424
@@ -404,13 +429,13 @@ recursiveExtractJsonPath2(JsonPathItem *jpi,
404429 }
405430
406431 return recursiveExtractJsonPath (& next , lax , not , indirect , unwrap , path ,
407- paths );
432+ paths , filters );
408433}
409434
410435static bool
411436recursiveExtractJsonPath (JsonPathItem * jpi ,
412437 bool lax , bool not , bool indirect , bool unwrap ,
413- PathItem * parent , List * * paths )
438+ PathItem * parent , List * * paths , List * filters )
414439{
415440 switch (jpi -> type )
416441 {
@@ -430,13 +455,14 @@ recursiveExtractJsonPath(JsonPathItem *jpi,
430455 ExtractedJsonPath * ejp = palloc (sizeof (* ejp ));
431456
432457 ejp -> path = parent ;
458+ ejp -> filters = filters ;
433459 ejp -> indirect = indirect ;
434460 ejp -> type = false;
435461
436462 * paths = lappend (* paths , ejp );
437463 }
438464 else if (!recursiveExtractJsonPath2 (& next , lax , not , indirect , unwrap ,
439- parent , paths ))
465+ parent , paths , filters ))
440466 return false;
441467 }
442468
@@ -448,7 +474,7 @@ recursiveExtractJsonPath(JsonPathItem *jpi,
448474 if (lax &&
449475 !recursiveExtractJsonPath2 (jpi , lax , not , true, unwrap ,
450476 makePathItem (iAnyArray , parent ),
451- paths ))
477+ paths , filters ))
452478 return false;
453479 break ;
454480
@@ -457,7 +483,7 @@ recursiveExtractJsonPath(JsonPathItem *jpi,
457483 }
458484
459485 return recursiveExtractJsonPath2 (jpi , lax , not , indirect , unwrap , parent ,
460- paths );
486+ paths , filters );
461487}
462488
463489static inline JsQueryItem *
@@ -496,7 +522,77 @@ jspConstToJsQueryItem(JsonPathItem *jpi)
496522}
497523
498524static ExtractedNode *
499- recursiveExtractJsonPathExpr (JsonPathItem * jpi , bool lax , bool not )
525+ appendJsonPathExprNode (ExtractedNode * result , ExtractedNode * node , PathItem * path ,
526+ List * filters )
527+ {
528+ ExtractedNode * orNode ;
529+
530+ if (filters )
531+ {
532+ ListCell * flc ;
533+
534+ foreach (flc , filters )
535+ {
536+ ExtractedNode * filter = lfirst (flc );
537+ ExtractedNode * andNode = palloc (sizeof (ExtractedNode ));
538+
539+ andNode -> type = eAnd ;
540+ andNode -> hint = jsqIndexDefault ;
541+ andNode -> path = path ;
542+ andNode -> indirect = false;
543+ andNode -> args .items = palloc (2 * sizeof (ExtractedNode * ));
544+ andNode -> args .items [0 ] = node ;
545+ andNode -> args .items [1 ] = filter ;
546+ andNode -> args .count = 2 ;
547+
548+ node = andNode ;
549+ }
550+ }
551+
552+ if (!result )
553+ return node ;
554+
555+ orNode = palloc (sizeof (ExtractedNode ));
556+
557+ orNode -> type = eOr ;
558+ orNode -> hint = jsqIndexDefault ;
559+ orNode -> path = path ;
560+ orNode -> indirect = false;
561+ orNode -> args .items = palloc (2 * sizeof (ExtractedNode * ));
562+ orNode -> args .items [0 ] = result ;
563+ orNode -> args .items [1 ] = node ;
564+ orNode -> args .count = 2 ;
565+
566+ return orNode ;
567+ }
568+
569+ static ExtractedNode *
570+ extractJsonPathExists (JsonPathItem * jpi , bool lax , PathItem * path )
571+ {
572+ List * paths = NIL ;
573+ ListCell * lc ;
574+ ExtractedNode * result ;
575+
576+ if (!recursiveExtractJsonPath (jpi , lax , false, false /* FIXME */ , false,
577+ path , & paths , NIL ))
578+ return NULL ;
579+
580+ result = NULL ;
581+
582+ foreach (lc , paths )
583+ {
584+ ExtractedJsonPath * ejp = lfirst (lc );
585+ ExtractedNode * node = makeAnyNode (false, ejp -> indirect , ejp -> path );
586+
587+ result = appendJsonPathExprNode (result , node , path , ejp -> filters );
588+ }
589+
590+ return result ;
591+ }
592+
593+ static ExtractedNode *
594+ recursiveExtractJsonPathExpr (JsonPathItem * jpi , bool lax , bool not ,
595+ PathItem * path )
500596{
501597 ExtractedNode * result ;
502598 JsonPathItem elem ;
@@ -516,10 +612,10 @@ recursiveExtractJsonPathExpr(JsonPathItem *jpi, bool lax, bool not)
516612 type = ((jpi -> type == jpiAnd ) == not ) ? eOr : eAnd ;
517613
518614 jspGetLeftArg (jpi , & elem );
519- leftNode = recursiveExtractJsonPathExpr (& elem , lax , not );
615+ leftNode = recursiveExtractJsonPathExpr (& elem , lax , not , path );
520616
521617 jspGetRightArg (jpi , & elem );
522- rightNode = recursiveExtractJsonPathExpr (& elem , lax , not );
618+ rightNode = recursiveExtractJsonPathExpr (& elem , lax , not , path );
523619
524620 if (!leftNode || !rightNode )
525621 {
@@ -540,7 +636,7 @@ recursiveExtractJsonPathExpr(JsonPathItem *jpi, bool lax, bool not)
540636
541637 result = palloc (sizeof (ExtractedNode ));
542638 result -> type = type ;
543- result -> path = NULL ;
639+ result -> path = path ;
544640 result -> indirect = indirect ;
545641 result -> args .items = palloc (2 * sizeof (ExtractedNode * ));
546642 result -> args .items [0 ] = leftNode ;
@@ -552,7 +648,7 @@ recursiveExtractJsonPathExpr(JsonPathItem *jpi, bool lax, bool not)
552648
553649 case jpiNot :
554650 jspGetArg (jpi , & elem );
555- return recursiveExtractJsonPathExpr (& elem , lax , !not );
651+ return recursiveExtractJsonPathExpr (& elem , lax , !not , path );
556652
557653 case jpiEqual :
558654 case jpiLess :
@@ -585,8 +681,8 @@ recursiveExtractJsonPathExpr(JsonPathItem *jpi, bool lax, bool not)
585681 {
586682 bound = jspConstToJsQueryItem (& rarg );
587683
588- if (!recursiveExtractJsonPath (& larg , lax , not , false/* FIXME */ , true, NULL ,
589- & paths ))
684+ if (!recursiveExtractJsonPath (& larg , lax , not , false/* FIXME */ , true, path ,
685+ & paths , NIL ))
590686 return NULL ;
591687 }
592688 else if (larg .type == jpiNumeric ||
@@ -597,8 +693,8 @@ recursiveExtractJsonPathExpr(JsonPathItem *jpi, bool lax, bool not)
597693 {
598694 bound = jspConstToJsQueryItem (& larg );
599695
600- if (!recursiveExtractJsonPath (& rarg , lax , not , false/* FIXME */ , true, NULL ,
601- & paths ))
696+ if (!recursiveExtractJsonPath (& rarg , lax , not , false/* FIXME */ , true, path ,
697+ & paths , NIL ))
602698 return NULL ;
603699
604700 greater = !greater ;
@@ -674,27 +770,23 @@ recursiveExtractJsonPathExpr(JsonPathItem *jpi, bool lax, bool not)
674770 }
675771 }
676772
677- if (result )
678- {
679- ExtractedNode * orNode = palloc (sizeof (ExtractedNode ));
680-
681- orNode -> type = eOr ;
682- orNode -> path = NULL ;
683- orNode -> indirect = false;
684- orNode -> args .items = palloc (2 * sizeof (ExtractedNode * ));
685- orNode -> args .items [0 ] = result ;
686- orNode -> args .items [1 ] = node ;
687- orNode -> args .count = 2 ;
688-
689- result = orNode ;
690- }
691- else
692- result = node ;
773+ result = appendJsonPathExprNode (result , node , path ,
774+ ejp -> filters );
693775 }
694776
695777 return result ;
696778 }
697779
780+ case jpiExists :
781+ {
782+ if (not )
783+ return NULL ;
784+
785+ jspGetArg (jpi , & elem );
786+
787+ return extractJsonPathExists (& elem , lax , path );
788+ }
789+
698790 default :
699791 /* elog(ERROR,"Wrong state: %d", jpi->type); */
700792 return NULL ;
@@ -1262,7 +1354,7 @@ extractJsonPath(JsonPath *jp, MakeEntryHandler makeHandler,
12621354 bool lax = (jp -> header & JSONPATH_LAX ) != 0 ;
12631355
12641356 jspInit (& jsp , jp );
1265- root = recursiveExtractJsonPathExpr (& jsp , lax , false);
1357+ root = recursiveExtractJsonPathExpr (& jsp , lax , false, NULL );
12661358 if (root )
12671359 {
12681360 flatternTree (root );
0 commit comments