Restructure jsonb_op.c
authorPeter Geoghegan <[email protected]>
Fri, 7 Mar 2014 20:55:03 +0000 (12:55 -0800)
committerPeter Geoghegan <[email protected]>
Fri, 7 Mar 2014 20:55:03 +0000 (12:55 -0800)
src/backend/utils/adt/jsonb_op.c

index 00e05283ca8ec535e759a8b1b51665b4dec855b6..0a1de1cffe9c915978c1bdef7915b59516701a4e 100644 (file)
@@ -11,7 +11,6 @@
  *
  *-------------------------------------------------------------------------
  */
-
 #include "postgres.h"
 
 #include "access/hash.h"
 #include "utils/memutils.h"
 #include "utils/pg_crc.h"
 
-static JsonbValue *
-arrayToJsonbSortedArray(ArrayType *a)
-{
-   Datum      *key_datums;
-   bool       *key_nulls;
-   int         key_count;
-   JsonbValue *v;
-   int         i,
-               j;
-   bool        hasNonUniq = false;
-
-   deconstruct_array(a,
-                     TEXTOID, -1, false, 'i',
-                     &key_datums, &key_nulls, &key_count);
-
-   if (key_count == 0)
-       return NULL;
-
-   /*
-    * A text array uses at least eight bytes per element, so any overflow in
-    * "key_count * sizeof(JsonbPair)" is small enough for palloc() to catch.
-    * However, credible improvements to the array format could invalidate
-    * that assumption.  Therefore, use an explicit check rather than relying
-    * on palloc() to complain.
-    */
-   if (key_count > MaxAllocSize / sizeof(JsonbPair))
-       ereport(ERROR,
-               (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
-             errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
-                    key_count, (int) (MaxAllocSize / sizeof(JsonbPair)))));
-
-   v = palloc(sizeof(*v));
-   v->type = jbvArray;
-   v->array.scalar = false;
-   v->array.elems = palloc(sizeof(*v->object.pairs) * key_count);
-
-   for (i = 0, j = 0; i < key_count; i++)
-   {
-       if (!key_nulls[i])
-       {
-           v->array.elems[j].type = jbvString;
-           v->array.elems[j].string.val = VARDATA(key_datums[i]);
-           v->array.elems[j].string.len = VARSIZE(key_datums[i]) - VARHDRSZ;
-           j++;
-       }
-   }
-   v->array.nelems = j;
-
-   if (v->array.nelems > 1)
-       qsort_arg(v->array.elems, v->array.nelems, sizeof(*v->array.elems),
-       compareJsonbStringValue /* compareJsonbStringValue */ , &hasNonUniq);
-
-   if (hasNonUniq)
-   {
-       JsonbValue *ptr = v->array.elems + 1,
-                  *res = v->array.elems;
-
-       while (ptr - v->array.elems < v->array.nelems)
-       {
-           if (!(ptr->string.len == res->string.len &&
-            memcmp(ptr->string.val, res->string.val, ptr->string.len) == 0))
-           {
-               res++;
-               *res = *ptr;
-           }
-
-           ptr++;
-       }
-
-       v->array.nelems = res + 1 - v->array.elems;
-   }
-
-   return v;
-}
+static bool deepContains(JsonbIterator ** it1, JsonbIterator ** it2);
+static JsonbValue *arrayToJsonbSortedArray(ArrayType *a);
 
 Datum
 jsonb_exists(PG_FUNCTION_ARGS)
@@ -193,157 +120,6 @@ jsonb_exists_all(PG_FUNCTION_ARGS)
    PG_RETURN_BOOL(res);
 }
 
