static bool executeArrayOp(char *jqBase, int32 jqPos, int32 type, int32 op, JsonbValue *jb) { int32 i, nelems, *arrayPos; int32 r; JsonbIterator *it; JsonbValue v; int32 nres = 0, nval = 0; if (jb->type != jbvBinary) return false; if (type != jqiArray) return false; read_int32(nelems, jqBase, jqPos); arrayPos = (int32*)(jqBase + jqPos); it = JsonbIteratorInit(jb->val.binary.data); while((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE) { if (r == WJB_BEGIN_ARRAY) nval = v.val.array.nElems; if (r == WJB_ELEM) { bool res = false; for(i=0; i<nelems; i++) { if (executeExpr(jqBase, arrayPos[i], jqiEqual, &v)) { if (op == jqiOverlap) return true; nres++; res = true; break; } } } } if (op == jqiContains) return (nres == nelems && nelems > 0); if (op == jqiContained) return (nres == nval && nval > 0); return false; }
static bool checkIn(char *jqBase, int32 jqPos, int32 type, JsonbValue *jb) { int32 i, nelems, *arrayPos; if (jb->type == jbvBinary) return false; if (type != jqiArray) return false; read_int32(nelems, jqBase, jqPos); arrayPos = (int32*)(jqBase + jqPos); for(i=0; i<nelems; i++) if (executeExpr(jqBase, arrayPos[i], jqiEqual, jb)) return true; return false; }
static bool checkArrayEquality(char *jqBase, int32 jqPos, int32 type, JsonbValue *jb) { int32 i, nelems, *arrayPos; int32 r; JsonbIterator *it; JsonbValue v; if (!(type == jqiArray && jb->type == jbvBinary)) return false; read_int32(nelems, jqBase, jqPos); arrayPos = (int32*)(jqBase + jqPos); it = JsonbIteratorInit(jb->val.binary.data); r = JsonbIteratorNext(&it, &v, true); if (r != WJB_BEGIN_ARRAY) return false; if (v.val.array.nElems != nelems) return false; i = 0; while((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE) { if (r == WJB_ELEM && i<nelems) { if (executeExpr(jqBase, arrayPos[i], jqiEqual, &v) == false) return false; i++; } } return true; }
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; }