From ff7bbb0176a667aeb0577e4d48d651ffdb6afd50 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Fri, 9 May 2014 13:09:59 +0300 Subject: [PATCH] Minor cleanup of jsonb_util.c Move the functions around to group related functions together. Remove binequal argument from lengthCompareJsonbStringValue, moving that responsibility to lengthCompareJsonbPair. Fix typo in comment. --- src/backend/utils/adt/jsonb_util.c | 378 ++++++++++++++--------------- 1 file changed, 187 insertions(+), 191 deletions(-) diff --git a/src/backend/utils/adt/jsonb_util.c b/src/backend/utils/adt/jsonb_util.c index f6d6fab74e..d454cd78ba 100644 --- a/src/backend/utils/adt/jsonb_util.c +++ b/src/backend/utils/adt/jsonb_util.c @@ -68,7 +68,7 @@ static JsonbParseState *pushState(JsonbParseState **pstate); static void appendKey(JsonbParseState *pstate, JsonbValue *scalarVal); static void appendValue(JsonbParseState *pstate, JsonbValue *scalarVal); static void appendElement(JsonbParseState *pstate, JsonbValue *scalarVal); -static int lengthCompareJsonbStringValue(const void *a, const void *b, void *arg); +static int lengthCompareJsonbStringValue(const void *a, const void *b); static int lengthCompareJsonbPair(const void *a, const void *b, void *arg); static void uniqueifyJsonbObject(JsonbValue *object); @@ -329,7 +329,7 @@ findJsonbValueFromContainer(JsonbContainer *container, uint32 flags, candidate.val.string.val = data + JBE_OFF(*entry); candidate.val.string.len = JBE_LEN(*entry); - difference = lengthCompareJsonbStringValue(&candidate, key, NULL); + difference = lengthCompareJsonbStringValue(&candidate, key); if (difference == 0) { @@ -533,6 +533,86 @@ pushJsonbValue(JsonbParseState **pstate, JsonbIteratorToken seq, return result; } +/* + * pushJsonbValue() worker: Iteration-like forming of Jsonb + */ +static JsonbParseState * +pushState(JsonbParseState **pstate) +{ + JsonbParseState *ns = palloc(sizeof(JsonbParseState)); + + ns->next = *pstate; + return ns; +} + +/* + * pushJsonbValue() worker: Append a pair key to state when generating a Jsonb + */ +static void +appendKey(JsonbParseState *pstate, JsonbValue *string) +{ + JsonbValue *object = &pstate->contVal; + + Assert(object->type == jbvObject); + Assert(string->type == jbvString); + + if (object->val.object.nPairs >= JSONB_MAX_PAIRS) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("number of jsonb object pairs exceeds the maximum allowed (%zu)", + JSONB_MAX_PAIRS))); + + if (object->val.object.nPairs >= pstate->size) + { + pstate->size *= 2; + object->val.object.pairs = repalloc(object->val.object.pairs, + sizeof(JsonbPair) * pstate->size); + } + + object->val.object.pairs[object->val.object.nPairs].key = *string; + object->val.object.pairs[object->val.object.nPairs].order = object->val.object.nPairs; +} + +/* + * pushJsonbValue() worker: Append a pair value to state when generating a + * Jsonb + */ +static void +appendValue(JsonbParseState *pstate, JsonbValue *scalarVal) +{ + JsonbValue *object = &pstate->contVal; + + Assert(object->type == jbvObject); + + object->val.object.pairs[object->val.object.nPairs++].value = *scalarVal; +} + +/* + * pushJsonbValue() worker: Append an element to state when generating a Jsonb + */ +static void +appendElement(JsonbParseState *pstate, JsonbValue *scalarVal) +{ + JsonbValue *array = &pstate->contVal; + + Assert(array->type == jbvArray); + + if (array->val.array.nElems >= JSONB_MAX_ELEMS) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("number of jsonb array elements exceeds the maximum allowed (%zu)", + JSONB_MAX_ELEMS))); + + if (array->val.array.nElems >= pstate->size) + { + pstate->size *= 2; + array->val.array.elems = repalloc(array->val.array.elems, + sizeof(JsonbValue) * pstate->size); + } + + array->val.array.elems[array->val.array.nElems++] = *scalarVal; +} + /* * Given a JsonbContainer, expand to JsonbIterator to iterate over items * fully expanded to in-memory representation for manipulation. @@ -709,6 +789,101 @@ JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested) return -1; } +/* + * Initialize an iterator for iterating all elements in a container. + */ +static void +iteratorFromContainer(JsonbIterator *it, JsonbContainer *container) +{ + it->containerType = container->header & (JB_FARRAY | JB_FOBJECT); + it->nElems = container->header & JB_CMASK; + it->buffer = (char *) container; + + /* Array starts just after header */ + it->meta = container->children; + it->state = jbi_start; + + switch (it->containerType) + { + case JB_FARRAY: + it->dataProper = + (char *) it->meta + it->nElems * sizeof(JEntry); + it->isScalar = (container->header & JB_FSCALAR) != 0; + /* This is either a "raw scalar", or an array */ + Assert(!it->isScalar || it->nElems == 1); + break; + case JB_FOBJECT: + + /* + * Offset reflects that nElems indicates JsonbPairs in an object. + * Each key and each value contain Jentry metadata just the same. + */ + it->dataProper = + (char *) it->meta + it->nElems * sizeof(JEntry) * 2; + break; + default: + elog(ERROR, "unknown type of jsonb container"); + } +} + +/* + * JsonbIteratorNext() worker + * + * Returns bool indicating if v was a non-jbvBinary container, and thus if + * further recursion is required by caller (according to its skipNested + * preference). If it is required, we set the caller's iterator for further + * recursion into the nested value. If we're going to skip nested items, just + * set v to a jbvBinary value, but don't set caller's iterator. + * + * Unlike with containers (either in this function or in any + * JsonbIteratorNext() infrastructure), we fully convert from what is + * ultimately a Jsonb on-disk representation, to a JsonbValue in-memory + * representation (for scalar values only). JsonbIteratorNext() initializes + * container Jsonbvalues, but without a sane private buffer. For scalar values + * it has to be done for real (even if we don't actually allocate more memory + * to do this. The point is that our JsonbValues scalars can be passed around + * anywhere). + */ +static bool +formIterIsContainer(JsonbIterator **it, JsonbValue *val, JEntry *ent, + bool skipNested) +{ + fillJsonbValue(ent, (*it)->dataProper, val); + + if (IsAJsonbScalar(val) || skipNested) + return false; + else + { + /* + * It's a container type, so setup caller's iterator to point to + * that, and return indication of that. + * + * Get child iterator. + */ + JsonbIterator *child = palloc(sizeof(JsonbIterator)); + + iteratorFromContainer(child, val->val.binary.data); + + child->parent = *it; + *it = child; + + return true; + } +} + +/* + * JsonbIteratorNext() worker: Return parent, while freeing memory for current + * iterator + */ +static JsonbIterator * +freeAndGetParent(JsonbIterator *it) +{ + JsonbIterator *v = it->parent; + + pfree(it); + return v; +} + /* * Worker for "contains" operator's function * @@ -1015,7 +1190,7 @@ compareJsonbScalarValue(JsonbValue *aScalar, JsonbValue *bScalar) case jbvNull: return 0; case jbvString: - return lengthCompareJsonbStringValue(aScalar, bScalar, NULL); + return lengthCompareJsonbStringValue(aScalar, bScalar); case jbvNumeric: return DatumGetInt32(DirectFunctionCall2(numeric_cmp, PointerGetDatum(aScalar->val.numeric), @@ -1059,7 +1234,7 @@ lexicalCompareJsonbStringValue(const void *a, const void *b) */ /* - * Rervere 'len' bytes, at the end of the buffer, enlarging it if necessary. + * Reserve 'len' bytes, at the end of the buffer, enlarging it if necessary. * Returns the offset to the reserved area. The caller is expected to copy * the data to the reserved area later with copyToBuffer() */ @@ -1367,181 +1542,6 @@ convertJsonbScalar(convertState *buffer, JEntry *jentry, JsonbValue *scalarVal) } } -/* - * Initialize an iterator for iterating all elements in a container. - */ -static void -iteratorFromContainer(JsonbIterator *it, JsonbContainer *container) -{ - it->containerType = container->header & (JB_FARRAY | JB_FOBJECT); - it->nElems = container->header & JB_CMASK; - it->buffer = (char *) container; - - /* Array starts just after header */ - it->meta = container->children; - it->state = jbi_start; - - switch (it->containerType) - { - case JB_FARRAY: - it->dataProper = - (char *) it->meta + it->nElems * sizeof(JEntry); - it->isScalar = (container->header & JB_FSCALAR) != 0; - /* This is either a "raw scalar", or an array */ - Assert(!it->isScalar || it->nElems == 1); - break; - case JB_FOBJECT: - - /* - * Offset reflects that nElems indicates JsonbPairs in an object. - * Each key and each value contain Jentry metadata just the same. - */ - it->dataProper = - (char *) it->meta + it->nElems * sizeof(JEntry) * 2; - break; - default: - elog(ERROR, "unknown type of jsonb container"); - } -} - -/* - * JsonbIteratorNext() worker - * - * Returns bool indicating if v was a non-jbvBinary container, and thus if - * further recursion is required by caller (according to its skipNested - * preference). If it is required, we set the caller's iterator for further - * recursion into the nested value. If we're going to skip nested items, just - * set v to a jbvBinary value, but don't set caller's iterator. - * - * Unlike with containers (either in this function or in any - * JsonbIteratorNext() infrastructure), we fully convert from what is - * ultimately a Jsonb on-disk representation, to a JsonbValue in-memory - * representation (for scalar values only). JsonbIteratorNext() initializes - * container Jsonbvalues, but without a sane private buffer. For scalar values - * it has to be done for real (even if we don't actually allocate more memory - * to do this. The point is that our JsonbValues scalars can be passed around - * anywhere). - */ -static bool -formIterIsContainer(JsonbIterator **it, JsonbValue *val, JEntry *ent, - bool skipNested) -{ - fillJsonbValue(ent, (*it)->dataProper, val); - - if (IsAJsonbScalar(val) || skipNested) - return false; - else - { - /* - * It's a container type, so setup caller's iterator to point to - * that, and return indication of that. - * - * Get child iterator. - */ - JsonbIterator *child = palloc(sizeof(JsonbIterator)); - - iteratorFromContainer(child, val->val.binary.data); - - child->parent = *it; - *it = child; - - return true; - } -} - -/* - * JsonbIteratorNext() worker: Return parent, while freeing memory for current - * iterator - */ -static JsonbIterator * -freeAndGetParent(JsonbIterator *it) -{ - JsonbIterator *v = it->parent; - - pfree(it); - return v; -} - -/* - * pushJsonbValue() worker: Iteration-like forming of Jsonb - */ -static JsonbParseState * -pushState(JsonbParseState **pstate) -{ - JsonbParseState *ns = palloc(sizeof(JsonbParseState)); - - ns->next = *pstate; - return ns; -} - -/* - * pushJsonbValue() worker: Append a pair key to state when generating a Jsonb - */ -static void -appendKey(JsonbParseState *pstate, JsonbValue *string) -{ - JsonbValue *object = &pstate->contVal; - - Assert(object->type == jbvObject); - Assert(string->type == jbvString); - - if (object->val.object.nPairs >= JSONB_MAX_PAIRS) - ereport(ERROR, - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("number of jsonb object pairs exceeds the maximum allowed (%zu)", - JSONB_MAX_PAIRS))); - - if (object->val.object.nPairs >= pstate->size) - { - pstate->size *= 2; - object->val.object.pairs = repalloc(object->val.object.pairs, - sizeof(JsonbPair) * pstate->size); - } - - object->val.object.pairs[object->val.object.nPairs].key = *string; - object->val.object.pairs[object->val.object.nPairs].order = object->val.object.nPairs; -} - -/* - * pushJsonbValue() worker: Append a pair value to state when generating a - * Jsonb - */ -static void -appendValue(JsonbParseState *pstate, JsonbValue *scalarVal) -{ - JsonbValue *object = &pstate->contVal; - - Assert(object->type == jbvObject); - - object->val.object.pairs[object->val.object.nPairs++].value = *scalarVal; -} - -/* - * pushJsonbValue() worker: Append an element to state when generating a Jsonb - */ -static void -appendElement(JsonbParseState *pstate, JsonbValue *scalarVal) -{ - JsonbValue *array = &pstate->contVal; - - Assert(array->type == jbvArray); - - if (array->val.array.nElems >= JSONB_MAX_ELEMS) - ereport(ERROR, - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("number of jsonb array elements exceeds the maximum allowed (%zu)", - JSONB_MAX_ELEMS))); - - if (array->val.array.nElems >= pstate->size) - { - pstate->size *= 2; - array->val.array.elems = repalloc(array->val.array.elems, - sizeof(JsonbValue) * pstate->size); - } - - array->val.array.elems[array->val.array.nElems++] = *scalarVal; -} - /* * Compare two jbvString JsonbValue values, a and b. * @@ -1553,13 +1553,9 @@ appendElement(JsonbParseState *pstate, JsonbValue *scalarVal) * * a and b are first sorted based on their length. If a tie-breaker is * required, only then do we consider string binary equality. - * - * Third argument 'binequal' may point to a bool. If it's set, *binequal is set - * to true iff a and b have full binary equality, since some callers have an - * interest in whether the two values are equal or merely equivalent. */ static int -lengthCompareJsonbStringValue(const void *a, const void *b, void *binequal) +lengthCompareJsonbStringValue(const void *a, const void *b) { const JsonbValue *va = (const JsonbValue *) a; const JsonbValue *vb = (const JsonbValue *) b; @@ -1571,8 +1567,6 @@ lengthCompareJsonbStringValue(const void *a, const void *b, void *binequal) if (va->val.string.len == vb->val.string.len) { res = memcmp(va->val.string.val, vb->val.string.val, va->val.string.len); - if (res == 0 && binequal) - *((bool *) binequal) = true; } else { @@ -1585,9 +1579,9 @@ lengthCompareJsonbStringValue(const void *a, const void *b, void *binequal) /* * qsort_arg() comparator to compare JsonbPair values. * - * Function implemented in terms of lengthCompareJsonbStringValue(), and thus the - * same "arg setting" hack will be applied here in respect of the pair's key - * values. + * Third argument 'binequal' may point to a bool. If it's set, *binequal is set + * to true iff a and b have full binary equality, since some callers have an + * interest in whether the two values are equal or merely equivalent. * * N.B: String comparisons here are "length-wise" * @@ -1600,7 +1594,9 @@ lengthCompareJsonbPair(const void *a, const void *b, void *binequal) const JsonbPair *pb = (const JsonbPair *) b; int res; - res = lengthCompareJsonbStringValue(&pa->key, &pb->key, binequal); + res = lengthCompareJsonbStringValue(&pa->key, &pb->key); + if (res == 0 && binequal) + *((bool *) binequal) = true; /* * Guarantee keeping order of equal pair. Unique algorithm will prefer @@ -1634,7 +1630,7 @@ uniqueifyJsonbObject(JsonbValue *object) while (ptr - object->val.object.pairs < object->val.object.nPairs) { /* Avoid copying over duplicate */ - if (lengthCompareJsonbStringValue(ptr, res, NULL) != 0) + if (lengthCompareJsonbStringValue(ptr, res) != 0) { res++; if (ptr != res)