Coverage Report

Created: 2025-08-12 06:43

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