@@ -43,6 +43,9 @@ static inline JsonPathExecResult recursiveExecute(JsonPathExecContext *cxt,
4343 JsonPathItem * jsp , JsonbValue * jb ,
4444 JsonValueList * found );
4545
46+ static inline JsonPathExecResult recursiveExecuteBool (JsonPathExecContext * cxt ,
47+ JsonPathItem * jsp , JsonbValue * jb );
48+
4649static inline JsonPathExecResult recursiveExecuteUnwrap (JsonPathExecContext * cxt ,
4750 JsonPathItem * jsp , JsonbValue * jb , JsonValueList * found );
4851
@@ -1211,6 +1214,34 @@ tryToParseDatetime(const char *template, text *datetime,
12111214 return ok ;
12121215}
12131216
1217+ static inline JsonPathExecResult
1218+ appendBoolResult (JsonPathExecContext * cxt , JsonPathItem * jsp ,
1219+ JsonValueList * found , JsonPathExecResult res , bool needBool )
1220+ {
1221+ JsonPathItem next ;
1222+ JsonbValue jbv ;
1223+ bool hasNext = jspGetNext (jsp , & next );
1224+
1225+ if (needBool )
1226+ {
1227+ Assert (!hasNext );
1228+ return res ;
1229+ }
1230+
1231+ if (!found && !hasNext )
1232+ return jperOk ; /* found singleton boolean value */
1233+
1234+ if (jperIsError (res ))
1235+ jbv .type = jbvNull ;
1236+ else
1237+ {
1238+ jbv .type = jbvBool ;
1239+ jbv .val .boolean = res == jperOk ;
1240+ }
1241+
1242+ return recursiveExecuteNext (cxt , jsp , & next , & jbv , found , true);
1243+ }
1244+
12141245/*
12151246 * Main executor function: walks on jsonpath structure and tries to find
12161247 * correspoding parts of jsonb. Note, jsonb and jsonpath values should be
@@ -1223,7 +1254,7 @@ tryToParseDatetime(const char *template, text *datetime,
12231254 */
12241255static JsonPathExecResult
12251256recursiveExecuteNoUnwrap (JsonPathExecContext * cxt , JsonPathItem * jsp ,
1226- JsonbValue * jb , JsonValueList * found )
1257+ JsonbValue * jb , JsonValueList * found , bool needBool )
12271258{
12281259 JsonPathItem elem ;
12291260 JsonPathExecResult res = jperNotFound ;
@@ -1235,7 +1266,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
12351266 switch (jsp -> type ) {
12361267 case jpiAnd :
12371268 jspGetLeftArg (jsp , & elem );
1238- res = recursiveExecute (cxt , & elem , jb , NULL );
1269+ res = recursiveExecuteBool (cxt , & elem , jb );
12391270 if (res != jperNotFound )
12401271 {
12411272 JsonPathExecResult res2 ;
@@ -1246,27 +1277,29 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
12461277 */
12471278
12481279 jspGetRightArg (jsp , & elem );
1249- res2 = recursiveExecute (cxt , & elem , jb , NULL );
1280+ res2 = recursiveExecuteBool (cxt , & elem , jb );
12501281
12511282 res = (res2 == jperOk ) ? res : res2 ;
12521283 }
1284+ res = appendBoolResult (cxt , jsp , found , res , needBool );
12531285 break ;
12541286 case jpiOr :
12551287 jspGetLeftArg (jsp , & elem );
1256- res = recursiveExecute (cxt , & elem , jb , NULL );
1288+ res = recursiveExecuteBool (cxt , & elem , jb );
12571289 if (res != jperOk )
12581290 {
12591291 JsonPathExecResult res2 ;
12601292
12611293 jspGetRightArg (jsp , & elem );
1262- res2 = recursiveExecute (cxt , & elem , jb , NULL );
1294+ res2 = recursiveExecuteBool (cxt , & elem , jb );
12631295
12641296 res = (res2 == jperNotFound ) ? res : res2 ;
12651297 }
1298+ res = appendBoolResult (cxt , jsp , found , res , needBool );
12661299 break ;
12671300 case jpiNot :
12681301 jspGetArg (jsp , & elem );
1269- switch ((res = recursiveExecute (cxt , & elem , jb , NULL )))
1302+ switch ((res = recursiveExecuteBool (cxt , & elem , jb )))
12701303 {
12711304 case jperOk :
12721305 res = jperNotFound ;
@@ -1277,11 +1310,13 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
12771310 default :
12781311 break ;
12791312 }
1313+ res = appendBoolResult (cxt , jsp , found , res , needBool );
12801314 break ;
12811315 case jpiIsUnknown :
12821316 jspGetArg (jsp , & elem );
1283- res = recursiveExecute (cxt , & elem , jb , NULL );
1317+ res = recursiveExecuteBool (cxt , & elem , jb );
12841318 res = jperIsError (res ) ? jperOk : jperNotFound ;
1319+ res = appendBoolResult (cxt , jsp , found , res , needBool );
12851320 break ;
12861321 case jpiKey :
12871322 if (JsonbType (jb ) == jbvObject )
@@ -1548,6 +1583,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
15481583 case jpiLessOrEqual :
15491584 case jpiGreaterOrEqual :
15501585 res = executeExpr (cxt , jsp , jb );
1586+ res = appendBoolResult (cxt , jsp , found , res , needBool );
15511587 break ;
15521588 case jpiAdd :
15531589 case jpiSub :
@@ -1562,7 +1598,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
15621598 break ;
15631599 case jpiFilter :
15641600 jspGetArg (jsp , & elem );
1565- res = recursiveExecute (cxt , & elem , jb , NULL );
1601+ res = recursiveExecuteBool (cxt , & elem , jb );
15661602 if (res != jperOk )
15671603 res = jperNotFound ;
15681604 else
@@ -1611,6 +1647,8 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
16111647 if (!jperIsError (res ))
16121648 res = JsonValueListIsEmpty (& vals ) ? jperNotFound : jperOk ;
16131649 }
1650+
1651+ res = appendBoolResult (cxt , jsp , found , res , needBool );
16141652 break ;
16151653 case jpiNull :
16161654 case jpiBool :
@@ -1946,9 +1984,11 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
19461984 break ;
19471985 case jpiStartsWith :
19481986 res = executeStartsWithPredicate (cxt , jsp , jb );
1987+ res = appendBoolResult (cxt , jsp , found , res , needBool );
19491988 break ;
19501989 case jpiLikeRegex :
19511990 res = executeLikeRegexPredicate (cxt , jsp , jb );
1991+ res = appendBoolResult (cxt , jsp , found , res , needBool );
19521992 break ;
19531993 default :
19541994 elog (ERROR , "unrecognized jsonpath item type: %d" , jsp -> type );
@@ -1970,7 +2010,7 @@ recursiveExecuteUnwrapArray(JsonPathExecContext *cxt, JsonPathItem *jsp,
19702010
19712011 for (; elem < last ; elem ++ )
19722012 {
1973- res = recursiveExecuteNoUnwrap (cxt , jsp , elem , found );
2013+ res = recursiveExecuteNoUnwrap (cxt , jsp , elem , found , false );
19742014
19752015 if (jperIsError (res ))
19762016 break ;
@@ -1990,7 +2030,7 @@ recursiveExecuteUnwrapArray(JsonPathExecContext *cxt, JsonPathItem *jsp,
19902030 {
19912031 if (tok == WJB_ELEM )
19922032 {
1993- res = recursiveExecuteNoUnwrap (cxt , jsp , & v , found );
2033+ res = recursiveExecuteNoUnwrap (cxt , jsp , & v , found , false );
19942034 if (jperIsError (res ))
19952035 break ;
19962036 if (res == jperOk && !found )
@@ -2009,7 +2049,7 @@ recursiveExecuteUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
20092049 if (cxt -> lax && JsonbType (jb ) == jbvArray )
20102050 return recursiveExecuteUnwrapArray (cxt , jsp , jb , found );
20112051
2012- return recursiveExecuteNoUnwrap (cxt , jsp , jb , found );
2052+ return recursiveExecuteNoUnwrap (cxt , jsp , jb , found , false );
20132053}
20142054
20152055/*
@@ -2085,7 +2125,39 @@ recursiveExecute(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
20852125 }
20862126 }
20872127
2088- return recursiveExecuteNoUnwrap (cxt , jsp , jb , found );
2128+ return recursiveExecuteNoUnwrap (cxt , jsp , jb , found , false);
2129+ }
2130+
2131+ static inline JsonPathExecResult
2132+ recursiveExecuteBool (JsonPathExecContext * cxt , JsonPathItem * jsp ,
2133+ JsonbValue * jb )
2134+ {
2135+ if (jspHasNext (jsp ))
2136+ elog (ERROR , "boolean jsonpath item can not have next item" );
2137+
2138+ switch (jsp -> type )
2139+ {
2140+ case jpiAnd :
2141+ case jpiOr :
2142+ case jpiNot :
2143+ case jpiIsUnknown :
2144+ case jpiEqual :
2145+ case jpiNotEqual :
2146+ case jpiGreater :
2147+ case jpiGreaterOrEqual :
2148+ case jpiLess :
2149+ case jpiLessOrEqual :
2150+ case jpiExists :
2151+ case jpiStartsWith :
2152+ case jpiLikeRegex :
2153+ break ;
2154+
2155+ default :
2156+ elog (ERROR , "invalid boolean jsonpath item type: %d" , jsp -> type );
2157+ break ;
2158+ }
2159+
2160+ return recursiveExecuteNoUnwrap (cxt , jsp , jb , NULL , true);
20892161}
20902162
20912163/*
0 commit comments