LCOV - code coverage report
Current view: top level - src/backend/utils/adt - jsonb_util.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 553 586 94.4 %
Date: 2017-09-29 13:40:31 Functions: 34 34 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * jsonb_util.c
       4             :  *    converting between Jsonb and JsonbValues, and iterating.
       5             :  *
       6             :  * Copyright (c) 2014-2017, PostgreSQL Global Development Group
       7             :  *
       8             :  *
       9             :  * IDENTIFICATION
      10             :  *    src/backend/utils/adt/jsonb_util.c
      11             :  *
      12             :  *-------------------------------------------------------------------------
      13             :  */
      14             : #include "postgres.h"
      15             : 
      16             : #include "access/hash.h"
      17             : #include "catalog/pg_collation.h"
      18             : #include "miscadmin.h"
      19             : #include "utils/builtins.h"
      20             : #include "utils/jsonb.h"
      21             : #include "utils/memutils.h"
      22             : #include "utils/varlena.h"
      23             : 
      24             : /*
      25             :  * Maximum number of elements in an array (or key/value pairs in an object).
      26             :  * This is limited by two things: the size of the JEntry array must fit
      27             :  * in MaxAllocSize, and the number of elements (or pairs) must fit in the bits
      28             :  * reserved for that in the JsonbContainer.header field.
      29             :  *
      30             :  * (The total size of an array's or object's elements is also limited by
      31             :  * JENTRY_OFFLENMASK, but we're not concerned about that here.)
      32             :  */
      33             : #define JSONB_MAX_ELEMS (Min(MaxAllocSize / sizeof(JsonbValue), JB_CMASK))
      34             : #define JSONB_MAX_PAIRS (Min(MaxAllocSize / sizeof(JsonbPair), JB_CMASK))
      35             : 
      36             : static void fillJsonbValue(JsonbContainer *container, int index,
      37             :                char *base_addr, uint32 offset,
      38             :                JsonbValue *result);
      39             : static bool equalsJsonbScalarValue(JsonbValue *a, JsonbValue *b);
      40             : static int  compareJsonbScalarValue(JsonbValue *a, JsonbValue *b);
      41             : static Jsonb *convertToJsonb(JsonbValue *val);
      42             : static void convertJsonbValue(StringInfo buffer, JEntry *header, JsonbValue *val, int level);
      43             : static void convertJsonbArray(StringInfo buffer, JEntry *header, JsonbValue *val, int level);
      44             : static void convertJsonbObject(StringInfo buffer, JEntry *header, JsonbValue *val, int level);
      45             : static void convertJsonbScalar(StringInfo buffer, JEntry *header, JsonbValue *scalarVal);
      46             : 
      47             : static int  reserveFromBuffer(StringInfo buffer, int len);
      48             : static void appendToBuffer(StringInfo buffer, const char *data, int len);
      49             : static void copyToBuffer(StringInfo buffer, int offset, const char *data, int len);
      50             : static short padBufferToInt(StringInfo buffer);
      51             : 
      52             : static JsonbIterator *iteratorFromContainer(JsonbContainer *container, JsonbIterator *parent);
      53             : static JsonbIterator *freeAndGetParent(JsonbIterator *it);
      54             : static JsonbParseState *pushState(JsonbParseState **pstate);
      55             : static void appendKey(JsonbParseState *pstate, JsonbValue *scalarVal);
      56             : static void appendValue(JsonbParseState *pstate, JsonbValue *scalarVal);
      57             : static void appendElement(JsonbParseState *pstate, JsonbValue *scalarVal);
      58             : static int  lengthCompareJsonbStringValue(const void *a, const void *b);
      59             : static int  lengthCompareJsonbPair(const void *a, const void *b, void *arg);
      60             : static void uniqueifyJsonbObject(JsonbValue *object);
      61             : static JsonbValue *pushJsonbValueScalar(JsonbParseState **pstate,
      62             :                      JsonbIteratorToken seq,
      63             :                      JsonbValue *scalarVal);
      64             : 
      65             : /*
      66             :  * Turn an in-memory JsonbValue into a Jsonb for on-disk storage.
      67             :  *
      68             :  * There isn't a JsonbToJsonbValue(), because generally we find it more
      69             :  * convenient to directly iterate through the Jsonb representation and only
      70             :  * really convert nested scalar values.  JsonbIteratorNext() does this, so that
      71             :  * clients of the iteration code don't have to directly deal with the binary
      72             :  * representation (JsonbDeepContains() is a notable exception, although all
      73             :  * exceptions are internal to this module).  In general, functions that accept
      74             :  * a JsonbValue argument are concerned with the manipulation of scalar values,
      75             :  * or simple containers of scalar values, where it would be inconvenient to
      76             :  * deal with a great amount of other state.
      77             :  */
      78             : Jsonb *
      79       11766 : JsonbValueToJsonb(JsonbValue *val)
      80             : {
      81             :     Jsonb      *out;
      82             : 
      83       11766 :     if (IsAJsonbScalar(val))
      84             :     {
      85             :         /* Scalar value */
      86        9799 :         JsonbParseState *pstate = NULL;
      87             :         JsonbValue *res;
      88             :         JsonbValue  scalarArray;
      89             : 
      90        9799 :         scalarArray.type = jbvArray;
      91        9799 :         scalarArray.val.array.rawScalar = true;
      92        9799 :         scalarArray.val.array.nElems = 1;
      93             : 
      94        9799 :         pushJsonbValue(&pstate, WJB_BEGIN_ARRAY, &scalarArray);
      95        9799 :         pushJsonbValue(&pstate, WJB_ELEM, val);
      96        9799 :         res = pushJsonbValue(&pstate, WJB_END_ARRAY, NULL);
      97             : 
      98        9799 :         out = convertToJsonb(res);
      99             :     }
     100        1967 :     else if (val->type == jbvObject || val->type == jbvArray)
     101             :     {
     102        1878 :         out = convertToJsonb(val);
     103             :     }
     104             :     else
     105             :     {
     106          89 :         Assert(val->type == jbvBinary);
     107          89 :         out = palloc(VARHDRSZ + val->val.binary.len);
     108          89 :         SET_VARSIZE(out, VARHDRSZ + val->val.binary.len);
     109          89 :         memcpy(VARDATA(out), val->val.binary.data, val->val.binary.len);
     110             :     }
     111             : 
     112       11766 :     return out;
     113             : }
     114             : 
     115             : /*
     116             :  * Get the offset of the variable-length portion of a Jsonb node within
     117             :  * the variable-length-data part of its container.  The node is identified
     118             :  * by index within the container's JEntry array.
     119             :  */
     120             : uint32
     121      262931 : getJsonbOffset(const JsonbContainer *jc, int index)
     122             : {
     123      262931 :     uint32      offset = 0;
     124             :     int         i;
     125             : 
     126             :     /*
     127             :      * Start offset of this entry is equal to the end offset of the previous
     128             :      * entry.  Walk backwards to the most recent entry stored as an end
     129             :      * offset, returning that offset plus any lengths in between.
     130             :      */
     131      837590 :     for (i = index - 1; i >= 0; i--)
     132             :     {
     133      731221 :         offset += JBE_OFFLENFLD(jc->children[i]);
     134      731221 :         if (JBE_HAS_OFF(jc->children[i]))
     135      156562 :             break;
     136             :     }
     137             : 
     138      262931 :     return offset;
     139             : }
     140             : 
     141             : /*
     142             :  * Get the length of the variable-length portion of a Jsonb node.
     143             :  * The node is identified by index within the container's JEntry array.
     144             :  */
     145             : uint32
     146      211651 : getJsonbLength(const JsonbContainer *jc, int index)
     147             : {
     148             :     uint32      off;
     149             :     uint32      len;
     150             : 
     151             :     /*
     152             :      * If the length is stored directly in the JEntry, just return it.
     153             :      * Otherwise, get the begin offset of the entry, and subtract that from
     154             :      * the stored end+1 offset.
     155             :      */
     156      211651 :     if (JBE_HAS_OFF(jc->children[index]))
     157             :     {
     158       89421 :         off = getJsonbOffset(jc, index);
     159       89421 :         len = JBE_OFFLENFLD(jc->children[index]) - off;
     160             :     }
     161             :     else
     162      122230 :         len = JBE_OFFLENFLD(jc->children[index]);
     163             : 
     164      211651 :     return len;
     165             : }
     166             : 
     167             : /*
     168             :  * BT comparator worker function.  Returns an integer less than, equal to, or
     169             :  * greater than zero, indicating whether a is less than, equal to, or greater
     170             :  * than b.  Consistent with the requirements for a B-Tree operator class
     171             :  *
     172             :  * Strings are compared lexically, in contrast with other places where we use a
     173             :  * much simpler comparator logic for searching through Strings.  Since this is
     174             :  * called from B-Tree support function 1, we're careful about not leaking
     175             :  * memory here.
     176             :  */
     177             : int
     178       56080 : compareJsonbContainers(JsonbContainer *a, JsonbContainer *b)
     179             : {
     180             :     JsonbIterator *ita,
     181             :                *itb;
     182       56080 :     int         res = 0;
     183             : 
     184       56080 :     ita = JsonbIteratorInit(a);
     185       56080 :     itb = JsonbIteratorInit(b);
     186             : 
     187             :     do
     188             :     {
     189             :         JsonbValue  va,
     190             :                     vb;
     191             :         JsonbIteratorToken ra,
     192             :                     rb;
     193             : 
     194      157516 :         ra = JsonbIteratorNext(&ita, &va, false);
     195      157516 :         rb = JsonbIteratorNext(&itb, &vb, false);
     196             : 
     197      157516 :         if (ra == rb)
     198             :         {
     199      157516 :             if (ra == WJB_DONE)
     200             :             {
     201             :                 /* Decisively equal */
     202        5441 :                 break;
     203             :             }
     204             : 
     205      152075 :             if (ra == WJB_END_ARRAY || ra == WJB_END_OBJECT)
     206             :             {
     207             :                 /*
     208             :                  * There is no array or object to compare at this stage of
     209             :                  * processing.  jbvArray/jbvObject values are compared
     210             :                  * initially, at the WJB_BEGIN_ARRAY and WJB_BEGIN_OBJECT
     211             :                  * tokens.
     212             :                  */
     213        5468 :                 continue;
     214             :             }
     215             : 
     216      146607 :             if (va.type == vb.type)
     217             :             {
     218      146607 :                 switch (va.type)
     219             :                 {
     220             :                     case jbvString:
     221             :                     case jbvNull:
     222             :                     case jbvNumeric:
     223             :                     case jbvBool:
     224       90447 :                         res = compareJsonbScalarValue(&va, &vb);
     225       90447 :                         break;
     226             :                     case jbvArray:
     227             : 
     228             :                         /*
     229             :                          * This could be a "raw scalar" pseudo array.  That's
     230             :                          * a special case here though, since we still want the
     231             :                          * general type-based comparisons to apply, and as far
     232             :                          * as we're concerned a pseudo array is just a scalar.
     233             :                          */
     234          61 :                         if (va.val.array.rawScalar != vb.val.array.rawScalar)
     235           0 :                             res = (va.val.array.rawScalar) ? -1 : 1;
     236          61 :                         if (va.val.array.nElems != vb.val.array.nElems)
     237          30 :                             res = (va.val.array.nElems > vb.val.array.nElems) ? 1 : -1;
     238          61 :                         break;
     239             :                     case jbvObject:
     240       56099 :                         if (va.val.object.nPairs != vb.val.object.nPairs)
     241       17422 :                             res = (va.val.object.nPairs > vb.val.object.nPairs) ? 1 : -1;
     242       56099 :                         break;
     243             :                     case jbvBinary:
     244           0 :                         elog(ERROR, "unexpected jbvBinary value");
     245             :                 }
     246             :             }
     247             :             else
     248             :             {
     249             :                 /* Type-defined order */
     250           0 :                 res = (va.type > vb.type) ? 1 : -1;
     251             :             }
     252             :         }
     253             :         else
     254             :         {
     255             :             /*
     256             :              * It's safe to assume that the types differed, and that the va
     257             :              * and vb values passed were set.
     258             :              *
     259             :              * If the two values were of the same container type, then there'd
     260             :              * have been a chance to observe the variation in the number of
     261             :              * elements/pairs (when processing WJB_BEGIN_OBJECT, say). They're
     262             :              * either two heterogeneously-typed containers, or a container and
     263             :              * some scalar type.
     264             :              *
     265             :              * We don't have to consider the WJB_END_ARRAY and WJB_END_OBJECT
     266             :              * cases here, because we would have seen the corresponding
     267             :              * WJB_BEGIN_ARRAY and WJB_BEGIN_OBJECT tokens first, and
     268             :              * concluded that they don't match.
     269             :              */
     270           0 :             Assert(ra != WJB_END_ARRAY && ra != WJB_END_OBJECT);
     271           0 :             Assert(rb != WJB_END_ARRAY && rb != WJB_END_OBJECT);
     272             : 
     273           0 :             Assert(va.type != vb.type);
     274           0 :             Assert(va.type != jbvBinary);
     275           0 :             Assert(vb.type != jbvBinary);
     276             :             /* Type-defined order */
     277           0 :             res = (va.type > vb.type) ? 1 : -1;
     278             :         }
     279             :     }
     280      152075 :     while (res == 0);
     281             : 
     282      162852 :     while (ita != NULL)
     283             :     {
     284       50692 :         JsonbIterator *i = ita->parent;
     285             : 
     286       50692 :         pfree(ita);
     287       50692 :         ita = i;
     288             :     }
     289      162852 :     while (itb != NULL)
     290             :     {
     291       50692 :         JsonbIterator *i = itb->parent;
     292             : 
     293       50692 :         pfree(itb);
     294       50692 :         itb = i;
     295             :     }
     296             : 
     297       56080 :     return res;
     298             : }
     299             : 
     300             : /*
     301             :  * Find value in object (i.e. the "value" part of some key/value pair in an
     302             :  * object), or find a matching element if we're looking through an array.  Do
     303             :  * so on the basis of equality of the object keys only, or alternatively
     304             :  * element values only, with a caller-supplied value "key".  The "flags"
     305             :  * argument allows the caller to specify which container types are of interest.
     306             :  *
     307             :  * This exported utility function exists to facilitate various cases concerned
     308             :  * with "containment".  If asked to look through an object, the caller had
     309             :  * better pass a Jsonb String, because their keys can only be strings.
     310             :  * Otherwise, for an array, any type of JsonbValue will do.
     311             :  *
     312             :  * In order to proceed with the search, it is necessary for callers to have
     313             :  * both specified an interest in exactly one particular container type with an
     314             :  * appropriate flag, as well as having the pointed-to Jsonb container be of
     315             :  * one of those same container types at the top level. (Actually, we just do
     316             :  * whichever makes sense to save callers the trouble of figuring it out - at
     317             :  * most one can make sense, because the container either points to an array
     318             :  * (possibly a "raw scalar" pseudo array) or an object.)
     319             :  *
     320             :  * Note that we can return a jbvBinary JsonbValue if this is called on an
     321             :  * object, but we never do so on an array.  If the caller asks to look through
     322             :  * a container type that is not of the type pointed to by the container,
     323             :  * immediately fall through and return NULL.  If we cannot find the value,
     324             :  * return NULL.  Otherwise, return palloc()'d copy of value.
     325             :  */
     326             : JsonbValue *
     327       17163 : findJsonbValueFromContainer(JsonbContainer *container, uint32 flags,
     328             :                             JsonbValue *key)
     329             : {
     330       17163 :     JEntry     *children = container->children;
     331       17163 :     int         count = JsonContainerSize(container);
     332             :     JsonbValue *result;
     333             : 
     334       17163 :     Assert((flags & ~(JB_FARRAY | JB_FOBJECT)) == 0);
     335             : 
     336             :     /* Quick out without a palloc cycle if object/array is empty */
     337       17163 :     if (count <= 0)
     338        1062 :         return NULL;
     339             : 
     340       16101 :     result = palloc(sizeof(JsonbValue));
     341             : 
     342       16101 :     if ((flags & JB_FARRAY) && JsonContainerIsArray(container))
     343          16 :     {
     344          80 :         char       *base_addr = (char *) (children + count);
     345          80 :         uint32      offset = 0;
     346             :         int         i;
     347             : 
     348         149 :         for (i = 0; i < count; i++)
     349             :         {
     350         133 :             fillJsonbValue(container, i, base_addr, offset, result);
     351             : 
     352         133 :             if (key->type == result->type)
     353             :             {
     354         118 :                 if (equalsJsonbScalarValue(key, result))
     355          64 :                     return result;
     356             :             }
     357             : 
     358          69 :             JBE_ADVANCE_OFFSET(offset, children[i]);
     359             :         }
     360             :     }
     361       16021 :     else if ((flags & JB_FOBJECT) && JsonContainerIsObject(container))
     362             :     {
     363             :         /* Since this is an object, account for *Pairs* of Jentrys */
     364       16021 :         char       *base_addr = (char *) (children + count * 2);
     365       16021 :         uint32      stopLow = 0,
     366       16021 :                     stopHigh = count;
     367             : 
     368             :         /* Object key passed by caller must be a string */
     369       16021 :         Assert(key->type == jbvString);
     370             : 
     371             :         /* Binary search on object/pair keys *only* */
     372       67149 :         while (stopLow < stopHigh)
     373             :         {
     374             :             uint32      stopMiddle;
     375             :             int         difference;
     376             :             JsonbValue  candidate;
     377             : 
     378       37894 :             stopMiddle = stopLow + (stopHigh - stopLow) / 2;
     379             : 
     380       37894 :             candidate.type = jbvString;
     381       37894 :             candidate.val.string.val =
     382       37894 :                 base_addr + getJsonbOffset(container, stopMiddle);
     383       37894 :             candidate.val.string.len = getJsonbLength(container, stopMiddle);
     384             : 
     385       37894 :             difference = lengthCompareJsonbStringValue(&candidate, key);
     386             : 
     387       37894 :             if (difference == 0)
     388             :             {
     389             :                 /* Found our key, return corresponding value */
     390        2787 :                 int         index = stopMiddle + count;
     391             : 
     392        2787 :                 fillJsonbValue(container, index, base_addr,
     393             :                                getJsonbOffset(container, index),
     394             :                                result);
     395             : 
     396        2787 :                 return result;
     397             :             }
     398             :             else
     399             :             {
     400       35107 :                 if (difference < 0)
     401       14023 :                     stopLow = stopMiddle + 1;
     402             :                 else
     403       21084 :                     stopHigh = stopMiddle;
     404             :             }
     405             :         }
     406             :     }
     407             : 
     408             :     /* Not found */
     409       13250 :     pfree(result);
     410       13250 :     return NULL;
     411             : }
     412             : 
     413             : /*
     414             :  * Get i-th value of a Jsonb array.
     415             :  *
     416             :  * Returns palloc()'d copy of the value, or NULL if it does not exist.
     417             :  */
     418             : JsonbValue *
     419          57 : getIthJsonbValueFromContainer(JsonbContainer *container, uint32 i)
     420             : {
     421             :     JsonbValue *result;
     422             :     char       *base_addr;
     423             :     uint32      nelements;
     424             : 
     425          57 :     if (!JsonContainerIsArray(container))
     426           0 :         elog(ERROR, "not a jsonb array");
     427             : 
     428          57 :     nelements = JsonContainerSize(container);
     429          57 :     base_addr = (char *) &container->children[nelements];
     430             : 
     431          57 :     if (i >= nelements)
     432           9 :         return NULL;
     433             : 
     434          48 :     result = palloc(sizeof(JsonbValue));
     435             : 
     436          48 :     fillJsonbValue(container, i, base_addr,
     437             :                    getJsonbOffset(container, i),
     438             :                    result);
     439             : 
     440          48 :     return result;
     441             : }
     442             : 
     443             : /*
     444             :  * A helper function to fill in a JsonbValue to represent an element of an
     445             :  * array, or a key or value of an object.
     446             :  *
     447             :  * The node's JEntry is at container->children[index], and its variable-length
     448             :  * data is at base_addr + offset.  We make the caller determine the offset
     449             :  * since in many cases the caller can amortize that work across multiple
     450             :  * children.  When it can't, it can just call getJsonbOffset().
     451             :  *
     452             :  * A nested array or object will be returned as jbvBinary, ie. it won't be
     453             :  * expanded.
     454             :  */
     455             : static void
     456      250748 : fillJsonbValue(JsonbContainer *container, int index,
     457             :                char *base_addr, uint32 offset,
     458             :                JsonbValue *result)
     459             : {
     460      250748 :     JEntry      entry = container->children[index];
     461             : 
     462      250748 :     if (JBE_ISNULL(entry))
     463             :     {
     464         474 :         result->type = jbvNull;
     465             :     }
     466      250274 :     else if (JBE_ISSTRING(entry))
     467             :     {
     468      172399 :         result->type = jbvString;
     469      172399 :         result->val.string.val = base_addr + offset;
     470      172399 :         result->val.string.len = getJsonbLength(container, index);
     471      172399 :         Assert(result->val.string.len >= 0);
     472             :     }
     473       77875 :     else if (JBE_ISNUMERIC(entry))
     474             :     {
     475       54795 :         result->type = jbvNumeric;
     476       54795 :         result->val.numeric = (Numeric) (base_addr + INTALIGN(offset));
     477             :     }
     478       23080 :     else if (JBE_ISBOOL_TRUE(entry))
     479             :     {
     480       10414 :         result->type = jbvBool;
     481       10414 :         result->val.boolean = true;
     482             :     }
     483       12666 :     else if (JBE_ISBOOL_FALSE(entry))
     484             :     {
     485       11308 :         result->type = jbvBool;
     486       11308 :         result->val.boolean = false;
     487             :     }
     488             :     else
     489             :     {
     490        1358 :         Assert(JBE_ISCONTAINER(entry));
     491        1358 :         result->type = jbvBinary;
     492             :         /* Remove alignment padding from data pointer and length */
     493        1358 :         result->val.binary.data = (JsonbContainer *) (base_addr + INTALIGN(offset));
     494        2716 :         result->val.binary.len = getJsonbLength(container, index) -
     495        1358 :             (INTALIGN(offset) - offset);
     496             :     }
     497      250748 : }
     498             : 
     499             : /*
     500             :  * Push JsonbValue into JsonbParseState.
     501             :  *
     502             :  * Used when parsing JSON tokens to form Jsonb, or when converting an in-memory
     503             :  * JsonbValue to a Jsonb.
     504             :  *
     505             :  * Initial state of *JsonbParseState is NULL, since it'll be allocated here
     506             :  * originally (caller will get JsonbParseState back by reference).
     507             :  *
     508             :  * Only sequential tokens pertaining to non-container types should pass a
     509             :  * JsonbValue.  There is one exception -- WJB_BEGIN_ARRAY callers may pass a
     510             :  * "raw scalar" pseudo array to append it - the actual scalar should be passed
     511             :  * next and it will be added as the only member of the array.
     512             :  *
     513             :  * Values of type jvbBinary, which are rolled up arrays and objects,
     514             :  * are unpacked before being added to the result.
     515             :  */
     516             : JsonbValue *
     517       51630 : pushJsonbValue(JsonbParseState **pstate, JsonbIteratorToken seq,
     518             :                JsonbValue *jbval)
     519             : {
     520             :     JsonbIterator *it;
     521       51630 :     JsonbValue *res = NULL;
     522             :     JsonbValue  v;
     523             :     JsonbIteratorToken tok;
     524             : 
     525       68632 :     if (!jbval || (seq != WJB_ELEM && seq != WJB_VALUE) ||
     526       17002 :         jbval->type != jbvBinary)
     527             :     {
     528             :         /* drop through */
     529       51628 :         return pushJsonbValueScalar(pstate, seq, jbval);
     530             :     }
     531             : 
     532             :     /* unpack the binary and add each piece to the pstate */
     533           2 :     it = JsonbIteratorInit(jbval->val.binary.data);
     534          14 :     while ((tok = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
     535          10 :         res = pushJsonbValueScalar(pstate, tok,
     536             :                                    tok < WJB_BEGIN_ARRAY ? &v : NULL);
     537             : 
     538           2 :     return res;
     539             : }
     540             : 
     541             : /*
     542             :  * Do the actual pushing, with only scalar or pseudo-scalar-array values
     543             :  * accepted.
     544             :  */
     545             : static JsonbValue *
     546       51638 : pushJsonbValueScalar(JsonbParseState **pstate, JsonbIteratorToken seq,
     547             :                      JsonbValue *scalarVal)
     548             : {
     549       51638 :     JsonbValue *result = NULL;
     550             : 
     551       51638 :     switch (seq)
     552             :     {
     553             :         case WJB_BEGIN_ARRAY:
     554       11660 :             Assert(!scalarVal || scalarVal->val.array.rawScalar);
     555       11660 :             *pstate = pushState(pstate);
     556       11660 :             result = &(*pstate)->contVal;
     557       11660 :             (*pstate)->contVal.type = jbvArray;
     558       11660 :             (*pstate)->contVal.val.array.nElems = 0;
     559       21586 :             (*pstate)->contVal.val.array.rawScalar = (scalarVal &&
     560        9926 :                                                       scalarVal->val.array.rawScalar);
     561       11660 :             if (scalarVal && scalarVal->val.array.nElems > 0)
     562             :             {
     563             :                 /* Assume that this array is still really a scalar */
     564        9926 :                 Assert(scalarVal->type == jbvArray);
     565        9926 :                 (*pstate)->size = scalarVal->val.array.nElems;
     566             :             }
     567             :             else
     568             :             {
     569        1734 :                 (*pstate)->size = 4;
     570             :             }
     571       23320 :             (*pstate)->contVal.val.array.elems = palloc(sizeof(JsonbValue) *
     572       11660 :                                                         (*pstate)->size);
     573       11660 :             break;
     574             :         case WJB_BEGIN_OBJECT:
     575        2922 :             Assert(!scalarVal);
     576        2922 :             *pstate = pushState(pstate);
     577        2922 :             result = &(*pstate)->contVal;
     578        2922 :             (*pstate)->contVal.type = jbvObject;
     579        2922 :             (*pstate)->contVal.val.object.nPairs = 0;
     580        2922 :             (*pstate)->size = 4;
     581        5844 :             (*pstate)->contVal.val.object.pairs = palloc(sizeof(JsonbPair) *
     582        2922 :                                                          (*pstate)->size);
     583        2922 :             break;
     584             :         case WJB_KEY:
     585        7406 :             Assert(scalarVal->type == jbvString);
     586        7406 :             appendKey(*pstate, scalarVal);
     587        7406 :             break;
     588             :         case WJB_VALUE:
     589        5923 :             Assert(IsAJsonbScalar(scalarVal));
     590        5923 :             appendValue(*pstate, scalarVal);
     591        5923 :             break;
     592             :         case WJB_ELEM:
     593       11081 :             Assert(IsAJsonbScalar(scalarVal));
     594       11081 :             appendElement(*pstate, scalarVal);
     595       11081 :             break;
     596             :         case WJB_END_OBJECT:
     597        2010 :             uniqueifyJsonbObject(&(*pstate)->contVal);
     598             :             /* fall through! */
     599             :         case WJB_END_ARRAY:
     600             :             /* Steps here common to WJB_END_OBJECT case */
     601       12646 :             Assert(!scalarVal);
     602       12646 :             result = &(*pstate)->contVal;
     603             : 
     604             :             /*
     605             :              * Pop stack and push current array/object as value in parent
     606             :              * array/object
     607             :              */
     608       12646 :             *pstate = (*pstate)->next;
     609       12646 :             if (*pstate)
     610             :             {
     611         967 :                 switch ((*pstate)->contVal.type)
     612             :                 {
     613             :                     case jbvArray:
     614         368 :                         appendElement(*pstate, result);
     615         368 :                         break;
     616             :                     case jbvObject:
     617         599 :                         appendValue(*pstate, result);
     618         599 :                         break;
     619             :                     default:
     620           0 :                         elog(ERROR, "invalid jsonb container type");
     621             :                 }
     622             :             }
     623       12646 :             break;
     624             :         default:
     625           0 :             elog(ERROR, "unrecognized jsonb sequential processing token");
     626             :     }
     627             : 
     628       51638 :     return result;
     629             : }
     630             : 
     631             : /*
     632             :  * pushJsonbValue() worker:  Iteration-like forming of Jsonb
     633             :  */
     634             : static JsonbParseState *
     635       14582 : pushState(JsonbParseState **pstate)
     636             : {
     637       14582 :     JsonbParseState *ns = palloc(sizeof(JsonbParseState));
     638             : 
     639       14582 :     ns->next = *pstate;
     640       14582 :     return ns;
     641             : }
     642             : 
     643             : /*
     644             :  * pushJsonbValue() worker:  Append a pair key to state when generating a Jsonb
     645             :  */
     646             : static void
     647        7406 : appendKey(JsonbParseState *pstate, JsonbValue *string)
     648             : {
     649        7406 :     JsonbValue *object = &pstate->contVal;
     650             : 
     651        7406 :     Assert(object->type == jbvObject);
     652        7406 :     Assert(string->type == jbvString);
     653             : 
     654        7406 :     if (object->val.object.nPairs >= JSONB_MAX_PAIRS)
     655           0 :         ereport(ERROR,
     656             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     657             :                  errmsg("number of jsonb object pairs exceeds the maximum allowed (%zu)",
     658             :                         JSONB_MAX_PAIRS)));
     659             : 
     660        7406 :     if (object->val.object.nPairs >= pstate->size)
     661             :     {
     662         682 :         pstate->size *= 2;
     663         682 :         object->val.object.pairs = repalloc(object->val.object.pairs,
     664         682 :                                             sizeof(JsonbPair) * pstate->size);
     665             :     }
     666             : 
     667        7406 :     object->val.object.pairs[object->val.object.nPairs].key = *string;
     668        7406 :     object->val.object.pairs[object->val.object.nPairs].order = object->val.object.nPairs;
     669        7406 : }
     670             : 
     671             : /*
     672             :  * pushJsonbValue() worker:  Append a pair value to state when generating a
     673             :  * Jsonb
     674             :  */
     675             : static void
     676        6522 : appendValue(JsonbParseState *pstate, JsonbValue *scalarVal)
     677             : {
     678        6522 :     JsonbValue *object = &pstate->contVal;
     679             : 
     680        6522 :     Assert(object->type == jbvObject);
     681             : 
     682        6522 :     object->val.object.pairs[object->val.object.nPairs++].value = *scalarVal;
     683        6522 : }
     684             : 
     685             : /*
     686             :  * pushJsonbValue() worker:  Append an element to state when generating a Jsonb
     687             :  */
     688             : static void
     689       11449 : appendElement(JsonbParseState *pstate, JsonbValue *scalarVal)
     690             : {
     691       11449 :     JsonbValue *array = &pstate->contVal;
     692             : 
     693       11449 :     Assert(array->type == jbvArray);
     694             : 
     695       11449 :     if (array->val.array.nElems >= JSONB_MAX_ELEMS)
     696           0 :         ereport(ERROR,
     697             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     698             :                  errmsg("number of jsonb array elements exceeds the maximum allowed (%zu)",
     699             :                         JSONB_MAX_ELEMS)));
     700             : 
     701       11449 :     if (array->val.array.nElems >= pstate->size)
     702             :     {
     703          30 :         pstate->size *= 2;
     704          30 :         array->val.array.elems = repalloc(array->val.array.elems,
     705          30 :                                           sizeof(JsonbValue) * pstate->size);
     706             :     }
     707             : 
     708       11449 :     array->val.array.elems[array->val.array.nElems++] = *scalarVal;
     709       11449 : }
     710             : 
     711             : /*
     712             :  * Given a JsonbContainer, expand to JsonbIterator to iterate over items
     713             :  * fully expanded to in-memory representation for manipulation.
     714             :  *
     715             :  * See JsonbIteratorNext() for notes on memory management.
     716             :  */
     717             : JsonbIterator *
     718      133325 : JsonbIteratorInit(JsonbContainer *container)
     719             : {
     720      133325 :     return iteratorFromContainer(container, NULL);
     721             : }
     722             : 
     723             : /*
     724             :  * Get next JsonbValue while iterating
     725             :  *
     726             :  * Caller should initially pass their own, original iterator.  They may get
     727             :  * back a child iterator palloc()'d here instead.  The function can be relied
     728             :  * on to free those child iterators, lest the memory allocated for highly
     729             :  * nested objects become unreasonable, but only if callers don't end iteration
     730             :  * early (by breaking upon having found something in a search, for example).
     731             :  *
     732             :  * Callers in such a scenario, that are particularly sensitive to leaking
     733             :  * memory in a long-lived context may walk the ancestral tree from the final
     734             :  * iterator we left them with to its oldest ancestor, pfree()ing as they go.
     735             :  * They do not have to free any other memory previously allocated for iterators
     736             :  * but not accessible as direct ancestors of the iterator they're last passed
     737             :  * back.
     738             :  *
     739             :  * Returns "Jsonb sequential processing" token value.  Iterator "state"
     740             :  * reflects the current stage of the process in a less granular fashion, and is
     741             :  * mostly used here to track things internally with respect to particular
     742             :  * iterators.
     743             :  *
     744             :  * Clients of this function should not have to handle any jbvBinary values
     745             :  * (since recursive calls will deal with this), provided skipNested is false.
     746             :  * It is our job to expand the jbvBinary representation without bothering them
     747             :  * with it.  However, clients should not take it upon themselves to touch array
     748             :  * or Object element/pair buffers, since their element/pair pointers are
     749             :  * garbage.  Also, *val will not be set when returning WJB_END_ARRAY or
     750             :  * WJB_END_OBJECT, on the assumption that it's only useful to access values
     751             :  * when recursing in.
     752             :  */
     753             : JsonbIteratorToken
     754      418630 : JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
     755             : {
     756      418630 :     if (*it == NULL)
     757       17337 :         return WJB_DONE;
     758             : 
     759             :     /*
     760             :      * When stepping into a nested container, we jump back here to start
     761             :      * processing the child. We will not recurse further in one call, because
     762             :      * processing the child will always begin in JBI_ARRAY_START or
     763             :      * JBI_OBJECT_START state.
     764             :      */
     765             : recurse:
     766      402016 :     switch ((*it)->state)
     767             :     {
     768             :         case JBI_ARRAY_START:
     769             :             /* Set v to array on first array call */
     770        1267 :             val->type = jbvArray;
     771        1267 :             val->val.array.nElems = (*it)->nElems;
     772             : 
     773             :             /*
     774             :              * v->val.array.elems is not actually set, because we aren't doing
     775             :              * a full conversion
     776             :              */
     777        1267 :             val->val.array.rawScalar = (*it)->isScalar;
     778        1267 :             (*it)->curIndex = 0;
     779        1267 :             (*it)->curDataOffset = 0;
     780        1267 :             (*it)->curValueOffset = 0;   /* not actually used */
     781             :             /* Set state for next call */
     782        1267 :             (*it)->state = JBI_ARRAY_ELEM;
     783        1267 :             return WJB_BEGIN_ARRAY;
     784             : 
     785             :         case JBI_ARRAY_ELEM:
     786        3112 :             if ((*it)->curIndex >= (*it)->nElems)
     787             :             {
     788             :                 /*
     789             :                  * All elements within array already processed.  Report this
     790             :                  * to caller, and give it back original parent iterator (which
     791             :                  * independently tracks iteration progress at its level of
     792             :                  * nesting).
     793             :                  */
     794        1033 :                 *it = freeAndGetParent(*it);
     795        1033 :                 return WJB_END_ARRAY;
     796             :             }
     797             : 
     798        4158 :             fillJsonbValue((*it)->container, (*it)->curIndex,
     799        4158 :                            (*it)->dataProper, (*it)->curDataOffset,
     800             :                            val);
     801             : 
     802        2079 :             JBE_ADVANCE_OFFSET((*it)->curDataOffset,
     803             :                                (*it)->children[(*it)->curIndex]);
     804        2079 :             (*it)->curIndex++;
     805             : 
     806        2079 :             if (!IsAJsonbScalar(val) && !skipNested)
     807             :             {
     808             :                 /* Recurse into container. */
     809         197 :                 *it = iteratorFromContainer(val->val.binary.data, *it);
     810         197 :                 goto recurse;
     811             :             }
     812             :             else
     813             :             {
     814             :                 /*
     815             :                  * Scalar item in array, or a container and caller didn't want
     816             :                  * us to recurse into it.
     817             :                  */
     818        1882 :                 return WJB_ELEM;
     819             :             }
     820             : 
     821             :         case JBI_OBJECT_START:
     822             :             /* Set v to object on first object call */
     823      132781 :             val->type = jbvObject;
     824      132781 :             val->val.object.nPairs = (*it)->nElems;
     825             : 
     826             :             /*
     827             :              * v->val.object.pairs is not actually set, because we aren't
     828             :              * doing a full conversion
     829             :              */
     830      132781 :             (*it)->curIndex = 0;
     831      132781 :             (*it)->curDataOffset = 0;
     832      265562 :             (*it)->curValueOffset = getJsonbOffset((*it)->container,
     833      132781 :                                                    (*it)->nElems);
     834             :             /* Set state for next call */
     835      132781 :             (*it)->state = JBI_OBJECT_KEY;
     836      132781 :             return WJB_BEGIN_OBJECT;
     837             : 
     838             :         case JBI_OBJECT_KEY:
     839      157448 :             if ((*it)->curIndex >= (*it)->nElems)
     840             :             {
     841             :                 /*
     842             :                  * All pairs within object already processed.  Report this to
     843             :                  * caller, and give it back original containing iterator
     844             :                  * (which independently tracks iteration progress at its level
     845             :                  * of nesting).
     846             :                  */
     847       19155 :                 *it = freeAndGetParent(*it);
     848       19155 :                 return WJB_END_OBJECT;
     849             :             }
     850             :             else
     851             :             {
     852             :                 /* Return key of a key/value pair.  */
     853      276586 :                 fillJsonbValue((*it)->container, (*it)->curIndex,
     854      276586 :                                (*it)->dataProper, (*it)->curDataOffset,
     855             :                                val);
     856      138293 :                 if (val->type != jbvString)
     857           0 :                     elog(ERROR, "unexpected jsonb type as object key");
     858             : 
     859             :                 /* Set state for next call */
     860      138293 :                 (*it)->state = JBI_OBJECT_VALUE;
     861      138293 :                 return WJB_KEY;
     862             :             }
     863             : 
     864             :         case JBI_OBJECT_VALUE:
     865             :             /* Set state for next call */
     866      107408 :             (*it)->state = JBI_OBJECT_KEY;
     867             : 
     868      214816 :             fillJsonbValue((*it)->container, (*it)->curIndex + (*it)->nElems,
     869      214816 :                            (*it)->dataProper, (*it)->curValueOffset,
     870             :                            val);
     871             : 
     872      107408 :             JBE_ADVANCE_OFFSET((*it)->curDataOffset,
     873             :                                (*it)->children[(*it)->curIndex]);
     874      107408 :             JBE_ADVANCE_OFFSET((*it)->curValueOffset,
     875             :                                (*it)->children[(*it)->curIndex + (*it)->nElems]);
     876      107408 :             (*it)->curIndex++;
     877             : 
     878             :             /*
     879             :              * Value may be a container, in which case we recurse with new,
     880             :              * child iterator (unless the caller asked not to, by passing
     881             :              * skipNested).
     882             :              */
     883      107408 :             if (!IsAJsonbScalar(val) && !skipNested)
     884             :             {
     885         526 :                 *it = iteratorFromContainer(val->val.binary.data, *it);
     886         526 :                 goto recurse;
     887             :             }
     888             :             else
     889      106882 :                 return WJB_VALUE;
     890             :     }
     891             : 
     892           0 :     elog(ERROR, "invalid iterator state");
     893             :     return -1;
     894             : }
     895             : 
     896             : /*
     897             :  * Initialize an iterator for iterating all elements in a container.
     898             :  */
     899             : static JsonbIterator *
     900      134048 : iteratorFromContainer(JsonbContainer *container, JsonbIterator *parent)
     901             : {
     902             :     JsonbIterator *it;
     903             : 
     904      134048 :     it = palloc(sizeof(JsonbIterator));
     905      134048 :     it->container = container;
     906      134048 :     it->parent = parent;
     907      134048 :     it->nElems = JsonContainerSize(container);
     908             : 
     909             :     /* Array starts just after header */
     910      134048 :     it->children = container->children;
     911             : 
     912      134048 :     switch (container->header & (JB_FARRAY | JB_FOBJECT))
     913             :     {
     914             :         case JB_FARRAY:
     915        1267 :             it->dataProper =
     916        1267 :                 (char *) it->children + it->nElems * sizeof(JEntry);
     917        1267 :             it->isScalar = JsonContainerIsScalar(container);
     918             :             /* This is either a "raw scalar", or an array */
     919        1267 :             Assert(!it->isScalar || it->nElems == 1);
     920             : 
     921        1267 :             it->state = JBI_ARRAY_START;
     922        1267 :             break;
     923             : 
     924             :         case JB_FOBJECT:
     925      132781 :             it->dataProper =
     926      132781 :                 (char *) it->children + it->nElems * sizeof(JEntry) * 2;
     927      132781 :             it->state = JBI_OBJECT_START;
     928      132781 :             break;
     929             : 
     930             :         default:
     931           0 :             elog(ERROR, "unknown type of jsonb container");
     932             :     }
     933             : 
     934      134048 :     return it;
     935             : }
     936             : 
     937             : /*
     938             :  * JsonbIteratorNext() worker:  Return parent, while freeing memory for current
     939             :  * iterator
     940             :  */
     941             : static JsonbIterator *
     942       20188 : freeAndGetParent(JsonbIterator *it)
     943             : {
     944       20188 :     JsonbIterator *v = it->parent;
     945             : 
     946       20188 :     pfree(it);
     947       20188 :     return v;
     948             : }
     949             : 
     950             : /*
     951             :  * Worker for "contains" operator's function
     952             :  *
     953             :  * Formally speaking, containment is top-down, unordered subtree isomorphism.
     954             :  *
     955             :  * Takes iterators that belong to some container type.  These iterators
     956             :  * "belong" to those values in the sense that they've just been initialized in
     957             :  * respect of them by the caller (perhaps in a nested fashion).
     958             :  *
     959             :  * "val" is lhs Jsonb, and mContained is rhs Jsonb when called from top level.
     960             :  * We determine if mContained is contained within val.
     961             :  */
     962             : bool
     963        7270 : JsonbDeepContains(JsonbIterator **val, JsonbIterator **mContained)
     964             : {
     965             :     JsonbValue  vval,
     966             :                 vcontained;
     967             :     JsonbIteratorToken rval,
     968             :                 rcont;
     969             : 
     970             :     /*
     971             :      * Guard against stack overflow due to overly complex Jsonb.
     972             :      *
     973             :      * Functions called here independently take this precaution, but that
     974             :      * might not be sufficient since this is also a recursive function.
     975             :      */
     976        7270 :     check_stack_depth();
     977             : 
     978        7270 :     rval = JsonbIteratorNext(val, &vval, false);
     979        7270 :     rcont = JsonbIteratorNext(mContained, &vcontained, false);
     980             : 
     981        7270 :     if (rval != rcont)
     982             :     {
     983             :         /*
     984             :          * The differing return values can immediately be taken as indicating
     985             :          * two differing container types at this nesting level, which is
     986             :          * sufficient reason to give up entirely (but it should be the case
     987             :          * that they're both some container type).
     988             :          */
     989           2 :         Assert(rval == WJB_BEGIN_OBJECT || rval == WJB_BEGIN_ARRAY);
     990           2 :         Assert(rcont == WJB_BEGIN_OBJECT || rcont == WJB_BEGIN_ARRAY);
     991           2 :         return false;
     992             :     }
     993        7268 :     else if (rcont == WJB_BEGIN_OBJECT)
     994             :     {
     995        7208 :         Assert(vval.type == jbvObject);
     996        7208 :         Assert(vcontained.type == jbvObject);
     997             : 
     998             :         /*
     999             :          * If the lhs has fewer pairs than the rhs, it can't possibly contain
    1000             :          * the rhs.  (This conclusion is safe only because we de-duplicate
    1001             :          * keys in all Jsonb objects; thus there can be no corresponding
    1002             :          * optimization in the array case.)  The case probably won't arise
    1003             :          * often, but since it's such a cheap check we may as well make it.
    1004             :          */
    1005        7208 :         if (vval.val.object.nPairs < vcontained.val.object.nPairs)
    1006         600 :             return false;
    1007             : 
    1008             :         /* Work through rhs "is it contained within?" object */
    1009             :         for (;;)
    1010             :         {
    1011             :             JsonbValue *lhsVal; /* lhsVal is from pair in lhs object */
    1012             : 
    1013        6743 :             rcont = JsonbIteratorNext(mContained, &vcontained, false);
    1014             : 
    1015             :             /*
    1016             :              * When we get through caller's rhs "is it contained within?"
    1017             :              * object without failing to find one of its values, it's
    1018             :              * contained.
    1019             :              */
    1020        6743 :             if (rcont == WJB_END_OBJECT)
    1021        2127 :                 return true;
    1022             : 
    1023        4616 :             Assert(rcont == WJB_KEY);
    1024             : 
    1025             :             /* First, find value by key... */
    1026        4616 :             lhsVal = findJsonbValueFromContainer((*val)->container,
    1027             :                                                  JB_FOBJECT,
    1028             :                                                  &vcontained);
    1029             : 
    1030        4616 :             if (!lhsVal)
    1031        3906 :                 return false;
    1032             : 
    1033             :             /*
    1034             :              * ...at this stage it is apparent that there is at least a key
    1035             :              * match for this rhs pair.
    1036             :              */
    1037         710 :             rcont = JsonbIteratorNext(mContained, &vcontained, true);
    1038             : 
    1039         710 :             Assert(rcont == WJB_VALUE);
    1040             : 
    1041             :             /*
    1042             :              * Compare rhs pair's value with lhs pair's value just found using
    1043             :              * key
    1044             :              */
    1045         710 :             if (lhsVal->type != vcontained.type)
    1046             :             {
    1047         195 :                 return false;
    1048             :             }
    1049         515 :             else if (IsAJsonbScalar(lhsVal))
    1050             :             {
    1051         493 :                 if (!equalsJsonbScalarValue(lhsVal, &vcontained))
    1052         374 :                     return false;
    1053             :             }
    1054             :             else
    1055             :             {
    1056             :                 /* Nested container value (object or array) */
    1057             :                 JsonbIterator *nestval,
    1058             :                            *nestContained;
    1059             : 
    1060          22 :                 Assert(lhsVal->type == jbvBinary);
    1061          22 :                 Assert(vcontained.type == jbvBinary);
    1062             : 
    1063          22 :                 nestval = JsonbIteratorInit(lhsVal->val.binary.data);
    1064          22 :                 nestContained = JsonbIteratorInit(vcontained.val.binary.data);
    1065             : 
    1066             :                 /*
    1067             :                  * Match "value" side of rhs datum object's pair recursively.
    1068             :                  * It's a nested structure.
    1069             :                  *
    1070             :                  * Note that nesting still has to "match up" at the right
    1071             :                  * nesting sub-levels.  However, there need only be zero or
    1072             :                  * more matching pairs (or elements) at each nesting level
    1073             :                  * (provided the *rhs* pairs/elements *all* match on each
    1074             :                  * level), which enables searching nested structures for a
    1075             :                  * single String or other primitive type sub-datum quite
    1076             :                  * effectively (provided the user constructed the rhs nested
    1077             :                  * structure such that we "know where to look").
    1078             :                  *
    1079             :                  * In other words, the mapping of container nodes in the rhs
    1080             :                  * "vcontained" Jsonb to internal nodes on the lhs is
    1081             :                  * injective, and parent-child edges on the rhs must be mapped
    1082             :                  * to parent-child edges on the lhs to satisfy the condition
    1083             :                  * of containment (plus of course the mapped nodes must be
    1084             :                  * equal).
    1085             :                  */
    1086          22 :                 if (!JsonbDeepContains(&nestval, &nestContained))
    1087           6 :                     return false;
    1088             :             }
    1089         135 :         }
    1090             :     }
    1091          60 :     else if (rcont == WJB_BEGIN_ARRAY)
    1092             :     {
    1093          60 :         JsonbValue *lhsConts = NULL;
    1094          60 :         uint32      nLhsElems = vval.val.array.nElems;
    1095             : 
    1096          60 :         Assert(vval.type == jbvArray);
    1097          60 :         Assert(vcontained.type == jbvArray);
    1098             : 
    1099             :         /*
    1100             :          * Handle distinction between "raw scalar" pseudo arrays, and real
    1101             :          * arrays.
    1102             :          *
    1103             :          * A raw scalar may contain another raw scalar, and an array may
    1104             :          * contain a raw scalar, but a raw scalar may not contain an array. We
    1105             :          * don't do something like this for the object case, since objects can
    1106             :          * only contain pairs, never raw scalars (a pair is represented by an
    1107             :          * rhs object argument with a single contained pair).
    1108             :          */
    1109          60 :         if (vval.val.array.rawScalar && !vcontained.val.array.rawScalar)
    1110           1 :             return false;
    1111             : 
    1112             :         /* Work through rhs "is it contained within?" array */
    1113             :         for (;;)
    1114             :         {
    1115         136 :             rcont = JsonbIteratorNext(mContained, &vcontained, true);
    1116             : 
    1117             :             /*
    1118             :              * When we get through caller's rhs "is it contained within?"
    1119             :              * array without failing to find one of its values, it's
    1120             :              * contained.
    1121             :              */
    1122         136 :             if (rcont == WJB_END_ARRAY)
    1123          48 :                 return true;
    1124             : 
    1125          88 :             Assert(rcont == WJB_ELEM);
    1126             : 
    1127          88 :             if (IsAJsonbScalar(&vcontained))
    1128             :             {
    1129          67 :                 if (!findJsonbValueFromContainer((*val)->container,
    1130             :                                                  JB_FARRAY,
    1131             :                                                  &vcontained))
    1132           9 :                     return false;
    1133             :             }
    1134             :             else
    1135             :             {
    1136             :                 uint32      i;
    1137             : 
    1138             :                 /*
    1139             :                  * If this is first container found in rhs array (at this
    1140             :                  * depth), initialize temp lhs array of containers
    1141             :                  */
    1142          21 :                 if (lhsConts == NULL)
    1143             :                 {
    1144          20 :                     uint32      j = 0;
    1145             : 
    1146             :                     /* Make room for all possible values */
    1147          20 :                     lhsConts = palloc(sizeof(JsonbValue) * nLhsElems);
    1148             : 
    1149          66 :                     for (i = 0; i < nLhsElems; i++)
    1150             :                     {
    1151             :                         /* Store all lhs elements in temp array */
    1152          46 :                         rcont = JsonbIteratorNext(val, &vval, true);
    1153          46 :                         Assert(rcont == WJB_ELEM);
    1154             : 
    1155          46 :                         if (vval.type == jbvBinary)
    1156          23 :                             lhsConts[j++] = vval;
    1157             :                     }
    1158             : 
    1159             :                     /* No container elements in temp array, so give up now */
    1160          20 :                     if (j == 0)
    1161           0 :                         return false;
    1162             : 
    1163             :                     /* We may have only partially filled array */
    1164          20 :                     nLhsElems = j;
    1165             :                 }
    1166             : 
    1167             :                 /* XXX: Nested array containment is O(N^2) */
    1168          26 :                 for (i = 0; i < nLhsElems; i++)
    1169             :                 {
    1170             :                     /* Nested container value (object or array) */
    1171             :                     JsonbIterator *nestval,
    1172             :                                *nestContained;
    1173             :                     bool        contains;
    1174             : 
    1175          24 :                     nestval = JsonbIteratorInit(lhsConts[i].val.binary.data);
    1176          24 :                     nestContained = JsonbIteratorInit(vcontained.val.binary.data);
    1177             : 
    1178          24 :                     contains = JsonbDeepContains(&nestval, &nestContained);
    1179             : 
    1180          24 :                     if (nestval)
    1181          24 :                         pfree(nestval);
    1182          24 :                     if (nestContained)
    1183           5 :                         pfree(nestContained);
    1184          24 :                     if (contains)
    1185          19 :                         break;
    1186             :                 }
    1187             : 
    1188             :                 /*
    1189             :                  * Report rhs container value is not contained if couldn't
    1190             :                  * match rhs container to *some* lhs cont
    1191             :                  */
    1192          21 :                 if (i == nLhsElems)
    1193           2 :                     return false;
    1194             :             }
    1195          77 :         }
    1196             :     }
    1197             :     else
    1198             :     {
    1199           0 :         elog(ERROR, "invalid jsonb container type");
    1200             :     }
    1201             : 
    1202             :     elog(ERROR, "unexpectedly fell off end of jsonb container");
    1203             :     return false;
    1204             : }
    1205             : 
    1206             : /*
    1207             :  * Hash a JsonbValue scalar value, mixing the hash value into an existing
    1208             :  * hash provided by the caller.
    1209             :  *
    1210             :  * Some callers may wish to independently XOR in JB_FOBJECT and JB_FARRAY
    1211             :  * flags.
    1212             :  */
    1213             : void
    1214       28867 : JsonbHashScalarValue(const JsonbValue *scalarVal, uint32 *hash)
    1215             : {
    1216             :     uint32      tmp;
    1217             : 
    1218             :     /* Compute hash value for scalarVal */
    1219       28867 :     switch (scalarVal->type)
    1220             :     {
    1221             :         case jbvNull:
    1222           7 :             tmp = 0x01;
    1223           7 :             break;
    1224             :         case jbvString:
    1225       21127 :             tmp = DatumGetUInt32(hash_any((const unsigned char *) scalarVal->val.string.val,
    1226             :                                           scalarVal->val.string.len));
    1227       21127 :             break;
    1228             :         case jbvNumeric:
    1229             :             /* Must hash equal numerics to equal hash codes */
    1230        4963 :             tmp = DatumGetUInt32(DirectFunctionCall1(hash_numeric,
    1231             :                                                      NumericGetDatum(scalarVal->val.numeric)));
    1232        4963 :             break;
    1233             :         case jbvBool:
    1234        2770 :             tmp = scalarVal->val.boolean ? 0x02 : 0x04;
    1235             : 
    1236        2770 :             break;
    1237             :         default:
    1238           0 :             elog(ERROR, "invalid jsonb scalar type");
    1239             :             tmp = 0;            /* keep compiler quiet */
    1240             :             break;
    1241             :     }
    1242             : 
    1243             :     /*
    1244             :      * Combine hash values of successive keys, values and elements by rotating
    1245             :      * the previous value left 1 bit, then XOR'ing in the new
    1246             :      * key/value/element's hash value.
    1247             :      */
    1248       28867 :     *hash = (*hash << 1) | (*hash >> 31);
    1249       28867 :     *hash ^= tmp;
    1250       28867 : }
    1251             : 
    1252             : /*
    1253             :  * Hash a value to a 64-bit value, with a seed. Otherwise, similar to
    1254             :  * JsonbHashScalarValue.
    1255             :  */
    1256             : void
    1257          36 : JsonbHashScalarValueExtended(const JsonbValue *scalarVal, uint64 *hash,
    1258             :                              uint64 seed)
    1259             : {
    1260             :     uint64      tmp;
    1261             : 
    1262          36 :     switch (scalarVal->type)
    1263             :     {
    1264             :         case jbvNull:
    1265           2 :             tmp = seed + 0x01;
    1266           2 :             break;
    1267             :         case jbvString:
    1268          30 :             tmp = DatumGetUInt64(hash_any_extended((const unsigned char *) scalarVal->val.string.val,
    1269             :                                                    scalarVal->val.string.len,
    1270             :                                                    seed));
    1271          30 :             break;
    1272             :         case jbvNumeric:
    1273           2 :             tmp = DatumGetUInt64(DirectFunctionCall2(hash_numeric_extended,
    1274             :                                                      NumericGetDatum(scalarVal->val.numeric),
    1275             :                                                      UInt64GetDatum(seed)));
    1276           2 :             break;
    1277             :         case jbvBool:
    1278           2 :             if (seed)
    1279           1 :                 tmp = DatumGetUInt64(DirectFunctionCall2(hashcharextended,
    1280             :                                                          BoolGetDatum(scalarVal->val.boolean),
    1281             :                                                          UInt64GetDatum(seed)));
    1282             :             else
    1283           1 :                 tmp = scalarVal->val.boolean ? 0x02 : 0x04;
    1284             : 
    1285           2 :             break;
    1286             :         default:
    1287           0 :             elog(ERROR, "invalid jsonb scalar type");
    1288             :             break;
    1289             :     }
    1290             : 
    1291          36 :     *hash = ROTATE_HIGH_AND_LOW_32BITS(*hash);
    1292          36 :     *hash ^= tmp;
    1293          36 : }
    1294             : 
    1295             : /*
    1296             :  * Are two scalar JsonbValues of the same type a and b equal?
    1297             :  */
    1298             : static bool
    1299         611 : equalsJsonbScalarValue(JsonbValue *aScalar, JsonbValue *bScalar)
    1300             : {
    1301         611 :     if (aScalar->type == bScalar->type)
    1302             :     {
    1303         611 :         switch (aScalar->type)
    1304             :         {
    1305             :             case jbvNull:
    1306           7 :                 return true;
    1307             :             case jbvString:
    1308         508 :                 return lengthCompareJsonbStringValue(aScalar, bScalar) == 0;
    1309             :             case jbvNumeric:
    1310          87 :                 return DatumGetBool(DirectFunctionCall2(numeric_eq,
    1311             :                                                         PointerGetDatum(aScalar->val.numeric),
    1312             :                                                         PointerGetDatum(bScalar->val.numeric)));
    1313             :             case jbvBool:
    1314           9 :                 return aScalar->val.boolean == bScalar->val.boolean;
    1315             : 
    1316             :             default:
    1317           0 :                 elog(ERROR, "invalid jsonb scalar type");
    1318             :         }
    1319             :     }
    1320           0 :     elog(ERROR, "jsonb scalar type mismatch");
    1321             :     return -1;
    1322             : }
    1323             : 
    1324             : /*
    1325             :  * Compare two scalar JsonbValues, returning -1, 0, or 1.
    1326             :  *
    1327             :  * Strings are compared using the default collation.  Used by B-tree
    1328             :  * operators, where a lexical sort order is generally expected.
    1329             :  */
    1330             : static int
    1331       90447 : compareJsonbScalarValue(JsonbValue *aScalar, JsonbValue *bScalar)
    1332             : {
    1333       90447 :     if (aScalar->type == bScalar->type)
    1334             :     {
    1335       90447 :         switch (aScalar->type)
    1336             :         {
    1337             :             case jbvNull:
    1338           3 :                 return 0;
    1339             :             case jbvString:
    1340       61317 :                 return varstr_cmp(aScalar->val.string.val,
    1341             :                                   aScalar->val.string.len,
    1342             :                                   bScalar->val.string.val,
    1343             :                                   bScalar->val.string.len,
    1344             :                                   DEFAULT_COLLATION_OID);
    1345             :             case jbvNumeric:
    1346       21756 :                 return DatumGetInt32(DirectFunctionCall2(numeric_cmp,
    1347             :                                                          PointerGetDatum(aScalar->val.numeric),
    1348             :                                                          PointerGetDatum(bScalar->val.numeric)));
    1349             :             case jbvBool:
    1350        7371 :                 if (aScalar->val.boolean == bScalar->val.boolean)
    1351        6267 :                     return 0;
    1352        1104 :                 else if (aScalar->val.boolean > bScalar->val.boolean)
    1353         552 :                     return 1;
    1354             :                 else
    1355         552 :                     return -1;
    1356             :             default:
    1357           0 :                 elog(ERROR, "invalid jsonb scalar type");
    1358             :         }
    1359             :     }
    1360           0 :     elog(ERROR, "jsonb scalar type mismatch");
    1361             :     return -1;
    1362             : }
    1363             : 
    1364             : 
    1365             : /*
    1366             :  * Functions for manipulating the resizeable buffer used by convertJsonb and
    1367             :  * its subroutines.
    1368             :  */
    1369             : 
    1370             : /*
    1371             :  * Reserve 'len' bytes, at the end of the buffer, enlarging it if necessary.
    1372             :  * Returns the offset to the reserved area. The caller is expected to fill
    1373             :  * the reserved area later with copyToBuffer().
    1374             :  */
    1375             : static int
    1376       76416 : reserveFromBuffer(StringInfo buffer, int len)
    1377             : {
    1378             :     int         offset;
    1379             : 
    1380             :     /* Make more room if needed */
    1381       76416 :     enlargeStringInfo(buffer, len);
    1382             : 
    1383             :     /* remember current offset */
    1384       76416 :     offset = buffer->len;
    1385             : 
    1386             :     /* reserve the space */
    1387       76416 :     buffer->len += len;
    1388             : 
    1389             :     /*
    1390             :      * Keep a trailing null in place, even though it's not useful for us; it
    1391             :      * seems best to preserve the invariants of StringInfos.
    1392             :      */
    1393       76416 :     buffer->data[buffer->len] = '\0';
    1394             : 
    1395       76416 :     return offset;
    1396             : }
    1397             : 
    1398             : /*
    1399             :  * Copy 'len' bytes to a previously reserved area in buffer.
    1400             :  */
    1401             : static void
    1402       57508 : copyToBuffer(StringInfo buffer, int offset, const char *data, int len)
    1403             : {
    1404       57508 :     memcpy(buffer->data + offset, data, len);
    1405       57508 : }
    1406             : 
    1407             : /*
    1408             :  * A shorthand for reserveFromBuffer + copyToBuffer.
    1409             :  */
    1410             : static void
    1411       33068 : appendToBuffer(StringInfo buffer, const char *data, int len)
    1412             : {
    1413             :     int         offset;
    1414             : 
    1415       33068 :     offset = reserveFromBuffer(buffer, len);
    1416       33068 :     copyToBuffer(buffer, offset, data, len);
    1417       33068 : }
    1418             : 
    1419             : 
    1420             : /*
    1421             :  * Append padding, so that the length of the StringInfo is int-aligned.
    1422             :  * Returns the number of padding bytes appended.
    1423             :  */
    1424             : static short
    1425       19032 : padBufferToInt(StringInfo buffer)
    1426             : {
    1427             :     int         padlen,
    1428             :                 p,
    1429             :                 offset;
    1430             : 
    1431       19032 :     padlen = INTALIGN(buffer->len) - buffer->len;
    1432             : 
    1433       19032 :     offset = reserveFromBuffer(buffer, padlen);
    1434             : 
    1435             :     /* padlen must be small, so this is probably faster than a memset */
    1436       22766 :     for (p = 0; p < padlen; p++)
    1437        3734 :         buffer->data[offset + p] = '\0';
    1438             : 
    1439       19032 :     return padlen;
    1440             : }
    1441             : 
    1442             : /*
    1443             :  * Given a JsonbValue, convert to Jsonb. The result is palloc'd.
    1444             :  */
    1445             : static Jsonb *
    1446       11677 : convertToJsonb(JsonbValue *val)
    1447             : {
    1448             :     StringInfoData buffer;
    1449             :     JEntry      jentry;
    1450             :     Jsonb      *res;
    1451             : 
    1452             :     /* Should not already have binary representation */
    1453       11677 :     Assert(val->type != jbvBinary);
    1454             : 
    1455             :     /* Allocate an output buffer. It will be enlarged as needed */
    1456       11677 :     initStringInfo(&buffer);
    1457             : 
    1458             :     /* Make room for the varlena header */
    1459       11677 :     reserveFromBuffer(&buffer, VARHDRSZ);
    1460             : 
    1461       11677 :     convertJsonbValue(&buffer, &jentry, val, 0);
    1462             : 
    1463             :     /*
    1464             :      * Note: the JEntry of the root is discarded. Therefore the root
    1465             :      * JsonbContainer struct must contain enough information to tell what kind
    1466             :      * of value it is.
    1467             :      */
    1468             : 
    1469       11677 :     res = (Jsonb *) buffer.data;
    1470             : 
    1471       11677 :     SET_VARSIZE(res, buffer.len);
    1472             : 
    1473       11677 :     return res;
    1474             : }
    1475             : 
    1476             : /*
    1477             :  * Subroutine of convertJsonb: serialize a single JsonbValue into buffer.
    1478             :  *
    1479             :  * The JEntry header for this node is returned in *header.  It is filled in
    1480             :  * with the length of this value and appropriate type bits.  If we wish to
    1481             :  * store an end offset rather than a length, it is the caller's responsibility
    1482             :  * to adjust for that.
    1483             :  *
    1484             :  * If the value is an array or an object, this recurses. 'level' is only used
    1485             :  * for debugging purposes.
    1486             :  */
    1487             : static void
    1488       29615 : convertJsonbValue(StringInfo buffer, JEntry *header, JsonbValue *val, int level)
    1489             : {
    1490       29615 :     check_stack_depth();
    1491             : 
    1492       29615 :     if (!val)
    1493       29615 :         return;
    1494             : 
    1495             :     /*
    1496             :      * A JsonbValue passed as val should never have a type of jbvBinary, and
    1497             :      * neither should any of its sub-components. Those values will be produced
    1498             :      * by convertJsonbArray and convertJsonbObject, the results of which will
    1499             :      * not be passed back to this function as an argument.
    1500             :      */
    1501             : 
    1502       29615 :     if (IsAJsonbScalar(val))
    1503       16976 :         convertJsonbScalar(buffer, header, val);
    1504       12639 :     else if (val->type == jbvArray)
    1505       10631 :         convertJsonbArray(buffer, header, val, level);
    1506        2008 :     else if (val->type == jbvObject)
    1507        2008 :         convertJsonbObject(buffer, header, val, level);
    1508             :     else
    1509           0 :         elog(ERROR, "unknown type of jsonb container to convert");
    1510             : }
    1511             : 
    1512             : static void
    1513       10631 : convertJsonbArray(StringInfo buffer, JEntry *pheader, JsonbValue *val, int level)
    1514             : {
    1515             :     int         base_offset;
    1516             :     int         jentry_offset;
    1517             :     int         i;
    1518             :     int         totallen;
    1519             :     uint32      header;
    1520       10631 :     int         nElems = val->val.array.nElems;
    1521             : 
    1522             :     /* Remember where in the buffer this array starts. */
    1523       10631 :     base_offset = buffer->len;
    1524             : 
    1525             :     /* Align to 4-byte boundary (any padding counts as part of my data) */
    1526       10631 :     padBufferToInt(buffer);
    1527             : 
    1528             :     /*
    1529             :      * Construct the header Jentry and store it in the beginning of the
    1530             :      * variable-length payload.
    1531             :      */
    1532       10631 :     header = nElems | JB_FARRAY;
    1533       10631 :     if (val->val.array.rawScalar)
    1534             :     {
    1535        9925 :         Assert(nElems == 1);
    1536        9925 :         Assert(level == 0);
    1537        9925 :         header |= JB_FSCALAR;
    1538             :     }
    1539             : 
    1540       10631 :     appendToBuffer(buffer, (char *) &header, sizeof(uint32));
    1541             : 
    1542             :     /* Reserve space for the JEntries of the elements. */
    1543       10631 :     jentry_offset = reserveFromBuffer(buffer, sizeof(JEntry) * nElems);
    1544             : 
    1545       10631 :     totallen = 0;
    1546       22067 :     for (i = 0; i < nElems; i++)
    1547             :     {
    1548       11436 :         JsonbValue *elem = &val->val.array.elems[i];
    1549             :         int         len;
    1550             :         JEntry      meta;
    1551             : 
    1552             :         /*
    1553             :          * Convert element, producing a JEntry and appending its
    1554             :          * variable-length data to buffer
    1555             :          */
    1556       11436 :         convertJsonbValue(buffer, &meta, elem, level + 1);
    1557             : 
    1558       11436 :         len = JBE_OFFLENFLD(meta);
    1559       11436 :         totallen += len;
    1560             : 
    1561             :         /*
    1562             :          * Bail out if total variable-length data exceeds what will fit in a
    1563             :          * JEntry length field.  We check this in each iteration, not just
    1564             :          * once at the end, to forestall possible integer overflow.
    1565             :          */
    1566       11436 :         if (totallen > JENTRY_OFFLENMASK)
    1567           0 :             ereport(ERROR,
    1568             :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1569             :                      errmsg("total size of jsonb array elements exceeds the maximum of %u bytes",
    1570             :                             JENTRY_OFFLENMASK)));
    1571             : 
    1572             :         /*
    1573             :          * Convert each JB_OFFSET_STRIDE'th length to an offset.
    1574             :          */
    1575       11436 :         if ((i % JB_OFFSET_STRIDE) == 0)
    1576       10600 :             meta = (meta & JENTRY_TYPEMASK) | totallen | JENTRY_HAS_OFF;
    1577             : 
    1578       11436 :         copyToBuffer(buffer, jentry_offset, (char *) &meta, sizeof(JEntry));
    1579       11436 :         jentry_offset += sizeof(JEntry);
    1580             :     }
    1581             : 
    1582             :     /* Total data size is everything we've appended to buffer */
    1583       10631 :     totallen = buffer->len - base_offset;
    1584             : 
    1585             :     /* Check length again, since we didn't include the metadata above */
    1586       10631 :     if (totallen > JENTRY_OFFLENMASK)
    1587           0 :         ereport(ERROR,
    1588             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1589             :                  errmsg("total size of jsonb array elements exceeds the maximum of %u bytes",
    1590             :                         JENTRY_OFFLENMASK)));
    1591             : 
    1592             :     /* Initialize the header of this node in the container's JEntry array */
    1593       10631 :     *pheader = JENTRY_ISCONTAINER | totallen;
    1594       10631 : }
    1595             : 
    1596             : static void
    1597        2008 : convertJsonbObject(StringInfo buffer, JEntry *pheader, JsonbValue *val, int level)
    1598             : {
    1599             :     int         base_offset;
    1600             :     int         jentry_offset;
    1601             :     int         i;
    1602             :     int         totallen;
    1603             :     uint32      header;
    1604        2008 :     int         nPairs = val->val.object.nPairs;
    1605             : 
    1606             :     /* Remember where in the buffer this object starts. */
    1607        2008 :     base_offset = buffer->len;
    1608             : 
    1609             :     /* Align to 4-byte boundary (any padding counts as part of my data) */
    1610        2008 :     padBufferToInt(buffer);
    1611             : 
    1612             :     /*
    1613             :      * Construct the header Jentry and store it in the beginning of the
    1614             :      * variable-length payload.
    1615             :      */
    1616        2008 :     header = nPairs | JB_FOBJECT;
    1617        2008 :     appendToBuffer(buffer, (char *) &header, sizeof(uint32));
    1618             : 
    1619             :     /* Reserve space for the JEntries of the keys and values. */
    1620        2008 :     jentry_offset = reserveFromBuffer(buffer, sizeof(JEntry) * nPairs * 2);
    1621             : 
    1622             :     /*
    1623             :      * Iterate over the keys, then over the values, since that is the ordering
    1624             :      * we want in the on-disk representation.
    1625             :      */
    1626        2008 :     totallen = 0;
    1627        8510 :     for (i = 0; i < nPairs; i++)
    1628             :     {
    1629        6502 :         JsonbPair  *pair = &val->val.object.pairs[i];
    1630             :         int         len;
    1631             :         JEntry      meta;
    1632             : 
    1633             :         /*
    1634             :          * Convert key, producing a JEntry and appending its variable-length
    1635             :          * data to buffer
    1636             :          */
    1637        6502 :         convertJsonbScalar(buffer, &meta, &pair->key);
    1638             : 
    1639        6502 :         len = JBE_OFFLENFLD(meta);
    1640        6502 :         totallen += len;
    1641             : 
    1642             :         /*
    1643             :          * Bail out if total variable-length data exceeds what will fit in a
    1644             :          * JEntry length field.  We check this in each iteration, not just
    1645             :          * once at the end, to forestall possible integer overflow.
    1646             :          */
    1647        6502 :         if (totallen > JENTRY_OFFLENMASK)
    1648           0 :             ereport(ERROR,
    1649             :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1650             :                      errmsg("total size of jsonb object elements exceeds the maximum of %u bytes",
    1651             :                             JENTRY_OFFLENMASK)));
    1652             : 
    1653             :         /*
    1654             :          * Convert each JB_OFFSET_STRIDE'th length to an offset.
    1655             :          */
    1656        6502 :         if ((i % JB_OFFSET_STRIDE) == 0)
    1657        1861 :             meta = (meta & JENTRY_TYPEMASK) | totallen | JENTRY_HAS_OFF;
    1658             : 
    1659        6502 :         copyToBuffer(buffer, jentry_offset, (char *) &meta, sizeof(JEntry));
    1660        6502 :         jentry_offset += sizeof(JEntry);
    1661             :     }
    1662        8510 :     for (i = 0; i < nPairs; i++)
    1663             :     {
    1664        6502 :         JsonbPair  *pair = &val->val.object.pairs[i];
    1665             :         int         len;
    1666             :         JEntry      meta;
    1667             : 
    1668             :         /*
    1669             :          * Convert value, producing a JEntry and appending its variable-length
    1670             :          * data to buffer
    1671             :          */
    1672        6502 :         convertJsonbValue(buffer, &meta, &pair->value, level + 1);
    1673             : 
    1674        6502 :         len = JBE_OFFLENFLD(meta);
    1675        6502 :         totallen += len;
    1676             : 
    1677             :         /*
    1678             :          * Bail out if total variable-length data exceeds what will fit in a
    1679             :          * JEntry length field.  We check this in each iteration, not just
    1680             :          * once at the end, to forestall possible integer overflow.
    1681             :          */
    1682        6502 :         if (totallen > JENTRY_OFFLENMASK)
    1683           0 :             ereport(ERROR,
    1684             :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1685             :                      errmsg("total size of jsonb object elements exceeds the maximum of %u bytes",
    1686             :                             JENTRY_OFFLENMASK)));
    1687             : 
    1688             :         /*
    1689             :          * Convert each JB_OFFSET_STRIDE'th length to an offset.
    1690             :          */
    1691        6502 :         if (((i + nPairs) % JB_OFFSET_STRIDE) == 0)
    1692           0 :             meta = (meta & JENTRY_TYPEMASK) | totallen | JENTRY_HAS_OFF;
    1693             : 
    1694        6502 :         copyToBuffer(buffer, jentry_offset, (char *) &meta, sizeof(JEntry));
    1695        6502 :         jentry_offset += sizeof(JEntry);
    1696             :     }
    1697             : 
    1698             :     /* Total data size is everything we've appended to buffer */
    1699        2008 :     totallen = buffer->len - base_offset;
    1700             : 
    1701             :     /* Check length again, since we didn't include the metadata above */
    1702        2008 :     if (totallen > JENTRY_OFFLENMASK)
    1703           0 :         ereport(ERROR,
    1704             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1705             :                  errmsg("total size of jsonb object elements exceeds the maximum of %u bytes",
    1706             :                         JENTRY_OFFLENMASK)));
    1707             : 
    1708             :     /* Initialize the header of this node in the container's JEntry array */
    1709        2008 :     *pheader = JENTRY_ISCONTAINER | totallen;
    1710        2008 : }
    1711             : 
    1712             : static void
    1713       23478 : convertJsonbScalar(StringInfo buffer, JEntry *jentry, JsonbValue *scalarVal)
    1714             : {
    1715             :     int         numlen;
    1716             :     short       padlen;
    1717             : 
    1718       23478 :     switch (scalarVal->type)
    1719             :     {
    1720             :         case jbvNull:
    1721         236 :             *jentry = JENTRY_ISNULL;
    1722         236 :             break;
    1723             : 
    1724             :         case jbvString:
    1725       14036 :             appendToBuffer(buffer, scalarVal->val.string.val, scalarVal->val.string.len);
    1726             : 
    1727       14036 :             *jentry = scalarVal->val.string.len;
    1728       14036 :             break;
    1729             : 
    1730             :         case jbvNumeric:
    1731        6393 :             numlen = VARSIZE_ANY(scalarVal->val.numeric);
    1732        6393 :             padlen = padBufferToInt(buffer);
    1733             : 
    1734        6393 :             appendToBuffer(buffer, (char *) scalarVal->val.numeric, numlen);
    1735             : 
    1736        6393 :             *jentry = JENTRY_ISNUMERIC | (padlen + numlen);
    1737        6393 :             break;
    1738             : 
    1739             :         case jbvBool:
    1740        2813 :             *jentry = (scalarVal->val.boolean) ?
    1741             :                 JENTRY_ISBOOL_TRUE : JENTRY_ISBOOL_FALSE;
    1742        2813 :             break;
    1743             : 
    1744             :         default:
    1745           0 :             elog(ERROR, "invalid jsonb scalar type");
    1746             :     }
    1747       23478 : }
    1748             : 
    1749             : /*
    1750             :  * Compare two jbvString JsonbValue values, a and b.
    1751             :  *
    1752             :  * This is a special qsort() comparator used to sort strings in certain
    1753             :  * internal contexts where it is sufficient to have a well-defined sort order.
    1754             :  * In particular, object pair keys are sorted according to this criteria to
    1755             :  * facilitate cheap binary searches where we don't care about lexical sort
    1756             :  * order.
    1757             :  *
    1758             :  * a and b are first sorted based on their length.  If a tie-breaker is
    1759             :  * required, only then do we consider string binary equality.
    1760             :  */
    1761             : static int
    1762       48648 : lengthCompareJsonbStringValue(const void *a, const void *b)
    1763             : {
    1764       48648 :     const JsonbValue *va = (const JsonbValue *) a;
    1765       48648 :     const JsonbValue *vb = (const JsonbValue *) b;
    1766             :     int         res;
    1767             : 
    1768       48648 :     Assert(va->type == jbvString);
    1769       48648 :     Assert(vb->type == jbvString);
    1770             : 
    1771       48648 :     if (va->val.string.len == vb->val.string.len)
    1772             :     {
    1773       16083 :         res = memcmp(va->val.string.val, vb->val.string.val, va->val.string.len);
    1774             :     }
    1775             :     else
    1776             :     {
    1777       32565 :         res = (va->val.string.len > vb->val.string.len) ? 1 : -1;
    1778             :     }
    1779             : 
    1780       48648 :     return res;
    1781             : }
    1782             : 
    1783             : /*
    1784             :  * qsort_arg() comparator to compare JsonbPair values.
    1785             :  *
    1786             :  * Third argument 'binequal' may point to a bool. If it's set, *binequal is set
    1787             :  * to true iff a and b have full binary equality, since some callers have an
    1788             :  * interest in whether the two values are equal or merely equivalent.
    1789             :  *
    1790             :  * N.B: String comparisons here are "length-wise"
    1791             :  *
    1792             :  * Pairs with equals keys are ordered such that the order field is respected.
    1793             :  */
    1794             : static int
    1795       10236 : lengthCompareJsonbPair(const void *a, const void *b, void *binequal)
    1796             : {
    1797       10236 :     const JsonbPair *pa = (const JsonbPair *) a;
    1798       10236 :     const JsonbPair *pb = (const JsonbPair *) b;
    1799             :     int         res;
    1800             : 
    1801       10236 :     res = lengthCompareJsonbStringValue(&pa->key, &pb->key);
    1802       10236 :     if (res == 0 && binequal)
    1803           4 :         *((bool *) binequal) = true;
    1804             : 
    1805             :     /*
    1806             :      * Guarantee keeping order of equal pair.  Unique algorithm will prefer
    1807             :      * first element as value.
    1808             :      */
    1809       10236 :     if (res == 0)
    1810           4 :         res = (pa->order > pb->order) ? -1 : 1;
    1811             : 
    1812       10236 :     return res;
    1813             : }
    1814             : 
    1815             : /*
    1816             :  * Sort and unique-ify pairs in JsonbValue object
    1817             :  */
    1818             : static void
    1819        2010 : uniqueifyJsonbObject(JsonbValue *object)
    1820             : {
    1821        2010 :     bool        hasNonUniq = false;
    1822             : 
    1823        2010 :     Assert(object->type == jbvObject);
    1824             : 
    1825        2010 :     if (object->val.object.nPairs > 1)
    1826        1319 :         qsort_arg(object->val.object.pairs, object->val.object.nPairs, sizeof(JsonbPair),
    1827             :                   lengthCompareJsonbPair, &hasNonUniq);
    1828             : 
    1829        2010 :     if (hasNonUniq)
    1830             :     {
    1831           3 :         JsonbPair  *ptr = object->val.object.pairs + 1,
    1832           3 :                    *res = object->val.object.pairs;
    1833             : 
    1834          16 :         while (ptr - object->val.object.pairs < object->val.object.nPairs)
    1835             :         {
    1836             :             /* Avoid copying over duplicate */
    1837          10 :             if (lengthCompareJsonbStringValue(ptr, res) != 0)
    1838             :             {
    1839           6 :                 res++;
    1840           6 :                 if (ptr != res)
    1841           5 :                     memcpy(res, ptr, sizeof(JsonbPair));
    1842             :             }
    1843          10 :             ptr++;
    1844             :         }
    1845             : 
    1846           3 :         object->val.object.nPairs = res + 1 - object->val.object.pairs;
    1847             :     }
    1848        2010 : }

Generated by: LCOV version 1.11