Clean-up "compression walking"
authorPeter Geoghegan <[email protected]>
Thu, 13 Mar 2014 02:28:47 +0000 (19:28 -0700)
committerPeter Geoghegan <[email protected]>
Thu, 13 Mar 2014 02:28:47 +0000 (19:28 -0700)
This doesn't have much to do with actual compression.  It actually
concerns converting an arbitrary JsonbValue to a 4 byte uncompressed
varlena representation (i.e. a Jsonb).  So stop using the misleading
term  compression, and start calling it conversion.  Use the type system
sensibly.  Clean-up and comment the code more generally.

src/backend/utils/adt/jsonb_op.c
src/backend/utils/adt/jsonb_support.c
src/include/utils/jsonb.h

index 728f4c8557d84b57066c1841a23eac99cba6c5a2..67e568d22f5906ef346b245842941dc25acaa31c 100644 (file)
@@ -54,9 +54,9 @@ jsonb_exists_any(PG_FUNCTION_ARGS)
 
    /*
     * We exploit the fact that the pairs list is already sorted into strictly
-    * increasing order to narrow the findUncompressedJsonbValue search; each
-    * search can start one entry past the previous "found" entry, or at the
-    * lower bound of the last search.
+    * increasing order to narrow the findJsonbValueFromSuperHeader search;
+    * each search can start one entry past the previous "found" entry, or at
+    * the lower bound of the last search.
     */
    for (i = 0; i < v->array.nElems; i++)
    {
@@ -93,9 +93,9 @@ jsonb_exists_all(PG_FUNCTION_ARGS)
 
    /*
     * We exploit the fact that the pairs list is already sorted into strictly
-    * increasing order to narrow the findUncompressedJsonbValue search; each
-    * search can start one entry past the previous "found" entry, or at the
-    * lower bound of the last search.
+    * increasing order to narrow the findJsonbValueFromSuperHeader search;
+    * each search can start one entry past the previous "found" entry, or at
+    * the lower bound of the last search.
     */
    for (i = 0; i < v->array.nElems; i++)
    {
index 37d972783decfedf00a8db4fa69600ba09f58b4e..0ab0ec35066d6fd05f0e9777a91188634d871504 100644 (file)
 #define JBE_ISBOOL_FALSE(he_)  (JBE_ISBOOL(he_) && !JBE_ISBOOL_TRUE(he_))
 
 /*
- * State used while rolling up an arbitrary JsonbValue into a varlena/Jsonb
- * value
+ * State used while converting an arbitrary JsonbValue into a Jsonb value
+ * (4-byte varlena uncompressed representation of a Jsonb)
  */
-typedef struct CompressState
+typedef struct ConvertState
 {
    /* Preallocated buffer in which to form varlena/Jsonb value */
-   char               *buffer;
-   JsonbSuperHeader    ptr;
+   Jsonb              *buffer;
+   /* Pointer into buffer */
+   char               *ptr;
 
    struct
    {
        uint32      i;
        uint32     *header;
-       JEntry     *array;
+       JEntry     *metaArray;
        char       *begin;
-   }          *levelstate, *lptr, *pptr;
+   }          *levelstate,
+       *curlptr,
+       *prvlptr;
 
-   uint32      maxlevel;
+   /* Current size of buffer holding levelstate */
+   Size        levelSz;
 
-}  CompressState;
+}  ConvertState;
 
 static int lexicalCompareJsonbStringValue(const void *a, const void *b);
-static uint32 compressJsonb(JsonbValue * v, JsonbSuperHeader sheader);
-static void walkUncompressedJsonb(JsonbValue * value, CompressState * state,
-                                 uint32 nestlevel);
+static Size convertJsonb(JsonbValue * v, Jsonb* buffer);
+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,
+                               uint32 level, uint32 i);
 static void parseBuffer(JsonbIterator * it, char *buffer);
 static bool formAnswer(JsonbIterator ** it, JsonbValue * v, JEntry * e,
                       bool skipNested);
 static JsonbIterator *up(JsonbIterator * it);
-static void compressJsonbValue(CompressState * state, JsonbValue * value,
-                              uint32 flags, uint32 level);
-static void putJEntryString(CompressState * state, JsonbValue * value,
-                           uint32 level, uint32 i);
 static ToJsonbState *pushState(ToJsonbState ** state);
 static void appendKey(ToJsonbState * state, JsonbValue * v);
 static void appendValue(ToJsonbState * state, JsonbValue * v);
