Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * jsonb_op.c
4 : : * Special operators for jsonb only, used by various index access methods
5 : : *
6 : : * Copyright (c) 2014-2024, PostgreSQL Global Development Group
7 : : *
8 : : *
9 : : * IDENTIFICATION
10 : : * src/backend/utils/adt/jsonb_op.c
11 : : *
12 : : *-------------------------------------------------------------------------
13 : : */
14 : : #include "postgres.h"
15 : :
16 : : #include "catalog/pg_type.h"
17 : : #include "utils/fmgrprotos.h"
18 : : #include "utils/jsonb.h"
19 : :
20 : : Datum
3675 andrew@dunslane.net 21 :CBC 6859 : jsonb_exists(PG_FUNCTION_ARGS)
22 : : {
2400 tgl@sss.pgh.pa.us 23 : 6859 : Jsonb *jb = PG_GETARG_JSONB_P(0);
3675 andrew@dunslane.net 24 : 6859 : text *key = PG_GETARG_TEXT_PP(1);
25 : : JsonbValue kval;
26 : 6859 : JsonbValue *v = NULL;
27 : :
28 : : /*
29 : : * We only match Object keys (which are naturally always Strings), or
30 : : * string elements in arrays. In particular, we do not match non-string
31 : : * scalar elements. Existence of a key/element is only considered at the
32 : : * top level. No recursion occurs.
33 : : */
34 : 6859 : kval.type = jbvString;
3665 tgl@sss.pgh.pa.us 35 [ - + ]: 6859 : kval.val.string.val = VARDATA_ANY(key);
36 [ - + - - : 6859 : kval.val.string.len = VARSIZE_ANY_EXHDR(key);
- - - - -
+ ]
37 : :
3630 heikki.linnakangas@i 38 : 6859 : v = findJsonbValueFromContainer(&jb->root,
39 : : JB_FOBJECT | JB_FARRAY,
40 : : &kval);
41 : :
3675 andrew@dunslane.net 42 : 6859 : PG_RETURN_BOOL(v != NULL);
43 : : }
44 : :
45 : : Datum
46 : 4077 : jsonb_exists_any(PG_FUNCTION_ARGS)
47 : : {
2400 tgl@sss.pgh.pa.us 48 : 4077 : Jsonb *jb = PG_GETARG_JSONB_P(0);
3675 andrew@dunslane.net 49 : 4077 : ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
50 : : int i;
51 : : Datum *key_datums;
52 : : bool *key_nulls;
53 : : int elem_count;
54 : :
653 peter@eisentraut.org 55 : 4077 : deconstruct_array_builtin(keys, TEXTOID, &key_datums, &key_nulls, &elem_count);
56 : :
3630 heikki.linnakangas@i 57 [ + + ]: 9003 : for (i = 0; i < elem_count; i++)
58 : : {
59 : : JsonbValue strVal;
60 : :
61 [ - + ]: 6966 : if (key_nulls[i])
3630 heikki.linnakangas@i 62 :UBC 0 : continue;
63 : :
3630 heikki.linnakangas@i 64 :CBC 6966 : strVal.type = jbvString;
65 : : /* We rely on the array elements not being toasted */
489 tgl@sss.pgh.pa.us 66 [ - + ]: 6966 : strVal.val.string.val = VARDATA_ANY(key_datums[i]);
67 [ - + - - : 6966 : strVal.val.string.len = VARSIZE_ANY_EXHDR(key_datums[i]);
- - - - -
+ ]
68 : :
3630 heikki.linnakangas@i 69 [ + + ]: 6966 : if (findJsonbValueFromContainer(&jb->root,
70 : : JB_FOBJECT | JB_FARRAY,
71 : : &strVal) != NULL)
3675 andrew@dunslane.net 72 : 2040 : PG_RETURN_BOOL(true);
73 : : }
74 : :
75 : 2037 : PG_RETURN_BOOL(false);
76 : : }
77 : :
78 : : Datum
79 : 3195 : jsonb_exists_all(PG_FUNCTION_ARGS)
80 : : {
2400 tgl@sss.pgh.pa.us 81 : 3195 : Jsonb *jb = PG_GETARG_JSONB_P(0);
3675 andrew@dunslane.net 82 : 3195 : ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
83 : : int i;
84 : : Datum *key_datums;
85 : : bool *key_nulls;
86 : : int elem_count;
87 : :
653 peter@eisentraut.org 88 : 3195 : deconstruct_array_builtin(keys, TEXTOID, &key_datums, &key_nulls, &elem_count);
89 : :
3630 heikki.linnakangas@i 90 [ + + ]: 4194 : for (i = 0; i < elem_count; i++)
91 : : {
92 : : JsonbValue strVal;
93 : :
94 [ - + ]: 3921 : if (key_nulls[i])
3630 heikki.linnakangas@i 95 :UBC 0 : continue;
96 : :
3630 heikki.linnakangas@i 97 :CBC 3921 : strVal.type = jbvString;
98 : : /* We rely on the array elements not being toasted */
489 tgl@sss.pgh.pa.us 99 [ - + ]: 3921 : strVal.val.string.val = VARDATA_ANY(key_datums[i]);
100 [ - + - - : 3921 : strVal.val.string.len = VARSIZE_ANY_EXHDR(key_datums[i]);
- - - - -
+ ]
101 : :
3630 heikki.linnakangas@i 102 [ + + ]: 3921 : if (findJsonbValueFromContainer(&jb->root,
103 : : JB_FOBJECT | JB_FARRAY,
104 : : &strVal) == NULL)
3675 andrew@dunslane.net 105 : 2922 : PG_RETURN_BOOL(false);
106 : : }
107 : :
108 : 273 : PG_RETURN_BOOL(true);
109 : : }
110 : :
111 : : Datum
112 : 21636 : jsonb_contains(PG_FUNCTION_ARGS)
113 : : {
2400 tgl@sss.pgh.pa.us 114 : 21636 : Jsonb *val = PG_GETARG_JSONB_P(0);
115 : 21636 : Jsonb *tmpl = PG_GETARG_JSONB_P(1);
116 : :
117 : : JsonbIterator *it1,
118 : : *it2;
119 : :
3473 120 [ + + ]: 21636 : if (JB_ROOT_IS_OBJECT(val) != JB_ROOT_IS_OBJECT(tmpl))
3675 andrew@dunslane.net 121 : 15 : PG_RETURN_BOOL(false);
122 : :
3630 heikki.linnakangas@i 123 : 21621 : it1 = JsonbIteratorInit(&val->root);
124 : 21621 : it2 = JsonbIteratorInit(&tmpl->root);
125 : :
3675 andrew@dunslane.net 126 : 21621 : PG_RETURN_BOOL(JsonbDeepContains(&it1, &it2));
127 : : }
128 : :
129 : : Datum
130 : 51 : jsonb_contained(PG_FUNCTION_ARGS)
131 : : {
132 : : /* Commutator of "contains" */
2400 tgl@sss.pgh.pa.us 133 : 51 : Jsonb *tmpl = PG_GETARG_JSONB_P(0);
134 : 51 : Jsonb *val = PG_GETARG_JSONB_P(1);
135 : :
136 : : JsonbIterator *it1,
137 : : *it2;
138 : :
3473 139 [ - + ]: 51 : if (JB_ROOT_IS_OBJECT(val) != JB_ROOT_IS_OBJECT(tmpl))
3675 andrew@dunslane.net 140 :UBC 0 : PG_RETURN_BOOL(false);
141 : :
3630 heikki.linnakangas@i 142 :CBC 51 : it1 = JsonbIteratorInit(&val->root);
143 : 51 : it2 = JsonbIteratorInit(&tmpl->root);
144 : :
3675 andrew@dunslane.net 145 : 51 : PG_RETURN_BOOL(JsonbDeepContains(&it1, &it2));
146 : : }
147 : :
148 : : Datum
149 : 6 : jsonb_ne(PG_FUNCTION_ARGS)
150 : : {
2400 tgl@sss.pgh.pa.us 151 : 6 : Jsonb *jba = PG_GETARG_JSONB_P(0);
152 : 6 : Jsonb *jbb = PG_GETARG_JSONB_P(1);
153 : : bool res;
154 : :
3630 heikki.linnakangas@i 155 : 6 : res = (compareJsonbContainers(&jba->root, &jbb->root) != 0);
156 : :
3675 andrew@dunslane.net 157 [ - + ]: 6 : PG_FREE_IF_COPY(jba, 0);
158 [ - + ]: 6 : PG_FREE_IF_COPY(jbb, 1);
159 : 6 : PG_RETURN_BOOL(res);
160 : : }
161 : :
162 : : /*
163 : : * B-Tree operator class operators, support function
164 : : */
165 : : Datum
3675 andrew@dunslane.net 166 :GBC 6 : jsonb_lt(PG_FUNCTION_ARGS)
167 : : {
2400 tgl@sss.pgh.pa.us 168 : 6 : Jsonb *jba = PG_GETARG_JSONB_P(0);
169 : 6 : Jsonb *jbb = PG_GETARG_JSONB_P(1);
170 : : bool res;
171 : :
3630 heikki.linnakangas@i 172 : 6 : res = (compareJsonbContainers(&jba->root, &jbb->root) < 0);
173 : :
3675 andrew@dunslane.net 174 [ - + ]: 6 : PG_FREE_IF_COPY(jba, 0);
175 [ - + ]: 6 : PG_FREE_IF_COPY(jbb, 1);
176 : 6 : PG_RETURN_BOOL(res);
177 : : }
178 : :
179 : : Datum
3675 andrew@dunslane.net 180 :CBC 2778 : jsonb_gt(PG_FUNCTION_ARGS)
181 : : {
2400 tgl@sss.pgh.pa.us 182 : 2778 : Jsonb *jba = PG_GETARG_JSONB_P(0);
183 : 2778 : Jsonb *jbb = PG_GETARG_JSONB_P(1);
184 : : bool res;
185 : :
3630 heikki.linnakangas@i 186 : 2778 : res = (compareJsonbContainers(&jba->root, &jbb->root) > 0);
187 : :
3675 andrew@dunslane.net 188 [ + + ]: 2778 : PG_FREE_IF_COPY(jba, 0);
189 [ - + ]: 2778 : PG_FREE_IF_COPY(jbb, 1);
190 : 2778 : PG_RETURN_BOOL(res);
191 : : }
192 : :
193 : : Datum
3675 andrew@dunslane.net 194 :UBC 0 : jsonb_le(PG_FUNCTION_ARGS)
195 : : {
2400 tgl@sss.pgh.pa.us 196 : 0 : Jsonb *jba = PG_GETARG_JSONB_P(0);
197 : 0 : Jsonb *jbb = PG_GETARG_JSONB_P(1);
198 : : bool res;
199 : :
3630 heikki.linnakangas@i 200 : 0 : res = (compareJsonbContainers(&jba->root, &jbb->root) <= 0);
201 : :
3675 andrew@dunslane.net 202 [ # # ]: 0 : PG_FREE_IF_COPY(jba, 0);
203 [ # # ]: 0 : PG_FREE_IF_COPY(jbb, 1);
204 : 0 : PG_RETURN_BOOL(res);
205 : : }
206 : :
207 : : Datum
208 : 0 : jsonb_ge(PG_FUNCTION_ARGS)
209 : : {
2400 tgl@sss.pgh.pa.us 210 : 0 : Jsonb *jba = PG_GETARG_JSONB_P(0);
211 : 0 : Jsonb *jbb = PG_GETARG_JSONB_P(1);
212 : : bool res;
213 : :
3630 heikki.linnakangas@i 214 : 0 : res = (compareJsonbContainers(&jba->root, &jbb->root) >= 0);
215 : :
3675 andrew@dunslane.net 216 [ # # ]: 0 : PG_FREE_IF_COPY(jba, 0);
217 [ # # ]: 0 : PG_FREE_IF_COPY(jbb, 1);
218 : 0 : PG_RETURN_BOOL(res);
219 : : }
220 : :
221 : : Datum
3675 andrew@dunslane.net 222 :CBC 12515 : jsonb_eq(PG_FUNCTION_ARGS)
223 : : {
2400 tgl@sss.pgh.pa.us 224 : 12515 : Jsonb *jba = PG_GETARG_JSONB_P(0);
225 : 12515 : Jsonb *jbb = PG_GETARG_JSONB_P(1);
226 : : bool res;
227 : :
3630 heikki.linnakangas@i 228 : 12515 : res = (compareJsonbContainers(&jba->root, &jbb->root) == 0);
229 : :
3675 andrew@dunslane.net 230 [ + + ]: 12515 : PG_FREE_IF_COPY(jba, 0);
231 [ + + ]: 12515 : PG_FREE_IF_COPY(jbb, 1);
232 : 12515 : PG_RETURN_BOOL(res);
233 : : }
234 : :
235 : : Datum
236 : 121360 : jsonb_cmp(PG_FUNCTION_ARGS)
237 : : {
2400 tgl@sss.pgh.pa.us 238 : 121360 : Jsonb *jba = PG_GETARG_JSONB_P(0);
239 : 121360 : Jsonb *jbb = PG_GETARG_JSONB_P(1);
240 : : int res;
241 : :
3630 heikki.linnakangas@i 242 : 121360 : res = compareJsonbContainers(&jba->root, &jbb->root);
243 : :
3675 andrew@dunslane.net 244 [ + + ]: 121360 : PG_FREE_IF_COPY(jba, 0);
245 [ + + ]: 121360 : PG_FREE_IF_COPY(jbb, 1);
246 : 121360 : PG_RETURN_INT32(res);
247 : : }
248 : :
249 : : /*
250 : : * Hash operator class jsonb hashing function
251 : : */
252 : : Datum
253 : 6090 : jsonb_hash(PG_FUNCTION_ARGS)
254 : : {
2400 tgl@sss.pgh.pa.us 255 : 6090 : Jsonb *jb = PG_GETARG_JSONB_P(0);
256 : : JsonbIterator *it;
257 : : JsonbValue v;
258 : : JsonbIteratorToken r;
3675 andrew@dunslane.net 259 : 6090 : uint32 hash = 0;
260 : :
261 [ + + ]: 6090 : if (JB_ROOT_COUNT(jb) == 0)
262 : 708 : PG_RETURN_INT32(0);
263 : :
3630 heikki.linnakangas@i 264 : 5382 : it = JsonbIteratorInit(&jb->root);
265 : :
3675 andrew@dunslane.net 266 [ + + ]: 73956 : while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
267 : : {
268 [ + + + + : 68574 : switch (r)
- ]
269 : : {
270 : : /* Rotation is left to JsonbHashScalarValue() */
271 : 42 : case WJB_BEGIN_ARRAY:
272 : 42 : hash ^= JB_FARRAY;
273 : 42 : break;
274 : 5418 : case WJB_BEGIN_OBJECT:
275 : 5418 : hash ^= JB_FOBJECT;
276 : 5418 : break;
277 : 57654 : case WJB_KEY:
278 : : case WJB_VALUE:
279 : : case WJB_ELEM:
280 : 57654 : JsonbHashScalarValue(&v, &hash);
281 : 57654 : break;
282 : 5460 : case WJB_END_ARRAY:
283 : : case WJB_END_OBJECT:
284 : 5460 : break;
3675 andrew@dunslane.net 285 :UBC 0 : default:
3108 noah@leadboat.com 286 [ # # ]: 0 : elog(ERROR, "invalid JsonbIteratorNext rc: %d", (int) r);
287 : : }
288 : : }
289 : :
3675 andrew@dunslane.net 290 [ + + ]:CBC 5382 : PG_FREE_IF_COPY(jb, 0);
291 : 5382 : PG_RETURN_INT32(hash);
292 : : }
293 : :
294 : : Datum
2418 rhaas@postgresql.org 295 : 18 : jsonb_hash_extended(PG_FUNCTION_ARGS)
296 : : {
2400 tgl@sss.pgh.pa.us 297 : 18 : Jsonb *jb = PG_GETARG_JSONB_P(0);
2418 rhaas@postgresql.org 298 : 18 : uint64 seed = PG_GETARG_INT64(1);
299 : : JsonbIterator *it;
300 : : JsonbValue v;
301 : : JsonbIteratorToken r;
302 : 18 : uint64 hash = 0;
303 : :
304 [ - + ]: 18 : if (JB_ROOT_COUNT(jb) == 0)
2418 rhaas@postgresql.org 305 :UBC 0 : PG_RETURN_UINT64(seed);
306 : :
2418 rhaas@postgresql.org 307 :CBC 18 : it = JsonbIteratorInit(&jb->root);
308 : :
309 [ + + ]: 222 : while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
310 : : {
311 [ + + + + : 204 : switch (r)
- ]
312 : : {
313 : : /* Rotation is left to JsonbHashScalarValueExtended() */
314 : 12 : case WJB_BEGIN_ARRAY:
315 : 12 : hash ^= ((uint64) JB_FARRAY) << 32 | JB_FARRAY;
316 : 12 : break;
317 : 36 : case WJB_BEGIN_OBJECT:
318 : 36 : hash ^= ((uint64) JB_FOBJECT) << 32 | JB_FOBJECT;
319 : 36 : break;
320 : 108 : case WJB_KEY:
321 : : case WJB_VALUE:
322 : : case WJB_ELEM:
323 : 108 : JsonbHashScalarValueExtended(&v, &hash, seed);
324 : 108 : break;
325 : 48 : case WJB_END_ARRAY:
326 : : case WJB_END_OBJECT:
327 : 48 : break;
2418 rhaas@postgresql.org 328 :UBC 0 : default:
329 [ # # ]: 0 : elog(ERROR, "invalid JsonbIteratorNext rc: %d", (int) r);
330 : : }
331 : : }
332 : :
2418 rhaas@postgresql.org 333 [ - + ]:CBC 18 : PG_FREE_IF_COPY(jb, 0);
334 : 18 : PG_RETURN_UINT64(hash);
335 : : }
|