}
/*
- * Gives consistent ordering of Jsonb values.
+ * BT comparator worker function. Returns an integer less than, equal to, or
+ * greater than zero, indicating whether a is less than, equal to, or greater
+ * than b. Consistent with the requirements for a B-Tree operator class
*
- * Strings are compared lexically, making this suitable as a sort comparator.
- *
- * This is called from B-Tree support function 1.
+ * Strings are compared lexically. Since this is called from B-Tree support
+ * function 1, we're careful about not leaking memory here.
*/
int
compareJsonbSuperHeaderValue(JsonbSuperHeader a, JsonbSuperHeader b)
{
JsonbIterator *it1,
- *it2;
+ *it2;
int res = 0;
it1 = JsonbIteratorInit(a);
if (r1 == r2)
{
- if (r1 == 0)
+ if (r1 == WJB_DONE)
break; /* equal */
if (v1.type == v2.type)
}
while (res == 0);
+ while (it1 != NULL)
+ {
+ JsonbIterator *i = it1->parent;
+ pfree(it1);
+ it1 = i;
+ }
+ while (it2 != NULL)
+ {
+ JsonbIterator *i = it2->parent;
+ pfree(it2);
+ it2 = i;
+ }
+
return res;
}
JsonbValue *
pushJsonbValue(ToJsonbState ** state, int r, JsonbValue * v)
{
- JsonbValue *h = NULL;
+ JsonbValue *result = NULL;
switch (r)
{
case WJB_BEGIN_ARRAY:
*state = pushState(state);
- h = &(*state)->v;
+ result = &(*state)->v;
(*state)->v.type = jbvArray;
(*state)->v.size = 3 * sizeof(JEntry);
(*state)->v.array.nElems = 0;
break;
case WJB_BEGIN_OBJECT:
*state = pushState(state);
- h = &(*state)->v;
+ result = &(*state)->v;
(*state)->v.type = jbvObject;
(*state)->v.size = 3 * sizeof(JEntry);
(*state)->v.object.nPairs = 0;
appendElement(*state, v);
break;
case WJB_END_OBJECT:
- h = &(*state)->v;
+ result = &(*state)->v;
/*
* When v != NULL and control reaches here, keys should already be
* sorted
*/
if (v == NULL)
- uniqueifyJsonbObject(h);
+ uniqueifyJsonbObject(result);
/*
* No break statement here - fall through and perform those steps
* in the same fashion as arrays.
*/
case WJB_END_ARRAY:
- h = &(*state)->v;
+ result = &(*state)->v;
/*
* Pop stack and push current array/"object" as value in parent
switch ((*state)->v.type)
{
case jbvArray:
- appendElement(*state, h);
+ appendElement(*state, result);
break;
case jbvObject:
- appendValue(*state, h);
+ appendValue(*state, result);
break;
default:
elog(ERROR, "invalid jsonb container type");
elog(ERROR, "invalid jsonb container type");
}
- return h;
+ return result;
}
/*
* Given a Jsonb superheader, expand to JsonbIterator to iterate over items
* fully expanded to in-memory representation for manipulation.
+ *
+ * See JsonbIteratorNext() for notes on memory management.
*/
JsonbIterator *
JsonbIteratorInit(JsonbSuperHeader sheader)
* back a child iterator palloc()'d here instead. The function can be relied
* on to free those child iterators, lest the memory allocated for highly
* nested objects become unreasonable, but only if callers don't end iteration
- * early.
+ * early (by breaking upon having found something in a search, for example).
+ *
+ * Callers in such a scenario, that are particularly sensitive to leaking
+ * memory in a long-lived context may walk the ancestral tree from the final
+ * iterator we left them with to its oldest ancestor, pfree()ing as they go.
+ * They can depended on having any other memory previously allocated for
+ * iterators but not in that line having already been freed here.
*/
int
JsonbIteratorNext(JsonbIterator ** it, JsonbValue * v, bool skipNested)
{
/*
* Must be container type, so setup caller's iterator to point to that,
- * and return indication of that
+ * and return indication of that.
+ *
+ * Get child iterator.
*/
- JsonbIterator *nit = palloc(sizeof(JsonbIterator));
+ JsonbIterator *child = palloc(sizeof(JsonbIterator));
- /* Get child iterator */
- iteratorFromContainerBuf(nit,
+ iteratorFromContainerBuf(child,
(*it)->dataProper + INTALIGN(JBE_OFF(*e)));
- nit->parent = *it;
- *it = nit;
+ child->parent = *it;
+ *it = child;
return true;
}
/*
* When using a GIN index for jsonb, we choose to index both keys and values.
* The storage format is "text" values, with K, V, or N prepended to the string
- * to indicate key, value, or null values. (As of 9.1 it might be better to
- * store null values as nulls, but we'll keep it this way for on-disk
- * compatibility.)
+ * to indicate key/element, value, or SQL NULL value.
*
- * jsonb Keys and elements are treated equivalently when serialized to text
- * index storage.
+ * Jsonb Keys and elements are treated equivalently when serialized to text
+ * index storage. One day we may wish to create an opclass that only indexes
+ * keys (or only values), but for now it's always keys and values together, or
+ * just array elements.
*/
#define KEYELEMFLAG 'K'
#define VALFLAG 'V'
*
* We have an abstraction called a "superheader". This is a pointer that
* conventionally points to the first item after our 4-byte uncompressed
- * varlena header, from which we can read uint32 values through bitwise
- * operations.
+ * varlena header, from which we can read flags using bitwise operations.
*
- * Sometimes we pass a superheader reference to a function, and it doesn't
+ * Frequently, we pass a superheader reference to a function, and it doesn't
* matter if it points to just after the start of a Jsonb, or to a Jentry.
* Either way, the type punning works and the superheader/header metadata is
* used to operate on an underlying JsonbValue.
*
- * In a few contexts, when passing a superheader, there actually is an
- * assumption that it really does point to just past vl_len_ in a Jsonb. We
- * assert that it's "superheader sane" in those contexts. In general, this is
- * expected to work just fine, as care has been taken to make the nested layout
- * consistent to the extent that it matters between the least nested level
- * (Jsonb), and deeper nested levels (Jentry).
+ * In a few contexts, when passing a superheader, there may be an assumption
+ * that it really does point to just past vl_len_ in a Jsonb, but that has
+ * nothing to do with layout. Care has been taken to make the nested layout
+ * consistent (to the extent that it matters) between the least nested level
+ * (Jsonb superheaders), and deeper nesting levels (Jentry headers).
*/
typedef struct
} Jsonb;
/*
- * JEntry: there is one of these for each key _and_ value in a jsonb object
+ * JEntry: there is one of these for each key _and_ value in a jsonb object.
*
* The position offset points to the _end_ so that we can get the length by
* subtraction from the previous entry. The JENTRY_ISFIRST flag indicates if
/* Pair within an Object */
struct JsonbPair
{
- JsonbValue key;
- JsonbValue value;
+ JsonbValue key; /* Must be a jbvString */
+ JsonbValue value; /* May be of any type */
uint32 order; /* preserves order of pairs with equal keys */
};
int i;
/* Current value */
- uint32 containerType; /* Never of value JB_FLAG_SCALAR, since
+ uint32 containerType; /* Never of value JB_FSCALAR, since
* scalars will appear in pseudo-arrays */
uint32 nElems; /* Number of elements in metaArray
* (we * 2 for pairs within objects) */
JEntry *meta;
/*
- * Data proper. Note that this points just past end of metaArray. We use
+ * Data proper. Note that this points just past end of meta array. We use
* "meta" metadata (Jentrys) with JBE_OFF() macro to find appropriate
* offsets into this array.
*/