@@ -96,7 +100,7 @@ JsonbValueToJsonb(JsonbValue * v)
        /* Scalar value */
        ToJsonbState *state = NULL;
        JsonbValue *res;
-       uint32      sz;
+       Size        sz;
        JsonbValue  scalarArray;
 
        scalarArray.type = jbvArray;
@@ -108,7 +112,7 @@ JsonbValueToJsonb(JsonbValue * v)
        res = pushJsonbValue(&state, WJB_END_ARRAY, NULL);
 
        out = palloc(VARHDRSZ + res->size);
-       sz = compressJsonb(res, VARDATA(out));
+       sz = convertJsonb(res, out);
        Assert(sz <= res->size);
        SET_VARSIZE(out, sz + VARHDRSZ);
    }
@@ -117,7 +121,7 @@ JsonbValueToJsonb(JsonbValue * v)
        uint32      sz;
 
        out = palloc(VARHDRSZ + v->size);
-       sz = compressJsonb(v, VARDATA(out));
+       sz = convertJsonb(v, out);
        Assert(sz <= v->size);
        SET_VARSIZE(out, VARHDRSZ + sz);
    }
@@ -811,35 +815,38 @@ lexicalCompareJsonbStringValue(const void *a, const void *b)
 }
 
 /*
- * puts JsonbValue tree into a preallocated buffer
+ * Put JsonbValue tree into a preallocated buffer Jsonb buffer
  */
-static uint32
-compressJsonb(JsonbValue * v, char *buffer)
+static Size
+convertJsonb(JsonbValue * v, Jsonb *buffer)
 {
    uint32      l = 0;
-   CompressState state;
+   ConvertState state;
 
    /* Should not already have binary representation */
    Assert(v->type != jbvBinary);
 
-   state.buffer = state.ptr = buffer;
-   state.maxlevel = 8;
-   state.levelstate = palloc(sizeof(*state.levelstate) * state.maxlevel);
+   state.buffer = buffer;
+   /* Start from superheader */
+   state.ptr = VARDATA(state.buffer);
+   state.levelSz = 8;
+   state.levelstate = palloc(sizeof(*state.levelstate) * state.levelSz);
 
-   walkUncompressedJsonb(v, &state, 0);
+   walkJsonbValueConversion(v, &state, 0);
 
-   l = state.ptr - buffer;
+   l = state.ptr - VARDATA(state.buffer);
    Assert(l <= v->size);
 
    return l;
 }
 
 /*
- * Walk the tree representation of jsonb
+ * Walk the tree representation of Jsonb, as part of the process of converting
+ * a JsonbValue to a Jsonb
  */
 static void
