Datum gin_extract_jsonb(PG_FUNCTION_ARGS) { Jsonb *jb = (Jsonb *) PG_GETARG_JSONB_P(0); int32 *nentries = (int32 *) PG_GETARG_POINTER(1); int total = 2 * JB_ROOT_COUNT(jb); JsonbIterator *it; JsonbValue v; JsonbIteratorToken r; int i = 0; Datum *entries; /* If the root level is empty, we certainly have no keys */ if (total == 0) { *nentries = 0; PG_RETURN_POINTER(NULL); } /* Otherwise, use 2 * root count as initial estimate of result size */ entries = (Datum *) palloc(sizeof(Datum) * total); it = JsonbIteratorInit(&jb->root); while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE) { /* Since we recurse into the object, we might need more space */ if (i >= total) { total *= 2; entries = (Datum *) repalloc(entries, sizeof(Datum) * total); } switch (r) { case WJB_KEY: entries[i++] = make_scalar_key(&v, true); break; case WJB_ELEM: /* Pretend string array elements are keys, see jsonb.h */ entries[i++] = make_scalar_key(&v, (v.type == jbvString)); break; case WJB_VALUE: entries[i++] = make_scalar_key(&v, false); break; default: /* we can ignore structural items */ break; } } *nentries = i; PG_RETURN_POINTER(entries); }
Datum gin_extract_jsonb(PG_FUNCTION_ARGS) { Jsonb *jb = (Jsonb *) PG_GETARG_JSONB_P(0); int32 *nentries = (int32 *) PG_GETARG_POINTER(1); int total = JB_ROOT_COUNT(jb); JsonbIterator *it; JsonbValue v; JsonbIteratorToken r; GinEntries entries; /* If the root level is empty, we certainly have no keys */ if (total == 0) { *nentries = 0; PG_RETURN_POINTER(NULL); } /* Otherwise, use 2 * root count as initial estimate of result size */ init_gin_entries(&entries, 2 * total); it = JsonbIteratorInit(&jb->root); while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE) { switch (r) { case WJB_KEY: add_gin_entry(&entries, make_scalar_key(&v, true)); break; case WJB_ELEM: /* Pretend string array elements are keys, see jsonb.h */ add_gin_entry(&entries, make_scalar_key(&v, v.type == jbvString)); break; case WJB_VALUE: add_gin_entry(&entries, make_scalar_key(&v, false)); break; default: /* we can ignore structural items */ break; } } *nentries = entries.count; PG_RETURN_POINTER(entries.buf); }
Datum gin_extract_jsonb(PG_FUNCTION_ARGS) { Jsonb *jb = (Jsonb *) PG_GETARG_JSONB(0); int32 *nentries = (int32 *) PG_GETARG_POINTER(1); Datum *entries = NULL; int total = 2 * JB_ROOT_COUNT(jb); int i = 0, r; JsonbIterator *it; JsonbValue v; if (total == 0) { *nentries = 0; PG_RETURN_POINTER(NULL); } entries = (Datum *) palloc(sizeof(Datum) * total); it = JsonbIteratorInit(VARDATA(jb)); while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE) { if (i >= total) { total *= 2; entries = (Datum *) repalloc(entries, sizeof(Datum) * total); } /* * Serialize keys and elements equivalently, but only when elements * are Jsonb strings. Otherwise, serialize elements as values. Array * elements are indexed as keys, for the benefit of * JsonbExistsStrategyNumber. Our definition of existence does not * allow for checking the existence of a non-jbvString element (just * like the definition of the underlying operator), because the * operator takes a text rhs argument (which is taken as a proxy for an * equivalent Jsonb string). * * The way existence is represented does not preclude an alternative * existence operator, that takes as its rhs value an arbitrarily * internally-typed Jsonb. The only reason that isn't the case here is * that the existence operator is only really intended to determine if * an object has a certain key (object pair keys are of course * invariably strings), which is extended to jsonb arrays. You could * think of the default Jsonb definition of existence as being * equivalent to a definition where all types of scalar array elements * are keys that we can check the existence of, while just forbidding * non-string notation. This inflexibility prevents the user from * having to qualify that the rhs string is a raw scalar string (that * is, naturally no internal string quoting in required for the text * argument), and allows us to not set the reset flag for * JsonbExistsStrategyNumber, since we know that keys are strings for * both objects and arrays, and don't have to further account for type * mismatch. Not having to set the reset flag makes it less than * tempting to tighten up the definition of existence to preclude array * elements entirely, which would arguably be a simpler alternative. * In any case the infrastructure used to implement the existence * operator could trivially support this hypothetical, slightly * distinct definition of existence. */ switch (r) { case WJB_KEY: /* Serialize key separately, for existence strategies */ entries[i++] = PointerGetDatum(make_scalar_key(&v, JKEYELEM)); break; case WJB_ELEM: if (v.type == jbvString) entries[i++] = PointerGetDatum(make_scalar_key(&v, JKEYELEM)); else entries[i++] = PointerGetDatum(make_scalar_key(&v, JVAL)); break; case WJB_VALUE: entries[i++] = PointerGetDatum(make_scalar_key(&v, JVAL)); break; default: continue; } } *nentries = i; PG_RETURN_POINTER(entries); }
static JsonPathGinNode * make_jsp_entry_node_scalar(JsonbValue *scalar, bool iskey) { return make_jsp_entry_node(make_scalar_key(scalar, iskey)); }