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