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