Datum jsonb_exists_all(PG_FUNCTION_ARGS) { Jsonb *jb = PG_GETARG_JSONB(0); ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1); int i; Datum *key_datums; bool *key_nulls; int elem_count; deconstruct_array(keys, TEXTOID, -1, false, 'i', &key_datums, &key_nulls, &elem_count); for (i = 0; i < elem_count; i++) { JsonbValue strVal; if (key_nulls[i]) continue; strVal.type = jbvString; strVal.val.string.val = VARDATA(key_datums[i]); strVal.val.string.len = VARSIZE(key_datums[i]) - VARHDRSZ; if (findJsonbValueFromContainer(&jb->root, JB_FOBJECT | JB_FARRAY, &strVal) == NULL) PG_RETURN_BOOL(false); } PG_RETURN_BOOL(true); }
Datum jsonb_exists(PG_FUNCTION_ARGS) { Jsonb *jb = PG_GETARG_JSONB(0); text *key = PG_GETARG_TEXT_PP(1); JsonbValue kval; JsonbValue *v = NULL; /* * We only match Object keys (which are naturally always Strings), or * string elements in arrays. In particular, we do not match non-string * scalar elements. Existence of a key/element is only considered at the * top level. No recursion occurs. */ kval.type = jbvString; kval.val.string.val = VARDATA_ANY(key); kval.val.string.len = VARSIZE_ANY_EXHDR(key); v = findJsonbValueFromContainer(&jb->root, JB_FOBJECT | JB_FARRAY, &kval); PG_RETURN_BOOL(v != NULL); }
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; }