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