Branch data 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-2026, 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
21 : 2286 : jsonb_exists(PG_FUNCTION_ARGS)
22 : : {
23 : 2286 : Jsonb *jb = PG_GETARG_JSONB_P(0);
24 : 2286 : text *key = PG_GETARG_TEXT_PP(1);
25 : 2286 : JsonbValue kval;
26 : 2286 : 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 : 2286 : kval.type = jbvString;
35 : 2286 : kval.val.string.val = VARDATA_ANY(key);
36 : 2286 : kval.val.string.len = VARSIZE_ANY_EXHDR(key);
37 : :
38 : 2286 : v = findJsonbValueFromContainer(&jb->root,
39 : : JB_FOBJECT | JB_FARRAY,
40 : : &kval);
41 : :
42 : 4572 : PG_RETURN_BOOL(v != NULL);
43 : 2286 : }
44 : :
45 : : Datum
46 : 1359 : jsonb_exists_any(PG_FUNCTION_ARGS)
47 : : {
48 : 1359 : Jsonb *jb = PG_GETARG_JSONB_P(0);
49 : 1359 : ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
50 : 1359 : int i;
51 : 1359 : Datum *key_datums;
52 : 1359 : bool *key_nulls;
53 : 1359 : int elem_count;
54 : :
55 : 1359 : deconstruct_array_builtin(keys, TEXTOID, &key_datums, &key_nulls, &elem_count);
56 : :
57 [ + + ]: 3001 : for (i = 0; i < elem_count; i++)
58 : : {
59 : 2322 : JsonbValue strVal;
60 : :
61 [ - + ]: 2322 : if (key_nulls[i])
62 : 0 : continue;
63 : :
64 : 2322 : strVal.type = jbvString;
65 : : /* We rely on the array elements not being toasted */
66 : 2322 : strVal.val.string.val = VARDATA_ANY(DatumGetPointer(key_datums[i]));
67 : 2322 : strVal.val.string.len = VARSIZE_ANY_EXHDR(DatumGetPointer(key_datums[i]));
68 : :
69 : 2322 : if (findJsonbValueFromContainer(&jb->root,
70 : : JB_FOBJECT | JB_FARRAY,
71 [ + + ]: 2322 : &strVal) != NULL)
72 : 680 : PG_RETURN_BOOL(true);
73 [ - + + ]: 2322 : }
74 : :
75 : 679 : PG_RETURN_BOOL(false);
76 : 1359 : }
77 : :
78 : : Datum
79 : 1065 : jsonb_exists_all(PG_FUNCTION_ARGS)
80 : : {
81 : 1065 : Jsonb *jb = PG_GETARG_JSONB_P(0);
82 : 1065 : ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
83 : 1065 : int i;
84 : 1065 : Datum *key_datums;
85 : 1065 : bool *key_nulls;
86 : 1065 : int elem_count;
87 : :
88 : 1065 : deconstruct_array_builtin(keys, TEXTOID, &key_datums, &key_nulls, &elem_count);
89 : :
90 [ + + ]: 1398 : for (i = 0; i < elem_count; i++)
91 : : {
92 : 1307 : JsonbValue strVal;
93 : :
94 [ - + ]: 1307 : if (key_nulls[i])
95 : 0 : continue;
96 : :
97 : 1307 : strVal.type = jbvString;
98 : : /* We rely on the array elements not being toasted */
99 : 1307 : strVal.val.string.val = VARDATA_ANY(DatumGetPointer(key_datums[i]));
100 : 1307 : strVal.val.string.len = VARSIZE_ANY_EXHDR(DatumGetPointer(key_datums[i]));
101 : :
102 : 1307 : if (findJsonbValueFromContainer(&jb->root,
103 : : JB_FOBJECT | JB_FARRAY,
104 [ + + ]: 1307 : &strVal) == NULL)
105 : 974 : PG_RETURN_BOOL(false);
106 [ - + + ]: 1307 : }
107 : :
108 : 91 : PG_RETURN_BOOL(true);
109 : 1065 : }
110 : :
111 : : Datum
112 : 7212 : jsonb_contains(PG_FUNCTION_ARGS)
113 : : {
114 : 7212 : Jsonb *val = PG_GETARG_JSONB_P(0);
115 : 7212 : Jsonb *tmpl = PG_GETARG_JSONB_P(1);
116 : :
117 : 7212 : JsonbIterator *it1,
118 : : *it2;
119 : :
120 [ + + ]: 7212 : if (JB_ROOT_IS_OBJECT(val) != JB_ROOT_IS_OBJECT(tmpl))
121 : 5 : PG_RETURN_BOOL(false);
122 : :
123 : 7207 : it1 = JsonbIteratorInit(&val->root);
124 : 7207 : it2 = JsonbIteratorInit(&tmpl->root);
125 : :
126 : 7207 : PG_RETURN_BOOL(JsonbDeepContains(&it1, &it2));
127 : 7212 : }
128 : :
129 : : Datum
130 : 17 : jsonb_contained(PG_FUNCTION_ARGS)
131 : : {
132 : : /* Commutator of "contains" */
133 : 17 : Jsonb *tmpl = PG_GETARG_JSONB_P(0);
134 : 17 : Jsonb *val = PG_GETARG_JSONB_P(1);
135 : :
136 : 17 : JsonbIterator *it1,
137 : : *it2;
138 : :
139 [ - + ]: 17 : if (JB_ROOT_IS_OBJECT(val) != JB_ROOT_IS_OBJECT(tmpl))
140 : 0 : PG_RETURN_BOOL(false);
141 : :
142 : 17 : it1 = JsonbIteratorInit(&val->root);
143 : 17 : it2 = JsonbIteratorInit(&tmpl->root);
144 : :
145 : 17 : PG_RETURN_BOOL(JsonbDeepContains(&it1, &it2));
146 : 17 : }
147 : :
148 : : Datum
149 : 2 : jsonb_ne(PG_FUNCTION_ARGS)
150 : : {
151 : 2 : Jsonb *jba = PG_GETARG_JSONB_P(0);
152 : 2 : Jsonb *jbb = PG_GETARG_JSONB_P(1);
153 : 2 : bool res;
154 : :
155 : 2 : res = (compareJsonbContainers(&jba->root, &jbb->root) != 0);
156 : :
157 [ + - ]: 2 : PG_FREE_IF_COPY(jba, 0);
158 [ + - ]: 2 : PG_FREE_IF_COPY(jbb, 1);
159 : 4 : PG_RETURN_BOOL(res);
160 : 2 : }
161 : :
162 : : /*
163 : : * B-Tree operator class operators, support function
164 : : */
165 : : Datum
166 : 0 : jsonb_lt(PG_FUNCTION_ARGS)
167 : : {
168 : 0 : Jsonb *jba = PG_GETARG_JSONB_P(0);
169 : 0 : Jsonb *jbb = PG_GETARG_JSONB_P(1);
170 : 0 : bool res;
171 : :
172 : 0 : res = (compareJsonbContainers(&jba->root, &jbb->root) < 0);
173 : :
174 [ # # ]: 0 : PG_FREE_IF_COPY(jba, 0);
175 [ # # ]: 0 : PG_FREE_IF_COPY(jbb, 1);
176 : 0 : PG_RETURN_BOOL(res);
177 : 0 : }
178 : :
179 : : Datum
180 : 926 : jsonb_gt(PG_FUNCTION_ARGS)
181 : : {
182 : 926 : Jsonb *jba = PG_GETARG_JSONB_P(0);
183 : 926 : Jsonb *jbb = PG_GETARG_JSONB_P(1);
184 : 926 : bool res;
185 : :
186 : 926 : res = (compareJsonbContainers(&jba->root, &jbb->root) > 0);
187 : :
188 [ + + ]: 926 : PG_FREE_IF_COPY(jba, 0);
189 [ + - ]: 926 : PG_FREE_IF_COPY(jbb, 1);
190 : 1852 : PG_RETURN_BOOL(res);
191 : 926 : }
192 : :
193 : : Datum
194 : 0 : jsonb_le(PG_FUNCTION_ARGS)
195 : : {
196 : 0 : Jsonb *jba = PG_GETARG_JSONB_P(0);
197 : 0 : Jsonb *jbb = PG_GETARG_JSONB_P(1);
198 : 0 : bool res;
199 : :
200 : 0 : res = (compareJsonbContainers(&jba->root, &jbb->root) <= 0);
201 : :
202 [ # # ]: 0 : PG_FREE_IF_COPY(jba, 0);
203 [ # # ]: 0 : PG_FREE_IF_COPY(jbb, 1);
204 : 0 : PG_RETURN_BOOL(res);
205 : 0 : }
206 : :
207 : : Datum
208 : 0 : jsonb_ge(PG_FUNCTION_ARGS)
209 : : {
210 : 0 : Jsonb *jba = PG_GETARG_JSONB_P(0);
211 : 0 : Jsonb *jbb = PG_GETARG_JSONB_P(1);
212 : 0 : bool res;
213 : :
214 : 0 : res = (compareJsonbContainers(&jba->root, &jbb->root) >= 0);
215 : :
216 [ # # ]: 0 : PG_FREE_IF_COPY(jba, 0);
217 [ # # ]: 0 : PG_FREE_IF_COPY(jbb, 1);
218 : 0 : PG_RETURN_BOOL(res);
219 : 0 : }
220 : :
221 : : Datum
222 : 4171 : jsonb_eq(PG_FUNCTION_ARGS)
223 : : {
224 : 4171 : Jsonb *jba = PG_GETARG_JSONB_P(0);
225 : 4171 : Jsonb *jbb = PG_GETARG_JSONB_P(1);
226 : 4171 : bool res;
227 : :
228 : 4171 : res = (compareJsonbContainers(&jba->root, &jbb->root) == 0);
229 : :
230 [ + + ]: 4171 : PG_FREE_IF_COPY(jba, 0);
231 [ + + ]: 4171 : PG_FREE_IF_COPY(jbb, 1);
232 : 8342 : PG_RETURN_BOOL(res);
233 : 4171 : }
234 : :
235 : : Datum
236 : 40522 : jsonb_cmp(PG_FUNCTION_ARGS)
237 : : {
238 : 40522 : Jsonb *jba = PG_GETARG_JSONB_P(0);
239 : 40522 : Jsonb *jbb = PG_GETARG_JSONB_P(1);
240 : 40522 : int res;
241 : :
242 : 40522 : res = compareJsonbContainers(&jba->root, &jbb->root);
243 : :
244 [ + + ]: 40522 : PG_FREE_IF_COPY(jba, 0);
245 [ + + ]: 40522 : PG_FREE_IF_COPY(jbb, 1);
246 : 81044 : PG_RETURN_INT32(res);
247 : 40522 : }
248 : :
249 : : /*
250 : : * Hash operator class jsonb hashing function
251 : : */
252 : : Datum
253 : 2030 : jsonb_hash(PG_FUNCTION_ARGS)
254 : : {
255 : 2030 : Jsonb *jb = PG_GETARG_JSONB_P(0);
256 : 2030 : JsonbIterator *it;
257 : 2030 : JsonbValue v;
258 : 2030 : JsonbIteratorToken r;
259 : 2030 : uint32 hash = 0;
260 : :
261 [ + + ]: 2030 : if (JB_ROOT_COUNT(jb) == 0)
262 : 236 : PG_RETURN_INT32(0);
263 : :
264 : 1794 : it = JsonbIteratorInit(&jb->root);
265 : :
266 [ + + ]: 24652 : while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
267 : : {
268 [ + + - + : 22858 : switch (r)
+ ]
269 : : {
270 : : /* Rotation is left to JsonbHashScalarValue() */
271 : : case WJB_BEGIN_ARRAY:
272 : 14 : hash ^= JB_FARRAY;
273 : 14 : break;
274 : : case WJB_BEGIN_OBJECT:
275 : 1806 : hash ^= JB_FOBJECT;
276 : 1806 : break;
277 : : case WJB_KEY:
278 : : case WJB_VALUE:
279 : : case WJB_ELEM:
280 : 19218 : JsonbHashScalarValue(&v, &hash);
281 : 19218 : break;
282 : : case WJB_END_ARRAY:
283 : : case WJB_END_OBJECT:
284 : 1820 : break;
285 : : default:
286 [ # # # # ]: 0 : elog(ERROR, "invalid JsonbIteratorNext rc: %d", (int) r);
287 : 0 : }
288 : : }
289 : :
290 [ + + ]: 1794 : PG_FREE_IF_COPY(jb, 0);
291 : 1794 : PG_RETURN_INT32(hash);
292 : 2030 : }
293 : :
294 : : Datum
295 : 6 : jsonb_hash_extended(PG_FUNCTION_ARGS)
296 : : {
297 : 6 : Jsonb *jb = PG_GETARG_JSONB_P(0);
298 : 6 : uint64 seed = PG_GETARG_INT64(1);
299 : 6 : JsonbIterator *it;
300 : 6 : JsonbValue v;
301 : 6 : JsonbIteratorToken r;
302 : 6 : uint64 hash = 0;
303 : :
304 [ + - ]: 6 : if (JB_ROOT_COUNT(jb) == 0)
305 : 0 : PG_RETURN_UINT64(seed);
306 : :
307 : 6 : it = JsonbIteratorInit(&jb->root);
308 : :
309 [ + + ]: 74 : while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
310 : : {
311 [ + + - + : 68 : switch (r)
+ ]
312 : : {
313 : : /* Rotation is left to JsonbHashScalarValueExtended() */
314 : : case WJB_BEGIN_ARRAY:
315 : 4 : hash ^= ((uint64) JB_FARRAY) << 32 | JB_FARRAY;
316 : 4 : break;
317 : : case WJB_BEGIN_OBJECT:
318 : 12 : hash ^= ((uint64) JB_FOBJECT) << 32 | JB_FOBJECT;
319 : 12 : break;
320 : : case WJB_KEY:
321 : : case WJB_VALUE:
322 : : case WJB_ELEM:
323 : 36 : JsonbHashScalarValueExtended(&v, &hash, seed);
324 : 36 : break;
325 : : case WJB_END_ARRAY:
326 : : case WJB_END_OBJECT:
327 : 16 : break;
328 : : default:
329 [ # # # # ]: 0 : elog(ERROR, "invalid JsonbIteratorNext rc: %d", (int) r);
330 : 0 : }
331 : : }
332 : :
333 [ + - ]: 6 : PG_FREE_IF_COPY(jb, 0);
334 : 6 : PG_RETURN_UINT64(hash);
335 : 6 : }
|