aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/jsonb_util.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2014-05-28 22:47:04 +0300
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2014-05-28 22:47:04 +0300
commitb3e5cfd5f979054e31d60adafd9e75bf9c38549a (patch)
tree52386e3074cc14d21c5e0957210414b049d6a770 /src/backend/utils/adt/jsonb_util.c
parent45b7abe59e9485657ac9380f35d2d917dd0da25b (diff)
downloadpostgresql-b3e5cfd5f979054e31d60adafd9e75bf9c38549a.tar.gz
postgresql-b3e5cfd5f979054e31d60adafd9e75bf9c38549a.zip
Jsonb comparison bug fixes.
Fix an over-zealous assertion, which didn't take into account that sometimes a scalar element can be compared against an array/object element. Avoid comparing possibly-uninitialized local variables when end-of-array or end-of-object is reached. Also fix and enhance comments a bit. Peter Geoghegan, per reports by Pavel Stehule and me.
Diffstat (limited to 'src/backend/utils/adt/jsonb_util.c')
-rw-r--r--src/backend/utils/adt/jsonb_util.c63
1 files changed, 38 insertions, 25 deletions
diff --git a/src/backend/utils/adt/jsonb_util.c b/src/backend/utils/adt/jsonb_util.c
index b741db66e90..434c68bd24e 100644
--- a/src/backend/utils/adt/jsonb_util.c
+++ b/src/backend/utils/adt/jsonb_util.c
@@ -62,13 +62,13 @@ static void uniqueifyJsonbObject(JsonbValue *object);
*
* There isn't a JsonbToJsonbValue(), because generally we find it more
* convenient to directly iterate through the Jsonb representation and only
- * really convert nested scalar values. formIterIsContainer() does this, so
- * that clients of the iteration code don't have to directly deal with the
- * binary representation (JsonbDeepContains() is a notable exception, although
- * all exceptions are internal to this module). In general, functions that
- * accept a JsonbValue argument are concerned with the manipulation of scalar
- * values, or simple containers of scalar values, where it would be
- * inconvenient to deal with a great amount of other state.
+ * really convert nested scalar values. JsonbIteratorNext() does this, so that
+ * clients of the iteration code don't have to directly deal with the binary
+ * representation (JsonbDeepContains() is a notable exception, although all
+ * exceptions are internal to this module). In general, functions that accept
+ * a JsonbValue argument are concerned with the manipulation of scalar values,
+ * or simple containers of scalar values, where it would be inconvenient to
+ * deal with a great amount of other state.
*/
Jsonb *
JsonbValueToJsonb(JsonbValue *val)
@@ -137,13 +137,6 @@ compareJsonbContainers(JsonbContainer *a, JsonbContainer *b)
ra = JsonbIteratorNext(&ita, &va, false);
rb = JsonbIteratorNext(&itb, &vb, 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 (ra == rb)
{
if (ra == WJB_DONE)
@@ -152,6 +145,17 @@ compareJsonbContainers(JsonbContainer *a, JsonbContainer *b)
break;
}
+ if (ra == WJB_END_ARRAY || ra == WJB_END_OBJECT)
+ {
+ /*
+ * There is no array or object to compare at this stage of
+ * processing. jbvArray/jbvObject values are compared
+ * initially, at the WJB_BEGIN_ARRAY and WJB_BEGIN_OBJECT
+ * tokens.
+ */
+ continue;
+ }
+
if (va.type == vb.type)
{
switch (va.type)
@@ -194,19 +198,26 @@ compareJsonbContainers(JsonbContainer *a, JsonbContainer *b)
else
{
/*
- * It's safe to assume that the types differed.
+ * It's safe to assume that the types differed, and that the va
+ * and vb values passed were set.
*
- * If the two values were the same container type, then there'd
+ * If the two values were of the same container type, then there'd
* have been a chance to observe the variation in the number of
- * elements/pairs (when processing WJB_BEGIN_OBJECT, say). They
- * can't be scalar types either, because then they'd have to be
- * contained in containers already ruled unequal due to differing
- * numbers of pairs/elements, or already directly ruled unequal
- * with a call to the underlying type's comparator.
+ * elements/pairs (when processing WJB_BEGIN_OBJECT, say). They're
+ * either two heterogeneously-typed containers, or a container and
+ * some scalar type.
+ *
+ * We don't have to consider the WJB_END_ARRAY and WJB_END_OBJECT
+ * cases here, because we would have seen the corresponding
+ * WJB_BEGIN_ARRAY and WJB_BEGIN_OBJECT tokens first, and
+ * concluded that they don't match.
*/
+ Assert(ra != WJB_END_ARRAY && ra != WJB_END_OBJECT);
+ Assert(rb != WJB_END_ARRAY && rb != WJB_END_OBJECT);
+
Assert(va.type != vb.type);
- Assert(va.type == jbvArray || va.type == jbvObject);
- Assert(vb.type == jbvArray || vb.type == jbvObject);
+ Assert(va.type != jbvBinary);
+ Assert(vb.type != jbvBinary);
/* Type-defined order */
res = (va.type > vb.type) ? 1 : -1;
}
@@ -630,7 +641,9 @@ JsonbIteratorInit(JsonbContainer *container)
* It is our job to expand the jbvBinary representation without bothering them
* with it. However, clients should not take it upon themselves to touch array
* or Object element/pair buffers, since their element/pair pointers are
- * garbage.
+ * garbage. Also, *val will not be set when returning WJB_END_ARRAY or
+ * WJB_END_OBJECT, on the assumption that it's only useful to access values
+ * when recursing in.
*/
JsonbIteratorToken
JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
@@ -686,7 +699,7 @@ recurse:
else
{
/*
- * Scalar item in array (or a container and caller didn't
+ * Scalar item in array, or a container and caller didn't
* want us to recurse into it.
*/
return WJB_ELEM;