Minor cleanup of jsonb_util.c
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Fri, 9 May 2014 10:09:59 +0000 (13:09 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Fri, 9 May 2014 10:09:59 +0000 (13:09 +0300)
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

index f6d6fab74e813ca1aba2c5c5a960f5f6de1114a0..d454cd78ba8f9d91301dc6d75e186f6350f70b86 100644 (file)
@@ -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)