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