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 = findJsonbValueFromSuperHeader(VARDATA(jb), JB_FOBJECT | JB_FARRAY, NULL, &kval); PG_RETURN_BOOL(v != NULL); }
Datum jsonb_exists_all(PG_FUNCTION_ARGS) { Jsonb *jb = PG_GETARG_JSONB(0); ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1); JsonbValue *arrKey = arrayToJsonbSortedArray(keys); uint32 *plowbound = NULL; uint32 lowbound = 0; int i; if (arrKey == NULL || arrKey->val.array.nElems == 0) PG_RETURN_BOOL(true); if (JB_ROOT_IS_OBJECT(jb)) plowbound = &lowbound; /* * We exploit the fact that the pairs list is already sorted into strictly * increasing order to narrow the findJsonbValueFromSuperHeader search; * each search can start one entry past the previous "found" entry, or at * the lower bound of the last search. */ for (i = 0; i < arrKey->val.array.nElems; i++) { if (findJsonbValueFromSuperHeader(VARDATA(jb), JB_FOBJECT | JB_FARRAY, plowbound, arrKey->val.array.elems + i) == NULL) PG_RETURN_BOOL(false); } PG_RETURN_BOOL(true); }
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; }