From: Peter Geoghegan Date: Thu, 13 Mar 2014 02:28:47 +0000 (-0700) Subject: Clean-up "compression walking" X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=8ecd488feafe0d311473df95b08d6340ee4a2304;p=users%2Fandresfreund%2Fpostgres.git Clean-up "compression walking" 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. --- diff --git a/src/backend/utils/adt/jsonb_op.c b/src/backend/utils/adt/jsonb_op.c index 728f4c8557..67e568d22f 100644 --- a/src/backend/utils/adt/jsonb_op.c +++ b/src/backend/utils/adt/jsonb_op.c @@ -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++) { diff --git a/src/backend/utils/adt/jsonb_support.c b/src/backend/utils/adt/jsonb_support.c index 37d972783d..0ab0ec3506 100644 --- a/src/backend/utils/adt/jsonb_support.c +++ b/src/backend/utils/adt/jsonb_support.c @@ -37,39 +37,43 @@ #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 */ diff --git a/src/include/utils/jsonb.h b/src/include/utils/jsonb.h index 9c0d175a35..1162f60172 100644 --- a/src/include/utils/jsonb.h +++ b/src/include/utils/jsonb.h @@ -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;