-static bool
-deepContains(JsonbIterator ** it1, JsonbIterator ** it2)
-{
-   uint32      r1,
-               r2;
-   JsonbValue  v1,
-               v2;
-   bool        res = true;
-
-   r1 = JsonbIteratorGet(it1, &v1, false);
-   r2 = JsonbIteratorGet(it2, &v2, false);
-
-   if (r1 != r2)
-   {
-       res = false;
-   }
-   else if (r1 == WJB_BEGIN_OBJECT)
-   {
-       uint32      lowbound = 0;
-       JsonbValue *v;
-
-       for (;;)
-       {
-           r2 = JsonbIteratorGet(it2, &v2, false);
-           if (r2 == WJB_END_OBJECT)
-               break;
-
-           Assert(r2 == WJB_KEY);
-
-           v = findUncompressedJsonbValueByValue((*it1)->buffer,
-                                                 JB_FLAG_OBJECT,
-                                                 &lowbound, &v2);
-
-           if (v == NULL)
-           {
-               res = false;
-               break;
-           }
-
-           r2 = JsonbIteratorGet(it2, &v2, true);
-           Assert(r2 == WJB_VALUE);
-
-           if (v->type != v2.type)
-           {
-               res = false;
-               break;
-           }
-           else if (v->type == jbvString || v->type == jbvNull ||
-                    v->type == jbvBool || v->type == jbvNumeric)
-           {
-               if (compareJsonbValue(v, &v2) != 0)
-               {
-                   res = false;
-                   break;
-               }
-           }
-           else
-           {
-               JsonbIterator *it1a,
-                          *it2a;
-
-               Assert(v2.type == jbvBinary);
-               Assert(v->type == jbvBinary);
-
-               it1a = JsonbIteratorInit(v->binary.data);
-               it2a = JsonbIteratorInit(v2.binary.data);
-
-               if ((res = deepContains(&it1a, &it2a)) == false)
-                   break;
-           }
-       }
-   }
-   else if (r1 == WJB_BEGIN_ARRAY)
-   {
-       JsonbValue *v;
-       JsonbValue *av = NULL;
-       uint32      nelems = v1.array.nelems;
-
-       for (;;)
-       {
-           r2 = JsonbIteratorGet(it2, &v2, true);
-           if (r2 == WJB_END_ARRAY)
-               break;
-
-           Assert(r2 == WJB_ELEM);
-
-           if (v2.type == jbvString || v2.type == jbvNull ||
-               v2.type == jbvBool || v2.type == jbvNumeric)
-           {
-               v = findUncompressedJsonbValueByValue((*it1)->buffer,
-                                                     JB_FLAG_ARRAY, NULL,
-                                                     &v2);
-               if (v == NULL)
-               {
-                   res = false;
-                   break;
-               }
-           }
-           else
-           {
-               uint32      i;
-
-               if (av == NULL)
-               {
-                   uint32      j = 0;
-
-                   av = palloc(sizeof(*av) * nelems);
-
-                   for (i = 0; i < nelems; i++)
-                   {
-                       r2 = JsonbIteratorGet(it1, &v1, true);
-                       Assert(r2 == WJB_ELEM);
-
-                       if (v1.type == jbvBinary)
-                           av[j++] = v1;
-                   }
-
-                   if (j == 0)
-                   {
-                       res = false;
-                       break;
-                   }
-
-                   nelems = j;
-               }
-
-               res = false;
-               for (i = 0; res == false && i < nelems; i++)
-               {
-                   JsonbIterator *it1a,
-                              *it2a;
-
-                   it1a = JsonbIteratorInit(av[i].binary.data);
-                   it2a = JsonbIteratorInit(v2.binary.data);
-
-                   res = deepContains(&it1a, &it2a);
-               }
-
-               if (res == false)
-                   break;
-           }
-       }
-   }
-   else
-   {
-       elog(ERROR, "invalid jsonb container type");
-   }
-
-   return res;
-}
-
 Datum
 jsonb_contains(PG_FUNCTION_ARGS)
 {
@@ -541,3 +317,229 @@ jsonb_hash(PG_FUNCTION_ARGS)
    PG_FREE_IF_COPY(jb, 0);
    PG_RETURN_INT32(crc);
 }
