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