Move array to jsonb sorted array function
authorPeter Geoghegan <[email protected]>
Wed, 12 Mar 2014 02:41:18 +0000 (19:41 -0700)
committerPeter Geoghegan <[email protected]>
Wed, 12 Mar 2014 02:42:37 +0000 (19:42 -0700)
src/backend/utils/adt/jsonb_op.c
src/backend/utils/adt/jsonb_support.c
src/include/utils/jsonb.h

index c56a78de23583ae73ea2131482fcd4c802b2c5f9..199ce6ef825ebcc54e498bdde70a054f83ff3c41 100644 (file)
@@ -22,7 +22,6 @@
 #include "utils/pg_crc.h"
 
 static bool deepContains(JsonbIterator ** it1, JsonbIterator ** it2);
-static JsonbValue *arrayToJsonbSortedArray(ArrayType *a);
 
 Datum
 jsonb_exists(PG_FUNCTION_ARGS)
@@ -328,6 +327,9 @@ jsonb_hash(PG_FUNCTION_ARGS)
    PG_RETURN_INT32(crc);
 }
 
+/*
+ * Worker for various "contains" operators
+ */
 static bool
 deepContains(JsonbIterator ** it1, JsonbIterator ** it2)
 {
@@ -479,87 +481,3 @@ deepContains(JsonbIterator ** it1, JsonbIterator ** it2)
    return res;
 }
 
-/*
- * Convert a Postgres text array to a JsonbSortedArray, with de-duplicated key
- * elements.
- */
-static JsonbValue *
-arrayToJsonbSortedArray(ArrayType *a)
-{
-   Datum      *key_datums;
-   bool       *key_nulls;
-   int         key_count;
-   JsonbValue *result;
-   int         i,
-               j;
-   bool        hasNonUniq = false;
-
-   /* Extract data for sorting */
-   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 (%zu)",
-                       key_count, MaxAllocSize / sizeof(JsonbPair))));
-
-   result = palloc(sizeof(JsonbValue));
-   result->type = jbvArray;
-   result->array.scalar = false;
-   result->array.elems = palloc(sizeof(*result->object.pairs) * key_count);
-
-   for (i = 0, j = 0; i < key_count; i++)
-   {
-       if (!key_nulls[i])
-       {
-           result->array.elems[j].type = jbvString;
-           result->array.elems[j].string.val = VARDATA(key_datums[i]);
-           result->array.elems[j].string.len = VARSIZE(key_datums[i]) - VARHDRSZ;
-           j++;
-       }
-   }
-   result->array.nelems = j;
-
-   /*
-    * Actually sort values, determining if any were equal on the basis of full
-    * binary equality (rather than just having the same string length).
-    */
-   if (result->array.nelems > 1)
-       qsort_arg(result->array.elems, result->array.nelems,
-                 sizeof(*result->array.elems), compareJsonbStringValue,
-                 &hasNonUniq);
-
-   if (hasNonUniq)
-   {
-       JsonbValue *ptr = result->array.elems + 1,
-                  *res = result->array.elems;
-
-       while (ptr - result->array.elems < result->array.nelems)
-       {
-           /* Avoid copying over binary duplicate */
-           if (!(ptr->string.len == res->string.len &&
-                 memcmp(ptr->string.val, res->string.val, ptr->string.len) == 0))
-           {
-               res++;
-               *res = *ptr;
-           }
-
-           ptr++;
-       }
-
-       result->array.nelems = res + 1 - result->array.elems;
-   }
-
-   return result;
-}
index 828a56830067a539932c307f8ec8ae7d54683459..09fc27658146bea597a3363a94322e85d93aacd7 100644 (file)
@@ -13,7 +13,9 @@
 
 #include "miscadmin.h"
 #include "catalog/pg_collation.h"
+#include "catalog/pg_type.h"
 #include "utils/builtins.h"
+#include "utils/memutils.h"
 #include "utils/jsonb.h"
 
 #define JENTRY_ISFIRST     (0x80000000)
@@ -263,7 +265,9 @@ compareJsonbValue(JsonbValue * a, JsonbValue * b)
 }
 
 /*
- * Gives consistent ordering of Jsonb values
+ * Gives consistent ordering of Jsonb values.
+ *
+ * Strings are compared lexically.
  */
 int
 compareJsonbBinaryValue(char *a, char *b)
@@ -797,6 +801,91 @@ JsonbIteratorNext(JsonbIterator ** it, JsonbValue * v, bool skipNested)
    return res;
 }
 
+/*
+ * Convert a Postgres text array to a JsonbSortedArray, with de-duplicated key
+ * elements.
+ */
+JsonbValue *
+arrayToJsonbSortedArray(ArrayType *a)
+{
+   Datum      *key_datums;
+   bool       *key_nulls;
+   int         key_count;
+   JsonbValue *result;
+   int         i,
+               j;
+   bool        hasNonUniq = false;
+
+   /* Extract data for sorting */
+   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 (%zu)",
+                       key_count, MaxAllocSize / sizeof(JsonbPair))));
+
+   result = palloc(sizeof(JsonbValue));
+   result->type = jbvArray;
+   result->array.scalar = false;
+   result->array.elems = palloc(sizeof(*result->object.pairs) * key_count);
+
+   for (i = 0, j = 0; i < key_count; i++)
+   {
+       if (!key_nulls[i])
+       {
+           result->array.elems[j].type = jbvString;
+           result->array.elems[j].string.val = VARDATA(key_datums[i]);
+           result->array.elems[j].string.len = VARSIZE(key_datums[i]) - VARHDRSZ;
+           j++;
+       }
+   }
+   result->array.nelems = j;
+
+   /*
+    * Actually sort values, determining if any were equal on the basis of full
+    * binary equality (rather than just having the same string length).
+    */
+   if (result->array.nelems > 1)
+       qsort_arg(result->array.elems, result->array.nelems,
+                 sizeof(*result->array.elems), compareJsonbStringValue,
+                 &hasNonUniq);
+
+   if (hasNonUniq)
+   {
+       JsonbValue *ptr = result->array.elems + 1,
+                  *res = result->array.elems;
+
+       while (ptr - result->array.elems < result->array.nelems)
+       {
+           /* Avoid copying over binary duplicate */
+           if (!(ptr->string.len == res->string.len &&
+                 memcmp(ptr->string.val, res->string.val, ptr->string.len) == 0))
+           {
+               res++;
+               *res = *ptr;
+           }
+
+           ptr++;
+       }
+
+       result->array.nelems = res + 1 - result->array.elems;
+   }
+
+   return result;
+}
+
 /*
  * Walk the tree representation of jsonb
  */
index 6345f420c7e5765e645ecc4c36e4234eef32999b..f7ea17eb998c36f457fffe663efb5c1a0097b447 100644 (file)
@@ -233,6 +233,7 @@ extern JsonbValue *pushJsonbValue(ToJsonbState ** state, int r, JsonbValue *v);
 extern JsonbIterator *JsonbIteratorInit(char *buffer);
 extern int JsonbIteratorNext(JsonbIterator **it, JsonbValue *v, bool skipNested);
 extern Jsonb *JsonbValueToJsonb(JsonbValue *v);
+extern JsonbValue *arrayToJsonbSortedArray(ArrayType *a);
 
 /* jsonb.c support function */
 extern char *JsonbToCString(StringInfo out, char *in, int estimated_len);