r1 = JsonbIteratorNext(&it1, &v1, false);
r2 = JsonbIteratorNext(&it2, &v2, false);
+ /*
+ * To a limited extent we'll redundantly iterate over an array/object
+ * while re-performing the same test without any reasonable expectation
+ * of the same container types having differing lengths (as when we
+ * process a WJB_BEGIN_OBJECT, and later the corresponding
+ * WJB_END_OBJECT), but no matter.
+ */
if (r1 == r2)
{
if (r1 == WJB_DONE)
- break; /* Decisely equal */
+ {
+ /* Decisively equal */
+ Assert(res == 0);
+ break;
+ }
if (v1.type == v2.type)
{
switch (v1.type)
{
+ case jbvNull:
+ res = 0;
+ break;
case jbvString:
res = lexicalCompareJsonbStringValue(&v1, &v2);
break;
- case jbvBool:
- if (v1.boolean == v2.boolean)
- res = 0;
- else
- res = (v1.boolean > v2.boolean) ? 1 : -1;
- break;
case jbvNumeric:
res = DatumGetInt32(DirectFunctionCall2(numeric_cmp,
PointerGetDatum(v1.numeric),
PointerGetDatum(v2.numeric)));
break;
+ case jbvBool:
+ if (v1.boolean != v2.boolean)
+ res = (v1.boolean > v2.boolean) ? 1 : -1;
+ break;
case jbvArray:
if (v1.array.nElems != v2.array.nElems)
res = (v1.array.nElems > v2.array.nElems) ? 1 : -1;
if (v1.object.nPairs != v2.object.nPairs)
res = (v1.object.nPairs > v2.object.nPairs) ? 1 : -1;
break;
- default:
+ case jbvBinary:
+ /*
+ * Do nothing. We can rely on next iterator to have
+ * details of underlying type.
+ */
break;
}
}
else
{
- res = (v1.type > v2.type) ? 1 : -1; /* dummy order */
+ res = (v1.type > v2.type) ? 1 : -1; /* Type-defined order */
+ break; /* out of while loop */
}
}
else
{
- res = (r1 > r2) ? 1 : -1; /* dummy order */
+ if (v1.type == v2.type)
+ {
+ Assert(res == 0);
+ /*
+ * Types were the same, and yet since iterator return codes
+ * differed, one must have finished before the other (and thus
+ * there must be a variable number of pairs/elements).
+ */
+ if (v1.type == jbvArray)
+ {
+ Assert(v1.array.nElems != v2.array.nElems);
+ res = (v1.array.nElems > v2.array.nElems) ? 1 : -1;
+ }
+ else if (v1.type == jbvObject)
+ {
+ Assert(v1.object.nPairs != v2.object.nPairs);
+ res = (v1.object.nPairs > v2.object.nPairs) ? 1 : -1;
+ }
+ else
+ {
+ elog(ERROR, "unexpected non-container: %d", v1.type);
+ }
+
+ Assert((r1 != WJB_DONE && r2 != WJB_DONE) || res != 0);
+ }
+ else
+ {
+ /* Type-defined order */
+ res = (v1.type > v2.type) ? 1 : -1;
+ }
+ break; /* out of while loop */
}
}
while (res == 0);
* iterator we left them with to its oldest ancestor, pfree()ing as they go.
* They can depend on having any other memory previously allocated for
* iterators but not in that line having already been freed here.
+ *
+ * Returns "Jsonb binary token" value. Iterator "state" reflects the current
+ * stage of the process in a less granular fashion, and is mostly used here to
+ * track things internally with respect to particular iterators.
*/
int
JsonbIteratorNext(JsonbIterator ** it, JsonbValue * v, bool skipNested)
}
/*
- * Put JsonbValue tree into a preallocated buffer Jsonb buffer
+ * Put JsonbValue tree into a preallocated Jsonb buffer
*/
static Size
convertJsonb(JsonbValue * v, Jsonb *buffer)
/*
* JsonbIteratorNext() worker
*
- * Returns bool indicating if v was a scalar, and thus if further recursion is
- * required by caller (according to its skipNested preference). If it is
- * required, we set the caller's iterator for further recursion into the nested
- * value. If we're going to skip nested items, just set v to a jbvBinary
- * value, but don't set caller's iterator.
+ * Returns bool indicating if v was a non-jbvBinary container, and thus if
+ * further recursion is required by caller (according to its skipNested
+ * preference). If it is required, we set the caller's iterator for further
+ * recursion into the nested value. If we're going to skip nested items, just
+ * set v to a jbvBinary value, but don't set caller's iterator.
*/
static bool
formIterIsContainer(JsonbIterator ** it, JsonbValue * v, JEntry * e,