Polish conversion functions
authorPeter Geoghegan <pg@heroku.com>
Wed, 19 Mar 2014 07:30:28 +0000 (00:30 -0700)
committerPeter Geoghegan <pg@heroku.com>
Wed, 19 Mar 2014 07:30:28 +0000 (00:30 -0700)
src/backend/utils/adt/jsonb_util.c

index 3cb05426c74dbb2fbd15be7679baf25159fa5b24..6e45031de799181d677ce99acb0142432ed5c01e 100644 (file)
  */
 typedef struct convertLevel
 {
-   uint32      i;
-   uint32     *header;
-   JEntry     *meta;
-   char       *begin;
+   uint32      i;      /* "nElems-wise" iterator (i.e. iterates once per pair) */
+   uint32     *header; /* Pointer to current container header */
+   JEntry     *meta;   /* This level's metadata */
+   char       *begin;  /* Pointer into convertState.buffer */
 } convertLevel;
 
 typedef struct convertState
@@ -57,7 +57,7 @@ static void walkJsonbValueConversion(JsonbValue * value, convertState * state,
                                     uint32 nestlevel);
 static void putJsonbValueConversion(convertState * state, JsonbValue * value,
                                    uint32 flags, uint32 level);
-static void putStringConversion(convertState * state, JsonbValue * value,
+static void putScalarConversion(convertState * state, JsonbValue * value,
                                uint32 level, uint32 i);
 static void iteratorFromContainerBuf(JsonbIterator * it, char *buffer);
 static bool formIterIsContainer(JsonbIterator ** it, JsonbValue * v,
@@ -1122,7 +1122,11 @@ convertJsonb(JsonbValue * v, Jsonb *buffer)
 
 /*
  * Walk the tree representation of Jsonb, as part of the process of converting
- * a JsonbValue to a Jsonb
+ * a JsonbValue to a Jsonb.
+ *
+ * This high-level traffic cop function takes care of recursion into
+ * sub-containers, but at the top level calls putJsonbValueConversion once per
+ * sequential processing token (in a manner similar to generic iteration).
  */
 static void
 walkJsonbValueConversion(JsonbValue * value, convertState * state,
@@ -1138,6 +1142,7 @@ walkJsonbValueConversion(JsonbValue * value, convertState * state,
    switch (value->type)
    {
        case jbvArray:
+
            putJsonbValueConversion(state, value, WJB_BEGIN_ARRAY, nestlevel);
            for (i = 0; i < value->array.nElems; i++)
            {
@@ -1151,10 +1156,11 @@ walkJsonbValueConversion(JsonbValue * value, convertState * state,
                                             nestlevel + 1);
            }
            putJsonbValueConversion(state, value, WJB_END_ARRAY, nestlevel);
+
            break;
        case jbvObject:
-           putJsonbValueConversion(state, value, WJB_BEGIN_OBJECT, nestlevel);
 
+           putJsonbValueConversion(state, value, WJB_BEGIN_OBJECT, nestlevel);
            for (i = 0; i < value->object.nPairs; i++)
            {
                putJsonbValueConversion(state, &value->object.pairs[i].key,
@@ -1170,8 +1176,8 @@ walkJsonbValueConversion(JsonbValue * value, convertState * state,
                    walkJsonbValueConversion(&value->object.pairs[i].value,
                                             state, nestlevel + 1);
            }
-
            putJsonbValueConversion(state, value, WJB_END_OBJECT, nestlevel);
+
            break;
        default:
            elog(ERROR, "unknown type of jsonb container");
@@ -1207,8 +1213,9 @@ short addPaddingInt(convertState * state)
  * type of value, even containers (Objects/arrays).  However, it is not
  * responsible for recursive aspects of walking the tree (so only top-level
  * Object/array details are handled).  No details about their
- * keys/values/elements are touched.  The function is called separately for the
- * start of an Object/Array, and the end.
+ * keys/values/elements are handled recursively - rather, the function is
+ * called as required for the start of an Object/Array, and the end (i.e.
+ * there is one call per sequential processing WJB_* token).
  */
 static void
 putJsonbValueConversion(convertState * state, JsonbValue * value, uint32 flags,
@@ -1228,14 +1235,15 @@ putJsonbValueConversion(convertState * state, JsonbValue * value, uint32 flags,
        Assert(((flags & WJB_BEGIN_ARRAY) && value->type == jbvArray) ||
               ((flags & WJB_BEGIN_OBJECT) && value->type == jbvObject));
 
+       /* Initialize pointer into conversion buffer at this level */
        state->curlptr->begin = state->ptr;
 
        addPaddingInt(state);
 
+       /* Initialize everything else at this level */
        state->curlptr->header = (uint32 *) state->ptr;
        /* Advance past header */
        state->ptr += sizeof(uint32);
-
        state->curlptr->meta = (JEntry *) state->ptr;
        state->curlptr->i = 0;
 
@@ -1259,18 +1267,18 @@ putJsonbValueConversion(convertState * state, JsonbValue * value, uint32 flags,
    }
    else if (flags & WJB_ELEM)
    {
-       putStringConversion(state, value, level, state->curlptr->i);
+       putScalarConversion(state, value, level, state->curlptr->i);
        state->curlptr->i++;
    }
    else if (flags & WJB_KEY)
    {
        Assert(value->type == jbvString);
 
-       putStringConversion(state, value, level, state->curlptr->i * 2);
+       putScalarConversion(state, value, level, state->curlptr->i * 2);
    }
    else if (flags & WJB_VALUE)
    {
-       putStringConversion(state, value, level, state->curlptr->i * 2 + 1);
+       putScalarConversion(state, value, level, state->curlptr->i * 2 + 1);
        state->curlptr->i++;
    }
    else if (flags & (WJB_END_ARRAY | WJB_END_OBJECT))
@@ -1325,16 +1333,15 @@ putJsonbValueConversion(convertState * state, JsonbValue * value, uint32 flags,
 
 /*
  * As part of the process of converting an arbitrary JsonbValue to a Jsonb,
- * copy a string associated with a scalar value.
+ * serialize and copy a scalar value into buffer.
  *
  * This is a worker function for putJsonbValueConversion() (itself a worker for
- * walkJsonbValueConversion()), handling aspects of copying strings in respect
- * of all scalar values.  It handles the details with regard to Jentry metadata
- * within convert state.
+ * walkJsonbValueConversion()).  It handles the details with regard to Jentry
+ * metadata peculiar to each scalar type.
  */
 static void
-putStringConversion(convertState * state, JsonbValue * value,
-                   uint32 level, uint32 i)
+putScalarConversion(convertState * state, JsonbValue * value, uint32 level,
+                   uint32 i)
 {
    int         numlen;
    short       padlen;
@@ -1366,18 +1373,6 @@ putStringConversion(convertState * state, JsonbValue * value,
                    (state->curlptr->meta[i - 1].header & JENTRY_POSMASK) +
                    value->string.len;
            break;
-       case jbvBool:
-           state->curlptr->meta[i].header |= (value->boolean) ?
-               JENTRY_ISTRUE : JENTRY_ISFALSE;
-
-           /*
-            * Store a delta from start of meta array until end (add last
-            * item's offset to length of item to get our offset)
-            */
-           if (i > 0)
-               state->curlptr->meta[i].header |=
-                   state->curlptr->meta[i - 1].header & JENTRY_POSMASK;
-           break;
        case jbvNumeric:
            numlen = VARSIZE_ANY(value->numeric);
            padlen = addPaddingInt(state);
@@ -1393,6 +1388,14 @@ putStringConversion(convertState * state, JsonbValue * value,
                    (state->curlptr->meta[i - 1].header & JENTRY_POSMASK)
                    + padlen + numlen;
            break;
+       case jbvBool:
+           state->curlptr->meta[i].header |= (value->boolean) ?
+               JENTRY_ISTRUE : JENTRY_ISFALSE;
+
+           if (i > 0)
+               state->curlptr->meta[i].header |=
+                   state->curlptr->meta[i - 1].header & JENTRY_POSMASK;
+           break;
        default:
            elog(ERROR, "invalid jsonb scalar type");
    }
@@ -1450,20 +1453,19 @@ static bool
 formIterIsContainer(JsonbIterator ** it, JsonbValue * v, JEntry * e,
                    bool skipNested)
 {
-   if (JBE_ISSTRING(*e))
+   if (JBE_ISNULL(*e))
    {
-       v->type = jbvString;
-       v->string.val = (*it)->dataProper + JBE_OFF(*e);
-       v->string.len = JBE_LEN(*e);
-       v->estSize = sizeof(JEntry) + v->string.len;
+       v->type = jbvNull;
+       v->estSize = sizeof(JEntry);
 
        return false;
    }
-   else if (JBE_ISBOOL(*e))
+   else if (JBE_ISSTRING(*e))
    {
-       v->type = jbvBool;
-       v->boolean = JBE_ISBOOL_TRUE(*e) != 0;
-       v->estSize = sizeof(JEntry);
+       v->type = jbvString;
+       v->string.val = (*it)->dataProper + JBE_OFF(*e);
+       v->string.len = JBE_LEN(*e);
+       v->estSize = sizeof(JEntry) + v->string.len;
 
        return false;
    }
@@ -1475,9 +1477,10 @@ formIterIsContainer(JsonbIterator ** it, JsonbValue * v, JEntry * e,
 
        return false;
    }
-   else if (JBE_ISNULL(*e))
+   else if (JBE_ISBOOL(*e))
    {
-       v->type = jbvNull;
+       v->type = jbvBool;
+       v->boolean = JBE_ISBOOL_TRUE(*e) != 0;
        v->estSize = sizeof(JEntry);
 
        return false;