+
+static bool
+deepContains(JsonbIterator ** it1, JsonbIterator ** it2)
+{
+   uint32      r1,
+               r2;
+   JsonbValue  v1,
+               v2;
+   bool        res = true;
+
+   r1 = JsonbIteratorGet(it1, &v1, false);
+   r2 = JsonbIteratorGet(it2, &v2, false);
+
+   if (r1 != r2)
+   {
+       res = false;
+   }
+   else if (r1 == WJB_BEGIN_OBJECT)
+   {
+       uint32      lowbound = 0;
+       JsonbValue *v;
+
+       for (;;)
+       {
+           r2 = JsonbIteratorGet(it2, &v2, false);
+           if (r2 == WJB_END_OBJECT)
+               break;
+
+           Assert(r2 == WJB_KEY);
+
+           v = findUncompressedJsonbValueByValue((*it1)->buffer,
+                                                 JB_FLAG_OBJECT,
+                                                 &lowbound, &v2);
+
+           if (v == NULL)
+           {
+               res = false;
+               break;
+           }
+
+           r2 = JsonbIteratorGet(it2, &v2, true);
+           Assert(r2 == WJB_VALUE);
+
+           if (v->type != v2.type)
+           {
+               res = false;
+               break;
+           }
+           else if (v->type == jbvString || v->type == jbvNull ||
+                    v->type == jbvBool || v->type == jbvNumeric)
+           {
+               if (compareJsonbValue(v, &v2) != 0)
+               {
+                   res = false;
+                   break;
+               }
+           }
+           else
+           {
+               JsonbIterator *it1a,
+                          *it2a;
+
+               Assert(v2.type == jbvBinary);
+               Assert(v->type == jbvBinary);
+
+               it1a = JsonbIteratorInit(v->binary.data);
+               it2a = JsonbIteratorInit(v2.binary.data);
+
+               if ((res = deepContains(&it1a, &it2a)) == false)
+                   break;
+           }
+       }
+   }
+   else if (r1 == WJB_BEGIN_ARRAY)
+   {
+       JsonbValue *v;
+       JsonbValue *av = NULL;
+       uint32      nelems = v1.array.nelems;
+
+       for (;;)
+       {
+           r2 = JsonbIteratorGet(it2, &v2, true);
+           if (r2 == WJB_END_ARRAY)
+               break;
+
+           Assert(r2 == WJB_ELEM);
+
+           if (v2.type == jbvString || v2.type == jbvNull ||
+               v2.type == jbvBool || v2.type == jbvNumeric)
+           {
+               v = findUncompressedJsonbValueByValue((*it1)->buffer,
+                                                     JB_FLAG_ARRAY, NULL,
+                                                     &v2);
+               if (v == NULL)
+               {
+                   res = false;
+                   break;
+               }
+           }
+           else
+           {
+               uint32      i;
+
+               if (av == NULL)
+               {
+                   uint32      j = 0;
+
+                   av = palloc(sizeof(*av) * nelems);
+
+                   for (i = 0; i < nelems; i++)
+                   {
+                       r2 = JsonbIteratorGet(it1, &v1, true);
+                       Assert(r2 == WJB_ELEM);
+
+                       if (v1.type == jbvBinary)
+                           av[j++] = v1;
+                   }
+
+                   if (j == 0)
+                   {
+                       res = false;
+                       break;
+                   }
+
+                   nelems = j;
+               }
+
+               res = false;
+               for (i = 0; res == false && i < nelems; i++)
+               {
+                   JsonbIterator *it1a,
+                              *it2a;
+
+                   it1a = JsonbIteratorInit(av[i].binary.data);
+                   it2a = JsonbIteratorInit(v2.binary.data);
+
+                   res = deepContains(&it1a, &it2a);
+               }
+
+               if (res == false)
+                   break;
+           }
+       }
+   }
+   else
+   {
+       elog(ERROR, "invalid jsonb container type");
+   }
+
+   return res;
+}
+
+static JsonbValue *
+arrayToJsonbSortedArray(ArrayType *a)
+{
+   Datum      *key_datums;
+   bool       *key_nulls;
+   int         key_count;
+   JsonbValue *v;
+   int         i,
+               j;
+   bool        hasNonUniq = false;
+
+   deconstruct_array(a,
+                     TEXTOID, -1, false, 'i',
+                     &key_datums, &key_nulls, &key_count);
+
+   if (key_count == 0)
+       return NULL;
+
+   /*
+    * A text array uses at least eight bytes per element, so any overflow in
+    * "key_count * sizeof(JsonbPair)" is small enough for palloc() to catch.
+    * However, credible improvements to the array format could invalidate
+    * that assumption.  Therefore, use an explicit check rather than relying
+    * on palloc() to complain.
+    */
+   if (key_count > MaxAllocSize / sizeof(JsonbPair))
+       ereport(ERROR,
+               (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+             errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
+                    key_count, (int) (MaxAllocSize / sizeof(JsonbPair)))));
+
+   v = palloc(sizeof(*v));
+   v->type = jbvArray;
+   v->array.scalar = false;
+   v->array.elems = palloc(sizeof(*v->object.pairs) * key_count);
+
+   for (i = 0, j = 0; i < key_count; i++)
+   {
+       if (!key_nulls[i])
+       {
+           v->array.elems[j].type = jbvString;
+           v->array.elems[j].string.val = VARDATA(key_datums[i]);
+           v->array.elems[j].string.len = VARSIZE(key_datums[i]) - VARHDRSZ;
+           j++;
+       }
+   }
+   v->array.nelems = j;
+
+   if (v->array.nelems > 1)
+       qsort_arg(v->array.elems, v->array.nelems, sizeof(*v->array.elems),
+       compareJsonbStringValue /* compareJsonbStringValue */ , &hasNonUniq);
+
+   if (hasNonUniq)
+   {
+       JsonbValue *ptr = v->array.elems + 1,
+                  *res = v->array.elems;
+
+       while (ptr - v->array.elems < v->array.nelems)
+       {
+           if (!(ptr->string.len == res->string.len &&
+            memcmp(ptr->string.val, res->string.val, ptr->string.len) == 0))
+           {
+               res++;
+               *res = *ptr;
+           }
+
+           ptr++;
+       }
+
+       v->array.nelems = res + 1 - v->array.elems;
+   }
+
+   return v;
+}