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)