@@ -42,6 +42,9 @@ static inline JsonPathExecResult recursiveExecute(JsonPathExecContext *cxt,
4242 JsonPathItem * jsp , JsonbValue * jb ,
4343 JsonValueList * found );
4444
45+ static inline JsonPathExecResult recursiveExecuteBool (JsonPathExecContext * cxt ,
46+ JsonPathItem * jsp , JsonbValue * jb );
47+
4548static inline JsonPathExecResult recursiveExecuteUnwrap (JsonPathExecContext * cxt ,
4649 JsonPathItem * jsp , JsonbValue * jb , JsonValueList * found );
4750
@@ -1239,6 +1242,34 @@ tryToParseDatetime(const char *template, text *datetime,
12391242 return ok ;
12401243}
12411244
1245+ static inline JsonPathExecResult
1246+ appendBoolResult (JsonPathExecContext * cxt , JsonPathItem * jsp ,
1247+ JsonValueList * found , JsonPathExecResult res , bool needBool )
1248+ {
1249+ JsonPathItem next ;
1250+ JsonbValue jbv ;
1251+ bool hasNext = jspGetNext (jsp , & next );
1252+
1253+ if (needBool )
1254+ {
1255+ Assert (!hasNext );
1256+ return res ;
1257+ }
1258+
1259+ if (!found && !hasNext )
1260+ return jperOk ; /* found singleton boolean value */
1261+
1262+ if (jperIsError (res ))
1263+ jbv .type = jbvNull ;
1264+ else
1265+ {
1266+ jbv .type = jbvBool ;
1267+ jbv .val .boolean = res == jperOk ;
1268+ }
1269+
1270+ return recursiveExecuteNext (cxt , jsp , & next , & jbv , found , true);
1271+ }
1272+
12421273/*
12431274 * Main executor function: walks on jsonpath structure and tries to find
12441275 * correspoding parts of jsonb. Note, jsonb and jsonpath values should be
@@ -1251,7 +1282,7 @@ tryToParseDatetime(const char *template, text *datetime,
12511282 */
12521283static JsonPathExecResult
12531284recursiveExecuteNoUnwrap (JsonPathExecContext * cxt , JsonPathItem * jsp ,
1254- JsonbValue * jb , JsonValueList * found )
1285+ JsonbValue * jb , JsonValueList * found , bool needBool )
12551286{
12561287 JsonPathItem elem ;
12571288 JsonPathExecResult res = jperNotFound ;
@@ -1262,7 +1293,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
12621293 switch (jsp -> type ) {
12631294 case jpiAnd :
12641295 jspGetLeftArg (jsp , & elem );
1265- res = recursiveExecute (cxt , & elem , jb , NULL );
1296+ res = recursiveExecuteBool (cxt , & elem , jb );
12661297 if (res != jperNotFound )
12671298 {
12681299 JsonPathExecResult res2 ;
@@ -1273,27 +1304,29 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
12731304 */
12741305
12751306 jspGetRightArg (jsp , & elem );
1276- res2 = recursiveExecute (cxt , & elem , jb , NULL );
1307+ res2 = recursiveExecuteBool (cxt , & elem , jb );
12771308
12781309 res = (res2 == jperOk ) ? res : res2 ;
12791310 }
1311+ res = appendBoolResult (cxt , jsp , found , res , needBool );
12801312 break ;
12811313 case jpiOr :
12821314 jspGetLeftArg (jsp , & elem );
1283- res = recursiveExecute (cxt , & elem , jb , NULL );
1315+ res = recursiveExecuteBool (cxt , & elem , jb );
12841316 if (res != jperOk )
12851317 {
12861318 JsonPathExecResult res2 ;
12871319
12881320 jspGetRightArg (jsp , & elem );
1289- res2 = recursiveExecute (cxt , & elem , jb , NULL );
1321+ res2 = recursiveExecuteBool (cxt , & elem , jb );
12901322
12911323 res = (res2 == jperNotFound ) ? res : res2 ;
12921324 }
1325+ res = appendBoolResult (cxt , jsp , found , res , needBool );
12931326 break ;
12941327 case jpiNot :
12951328 jspGetArg (jsp , & elem );
1296- switch ((res = recursiveExecute (cxt , & elem , jb , NULL )))
1329+ switch ((res = recursiveExecuteBool (cxt , & elem , jb )))
12971330 {
12981331 case jperOk :
12991332 res = jperNotFound ;
@@ -1304,11 +1337,13 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
13041337 default :
13051338 break ;
13061339 }
1340+ res = appendBoolResult (cxt , jsp , found , res , needBool );
13071341 break ;
13081342 case jpiIsUnknown :
13091343 jspGetArg (jsp , & elem );
1310- res = recursiveExecute (cxt , & elem , jb , NULL );
1344+ res = recursiveExecuteBool (cxt , & elem , jb );
13111345 res = jperIsError (res ) ? jperOk : jperNotFound ;
1346+ res = appendBoolResult (cxt , jsp , found , res , needBool );
13121347 break ;
13131348 case jpiKey :
13141349 if (JsonbType (jb ) == jbvObject )
@@ -1575,6 +1610,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
15751610 case jpiLessOrEqual :
15761611 case jpiGreaterOrEqual :
15771612 res = executeExpr (cxt , jsp , jb );
1613+ res = appendBoolResult (cxt , jsp , found , res , needBool );
15781614 break ;
15791615 case jpiAdd :
15801616 case jpiSub :
@@ -1589,7 +1625,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
15891625 break ;
15901626 case jpiFilter :
15911627 jspGetArg (jsp , & elem );
1592- res = recursiveExecute (cxt , & elem , jb , NULL );
1628+ res = recursiveExecuteBool (cxt , & elem , jb );
15931629 if (res != jperOk )
15941630 res = jperNotFound ;
15951631 else
@@ -1638,6 +1674,8 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
16381674 if (!jperIsError (res ))
16391675 res = JsonValueListIsEmpty (& vals ) ? jperNotFound : jperOk ;
16401676 }
1677+
1678+ res = appendBoolResult (cxt , jsp , found , res , needBool );
16411679 break ;
16421680 case jpiNull :
16431681 case jpiBool :
@@ -1973,9 +2011,11 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
19732011 break ;
19742012 case jpiStartsWith :
19752013 res = executeStartsWithPredicate (cxt , jsp , jb );
2014+ res = appendBoolResult (cxt , jsp , found , res , needBool );
19762015 break ;
19772016 case jpiLikeRegex :
19782017 res = executeLikeRegexPredicate (cxt , jsp , jb );
2018+ res = appendBoolResult (cxt , jsp , found , res , needBool );
19792019 break ;
19802020 default :
19812021 elog (ERROR , "unrecognized jsonpath item type: %d" , jsp -> type );
@@ -1997,7 +2037,7 @@ recursiveExecuteUnwrapArray(JsonPathExecContext *cxt, JsonPathItem *jsp,
19972037
19982038 for (; elem < last ; elem ++ )
19992039 {
2000- res = recursiveExecuteNoUnwrap (cxt , jsp , elem , found );
2040+ res = recursiveExecuteNoUnwrap (cxt , jsp , elem , found , false );
20012041
20022042 if (jperIsError (res ))
20032043 break ;
@@ -2017,7 +2057,7 @@ recursiveExecuteUnwrapArray(JsonPathExecContext *cxt, JsonPathItem *jsp,
20172057 {
20182058 if (tok == WJB_ELEM )
20192059 {
2020- res = recursiveExecuteNoUnwrap (cxt , jsp , & v , found );
2060+ res = recursiveExecuteNoUnwrap (cxt , jsp , & v , found , false );
20212061 if (jperIsError (res ))
20222062 break ;
20232063 if (res == jperOk && !found )
@@ -2036,7 +2076,7 @@ recursiveExecuteUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
20362076 if (cxt -> lax && JsonbType (jb ) == jbvArray )
20372077 return recursiveExecuteUnwrapArray (cxt , jsp , jb , found );
20382078
2039- return recursiveExecuteNoUnwrap (cxt , jsp , jb , found );
2079+ return recursiveExecuteNoUnwrap (cxt , jsp , jb , found , false );
20402080}
20412081
20422082/*
@@ -2112,7 +2152,39 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
21122152 }
21132153 }
21142154
2115- return recursiveExecuteNoUnwrap (cxt , jsp , jb , found );
2155+ return recursiveExecuteNoUnwrap (cxt , jsp , jb , found , false);
2156+ }
2157+
2158+ static inline JsonPathExecResult
2159+ recursiveExecuteBool (JsonPathExecContext * cxt , JsonPathItem * jsp ,
2160+ JsonbValue * jb )
2161+ {
2162+ if (jspHasNext (jsp ))
2163+ elog (ERROR , "boolean jsonpath item can not have next item" );
2164+
2165+ switch (jsp -> type )
2166+ {
2167+ case jpiAnd :
2168+ case jpiOr :
2169+ case jpiNot :
2170+ case jpiIsUnknown :
2171+ case jpiEqual :
2172+ case jpiNotEqual :
2173+ case jpiGreater :
2174+ case jpiGreaterOrEqual :
2175+ case jpiLess :
2176+ case jpiLessOrEqual :
2177+ case jpiExists :
2178+ case jpiStartsWith :
2179+ case jpiLikeRegex :
2180+ break ;
2181+
2182+ default :
2183+ elog (ERROR , "invalid boolean jsonpath item type: %d" , jsp -> type );
2184+ break ;
2185+ }
2186+
2187+ return recursiveExecuteNoUnwrap (cxt , jsp , jb , NULL , true);
21162188}
21172189
21182190/*
0 commit comments