1 /*-------------------------------------------------------------------------
2 *
3 * jsonb_op.c
4 * Special operators for jsonb only, used by various index access methods
5 *
6 * Copyright (c) 2014-2017, 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
jsonb_exists(PG_FUNCTION_ARGS)22 jsonb_exists(PG_FUNCTION_ARGS)
23 {
24 Jsonb *jb = PG_GETARG_JSONB(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
46 Datum
jsonb_exists_any(PG_FUNCTION_ARGS)47 jsonb_exists_any(PG_FUNCTION_ARGS)
48 {
49 Jsonb *jb = PG_GETARG_JSONB(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
79 Datum
jsonb_exists_all(PG_FUNCTION_ARGS)80 jsonb_exists_all(PG_FUNCTION_ARGS)
81 {
82 Jsonb *jb = PG_GETARG_JSONB(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
112 Datum
jsonb_contains(PG_FUNCTION_ARGS)113 jsonb_contains(PG_FUNCTION_ARGS)
114 {
115 Jsonb *val = PG_GETARG_JSONB(0);
116 Jsonb *tmpl = PG_GETARG_JSONB(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
130 Datum
jsonb_contained(PG_FUNCTION_ARGS)131 jsonb_contained(PG_FUNCTION_ARGS)
132 {
133 /* Commutator of "contains" */
134 Jsonb *tmpl = PG_GETARG_JSONB(0);
135 Jsonb *val = PG_GETARG_JSONB(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
149 Datum
jsonb_ne(PG_FUNCTION_ARGS)150 jsonb_ne(PG_FUNCTION_ARGS)
151 {
152 Jsonb *jba = PG_GETARG_JSONB(0);
153 Jsonb *jbb = PG_GETARG_JSONB(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 */
166 Datum
jsonb_lt(PG_FUNCTION_ARGS)167 jsonb_lt(PG_FUNCTION_ARGS)
168 {
169 Jsonb *jba = PG_GETARG_JSONB(0);
170 Jsonb *jbb = PG_GETARG_JSONB(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
180 Datum
jsonb_gt(PG_FUNCTION_ARGS)181 jsonb_gt(PG_FUNCTION_ARGS)
182 {
183 Jsonb *jba = PG_GETARG_JSONB(0);
184 Jsonb *jbb = PG_GETARG_JSONB(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
194 Datum
jsonb_le(PG_FUNCTION_ARGS)195 jsonb_le(PG_FUNCTION_ARGS)
196 {
197 Jsonb *jba = PG_GETARG_JSONB(0);
198 Jsonb *jbb = PG_GETARG_JSONB(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
208 Datum
jsonb_ge(PG_FUNCTION_ARGS)209 jsonb_ge(PG_FUNCTION_ARGS)
210 {
211 Jsonb *jba = PG_GETARG_JSONB(0);
212 Jsonb *jbb = PG_GETARG_JSONB(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
222 Datum
jsonb_eq(PG_FUNCTION_ARGS)223 jsonb_eq(PG_FUNCTION_ARGS)
224 {
225 Jsonb *jba = PG_GETARG_JSONB(0);
226 Jsonb *jbb = PG_GETARG_JSONB(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
236 Datum
jsonb_cmp(PG_FUNCTION_ARGS)237 jsonb_cmp(PG_FUNCTION_ARGS)
238 {
239 Jsonb *jba = PG_GETARG_JSONB(0);
240 Jsonb *jbb = PG_GETARG_JSONB(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 */
253 Datum
jsonb_hash(PG_FUNCTION_ARGS)254 jsonb_hash(PG_FUNCTION_ARGS)
255 {
256 Jsonb *jb = PG_GETARG_JSONB(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