From ddc7c28f8f08b892e84e468cc337eecfe7da0962 Mon Sep 17 00:00:00 2001 From: Peter Geoghegan Date: Wed, 19 Mar 2014 00:30:28 -0700 Subject: [PATCH] Polish conversion functions --- src/backend/utils/adt/jsonb_util.c | 89 +++++++++++++++--------------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/src/backend/utils/adt/jsonb_util.c b/src/backend/utils/adt/jsonb_util.c index 3cb05426c7..6e45031de7 100644 --- a/src/backend/utils/adt/jsonb_util.c +++ b/src/backend/utils/adt/jsonb_util.c @@ -27,10 +27,10 @@ */ 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; -- 2.39.5