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
21 13718 : jsonb_exists(PG_FUNCTION_ARGS)
22 : {
23 13718 : Jsonb *jb = PG_GETARG_JSONB_P(0);
24 13718 : text *key = PG_GETARG_TEXT_PP(1);
25 : JsonbValue kval;
26 13718 : 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 13718 : kval.type = jbvString;
35 13718 : kval.val.string.val = VARDATA_ANY(key);
36 13718 : kval.val.string.len = VARSIZE_ANY_EXHDR(key);
37 :
38 13718 : v = findJsonbValueFromContainer(&jb->root,
39 : JB_FOBJECT | JB_FARRAY,
40 : &kval);
41 :
42 13718 : PG_RETURN_BOOL(v != NULL);
43 : }
44 :
45 : Datum
46 8154 : jsonb_exists_any(PG_FUNCTION_ARGS)
47 : {
48 8154 : Jsonb *jb = PG_GETARG_JSONB_P(0);
49 8154 : ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
50 : int i;
51 : Datum *key_datums;
52 : bool *key_nulls;
53 : int elem_count;
54 :
55 8154 : deconstruct_array_builtin(keys, TEXTOID, &key_datums, &key_nulls, &elem_count);
56 :
57 18006 : for (i = 0; i < elem_count; i++)
58 : {
59 : JsonbValue strVal;
60 :
61 13932 : if (key_nulls[i])
62 0 : continue;
63 :
64 13932 : strVal.type = jbvString;
65 : /* We rely on the array elements not being toasted */
66 13932 : strVal.val.string.val = VARDATA_ANY(key_datums[i]);
67 13932 : strVal.val.string.len = VARSIZE_ANY_EXHDR(key_datums[i]);
68 :
69 13932 : if (findJsonbValueFromContainer(&jb->root,
70 : JB_FOBJECT | JB_FARRAY,
71 : &strVal) != NULL)
72 4080 : PG_RETURN_BOOL(true);
73 : }
74 :
75 4074 : PG_RETURN_BOOL(false);
76 : }
77 :
78 : Datum
79 6390 : jsonb_exists_all(PG_FUNCTION_ARGS)
80 : {
81 6390 : Jsonb *jb = PG_GETARG_JSONB_P(0);
82 6390 : ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
83 : int i;
84 : Datum *key_datums;
85 : bool *key_nulls;
86 : int elem_count;
87 :
88 6390 : deconstruct_array_builtin(keys, TEXTOID, &key_datums, &key_nulls, &elem_count);
89 :
90 8388 : for (i = 0; i < elem_count; i++)
91 : {
92 : JsonbValue strVal;
93 :
94 7842 : if (key_nulls[i])
95 0 : continue;
96 :
97 7842 : strVal.type = jbvString;
98 : /* We rely on the array elements not being toasted */
99 7842 : strVal.val.string.val = VARDATA_ANY(key_datums[i]);
100 7842 : strVal.val.string.len = VARSIZE_ANY_EXHDR(key_datums[i]);
101 :
102 7842 : if (findJsonbValueFromContainer(&jb->root,
103 : JB_FOBJECT | JB_FARRAY,
104 : &strVal) == NULL)
105 5844 : PG_RETURN_BOOL(false);
106 : }
107 :
108 546 : PG_RETURN_BOOL(true);
109 : }
110 :
111 : Datum
112 43272 : jsonb_contains(PG_FUNCTION_ARGS)
113 : {
114 43272 : Jsonb *val = PG_GETARG_JSONB_P(0);
115 43272 : Jsonb *tmpl = PG_GETARG_JSONB_P(1);
116 :
117 : JsonbIterator *it1,
118 : *it2;
119 :
120 43272 : if (JB_ROOT_IS_OBJECT(val) != JB_ROOT_IS_OBJECT(tmpl))
121 30 : PG_RETURN_BOOL(false);
122 :
123 43242 : it1 = JsonbIteratorInit(&val->root);
124 43242 : it2 = JsonbIteratorInit(&tmpl->root);
125 :
126 43242 : PG_RETURN_BOOL(JsonbDeepContains(&it1, &it2));
127 : }
128 :
129 : Datum
130 102 : jsonb_contained(PG_FUNCTION_ARGS)
131 : {
132 : /* Commutator of "contains" */
133 102 : Jsonb *tmpl = PG_GETARG_JSONB_P(0);
134 102 : Jsonb *val = PG_GETARG_JSONB_P(1);
135 :
136 : JsonbIterator *it1,
137 : *it2;
138 :
139 102 : if (JB_ROOT_IS_OBJECT(val) != JB_ROOT_IS_OBJECT(tmpl))
140 0 : PG_RETURN_BOOL(false);
141 :
142 102 : it1 = JsonbIteratorInit(&val->root);
143 102 : it2 = JsonbIteratorInit(&tmpl->root);
144 :
145 102 : PG_RETURN_BOOL(JsonbDeepContains(&it1, &it2));
146 : }
147 :
148 : Datum
149 12 : jsonb_ne(PG_FUNCTION_ARGS)
150 : {
151 12 : Jsonb *jba = PG_GETARG_JSONB_P(0);
152 12 : Jsonb *jbb = PG_GETARG_JSONB_P(1);
153 : bool res;
154 :
155 12 : res = (compareJsonbContainers(&jba->root, &jbb->root) != 0);
156 :
157 12 : PG_FREE_IF_COPY(jba, 0);
158 12 : PG_FREE_IF_COPY(jbb, 1);
159 12 : PG_RETURN_BOOL(res);
160 : }
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 : 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 : }
178 :
179 : Datum
180 174 : jsonb_gt(PG_FUNCTION_ARGS)
181 : {
182 174 : Jsonb *jba = PG_GETARG_JSONB_P(0);
183 174 : Jsonb *jbb = PG_GETARG_JSONB_P(1);
184 : bool res;
185 :
186 174 : res = (compareJsonbContainers(&jba->root, &jbb->root) > 0);
187 :
188 174 : PG_FREE_IF_COPY(jba, 0);
189 174 : PG_FREE_IF_COPY(jbb, 1);
190 174 : PG_RETURN_BOOL(res);
191 : }
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 : 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 : }
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 : 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 : }
220 :
221 : Datum
222 25030 : jsonb_eq(PG_FUNCTION_ARGS)
223 : {
224 25030 : Jsonb *jba = PG_GETARG_JSONB_P(0);
225 25030 : Jsonb *jbb = PG_GETARG_JSONB_P(1);
226 : bool res;
227 :
228 25030 : res = (compareJsonbContainers(&jba->root, &jbb->root) == 0);
229 :
230 25030 : PG_FREE_IF_COPY(jba, 0);
231 25030 : PG_FREE_IF_COPY(jbb, 1);
232 25030 : PG_RETURN_BOOL(res);
233 : }
234 :
235 : Datum
236 242720 : jsonb_cmp(PG_FUNCTION_ARGS)
237 : {
238 242720 : Jsonb *jba = PG_GETARG_JSONB_P(0);
239 242720 : Jsonb *jbb = PG_GETARG_JSONB_P(1);
240 : int res;
241 :
242 242720 : res = compareJsonbContainers(&jba->root, &jbb->root);
243 :
244 242720 : PG_FREE_IF_COPY(jba, 0);
245 242720 : PG_FREE_IF_COPY(jbb, 1);
246 242720 : PG_RETURN_INT32(res);
247 : }
248 :
249 : /*
250 : * Hash operator class jsonb hashing function
251 : */
252 : Datum
253 12180 : jsonb_hash(PG_FUNCTION_ARGS)
254 : {
255 12180 : Jsonb *jb = PG_GETARG_JSONB_P(0);
256 : JsonbIterator *it;
257 : JsonbValue v;
258 : JsonbIteratorToken r;
259 12180 : uint32 hash = 0;
260 :
261 12180 : if (JB_ROOT_COUNT(jb) == 0)
262 1416 : PG_RETURN_INT32(0);
263 :
264 10764 : it = JsonbIteratorInit(&jb->root);
265 :
266 147912 : while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
267 : {
268 137148 : switch (r)
269 : {
270 : /* Rotation is left to JsonbHashScalarValue() */
271 84 : case WJB_BEGIN_ARRAY:
272 84 : hash ^= JB_FARRAY;
273 84 : break;
274 10836 : case WJB_BEGIN_OBJECT:
275 10836 : hash ^= JB_FOBJECT;
276 10836 : break;
277 115308 : case WJB_KEY:
278 : case WJB_VALUE:
279 : case WJB_ELEM:
280 115308 : JsonbHashScalarValue(&v, &hash);
281 115308 : break;
282 10920 : case WJB_END_ARRAY:
283 : case WJB_END_OBJECT:
284 10920 : break;
285 0 : default:
286 0 : elog(ERROR, "invalid JsonbIteratorNext rc: %d", (int) r);
287 : }
288 : }
289 :
290 10764 : PG_FREE_IF_COPY(jb, 0);
291 10764 : PG_RETURN_INT32(hash);
292 : }
293 :
294 : Datum
295 36 : jsonb_hash_extended(PG_FUNCTION_ARGS)
296 : {
297 36 : Jsonb *jb = PG_GETARG_JSONB_P(0);
298 36 : uint64 seed = PG_GETARG_INT64(1);
299 : JsonbIterator *it;
300 : JsonbValue v;
301 : JsonbIteratorToken r;
302 36 : uint64 hash = 0;
303 :
304 36 : if (JB_ROOT_COUNT(jb) == 0)
305 0 : PG_RETURN_UINT64(seed);
306 :
307 36 : it = JsonbIteratorInit(&jb->root);
308 :
309 444 : while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
310 : {
311 408 : switch (r)
312 : {
313 : /* Rotation is left to JsonbHashScalarValueExtended() */
314 24 : case WJB_BEGIN_ARRAY:
315 24 : hash ^= ((uint64) JB_FARRAY) << 32 | JB_FARRAY;
316 24 : break;
317 72 : case WJB_BEGIN_OBJECT:
318 72 : hash ^= ((uint64) JB_FOBJECT) << 32 | JB_FOBJECT;
319 72 : break;
320 216 : case WJB_KEY:
321 : case WJB_VALUE:
322 : case WJB_ELEM:
323 216 : JsonbHashScalarValueExtended(&v, &hash, seed);
324 216 : break;
325 96 : case WJB_END_ARRAY:
326 : case WJB_END_OBJECT:
327 96 : break;
328 0 : default:
329 0 : elog(ERROR, "invalid JsonbIteratorNext rc: %d", (int) r);
330 : }
331 : }
332 :
333 36 : PG_FREE_IF_COPY(jb, 0);
334 36 : PG_RETURN_UINT64(hash);
335 : }
|