static bool recursiveAny(JsQueryItem *jsq, JsonbValue *jb) { bool res = false; JsonbIterator *it; int32 r; JsonbValue v; check_stack_depth(); it = JsonbIteratorInit(jb->val.binary.data); while(res == false && (r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE) { if (r == WJB_KEY) { r = JsonbIteratorNext(&it, &v, true); Assert(r == WJB_VALUE); } if (r == WJB_VALUE || r == WJB_ELEM) { res = recursiveExecute(jsq, &v, NULL); if (res == false && v.type == jbvBinary) res = recursiveAny(jsq, &v); } } return res; }
static bool recursiveExecute(JsQueryItem *jsq, JsonbValue *jb, JsQueryItem *jsqLeftArg) { JsQueryItem elem; bool res = false; check_stack_depth(); switch(jsq->type) { case jqiAnd: jsqGetLeftArg(jsq, &elem); res = recursiveExecute(&elem, jb, jsqLeftArg); if (res == true) { jsqGetRightArg(jsq, &elem); res = recursiveExecute(&elem, jb, jsqLeftArg); } break; case jqiOr: jsqGetLeftArg(jsq, &elem); res = recursiveExecute(&elem, jb, jsqLeftArg); if (res == false) { jsqGetRightArg(jsq, &elem); res = recursiveExecute(&elem, jb, jsqLeftArg); } break; case jqiNot: jsqGetArg(jsq, &elem); res = !recursiveExecute(&elem, jb, jsqLeftArg); break; case jqiKey: if (JsonbType(jb) == jbvObject) { JsonbValue *v, key; key.type = jbvString; key.val.string.val = jsqGetString(jsq, &key.val.string.len); v = findJsonbValueFromContainer(jb->val.binary.data, JB_FOBJECT, &key); if (v != NULL) { jsqGetNext(jsq, &elem); res = recursiveExecute(&elem, v, NULL); pfree(v); } } break; case jqiCurrent: jsqGetNext(jsq, &elem); if (JsonbType(jb) == jbvScalar) { JsonbIterator *it; int32 r; JsonbValue v; it = JsonbIteratorInit(jb->val.binary.data); r = JsonbIteratorNext(&it, &v, true); Assert(r == WJB_BEGIN_ARRAY); Assert(v.val.array.rawScalar == 1); Assert(v.val.array.nElems == 1); r = JsonbIteratorNext(&it, &v, true); Assert(r == WJB_ELEM); res = recursiveExecute(&elem, &v, jsqLeftArg); } else { res = recursiveExecute(&elem, jb, jsqLeftArg); } break; case jqiAny: jsqGetNext(jsq, &elem); if (recursiveExecute(&elem, jb, NULL)) res = true; else if (jb->type == jbvBinary) res = recursiveAny(&elem, jb); break; case jqiAll: jsqGetNext(jsq, &elem); if ((res = recursiveExecute(&elem, jb, NULL)) == true) { if (jb->type == jbvBinary) res = recursiveAll(&elem, jb); } break; case jqiAnyArray: case jqiAllArray: if (JsonbType(jb) == jbvArray) { JsonbIterator *it; int32 r; JsonbValue v; jsqGetNext(jsq, &elem); it = JsonbIteratorInit(jb->val.binary.data); if (jsq->type == jqiAllArray) res = true; while((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE) { if (r == WJB_ELEM) { res = recursiveExecute(&elem, &v, NULL); if (jsq->type == jqiAnyArray) { if (res == true) break; } else if (jsq->type == jqiAllArray) { if (res == false) break; } } } } break; case jqiAnyKey: case jqiAllKey: if (JsonbType(jb) == jbvObject) { JsonbIterator *it; int32 r; JsonbValue v; jsqGetNext(jsq, &elem); it = JsonbIteratorInit(jb->val.binary.data); if (jsq->type == jqiAllKey) res = true; while((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE) { if (r == WJB_VALUE) { res = recursiveExecute(&elem, &v, NULL); if (jsq->type == jqiAnyKey) { if (res == true) break; } else if (jsq->type == jqiAllKey) { if (res == false) break; } } } } break; case jqiEqual: case jqiIn: case jqiLess: case jqiGreater: case jqiLessOrEqual: case jqiGreaterOrEqual: case jqiContains: case jqiContained: case jqiOverlap: jsqGetArg(jsq, &elem); res = executeExpr(&elem, jsq->type, jb, jsqLeftArg); break; case jqiLength: jsqGetNext(jsq, &elem); res = recursiveExecute(&elem, jb, jsq); break; case jqiIs: if (JsonbType(jb) == jbvScalar) { JsonbIterator *it; int32 r; JsonbValue v; it = JsonbIteratorInit(jb->val.binary.data); r = JsonbIteratorNext(&it, &v, true); Assert(r == WJB_BEGIN_ARRAY); Assert(v.val.array.rawScalar == 1); Assert(v.val.array.nElems == 1); r = JsonbIteratorNext(&it, &v, true); Assert(r == WJB_ELEM); res = (jsqGetIsType(jsq) == JsonbType(&v)); } else { res = (jsqGetIsType(jsq) == JsonbType(jb)); } break; default: elog(ERROR,"Wrong state: %d", jsq->type); } return res; }
static bool recursiveExecute(char *jqBase, int32 jqPos, JsonbValue *jb) { int32 type; int32 nextPos; int32 left, right, arg; bool res = false; check_stack_depth(); jqPos = readJsQueryHeader(jqBase, jqPos, &type, &nextPos); switch(type) { case jqiAnd: read_int32(left, jqBase, jqPos); read_int32(right, jqBase, jqPos); Assert(nextPos == 0); res = (recursiveExecute(jqBase, left, jb) && recursiveExecute(jqBase, right, jb)); break; case jqiOr: read_int32(left, jqBase, jqPos); read_int32(right, jqBase, jqPos); Assert(nextPos == 0); res = (recursiveExecute(jqBase, left, jb) || recursiveExecute(jqBase, right, jb)); break; case jqiNot: read_int32(arg, jqBase, jqPos); Assert(nextPos == 0); res = ! recursiveExecute(jqBase, arg, jb); break; case jqiKey: if (jb->type == jbvBinary) { int32 len; JsonbValue *v, key; read_int32(len, jqBase, jqPos); key.type = jbvString; key.val.string.val = jqBase + jqPos; key.val.string.len = len; jqPos += len + 1; v = findJsonbValueFromSuperHeader(jb->val.binary.data, JB_FOBJECT, NULL, &key); Assert(nextPos != 0); res = ((v != NULL) && recursiveExecute(jqBase, nextPos, v)); } break; case jqiAny: Assert(nextPos != 0); if (recursiveExecute(jqBase, nextPos, jb)) res = true; else if (jb->type == jbvBinary) res = recursiveAny(jqBase, nextPos, jb); break; case jqiAnyArray: Assert(nextPos != 0); if (jb->type == jbvBinary) { JsonbIterator *it; int32 r; JsonbValue v; it = JsonbIteratorInit(jb->val.binary.data); while(res == false && (r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE) { if (r == WJB_KEY) break; if (r == WJB_ELEM) res = recursiveExecute(jqBase, nextPos, &v); } } break; case jqiEqual: case jqiIn: case jqiLess: case jqiGreater: case jqiLessOrEqual: case jqiGreaterOrEqual: case jqiContains: case jqiContained: case jqiOverlap: read_int32(arg, jqBase, jqPos); res = executeExpr(jqBase, arg, type, jb); break; default: elog(ERROR,"Wrong state: %d", type); } return res; }