-walkUncompressedJsonb(JsonbValue * value, CompressState * state,
-                     uint32 nestlevel)
+walkJsonbValueConversion(JsonbValue * value, ConvertState * state,
+                        uint32 nestlevel)
 {
    int         i;
 
@@ -851,37 +858,40 @@ walkUncompressedJsonb(JsonbValue * value, CompressState * state,
    switch (value->type)
    {
        case jbvArray:
-           compressJsonbValue(state, value, WJB_BEGIN_ARRAY, nestlevel);
+           putJsonbValueConversion(state, value, WJB_BEGIN_ARRAY, nestlevel);
            for (i = 0; i < value->array.nElems; i++)
            {
                if ((value->array.elems[i].type >= jbvNull &&
                    value->array.elems[i].type < jbvArray) ||
                    value->array.elems[i].type == jbvBinary)
-                   compressJsonbValue(state, value->array.elems + i, WJB_ELEM, nestlevel);
+                   putJsonbValueConversion(state, value->array.elems + i,
+                                           WJB_ELEM, nestlevel);
                else
-                   walkUncompressedJsonb(value->array.elems + i, state,
+                   walkJsonbValueConversion(value->array.elems + i, state,
                                          nestlevel + 1);
            }
-           compressJsonbValue(state, value, WJB_END_ARRAY, nestlevel);
+           putJsonbValueConversion(state, value, WJB_END_ARRAY, nestlevel);
            break;
        case jbvObject:
-           compressJsonbValue(state, value, WJB_BEGIN_OBJECT, nestlevel);
+           putJsonbValueConversion(state, value, WJB_BEGIN_OBJECT, nestlevel);
 
            for (i = 0; i < value->object.nPairs; i++)
            {
-               compressJsonbValue(state, &value->object.pairs[i].key, WJB_KEY, nestlevel);
+               putJsonbValueConversion(state, &value->object.pairs[i].key,
+                                       WJB_KEY, nestlevel);
 
                if ((value->object.pairs[i].value.type >= jbvNull &&
                    value->object.pairs[i].value.type < jbvArray) ||
                    value->object.pairs[i].value.type == jbvBinary)
-                   compressJsonbValue(state, &value->object.pairs[i].value,
+                   putJsonbValueConversion(state,
+                                           &value->object.pairs[i].value,
                                       WJB_VALUE, nestlevel);
                else
-                   walkUncompressedJsonb(&value->object.pairs[i].value,
+                   walkJsonbValueConversion(&value->object.pairs[i].value,
                                          state, nestlevel + 1);
            }
 
-           compressJsonbValue(state, value, WJB_END_OBJECT, nestlevel);
+           putJsonbValueConversion(state, value, WJB_END_OBJECT, nestlevel);
            break;
        default:
            elog(ERROR, "unknown type of jsonb container");
@@ -889,133 +899,28 @@ walkUncompressedJsonb(JsonbValue * value, CompressState * state,
 }
 
 /*
- * Iteration over binary jsonb
- */
-
-/*
- * Initialize iterator from superheader
- */
-static void
-parseBuffer(JsonbIterator * it, JsonbSuperHeader sheader)
-{
-   uint32      superheader = *(uint32 *) sheader;
-
-   it->containerType = superheader & (JB_FLAG_ARRAY | JB_FLAG_OBJECT);
-   it->nElems = superheader & JB_COUNT_MASK;
-   it->buffer = sheader;
-
-   /* Array starts just after header */
-   it->metaArray = (JEntry *) (sheader + sizeof(uint32));
-   it->state = jbi_start;
-
-   switch (it->containerType)
-   {
-       case JB_FLAG_ARRAY:
-           it->dataProper =
-               (char *) it->metaArray + it->nElems * sizeof(JEntry);
-           it->isScalar = (superheader & JB_FLAG_SCALAR) != 0;
-           /* This is either a "raw scalar", or an array */
-           Assert(!it->isScalar || it->nElems == 1);
-           break;
-       case JB_FLAG_OBJECT:
-           /*
-            * Offset reflects that nElems indicates JsonbPairs in an object
-            *
-            * Each key and each value have Jentry metadata.
-            */
-           it->dataProper =
-               (char *) it->metaArray + it->nElems * sizeof(JEntry) * 2;
-           break;
-       default:
-           elog(ERROR, "unknown type of jsonb container");
-   }
-}
-
-static bool
-formAnswer(JsonbIterator ** it, JsonbValue * v, JEntry * e, bool skipNested)
-{
-   if (JBE_ISSTRING(*e))
-   {
-       v->type = jbvString;
-       v->string.val = (*it)->dataProper + JBE_OFF(*e);
-       v->string.len = JBE_LEN(*e);
-       v->size = sizeof(JEntry) + v->string.len;
-
-       return false;
-   }
-   else if (JBE_ISBOOL(*e))
-   {
-       v->type = jbvBool;
-       v->boolean = JBE_ISBOOL_TRUE(*e) != 0;
-       v->size = sizeof(JEntry);
-
-       return false;
-   }
-   else if (JBE_ISNUMERIC(*e))
-   {
-       v->type = jbvNumeric;
-       v->numeric = (Numeric) ((*it)->dataProper + INTALIGN(JBE_OFF(*e)));
-
-       v->size = 2 * sizeof(JEntry) + VARSIZE_ANY(v->numeric);
-
-       return false;
-   }
-   else if (JBE_ISNULL(*e))
-   {
-       v->type = jbvNull;
-       v->size = sizeof(JEntry);
-
-       return false;
-   }
-   else if (skipNested)
-   {
-       v->type = jbvBinary;
-       v->binary.data = (*it)->dataProper + INTALIGN(JBE_OFF(*e));
-       v->binary.len = JBE_LEN(*e) - (INTALIGN(JBE_OFF(*e)) - JBE_OFF(*e));
-       v->size = v->binary.len + 2 * sizeof(JEntry);
-
-       return false;
-   }
-   else
-   {
-       JsonbIterator *nit = palloc(sizeof(*nit));
-
-       parseBuffer(nit, (*it)->dataProper + INTALIGN(JBE_OFF(*e)));
-       nit->next = *it;
-       *it = nit;
-
-       return true;
-   }
-}
-
-static JsonbIterator *
-up(JsonbIterator * it)
-{
-   JsonbIterator *v = it->next;
-
-   pfree(it);
-
-   return v;
-}
-
-/*
- * Transformation from tree to binary representation of jsonb
+ * As part of the process of converting an arbitrary JsonbValue to a Jsonb,
+ * copy an arbitrary individual JsonbValue.  This function may copy over any
+ * 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.
+ *
+ * This is a worker function for walkJsonbValueConversion.
  */
-#define curLevelState  (state->lptr)
-#define prevLevelState (state->pptr)
-
 static void
-compressJsonbValue(CompressState * state, JsonbValue * value, uint32 flags,
-                  uint32 level)
+putJsonbValueConversion(ConvertState * state, JsonbValue * value, uint32 flags,
+                       uint32 level)
 {
-   if (level == state->maxlevel)
+   if (level == state->levelSz)
    {
-       state->maxlevel *= 2;
+       state->levelSz *= 2;
        state->levelstate = repalloc(state->levelstate,
-                              sizeof(*state->levelstate) * state->maxlevel);
+                              sizeof(*state->levelstate) * state->levelSz);
    }
 
-   curLevelState = state->levelstate + level;
+   state->curlptr = state->levelstate + level;
 
    if (flags & (WJB_BEGIN_ARRAY | WJB_BEGIN_OBJECT))
    {
@@ -1024,10 +929,11 @@ compressJsonbValue(CompressState * state, JsonbValue * value, uint32 flags,
        Assert(((flags & WJB_BEGIN_ARRAY) && value->type == jbvArray) ||
               ((flags & WJB_BEGIN_OBJECT) && value->type == jbvObject));
 
-       curLevelState->begin = state->ptr;
+       state->curlptr->begin = state->ptr;
+
+       padlen = INTALIGN(state->ptr - VARDATA(state->buffer)) -
+           (state->ptr - VARDATA(state->buffer));
 
-       padlen = INTALIGN(state->ptr - state->buffer) - (state->ptr -
-                                                        state->buffer);
        /*
         * Add padding as necessary
         */
@@ -1037,45 +943,46 @@ compressJsonbValue(CompressState * state, JsonbValue * value, uint32 flags,
            state->ptr++;
        }
 
-       curLevelState->header = (uint32 *) state->ptr;
-       state->ptr += sizeof(*curLevelState->header);
+       state->curlptr->header = (uint32 *) state->ptr;
+       /* Advance past header */
+       state->ptr += sizeof(* state->curlptr->header);
 
-       curLevelState->array = (JEntry *) state->ptr;
-       curLevelState->i = 0;
+       state->curlptr->metaArray = (JEntry *) state->ptr;
+       state->curlptr->i = 0;
 
        if (value->type == jbvArray)
        {
-           *curLevelState->header = value->array.nElems | JB_FLAG_ARRAY;
+           *state->curlptr->header = value->array.nElems | JB_FLAG_ARRAY;
            state->ptr += sizeof(JEntry) * value->array.nElems;
 
            if (value->array.scalar)
            {
                Assert(value->array.nElems == 1);
                Assert(level == 0);
-               *curLevelState->header |= JB_FLAG_SCALAR;
+               *state->curlptr->header |= JB_FLAG_SCALAR;
            }
        }
        else
        {
-           *curLevelState->header = value->object.nPairs | JB_FLAG_OBJECT;
+           *state->curlptr->header = value->object.nPairs | JB_FLAG_OBJECT;
            state->ptr += sizeof(JEntry) * value->object.nPairs * 2;
        }
    }
    else if (flags & WJB_ELEM)
    {
-       putJEntryString(state, value, level, curLevelState->i);
-       curLevelState->i++;
+       putStringConversion(state, value, level, state->curlptr->i);
+       state->curlptr->i++;
    }
    else if (flags & WJB_KEY)
    {
        Assert(value->type == jbvString);
 
-       putJEntryString(state, value, level, curLevelState->i * 2);
+       putStringConversion(state, value, level, state->curlptr->i * 2);
    }
    else if (flags & WJB_VALUE)
    {
-       putJEntryString(state, value, level, curLevelState->i * 2 + 1);
-       curLevelState->i++;
+       putStringConversion(state, value, level, state->curlptr->i * 2 + 1);
+       state->curlptr->i++;
    }
    else if (flags & (WJB_END_ARRAY | WJB_END_OBJECT))
    {
@@ -1084,95 +991,104 @@ compressJsonbValue(CompressState * state, JsonbValue * value, uint32 flags,
 
        Assert(((flags & WJB_END_ARRAY) && value->type == jbvArray) ||
               ((flags & WJB_END_OBJECT) && value->type == jbvObject));
+
        if (level == 0)
            return;
 
-       len = state->ptr - (char *) curLevelState->begin;
+       len = state->ptr - (char *) state->curlptr->begin;
 
-       prevLevelState = curLevelState - 1;
+       state->prvlptr = state->curlptr - 1;
 
-       if (*prevLevelState->header & JB_FLAG_ARRAY)
+       if (*state->prvlptr->header & JB_FLAG_ARRAY)
        {
-           i = prevLevelState->i;
+           i = state->prvlptr->i;
 
-           prevLevelState->array[i].header = JENTRY_ISNEST;
+           state->prvlptr->metaArray[i].header = JENTRY_ISNEST;
 
            if (i == 0)
-               prevLevelState->array[0].header |= JENTRY_ISFIRST | len;
+               state->prvlptr->metaArray[0].header |= JENTRY_ISFIRST | len;
            else
-               prevLevelState->array[i].header |=
-                   (prevLevelState->array[i - 1].header & JENTRY_POSMASK) + len;
+               state->prvlptr->metaArray[i].header |=
+                   (state->prvlptr->metaArray[i - 1].header & JENTRY_POSMASK) + len;
        }
-       else if (*prevLevelState->header & JB_FLAG_OBJECT)
+       else if (*state->prvlptr->header & JB_FLAG_OBJECT)
        {
-           i = 2 * prevLevelState->i + 1;      /* VALUE, not a KEY */
+           i = 2 * state->prvlptr->i + 1;      /* Value, not key */
 
-           prevLevelState->array[i].header = JENTRY_ISNEST;
+           state->prvlptr->metaArray[i].header = JENTRY_ISNEST;
 
-           prevLevelState->array[i].header |=
-               (prevLevelState->array[i - 1].header & JENTRY_POSMASK) + len;
+           state->prvlptr->metaArray[i].header |=
+               (state->prvlptr->metaArray[i - 1].header & JENTRY_POSMASK) + len;
        }
        else
        {
            elog(ERROR, "invalid jsonb container type");
        }
 
-       Assert(state->ptr - curLevelState->begin <= value->size);
-       prevLevelState->i++;
+       Assert(state->ptr - state->curlptr->begin <= value->size);
+       state->prvlptr->i++;
    }
    else
    {
-       elog(ERROR, "unknown flag in tree walk");
+       elog(ERROR, "unknown flag encountered during jsonb tree walk");
    }
 }
 
+/*
+ * As part of the process of converting an arbitrary JsonbValue to a Jsonb,
+ * copy a string.
+ *
+ * This is a worker function for putJsonbValueConversion(), handling aspects of
+ * copying strings in respect of all scalar values.  It handles the details
+ * with regard to Jentry meta-data within convert state.
+ */
 static void
-putJEntryString(CompressState * state, JsonbValue * value, uint32 level,
-               uint32 i)
+putStringConversion(ConvertState * state, JsonbValue * value,
+                   uint32 level, uint32 i)
 {
    short       p, padlen;
 
-   curLevelState = state->levelstate + level;
+   state->curlptr = state->levelstate + level;
 
    if (i == 0)
-       curLevelState->array[0].header = JENTRY_ISFIRST;
+       state->curlptr->metaArray[0].header = JENTRY_ISFIRST;
    else
-       curLevelState->array[i].header = 0;
+       state->curlptr->metaArray[i].header = 0;
 
    switch (value->type)
    {
        case jbvNull:
-           curLevelState->array[i].header |= JENTRY_ISNULL;
+           state->curlptr->metaArray[i].header |= JENTRY_ISNULL;
 
            if (i > 0)
-               curLevelState->array[i].header |=
-                   curLevelState->array[i - 1].header & JENTRY_POSMASK;
+               state->curlptr->metaArray[i].header |=
+                   state->curlptr->metaArray[i - 1].header & JENTRY_POSMASK;
            break;
        case jbvString:
            memcpy(state->ptr, value->string.val, value->string.len);
            state->ptr += value->string.len;
 
            if (i == 0)
-               curLevelState->array[i].header |= value->string.len;
+               state->curlptr->metaArray[i].header |= value->string.len;
            else
-               curLevelState->array[i].header |=
-                   (curLevelState->array[i - 1].header & JENTRY_POSMASK) +
+               state->curlptr->metaArray[i].header |=
+                   (state->curlptr->metaArray[i - 1].header & JENTRY_POSMASK) +
                    value->string.len;
            break;
        case jbvBool:
-           curLevelState->array[i].header |= (value->boolean) ?
+           state->curlptr->metaArray[i].header |= (value->boolean) ?
                JENTRY_ISTRUE : JENTRY_ISFALSE;
 
            if (i > 0)
-               curLevelState->array[i].header |=
-                   curLevelState->array[i - 1].header & JENTRY_POSMASK;
+               state->curlptr->metaArray[i].header |=
+                   state->curlptr->metaArray[i - 1].header & JENTRY_POSMASK;
            break;
        case jbvNumeric:
            {
                int numlen = VARSIZE_ANY(value->numeric);
 
-               padlen = INTALIGN(state->ptr - state->buffer) -
-                   (state->ptr - state->buffer);
+               padlen = INTALIGN(state->ptr - VARDATA(state->buffer)) -
+                   (state->ptr - VARDATA(state->buffer));
 
                /*
                 * Add padding as necessary
@@ -1186,19 +1102,20 @@ putJEntryString(CompressState * state, JsonbValue * value, uint32 level,
                memcpy(state->ptr, value->numeric, numlen);
                state->ptr += numlen;
 
-               curLevelState->array[i].header |= JENTRY_ISNUMERIC;
+               state->curlptr->metaArray[i].header |= JENTRY_ISNUMERIC;
                if (i == 0)
-                   curLevelState->array[i].header |= padlen + numlen;
+                   state->curlptr->metaArray[i].header |= padlen + numlen;
                else
-                   curLevelState->array[i].header |=
-                       (curLevelState->array[i - 1].header & JENTRY_POSMASK) +
+                   state->curlptr->metaArray[i].header |=
+                       (state->curlptr->metaArray[i - 1].header & JENTRY_POSMASK) +
                        padlen + numlen;
                break;
            }
        case jbvBinary:
            {
-               padlen = INTALIGN(state->ptr - state->buffer) - (state->ptr -
-                                                               state->buffer);
+               padlen = INTALIGN(state->ptr - VARDATA(state->buffer)) -
+                   (state->ptr - VARDATA(state->buffer));
+
                /*
                 * Add padding as necessary
                 */
@@ -1211,13 +1128,13 @@ putJEntryString(CompressState * state, JsonbValue * value, uint32 level,
                memcpy(state->ptr, value->binary.data, value->binary.len);
                state->ptr += value->binary.len;
 
-               curLevelState->array[i].header |= JENTRY_ISNEST;
+               state->curlptr->metaArray[i].header |= JENTRY_ISNEST;
 
                if (i == 0)
-                   curLevelState->array[i].header |= value->binary.len + padlen;
+                   state->curlptr->metaArray[i].header |= value->binary.len + padlen;
                else
-                   curLevelState->array[i].header |=
-                       (curLevelState->array[i - 1].header & JENTRY_POSMASK) +
+                   state->curlptr->metaArray[i].header |=
+                       (state->curlptr->metaArray[i - 1].header & JENTRY_POSMASK) +
                        value->binary.len + padlen;
            }
            break;
@@ -1226,6 +1143,116 @@ putJEntryString(CompressState * state, JsonbValue * value, uint32 level,
    }
 }
 
+/*
+ * Iteration over binary jsonb
+ */
+
+/*
+ * Initialize iterator from superheader
+ */
+static void
+parseBuffer(JsonbIterator * it, JsonbSuperHeader sheader)
+{
+   uint32      superheader = *(uint32 *) sheader;
+
+   it->containerType = superheader & (JB_FLAG_ARRAY | JB_FLAG_OBJECT);
+   it->nElems = superheader & JB_COUNT_MASK;
+   it->buffer = sheader;
+
+   /* Array starts just after header */
+   it->metaArray = (JEntry *) (sheader + sizeof(uint32));
+   it->state = jbi_start;
+
+   switch (it->containerType)
+   {
+       case JB_FLAG_ARRAY:
+           it->dataProper =
+               (char *) it->metaArray + it->nElems * sizeof(JEntry);
+           it->isScalar = (superheader & JB_FLAG_SCALAR) != 0;
+           /* This is either a "raw scalar", or an array */
+           Assert(!it->isScalar || it->nElems == 1);
+           break;
+       case JB_FLAG_OBJECT:
+           /*
+            * Offset reflects that nElems indicates JsonbPairs in an object
+            *
+            * Each key and each value have Jentry metadata.
+            */
+           it->dataProper =
+               (char *) it->metaArray + it->nElems * sizeof(JEntry) * 2;
+           break;
+       default:
+           elog(ERROR, "unknown type of jsonb container");
+   }
+}
+
+static bool
+formAnswer(JsonbIterator ** it, JsonbValue * v, JEntry * e, bool skipNested)
+{
+   if (JBE_ISSTRING(*e))
+   {
+       v->type = jbvString;
+       v->string.val = (*it)->dataProper + JBE_OFF(*e);
+       v->string.len = JBE_LEN(*e);
+       v->size = sizeof(JEntry) + v->string.len;
+
+       return false;
+   }
+   else if (JBE_ISBOOL(*e))
+   {
+       v->type = jbvBool;
+       v->boolean = JBE_ISBOOL_TRUE(*e) != 0;
+       v->size = sizeof(JEntry);
+
+       return false;
+   }
+   else if (JBE_ISNUMERIC(*e))
+   {
+       v->type = jbvNumeric;
+       v->numeric = (Numeric) ((*it)->dataProper + INTALIGN(JBE_OFF(*e)));
+
+       v->size = 2 * sizeof(JEntry) + VARSIZE_ANY(v->numeric);
+
+       return false;
+   }
+   else if (JBE_ISNULL(*e))
+   {
+       v->type = jbvNull;
+       v->size = sizeof(JEntry);
+
+       return false;
+   }
+   else if (skipNested)
+   {
+       v->type = jbvBinary;
+       v->binary.data = (*it)->dataProper + INTALIGN(JBE_OFF(*e));
+       v->binary.len = JBE_LEN(*e) - (INTALIGN(JBE_OFF(*e)) - JBE_OFF(*e));
+       v->size = v->binary.len + 2 * sizeof(JEntry);
+
+       return false;
+   }
+   else
+   {
+       JsonbIterator *nit = palloc(sizeof(*nit));
+
+       parseBuffer(nit, (*it)->dataProper + INTALIGN(JBE_OFF(*e)));
+       nit->next = *it;
+       *it = nit;
+
+       return true;
+   }
+}
+
+static JsonbIterator *
+up(JsonbIterator * it)
+{
+   JsonbIterator *v = it->next;
+
+   pfree(it);
+
+   return v;
+}
+
 /*
  * Iteration-like forming jsonb
  */
index 9c0d175a35aa3338f518197d409318343d14be60..1162f6017213eabc8aa7c4c1498d7dcb6212c019 100644 (file)
@@ -106,7 +106,7 @@ typedef struct
 {
    int32       vl_len_;        /* varlena header (do not touch directly!) */
    /* (uint32/Jsonb superheader of top-level Jsonb object/array follows) */
-   /* (array of JEntry follows, size determined using uint32 header) */
+   /* (array of JEntry follows, size determined using uint32 superheader) */
 } Jsonb;
 
 /*
@@ -180,6 +180,7 @@ struct JsonbPair
    uint32      order;          /* preserves order of pairs with equal keys */
 };
 
+/* Conversion state used when parsing Jsonb from text, or for type coercion */
 typedef struct ToJsonbState
 {
    JsonbValue  v;