*/
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
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,
/*
* 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,
switch (value->type)
{
case jbvArray:
+
putJsonbValueConversion(state, value, WJB_BEGIN_ARRAY, nestlevel);
for (i = 0; i < value->array.nElems; i++)
{
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,
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");
* 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,
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;
}
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))
/*
* 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;
(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);
(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");
}
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;
}
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;