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); }
Datum jsonb_contains(PG_FUNCTION_ARGS) { Jsonb *val = PG_GETARG_JSONB(0); Jsonb *tmpl = PG_GETARG_JSONB(1); JsonbIterator *it1, *it2; if (JB_ROOT_IS_OBJECT(val) != JB_ROOT_IS_OBJECT(tmpl)) PG_RETURN_BOOL(false); it1 = JsonbIteratorInit(&val->root); it2 = JsonbIteratorInit(&tmpl->root); PG_RETURN_BOOL(JsonbDeepContains(&it1, &it2)); }
Datum jsonb_contained(PG_FUNCTION_ARGS) { /* Commutator of "contains" */ Jsonb *tmpl = PG_GETARG_JSONB(0); Jsonb *val = PG_GETARG_JSONB(1); JsonbIterator *it1, *it2; if (JB_ROOT_COUNT(val) < JB_ROOT_COUNT(tmpl) || JB_ROOT_IS_OBJECT(val) != JB_ROOT_IS_OBJECT(tmpl)) PG_RETURN_BOOL(false); it1 = JsonbIteratorInit(VARDATA(val)); it2 = JsonbIteratorInit(VARDATA(tmpl)); PG_RETURN_BOOL(JsonbDeepContains(&it1, &it2)); }
/* * SQL function jsonb_typeof(jsonb) -> text * * This function is here because the analog json function is in json.c, since * it uses the json parser internals not exposed elsewhere. */ Datum jsonb_typeof(PG_FUNCTION_ARGS) { Jsonb *in = PG_GETARG_JSONB(0); JsonbIterator *it; JsonbValue v; char *result; if (JB_ROOT_IS_OBJECT(in)) result = "object"; else if (JB_ROOT_IS_ARRAY(in) && !JB_ROOT_IS_SCALAR(in)) result = "array"; else { Assert(JB_ROOT_IS_SCALAR(in)); it = JsonbIteratorInit(VARDATA_ANY(in)); /* * A root scalar is stored as an array of one element, so we get the * array and then its first (and only) member. */ (void) JsonbIteratorNext(&it, &v, true); Assert(v.type == jbvArray); (void) JsonbIteratorNext(&it, &v, true); switch (v.type) { case jbvNull: result = "null"; break; case jbvString: result = "string"; break; case jbvNumeric: result = "number"; break; case jbvBool: result = "boolean"; break; default: elog(ERROR, "unknown jsonb scalar type"); } } PG_RETURN_TEXT_P(cstring_to_text(result)); }
Datum jsonb_bool(PG_FUNCTION_ARGS) { Jsonb *j = PG_GETARG_JSONB(0); if (JB_ROOT_IS_SCALAR(j)) { JsonbValue *jv; jv = getIthJsonbValueFromContainer(&j->root, 0); switch (jv->type) { case jbvNull: PG_RETURN_NULL(); case jbvString: PG_RETURN_BOOL(jv->val.string.len > 0); case jbvNumeric: { Datum b; if (numeric_is_nan(jv->val.numeric)) PG_RETURN_BOOL(false); b = DirectFunctionCall2(numeric_ne, NumericGetDatum(jv->val.numeric), get_numeric_0_datum()); PG_RETURN_DATUM(b); } case jbvBool: PG_RETURN_BOOL(jv->val.boolean); default: elog(ERROR, "unknown jsonb scalar type"); } } Assert(JB_ROOT_IS_OBJECT(j) || JB_ROOT_IS_ARRAY(j)); PG_RETURN_BOOL(JB_ROOT_COUNT(j) > 0); }
Datum jsonb_add(PG_FUNCTION_ARGS) { Jsonb *l = PG_GETARG_JSONB(0); Jsonb *r = PG_GETARG_JSONB(1); JsonbValue *ljv; JsonbValue *rjv; JsonbValue jv; Size len; char *buf; Datum n; char *nstr; if (!(JB_ROOT_IS_SCALAR(l) && JB_ROOT_IS_SCALAR(r))) { Datum j; if ((JB_ROOT_IS_SCALAR(l) && JB_ROOT_IS_OBJECT(r)) || (JB_ROOT_IS_OBJECT(l) && JB_ROOT_IS_SCALAR(r)) || (JB_ROOT_IS_OBJECT(l) && JB_ROOT_IS_OBJECT(r))) ereport_op_str("+", l, r); j = DirectFunctionCall2(jsonb_concat, JsonbGetDatum(l), JsonbGetDatum(r)); PG_RETURN_DATUM(j); } ljv = getIthJsonbValueFromContainer(&l->root, 0); rjv = getIthJsonbValueFromContainer(&r->root, 0); if (ljv->type == jbvString && rjv->type == jbvString) { len = ljv->val.string.len + rjv->val.string.len; buf = palloc(len + 1); strncpy(buf, ljv->val.string.val, ljv->val.string.len); strncpy(buf + ljv->val.string.len, rjv->val.string.val, rjv->val.string.len); buf[len] = '\0'; jv.type = jbvString; jv.val.string.len = len; jv.val.string.val = buf; PG_RETURN_JSONB(JsonbValueToJsonb(&jv)); } else if (ljv->type == jbvString && rjv->type == jbvNumeric) { n = DirectFunctionCall1(numeric_out, NumericGetDatum(rjv->val.numeric)); nstr = DatumGetCString(n); len = ljv->val.string.len + strlen(nstr); buf = palloc(len + 1); strncpy(buf, ljv->val.string.val, ljv->val.string.len); strcpy(buf + ljv->val.string.len, nstr); jv.type = jbvString; jv.val.string.len = len; jv.val.string.val = buf; PG_RETURN_JSONB(JsonbValueToJsonb(&jv)); } else if (ljv->type == jbvNumeric && rjv->type == jbvString) { Size nlen; n = DirectFunctionCall1(numeric_out, NumericGetDatum(ljv->val.numeric)); nstr = DatumGetCString(n); nlen = strlen(nstr); len = nlen + rjv->val.string.len; buf = palloc(len + 1); strcpy(buf, nstr); strncpy(buf + nlen, rjv->val.string.val, rjv->val.string.len); buf[len] = '\0'; jv.type = jbvString; jv.val.string.len = len; jv.val.string.val = buf; PG_RETURN_JSONB(JsonbValueToJsonb(&jv)); } else if (ljv->type == jbvNumeric && rjv->type == jbvNumeric) { n = DirectFunctionCall2(numeric_add, NumericGetDatum(ljv->val.numeric), NumericGetDatum(rjv->val.numeric)); PG_RETURN_JSONB(numeric_to_jnumber(DatumGetNumeric(n))); } else { ereport_op_str("+", l, r); } PG_RETURN_NULL(); }