From f1fb01070a30cf7fcabd162ed8dcc58d03a731bc Mon Sep 17 00:00:00 2001 From: nnuanyang Date: Mon, 20 Nov 2023 22:52:00 -0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81=E9=A3=8E?= =?UTF-8?q?=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/backend/utils/adt/jsonfuncs.cpp | 993 ++++++++++----------- 1 file changed, 456 insertions(+), 537 deletions(-) diff --git a/src/common/backend/utils/adt/jsonfuncs.cpp b/src/common/backend/utils/adt/jsonfuncs.cpp index 5905aa862..5fb854b34 100644 --- a/src/common/backend/utils/adt/jsonfuncs.cpp +++ b/src/common/backend/utils/adt/jsonfuncs.cpp @@ -36,15 +36,14 @@ #include "utils/array.h" /* Operations available for setPath */ -#define JB_PATH_CREATE 0x0001 -#define JB_PATH_DELETE 0x0002 -#define JB_PATH_REPLACE 0x0004 -#define JB_PATH_INSERT_BEFORE 0x0008 -#define JB_PATH_INSERT_AFTER 0x0010 -#define JB_PATH_CREATE_OR_INSERT \ - (JB_PATH_INSERT_BEFORE | JB_PATH_INSERT_AFTER | JB_PATH_CREATE) -#define JB_PATH_FILL_GAPS 0x0020 -#define JB_PATH_CONSISTENT_POSITION 0x0040 +#define JB_PATH_CREATE 0x0001 +#define JB_PATH_DELETE 0x0002 +#define JB_PATH_REPLACE 0x0004 +#define JB_PATH_INSERT_BEFORE 0x0008 +#define JB_PATH_INSERT_AFTER 0x0010 +#define JB_PATH_CREATE_OR_INSERT (JB_PATH_INSERT_BEFORE | JB_PATH_INSERT_AFTER | JB_PATH_CREATE) +#define JB_PATH_FILL_GAPS 0x0020 +#define JB_PATH_CONSISTENT_POSITION 0x0040 /* semantic action functions for json_object_keys */ static void okeys_object_field_start(void *state, char *fname, bool isnull); @@ -119,18 +118,12 @@ static JsonbValue *findJsonbValueFromSuperHeaderLen(JsonbSuperHeader sheader, ui /* functions supporting jsonb_delete, jsonb_set and jsonb_concat */ static void addJsonbToParseState(JsonbParseState **pstate, Jsonb *jb); -static JsonbValue *setPath(JsonbIterator **it, Datum *path_elems, - bool *path_nulls, int path_len, - JsonbParseState **st, int level, Jsonb *newval, - int op_type); -static void setPathObject(JsonbIterator **it, Datum *path_elems, - bool *path_nulls, int path_len, JsonbParseState **st, - int level, - Jsonb *newval, uint32 npairs, int op_type); -static void setPathArray(JsonbIterator **it, Datum *path_elems, - bool *path_nulls, int path_len, JsonbParseState **st, - int level, - Jsonb *newval, uint32 nelems, int op_type); +static JsonbValue *setPath(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, + JsonbParseState **st, int level, Jsonb *newval, int op_type); +static void setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, + int level, Jsonb *newval, uint32 npairs, int op_type); +static void setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, JsonbParseState **st, + int level, Jsonb *newval, uint32 nelems, int op_type); /* search type classification for json_get* functions */ typedef enum { @@ -2786,629 +2779,555 @@ addJsonbToParseState(JsonbParseState **jbps, Jsonb *jb) * All path elements before the last must already exist * whatever bits in op_type are set, or nothing is done. */ -static JsonbValue *setPath(JsonbIterator **it, Datum *path_elems, - bool *path_nulls, int path_len, - JsonbParseState **st, int level, Jsonb *newval, int op_type) +static JsonbValue* setPath(JsonbIterator **it, Datum *path_elems, bool *path_nulls, int path_len, + JsonbParseState **st, int level, Jsonb *newval, int op_type) { - JsonbValue v; - int r; - JsonbValue *res; + JsonbValue v; + int r; + JsonbValue *res; - check_stack_depth(); + check_stack_depth(); - if (path_nulls[level]) - ereport(ERROR, - (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("path element at position %d is null", - level + 1))); + if (path_nulls[level]) + ereport(ERROR, + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("path element at position %d is null", level + 1))); - r = JsonbIteratorNext(it, &v, false); + r = JsonbIteratorNext(it, &v, false); - switch (r) - { - case WJB_BEGIN_ARRAY: + switch (r) { + case WJB_BEGIN_ARRAY: - /* - * If instructed complain about attempts to replace within a raw - * scalar value. This happens even when current level is equal to - * path_len, because the last path key should also correspond to - * an object or an array, not raw scalar. - */ - if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1) && - v.array.rawScalar) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("cannot replace existing key"), - errdetail("The path assumes key is a composite object, " - "but it is a scalar value."))); + /* + * If instructed complain about attempts to replace within a raw + * scalar value. This happens even when current level is equal to + * path_len, because the last path key should also correspond to + * an object or an array, not raw scalar. + */ + if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1) && v.array.rawScalar) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("cannot replace existing key"), + errdetail("The path assumes key is a composite object, " + "but it is a scalar value."))); - (void) pushJsonbValue(st, r, NULL); - setPathArray(it, path_elems, path_nulls, path_len, st, level, - newval, v.array.nElems, op_type); - r = JsonbIteratorNext(it, &v, false); - Assert(r == WJB_END_ARRAY); - res = pushJsonbValue(st, r, NULL); - break; - case WJB_BEGIN_OBJECT: - (void) pushJsonbValue(st, r, NULL); - setPathObject(it, path_elems, path_nulls, path_len, st, level, - newval, v.object.nPairs, op_type); - r = JsonbIteratorNext(it, &v, true); - Assert(r == WJB_END_OBJECT); - res = pushJsonbValue(st, r, NULL); - break; - case WJB_ELEM: - case WJB_VALUE: + (void) pushJsonbValue(st, r, NULL); + setPathArray(it, path_elems, path_nulls, path_len, st, level, newval, v.array.nElems, op_type); + r = JsonbIteratorNext(it, &v, false); + Assert(r == WJB_END_ARRAY); + res = pushJsonbValue(st, r, NULL); + break; + case WJB_BEGIN_OBJECT: + (void) pushJsonbValue(st, r, NULL); + setPathObject(it, path_elems, path_nulls, path_len, st, level, newval, v.object.nPairs, op_type); + r = JsonbIteratorNext(it, &v, true); + Assert(r == WJB_END_OBJECT); + res = pushJsonbValue(st, r, NULL); + break; + case WJB_ELEM: + case WJB_VALUE: - /* - * If instructed complain about attempts to replace within a - * scalar value. This happens even when current level is equal to - * path_len, because the last path key should also correspond to - * an object or an array, not an element or value. - */ - if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("cannot replace existing key"), - errdetail("The path assumes key is a composite object, " - "but it is a scalar value."))); + /* + * If instructed complain about attempts to replace within a + * scalar value. This happens even when current level is equal to + * path_len, because the last path key should also correspond to + * an object or an array, not an element or value. + */ + if ((op_type & JB_PATH_FILL_GAPS) && (level <= path_len - 1)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("cannot replace existing key"), + errdetail("The path assumes key is a composite object, but it is a scalar value."))); - res = pushJsonbValue(st, r, &v); - break; - default: - elog(ERROR, "unrecognized iterator result: %d", (int) r); - res = NULL; /* keep compiler quiet */ - break; - } + res = pushJsonbValue(st, r, &v); + break; + default: + elog(ERROR, "unrecognized iterator result: %d", (int) r); + res = NULL; /* keep compiler quiet */ + break; + } - return res; + return res; } /* * Object walker for setPath */ static void setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls, - int path_len, JsonbParseState **st, int level, - Jsonb *newval, uint32 npairs, int op_type) + int path_len, JsonbParseState **st, int level, Jsonb *newval, uint32 npairs, int op_type) { - text *pathelem = NULL; - int i; - JsonbValue k, - v; - bool done = false; + text *pathelem = NULL; + int i; + JsonbValue k, v; + bool done = false; - if (level >= path_len || path_nulls[level]) - done = true; - else - { - /* The path Datum could be toasted, in which case we must detoast it */ - pathelem = DatumGetTextPP(path_elems[level]); - } + if (level >= path_len || path_nulls[level]) { + done = true; + } else { + /* The path Datum could be toasted, in which case we must detoast it */ + pathelem = DatumGetTextPP(path_elems[level]); + } - /* empty object is a special case for create */ - if ((npairs == 0) && (op_type & JB_PATH_CREATE_OR_INSERT) && - (level == path_len - 1)) - { - JsonbValue newkey; + /* empty object is a special case for create */ + if ((npairs == 0) && (op_type & JB_PATH_CREATE_OR_INSERT) && (level == path_len - 1)) { + JsonbValue newkey; - newkey.type = jbvString; - newkey.string.val = VARDATA_ANY(pathelem); - newkey.string.len = VARSIZE_ANY_EXHDR(pathelem); + newkey.type = jbvString; + newkey.string.val = VARDATA_ANY(pathelem); + newkey.string.len = VARSIZE_ANY_EXHDR(pathelem); - (void) pushJsonbValue(st, WJB_KEY, &newkey); - addJsonbToParseState(st, newval); - } - - for (i = 0; i < npairs; i++) - { - int r = JsonbIteratorNext(it, &k, true); - - Assert(r == WJB_KEY); - - if (!done && - k.string.len == VARSIZE_ANY_EXHDR(pathelem) && - memcmp(k.string.val, VARDATA_ANY(pathelem), - k.string.len) == 0) - { - done = true; - - if (level == path_len - 1) - { - /* - * called from jsonb_insert(), it forbids redefining an - * existing value - */ - if (op_type & (JB_PATH_INSERT_BEFORE | JB_PATH_INSERT_AFTER)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("cannot replace existing key"), - errhint("Try using the function jsonb_set " - "to replace key value."))); - - r = JsonbIteratorNext(it, &v, true); /* skip value */ - if (!(op_type & JB_PATH_DELETE)) - { - (void) pushJsonbValue(st, WJB_KEY, &k); - addJsonbToParseState(st, newval); - } - } - else - { - (void) pushJsonbValue(st, r, &k); - setPath(it, path_elems, path_nulls, path_len, - st, level + 1, newval, op_type); - } - } - else - { - if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done && - level == path_len - 1 && i == npairs - 1) - { - JsonbValue newkey; - - newkey.type = jbvString; - newkey.string.val = VARDATA_ANY(pathelem); - newkey.string.len = VARSIZE_ANY_EXHDR(pathelem); - - (void) pushJsonbValue(st, WJB_KEY, &newkey); - addJsonbToParseState(st, newval); - } - - (void) pushJsonbValue(st, r, &k); - r = JsonbIteratorNext(it, &v, false); - (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL); - if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT) - { - int walking_level = 1; - - while (walking_level != 0) - { - r = JsonbIteratorNext(it, &v, false); - - if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT) - ++walking_level; - if (r == WJB_END_ARRAY || r == WJB_END_OBJECT) - --walking_level; - - (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL); - } - } - } - } -} - -/* - * Array walker for setPath - */ -static void setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, - int path_len, JsonbParseState **st, int level, - Jsonb *newval, uint32 nelems, int op_type) -{ - JsonbValue v; - int idx, - i; - bool done = false; - - /* pick correct index */ - if (level < path_len && !path_nulls[level]) - { - char *c = TextDatumGetCString(path_elems[level]); - char *badp; - long val; - - errno = 0; - val = strtol(c, &badp, 10); - if (errno != 0 || badp == c || badp[0] != '\0' || val > INT_MAX || - val < INT_MIN) - ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("path element at position %d is not an integer: \"%s\"", - level + 1, c))); - idx = val; - } - else - idx = nelems; - - if (idx < 0) - { - if (-idx > nelems) - { - /* - * If asked to keep elements position consistent, it's not allowed - * to prepend the array. - */ - if (op_type & JB_PATH_CONSISTENT_POSITION) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("path element at position %d is out of range: %d", - level + 1, idx))); - else - idx = INT_MIN; - } - else - idx = nelems + idx; - } - - /* - * Filling the gaps means there are no limits on the positive index are - * imposed, we can set any element. Otherwise limit the index by nelems. - */ - if (!(op_type & JB_PATH_FILL_GAPS)) - { - if (idx > 0 && idx > nelems) - idx = nelems; - } - - /* - * if we're creating, and idx == INT_MIN, we prepend the new value to the - * array also if the array is empty - in which case we don't really care - * what the idx value is - */ - if ((idx == INT_MIN || nelems == 0) && (level == path_len - 1) && - (op_type & JB_PATH_CREATE_OR_INSERT)) - { - Assert(newval != NULL); + (void) pushJsonbValue(st, WJB_KEY, &newkey); addJsonbToParseState(st, newval); - done = true; - } + } - /* iterate over the array elements */ - for (i = 0; i < nelems; i++) - { - int r; + for (i = 0; i < npairs; i++) { + int r = JsonbIteratorNext(it, &k, true); - if (i == idx && level < path_len) - { - done = true; + Assert(r == WJB_KEY); - if (level == path_len - 1) - { - r = JsonbIteratorNext(it, &v, true); /* skip */ + if (!done && k.string.len == VARSIZE_ANY_EXHDR(pathelem) && + memcmp(k.string.val, VARDATA_ANY(pathelem), k.string.len) == 0) { + done = true; - if (op_type & (JB_PATH_INSERT_BEFORE | JB_PATH_CREATE)) - addJsonbToParseState(st, newval); + if (level == path_len - 1) { + /* + * called from jsonb_insert(), it forbids redefining an + * existing value + */ + if (op_type & (JB_PATH_INSERT_BEFORE | JB_PATH_INSERT_AFTER)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("cannot replace existing key"), + errhint("Try using the function jsonb_set " + "to replace key value."))); - /* - * We should keep current value only in case of - * JB_PATH_INSERT_BEFORE or JB_PATH_INSERT_AFTER because - * otherwise it should be deleted or replaced - */ - if (op_type & (JB_PATH_INSERT_AFTER | JB_PATH_INSERT_BEFORE)) - (void) pushJsonbValue(st, r, &v); + r = JsonbIteratorNext(it, &v, true); /* skip value */ + if (!(op_type & JB_PATH_DELETE)) { + (void) pushJsonbValue(st, WJB_KEY, &k); + addJsonbToParseState(st, newval); + } + } else { + (void) pushJsonbValue(st, r, &k); + setPath(it, path_elems, path_nulls, path_len, + st, level + 1, newval, op_type); + } + } else { + if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done && level == path_len - 1 && i == npairs - 1) { + JsonbValue newkey; - if (op_type & (JB_PATH_INSERT_AFTER | JB_PATH_REPLACE)) - addJsonbToParseState(st, newval); - } - else - (void) setPath(it, path_elems, path_nulls, path_len, - st, level + 1, newval, op_type); - } - else - { - r = JsonbIteratorNext(it, &v, false); + newkey.type = jbvString; + newkey.string.val = VARDATA_ANY(pathelem); + newkey.string.len = VARSIZE_ANY_EXHDR(pathelem); - (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL); + (void) pushJsonbValue(st, WJB_KEY, &newkey); + addJsonbToParseState(st, newval); + } - if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT) - { - int walking_level = 1; + (void) pushJsonbValue(st, r, &k); + r = JsonbIteratorNext(it, &v, false); + (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL); + if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT) { + int walking_level = 1; - while (walking_level != 0) - { - r = JsonbIteratorNext(it, &v, false); + while (walking_level != 0) { + r = JsonbIteratorNext(it, &v, false); - if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT) - ++walking_level; - if (r == WJB_END_ARRAY || r == WJB_END_OBJECT) - --walking_level; + if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT) + ++walking_level; + if (r == WJB_END_ARRAY || r == WJB_END_OBJECT) + --walking_level; - (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL); - } - } - } - } - - if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done && level == path_len - 1) - { - /* - * If asked to fill the gaps, idx could be bigger than nelems, so - * prepend the new element with nulls if that's the case. - */ - if (op_type & JB_PATH_FILL_GAPS && idx > nelems) - push_null_elements(st, idx - nelems); - - addJsonbToParseState(st, newval); - done = true; - } + (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL); + } + } + } + } } /* - * SQL function jsonb_insert(jsonb, text[], jsonb, boolean) - */ +* Array walker for setPath +*/ +static void setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, + int path_len, JsonbParseState **st, int level, Jsonb *newval, uint32 nelems, int op_type) +{ + JsonbValue v; + int idx, + i; + bool done = false; + + /* pick correct index */ + if (level < path_len && !path_nulls[level]) { + char *c = TextDatumGetCString(path_elems[level]); + char *badp; + long val; + + errno = 0; + val = strtol(c, &badp, 10); + if (errno != 0 || badp == c || badp[0] != '\0' || val > INT_MAX || + val < INT_MIN) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("path element at position %d is not an integer: \"%s\"", + level + 1, c))); + idx = val; + } else + idx = nelems; + + if (idx < 0) { + if (-idx > nelems) { + /* + * If asked to keep elements position consistent, it's not allowed + * to prepend the array. + */ + if (op_type & JB_PATH_CONSISTENT_POSITION) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("path element at position %d is out of range: %d", + level + 1, idx))); + else + idx = INT_MIN; + } else + idx = nelems + idx; + } + + /* + * Filling the gaps means there are no limits on the positive index are + * imposed, we can set any element. Otherwise limit the index by nelems. + */ + if (!(op_type & JB_PATH_FILL_GAPS)) { + if (idx > 0 && idx > nelems) + idx = nelems; + } + + /* + * if we're creating, and idx == INT_MIN, we prepend the new value to the + * array also if the array is empty - in which case we don't really care + * what the idx value is + */ + if ((idx == INT_MIN || nelems == 0) && (level == path_len - 1) && (op_type & JB_PATH_CREATE_OR_INSERT)) { + Assert(newval != NULL); + addJsonbToParseState(st, newval); + done = true; + } + + /* iterate over the array elements */ + for (i = 0; i < nelems; i++) { + int r; + + if (i == idx && level < path_len) { + done = true; + + if (level == path_len - 1) { + r = JsonbIteratorNext(it, &v, true); /* skip */ + + if (op_type & (JB_PATH_INSERT_BEFORE | JB_PATH_CREATE)) + addJsonbToParseState(st, newval); + + /* + * We should keep current value only in case of + * JB_PATH_INSERT_BEFORE or JB_PATH_INSERT_AFTER because + * otherwise it should be deleted or replaced + */ + if (op_type & (JB_PATH_INSERT_AFTER | JB_PATH_INSERT_BEFORE)) + (void) pushJsonbValue(st, r, &v); + + if (op_type & (JB_PATH_INSERT_AFTER | JB_PATH_REPLACE)) + addJsonbToParseState(st, newval); + } else + (void) setPath(it, path_elems, path_nulls, path_len, st, level + 1, newval, op_type); + } else { + r = JsonbIteratorNext(it, &v, false); + + (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL); + + if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT) { + int walking_level = 1; + + while (walking_level != 0) { + r = JsonbIteratorNext(it, &v, false); + + if (r == WJB_BEGIN_ARRAY || r == WJB_BEGIN_OBJECT) + ++walking_level; + if (r == WJB_END_ARRAY || r == WJB_END_OBJECT) + --walking_level; + + (void) pushJsonbValue(st, r, r < WJB_BEGIN_ARRAY ? &v : NULL); + } + } + } + } + + if ((op_type & JB_PATH_CREATE_OR_INSERT) && !done && level == path_len - 1) { + /* + * If asked to fill the gaps, idx could be bigger than nelems, so + * prepend the new element with nulls if that's the case. + */ + if (op_type & JB_PATH_FILL_GAPS && idx > nelems) + push_null_elements(st, idx - nelems); + + addJsonbToParseState(st, newval); + done = true; + } +} + +/* +* SQL function jsonb_insert(jsonb, text[], jsonb, boolean) +*/ Datum jsonb_insert(PG_FUNCTION_ARGS) { - Jsonb *in = PG_GETARG_JSONB(0); - ArrayType *path = PG_GETARG_ARRAYTYPE_P(1); - Jsonb *newjsonb = PG_GETARG_JSONB(2); - bool after = PG_GETARG_BOOL(3); - JsonbValue *res = NULL; - Datum *path_elems; - bool *path_nulls; - int path_len; - JsonbIterator *it; - JsonbParseState *st = NULL; + Jsonb *in = PG_GETARG_JSONB(0); + ArrayType *path = PG_GETARG_ARRAYTYPE_P(1); + Jsonb *newjsonb = PG_GETARG_JSONB(2); + bool after = PG_GETARG_BOOL(3); + JsonbValue *res = NULL; + Datum *path_elems; + bool *path_nulls; + int path_len; + JsonbIterator *it; + JsonbParseState *st = NULL; - if (ARR_NDIM(path) > 1) - ereport(ERROR, - (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("wrong number of array subscripts"))); + if (ARR_NDIM(path) > 1) + ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("wrong number of array subscripts"))); - if (JB_ROOT_IS_SCALAR(in)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("cannot set path in scalar"))); + if (JB_ROOT_IS_SCALAR(in)) + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("cannot set path in scalar"))); - deconstruct_array(path, TEXTOID, -1, false, 'i', &path_elems, &path_nulls, &path_len); + deconstruct_array(path, TEXTOID, -1, false, 'i', &path_elems, &path_nulls, &path_len); - if (path_len == 0) - PG_RETURN_JSONB(in); + if (path_len == 0) + PG_RETURN_JSONB(in); - it = JsonbIteratorInit(VARDATA(in)); + it = JsonbIteratorInit(VARDATA(in)); - res = setPath(&it, path_elems, path_nulls, path_len, &st, 0, newjsonb, - after ? JB_PATH_INSERT_AFTER : JB_PATH_INSERT_BEFORE); + res = setPath(&it, path_elems, path_nulls, path_len, &st, 0, newjsonb, + after ? JB_PATH_INSERT_AFTER : JB_PATH_INSERT_BEFORE); - Assert(res != NULL); + Assert(res != NULL); - PG_RETURN_JSONB(JsonbValueToJsonb(res)); + PG_RETURN_JSONB(JsonbValueToJsonb(res)); } /* - * SQL function jsonb_delete (jsonb, text) - * - * return a copy of the jsonb with the indicated item - * removed. - */ -Datum -jsonb_delete(PG_FUNCTION_ARGS) +* SQL function jsonb_delete (jsonb, text) +* +* return a copy of the jsonb with the indicated item +* removed. +*/ +Datum jsonb_delete(PG_FUNCTION_ARGS) { - Jsonb *in = PG_GETARG_JSONB(0); - text *key = PG_GETARG_TEXT_PP(1); - char *keyptr = VARDATA_ANY(key); - int keylen = VARSIZE_ANY_EXHDR(key); - JsonbParseState *state = NULL; - JsonbIterator *it; - JsonbValue v, - *res = NULL; - bool skipNested = false; - int r; + Jsonb *in = PG_GETARG_JSONB(0); + text *key = PG_GETARG_TEXT_PP(1); + char *keyptr = VARDATA_ANY(key); + int keylen = VARSIZE_ANY_EXHDR(key); + JsonbParseState *state = NULL; + JsonbIterator *it; + JsonbValue v, *res = NULL; + bool skipNested = false; + int r; - if (JB_ROOT_IS_SCALAR(in)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("cannot delete from scalar"))); + if (JB_ROOT_IS_SCALAR(in)) + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("cannot delete from scalar"))); - if (JB_ROOT_COUNT(in) == 0) - PG_RETURN_JSONB(in); + if (JB_ROOT_COUNT(in) == 0) + PG_RETURN_JSONB(in); - it = JsonbIteratorInit(VARDATA(in)); + it = JsonbIteratorInit(VARDATA(in)); - while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE) - { - skipNested = true; + while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE) { + skipNested = true; - if ((r == WJB_ELEM || r == WJB_KEY) && - (v.type == jbvString && keylen == v.string.len && - memcmp(keyptr, v.string.val, keylen) == 0)) - { - /* skip corresponding value as well */ - if (r == WJB_KEY) - (void) JsonbIteratorNext(&it, &v, true); + if ((r == WJB_ELEM || r == WJB_KEY) && (v.type == jbvString && keylen == v.string.len && + memcmp(keyptr, v.string.val, keylen) == 0)) { + /* skip corresponding value as well */ + if (r == WJB_KEY) + (void) JsonbIteratorNext(&it, &v, true); - continue; - } + continue; + } - res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL); - } + res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL); + } - Assert(res != NULL); + Assert(res != NULL); - PG_RETURN_JSONB(JsonbValueToJsonb(res)); + PG_RETURN_JSONB(JsonbValueToJsonb(res)); } /* - * SQL function jsonb_delete (jsonb, variadic text[]) - * - * return a copy of the jsonb with the indicated items - * removed. - */ +* SQL function jsonb_delete (jsonb, variadic text[]) +* +* return a copy of the jsonb with the indicated items +* removed. +*/ Datum jsonb_delete_array(PG_FUNCTION_ARGS) { - Jsonb *in = PG_GETARG_JSONB(0); - ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1); - Datum *keys_elems; - bool *keys_nulls; - int keys_len; - JsonbParseState *state = NULL; - JsonbIterator *it; - JsonbValue v, - *res = NULL; - bool skipNested = false; - int r; + Jsonb *in = PG_GETARG_JSONB(0); + ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1); + Datum *keys_elems; + bool *keys_nulls; + int keys_len; + JsonbParseState *state = NULL; + JsonbIterator *it; + JsonbValue v, *res = NULL; + bool skipNested = false; + int r; - if (ARR_NDIM(keys) > 1) - ereport(ERROR, - (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("wrong number of array subscripts"))); + if (ARR_NDIM(keys) > 1) + ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("wrong number of array subscripts"))); - if (JB_ROOT_IS_SCALAR(in)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("cannot delete from scalar"))); + if (JB_ROOT_IS_SCALAR(in)) + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("cannot delete from scalar"))); - if (JB_ROOT_COUNT(in) == 0) - PG_RETURN_JSONB(in); + if (JB_ROOT_COUNT(in) == 0) + PG_RETURN_JSONB(in); - deconstruct_array(keys, TEXTOID, -1, false, 'i', &keys_elems, &keys_nulls, &keys_len); + deconstruct_array(keys, TEXTOID, -1, false, 'i', &keys_elems, &keys_nulls, &keys_len); - if (keys_len == 0) - PG_RETURN_JSONB(in); + if (keys_len == 0) + PG_RETURN_JSONB(in); - it = JsonbIteratorInit(VARDATA(in)); + it = JsonbIteratorInit(VARDATA(in)); - while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE) - { - skipNested = true; + while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE) { + skipNested = true; - if ((r == WJB_ELEM || r == WJB_KEY) && v.type == jbvString) - { - int i; - bool found = false; + if ((r == WJB_ELEM || r == WJB_KEY) && v.type == jbvString) { + int i; + bool found = false; - for (i = 0; i < keys_len; i++) - { - char *keyptr; - int keylen; + for (i = 0; i < keys_len; i++) { + char *keyptr; + int keylen; - if (keys_nulls[i]) - continue; + if (keys_nulls[i]) + continue; - /* We rely on the array elements not being toasted */ - keyptr = VARDATA_ANY(keys_elems[i]); - keylen = VARSIZE_ANY_EXHDR(keys_elems[i]); - if (keylen == v.string.len && - memcmp(keyptr, v.string.val, keylen) == 0) - { - found = true; - break; - } - } - if (found) - { - /* skip corresponding value as well */ - if (r == WJB_KEY) - (void) JsonbIteratorNext(&it, &v, true); + /* We rely on the array elements not being toasted */ + keyptr = VARDATA_ANY(keys_elems[i]); + keylen = VARSIZE_ANY_EXHDR(keys_elems[i]); + if (keylen == v.string.len && + memcmp(keyptr, v.string.val, keylen) == 0) + { + found = true; + break; + } + } + if (found) { + /* skip corresponding value as well */ + if (r == WJB_KEY) + (void) JsonbIteratorNext(&it, &v, true); - continue; - } - } + continue; + } + } - res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL); - } + res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL); + } - Assert(res != NULL); + Assert(res != NULL); - PG_RETURN_JSONB(JsonbValueToJsonb(res)); + PG_RETURN_JSONB(JsonbValueToJsonb(res)); } /* - * SQL function jsonb_delete (jsonb, int) - * - * return a copy of the jsonb with the indicated item - * removed. Negative int means count back from the - * end of the items. - */ -Datum -jsonb_delete_idx(PG_FUNCTION_ARGS) +* SQL function jsonb_delete (jsonb, int) +* +* return a copy of the jsonb with the indicated item +* removed. Negative int means count back from the +* end of the items. +*/ +Datum jsonb_delete_idx(PG_FUNCTION_ARGS) { - Jsonb *in = PG_GETARG_JSONB(0); - int idx = PG_GETARG_INT32(1); - JsonbParseState *state = NULL; - JsonbIterator *it; - uint32 i = 0, - n; - JsonbValue v, - *res = NULL; - int r; + Jsonb *in = PG_GETARG_JSONB(0); + int idx = PG_GETARG_INT32(1); + JsonbParseState *state = NULL; + JsonbIterator *it; + uint32 i = 0, + n; + JsonbValue v, + *res = NULL; + int r; - if (JB_ROOT_IS_SCALAR(in)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("cannot delete from scalar"))); + if (JB_ROOT_IS_SCALAR(in)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("cannot delete from scalar"))); - if (JB_ROOT_IS_OBJECT(in)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("cannot delete from object using integer index"))); + if (JB_ROOT_IS_OBJECT(in)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("cannot delete from object using integer index"))); - if (JB_ROOT_COUNT(in) == 0) - PG_RETURN_JSONB(in); + if (JB_ROOT_COUNT(in) == 0) + PG_RETURN_JSONB(in); - it = JsonbIteratorInit(VARDATA(in)); + it = JsonbIteratorInit(VARDATA(in)); - r = JsonbIteratorNext(&it, &v, false); - Assert(r == WJB_BEGIN_ARRAY); - n = v.array.nElems; + r = JsonbIteratorNext(&it, &v, false); + Assert(r == WJB_BEGIN_ARRAY); + n = v.array.nElems; - if (idx < 0) - { - if (-idx > n) - idx = n; - else - idx = n + idx; - } + if (idx < 0) { + if (-idx > n) + idx = n; + else + idx = n + idx; + } - if (idx >= n) - PG_RETURN_JSONB(in); + if (idx >= n) + PG_RETURN_JSONB(in); - pushJsonbValue(&state, r, NULL); + pushJsonbValue(&state, r, NULL); - while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE) - { - if (r == WJB_ELEM) - { - if (i++ == idx) - continue; - } + while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE) + { + if (r == WJB_ELEM) { + if (i++ == idx) + continue; + } - res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL); - } + res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL); + } - Assert(res != NULL); + Assert(res != NULL); - PG_RETURN_JSONB(JsonbValueToJsonb(res)); + PG_RETURN_JSONB(JsonbValueToJsonb(res)); } /* - * SQL function jsonb_set(jsonb, text[], jsonb, boolean) - */ +* SQL function jsonb_set(jsonb, text[], jsonb, boolean) +*/ Datum jsonb_set(PG_FUNCTION_ARGS) { - Jsonb *in = PG_GETARG_JSONB(0); - ArrayType *path = PG_GETARG_ARRAYTYPE_P(1); - Jsonb *newjsonb = PG_GETARG_JSONB(2); - bool create = PG_GETARG_BOOL(3); - JsonbValue *res = NULL; - Datum *path_elems; - bool *path_nulls; - int path_len; - JsonbIterator *it; - JsonbParseState *st = NULL; + Jsonb *in = PG_GETARG_JSONB(0); + ArrayType *path = PG_GETARG_ARRAYTYPE_P(1); + Jsonb *newjsonb = PG_GETARG_JSONB(2); + bool create = PG_GETARG_BOOL(3); + JsonbValue *res = NULL; + Datum *path_elems; + bool *path_nulls; + int path_len; + JsonbIterator *it; + JsonbParseState *st = NULL; - if (ARR_NDIM(path) > 1) - ereport(ERROR, - (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("wrong number of array subscripts"))); + if (ARR_NDIM(path) > 1) + ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("wrong number of array subscripts"))); - if (JB_ROOT_IS_SCALAR(in)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("cannot set path in scalar"))); + if (JB_ROOT_IS_SCALAR(in)) + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("cannot set path in scalar"))); - if (JB_ROOT_COUNT(in) == 0 && !create) - PG_RETURN_JSONB(in); + if (JB_ROOT_COUNT(in) == 0 && !create) + PG_RETURN_JSONB(in); - deconstruct_array(path, TEXTOID, -1, false, 'i', &path_elems, &path_nulls, &path_len); + deconstruct_array(path, TEXTOID, -1, false, 'i', &path_elems, &path_nulls, &path_len); - if (path_len == 0) - PG_RETURN_JSONB(in); + if (path_len == 0) + PG_RETURN_JSONB(in); - it = JsonbIteratorInit(VARDATA(in)); + it = JsonbIteratorInit(VARDATA(in)); - res = setPath(&it, path_elems, path_nulls, path_len, &st, - 0, newjsonb, create ? JB_PATH_CREATE : JB_PATH_REPLACE); + res = setPath(&it, path_elems, path_nulls, path_len, &st, 0, newjsonb, create ? JB_PATH_CREATE : JB_PATH_REPLACE); - Assert(res != NULL); + Assert(res != NULL); - PG_RETURN_JSONB(JsonbValueToJsonb(res)); + PG_RETURN_JSONB(JsonbValueToJsonb(res)); }