@ -621,6 +621,37 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
switch ( jsp - > type )
{
case jpiNull :
case jpiBool :
case jpiNumeric :
case jpiString :
case jpiVariable :
{
JsonbValue vbuf ;
JsonbValue * v ;
bool hasNext = jspGetNext ( jsp , & elem ) ;
if ( ! hasNext & & ! found & & jsp - > type ! = jpiVariable )
{
/*
* Skip evaluation , but not for variables . We must
* trigger an error for the missing variable .
*/
res = jperOk ;
break ;
}
v = hasNext ? & vbuf : palloc ( sizeof ( * v ) ) ;
baseObject = cxt - > baseObject ;
getJsonPathItem ( cxt , jsp , v ) ;
res = executeNextItem ( cxt , jsp , & elem ,
v , found , hasNext ) ;
cxt - > baseObject = baseObject ;
}
break ;
/* all boolean item types: */
case jpiAnd :
case jpiOr :
@ -642,63 +673,32 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
break ;
}
case jpiKey :
if ( JsonbType ( jb ) = = jbvObject )
{
JsonbValue * v ;
JsonbValue key ;
key . type = jbvString ;
key . val . string . val = jspGetString ( jsp , & key . val . string . len ) ;
v = findJsonbValueFromContainer ( jb - > val . binary . data ,
JB_FOBJECT , & key ) ;
case jpiAdd :
return executeBinaryArithmExpr ( cxt , jsp , jb ,
numeric_add_opt_error , found ) ;
if ( v ! = NULL )
{
res = executeNextItem ( cxt , jsp , NULL ,
v , found , false ) ;
case jpiSub :
return executeBinaryArithmExpr ( cxt , jsp , jb ,
numeric_sub_opt_error , found ) ;
/* free value if it was not added to found list */
if ( jspHasNext ( jsp ) | | ! found )
pfree ( v ) ;
}
else if ( ! jspIgnoreStructuralErrors ( cxt ) )
{
Assert ( found ) ;
case jpiMul :
return executeBinaryArithmExpr ( cxt , jsp , jb ,
numeric_mul_opt_error , found ) ;
if ( ! jspThrowErrors ( cxt ) )
return jperError ;
case jpiDiv :
return executeBinaryArithmExpr ( cxt , jsp , jb ,
numeric_div_opt_error , found ) ;
ereport ( ERROR ,
( errcode ( ERRCODE_SQL_JSON_MEMBER_NOT_FOUND ) , \
errmsg ( " JSON object does not contain key \" %s \" " ,
pnstrdup ( key . val . string . val ,
key . val . string . len ) ) ) ) ;
}
}
else if ( unwrap & & JsonbType ( jb ) = = jbvArray )
return executeItemUnwrapTargetArray ( cxt , jsp , jb , found , false ) ;
else if ( ! jspIgnoreStructuralErrors ( cxt ) )
{
Assert ( found ) ;
RETURN_ERROR ( ereport ( ERROR ,
( errcode ( ERRCODE_SQL_JSON_MEMBER_NOT_FOUND ) ,
errmsg ( " jsonpath member accessor can only be applied to an object " ) ) ) ) ;
}
break ;
case jpiMod :
return executeBinaryArithmExpr ( cxt , jsp , jb ,
numeric_mod_opt_error , found ) ;
case jpiRoot :
jb = cxt - > root ;
baseObject = setBaseObject ( cxt , jb , 0 ) ;
res = executeNextItem ( cxt , jsp , NULL , jb , found , true ) ;
cxt - > baseObject = baseObject ;
break ;
case jpiPlus :
return executeUnaryArithmExpr ( cxt , jsp , jb , NULL , found ) ;
case jpiCurrent :
res = executeNextItem ( cxt , jsp , NULL , cxt - > current ,
found , true ) ;
break ;
case jpiMinus :
return executeUnaryArithmExpr ( cxt , jsp , jb , numeric_uminus ,
found ) ;
case jpiAnyArray :
if ( JsonbType ( jb ) = = jbvArray )
@ -716,6 +716,30 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
errmsg ( " jsonpath wildcard array accessor can only be applied to an array " ) ) ) ) ;
break ;
case jpiAnyKey :
if ( JsonbType ( jb ) = = jbvObject )
{
bool hasNext = jspGetNext ( jsp , & elem ) ;
if ( jb - > type ! = jbvBinary )
elog ( ERROR , " invalid jsonb object type: %d " , jb - > type ) ;
return executeAnyItem
( cxt , hasNext ? & elem : NULL ,
jb - > val . binary . data , found , 1 , 1 , 1 ,
false , jspAutoUnwrap ( cxt ) ) ;
}
else if ( unwrap & & JsonbType ( jb ) = = jbvArray )
return executeItemUnwrapTargetArray ( cxt , jsp , jb , found , false ) ;
else if ( ! jspIgnoreStructuralErrors ( cxt ) )
{
Assert ( found ) ;
RETURN_ERROR ( ereport ( ERROR ,
( errcode ( ERRCODE_SQL_JSON_OBJECT_NOT_FOUND ) ,
errmsg ( " jsonpath wildcard member accessor can only be applied to an object " ) ) ) ) ;
}
break ;
case jpiIndexArray :
if ( JsonbType ( jb ) = = jbvArray | | jspAutoWrap ( cxt ) )
{
@ -822,46 +846,70 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
}
break ;
case jpiLast :
case jpiAny :
{
JsonbValue tmpjbv ;
JsonbValue * lastjbv ;
int last ;
bool hasNext = jspGetNext ( jsp , & elem ) ;
if ( cxt - > innermostArraySize < 0 )
elog ( ERROR , " evaluating jsonpath LAST outside of array subscript " ) ;
if ( ! hasNext & & ! found )
/* first try without any intermediate steps */
if ( jsp - > content . anybounds . first = = 0 )
{
res = jperOk ;
break ;
}
last = cxt - > innermostArraySize - 1 ;
bool savedIgnoreStructuralErrors ;
lastjbv = hasNext ? & tmpjbv : palloc ( sizeof ( * lastjbv ) ) ;
savedIgnoreStructuralErrors = cxt - > ignoreStructuralErrors ;
cxt - > ignoreStructuralErrors = true ;
res = executeNextItem ( cxt , jsp , & elem ,
jb , found , true ) ;
cxt - > ignoreStructuralErrors = savedIgnoreStructuralErrors ;
lastjbv - > type = jbvNumeric ;
lastjbv - > val . numeric = int64_to_numeric ( last ) ;
if ( res = = jperOk & & ! found )
break ;
}
res = executeNextItem ( cxt , jsp , & elem ,
lastjbv , found , hasNext ) ;
if ( jb - > type = = jbvBinary )
res = executeAnyItem
( cxt , hasNext ? & elem : NULL ,
jb - > val . binary . data , found ,
1 ,
jsp - > content . anybounds . first ,
jsp - > content . anybounds . last ,
true , jspAutoUnwrap ( cxt ) ) ;
break ;
}
break ;
case jpiAnyKey :
case jpiKey :
if ( JsonbType ( jb ) = = jbvObject )
{
bool hasNext = jspGetNext ( jsp , & elem ) ;
JsonbValue * v ;
JsonbValue key ;
if ( jb - > type ! = jbvBinary )
elog ( ERROR , " invalid jsonb object type: %d " , jb - > type ) ;
key . type = jbvString ;
key . val . string . val = jspGetString ( jsp , & key . val . string . len ) ;
return executeAnyItem
( cxt , hasNext ? & elem : NULL ,
jb - > val . binary . data , found , 1 , 1 , 1 ,
false , jspAutoUnwrap ( cxt ) ) ;
v = findJsonbValueFromContainer ( jb - > val . binary . data ,
JB_FOBJECT , & key ) ;
if ( v ! = NULL )
{
res = executeNextItem ( cxt , jsp , NULL ,
v , found , false ) ;
/* free value if it was not added to found list */
if ( jspHasNext ( jsp ) | | ! found )
pfree ( v ) ;
}
else if ( ! jspIgnoreStructuralErrors ( cxt ) )
{
Assert ( found ) ;
if ( ! jspThrowErrors ( cxt ) )
return jperError ;
ereport ( ERROR ,
( errcode ( ERRCODE_SQL_JSON_MEMBER_NOT_FOUND ) , \
errmsg ( " JSON object does not contain key \" %s \" " ,
pnstrdup ( key . val . string . val ,
key . val . string . len ) ) ) ) ;
}
}
else if ( unwrap & & JsonbType ( jb ) = = jbvArray )
return executeItemUnwrapTargetArray ( cxt , jsp , jb , found , false ) ;
@ -869,37 +917,22 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
{
Assert ( found ) ;
RETURN_ERROR ( ereport ( ERROR ,
( errcode ( ERRCODE_SQL_JSON_OBJECT _NOT_FOUND ) ,
errmsg ( " jsonpath wildcard member accessor can only be applied to an object " ) ) ) ) ;
( errcode ( ERRCODE_SQL_JSON_MEMBER _NOT_FOUND ) ,
errmsg ( " jsonpath member accessor can only be applied to an object " ) ) ) ) ;
}
break ;
case jpiAdd :
return executeBinaryArithmExpr ( cxt , jsp , jb ,
numeric_add_opt_error , found ) ;
case jpiSub :
return executeBinaryArithmExpr ( cxt , jsp , jb ,
numeric_sub_opt_error , found ) ;
case jpiMul :
return executeBinaryArithmExpr ( cxt , jsp , jb ,
numeric_mul_opt_error , found ) ;
case jpiDiv :
return executeBinaryArithmExpr ( cxt , jsp , jb ,
numeric_div_opt_error , found ) ;
case jpiMod :
return executeBinaryArithmExpr ( cxt , jsp , jb ,
numeric_mod_opt_error , found ) ;
case jpiPlus :
return executeUnaryArithmExpr ( cxt , jsp , jb , NULL , found ) ;
case jpiCurrent :
res = executeNextItem ( cxt , jsp , NULL , cxt - > current ,
found , true ) ;
break ;
case jpiMinus :
return executeUnaryArithmExpr ( cxt , jsp , jb , numeric_uminus ,
found ) ;
case jpiRoot :
jb = cxt - > root ;
baseObject = setBaseObject ( cxt , jb , 0 ) ;
res = executeNextItem ( cxt , jsp , NULL , jb , found , true ) ;
cxt - > baseObject = baseObject ;
break ;
case jpiFilter :
{
@ -919,67 +952,6 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
break ;
}
case jpiAny :
{
bool hasNext = jspGetNext ( jsp , & elem ) ;
/* first try without any intermediate steps */
if ( jsp - > content . anybounds . first = = 0 )
{
bool savedIgnoreStructuralErrors ;
savedIgnoreStructuralErrors = cxt - > ignoreStructuralErrors ;
cxt - > ignoreStructuralErrors = true ;
res = executeNextItem ( cxt , jsp , & elem ,
jb , found , true ) ;
cxt - > ignoreStructuralErrors = savedIgnoreStructuralErrors ;
if ( res = = jperOk & & ! found )
break ;
}
if ( jb - > type = = jbvBinary )
res = executeAnyItem
( cxt , hasNext ? & elem : NULL ,
jb - > val . binary . data , found ,
1 ,
jsp - > content . anybounds . first ,
jsp - > content . anybounds . last ,
true , jspAutoUnwrap ( cxt ) ) ;
break ;
}
case jpiNull :
case jpiBool :
case jpiNumeric :
case jpiString :
case jpiVariable :
{
JsonbValue vbuf ;
JsonbValue * v ;
bool hasNext = jspGetNext ( jsp , & elem ) ;
if ( ! hasNext & & ! found & & jsp - > type ! = jpiVariable )
{
/*
* Skip evaluation , but not for variables . We must
* trigger an error for the missing variable .
*/
res = jperOk ;
break ;
}
v = hasNext ? & vbuf : palloc ( sizeof ( * v ) ) ;
baseObject = cxt - > baseObject ;
getJsonPathItem ( cxt , jsp , v ) ;
res = executeNextItem ( cxt , jsp , & elem ,
v , found , hasNext ) ;
cxt - > baseObject = baseObject ;
}
break ;
case jpiType :
{
JsonbValue * jbv = palloc ( sizeof ( * jbv ) ) ;
@ -1110,6 +1082,34 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
return executeKeyValueMethod ( cxt , jsp , jb , found ) ;
case jpiLast :
{
JsonbValue tmpjbv ;
JsonbValue * lastjbv ;
int last ;
bool hasNext = jspGetNext ( jsp , & elem ) ;
if ( cxt - > innermostArraySize < 0 )
elog ( ERROR , " evaluating jsonpath LAST outside of array subscript " ) ;
if ( ! hasNext & & ! found )
{
res = jperOk ;
break ;
}
last = cxt - > innermostArraySize - 1 ;
lastjbv = hasNext ? & tmpjbv : palloc ( sizeof ( * lastjbv ) ) ;
lastjbv - > type = jbvNumeric ;
lastjbv - > val . numeric = int64_to_numeric ( last ) ;
res = executeNextItem ( cxt , jsp , & elem ,
lastjbv , found , hasNext ) ;
}
break ;
default :
elog ( ERROR , " unrecognized jsonpath item type: %d " , jsp - > type ) ;
}