Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * jsonpath.c
4 : * Input/output and supporting routines for jsonpath
5 : *
6 : * jsonpath expression is a chain of path items. First path item is $, $var,
7 : * literal or arithmetic expression. Subsequent path items are accessors
8 : * (.key, .*, [subscripts], [*]), filters (? (predicate)) and methods (.type(),
9 : * .size() etc).
10 : *
11 : * For instance, structure of path items for simple expression:
12 : *
13 : * $.a[*].type()
14 : *
15 : * is pretty evident:
16 : *
17 : * $ => .a => [*] => .type()
18 : *
19 : * Some path items such as arithmetic operations, predicates or array
20 : * subscripts may comprise subtrees. For instance, more complex expression
21 : *
22 : * ($.a + $[1 to 5, 7] ? (@ > 3).double()).type()
23 : *
24 : * have following structure of path items:
25 : *
26 : * + => .type()
27 : * ___/ \___
28 : * / \
29 : * $ => .a $ => [] => ? => .double()
30 : * _||_ |
31 : * / \ >
32 : * to to / \
33 : * / \ / @ 3
34 : * 1 5 7
35 : *
36 : * Binary encoding of jsonpath constitutes a sequence of 4-bytes aligned
37 : * variable-length path items connected by links. Every item has a header
38 : * consisting of item type (enum JsonPathItemType) and offset of next item
39 : * (zero means no next item). After the header, item may have payload
40 : * depending on item type. For instance, payload of '.key' accessor item is
41 : * length of key name and key name itself. Payload of '>' arithmetic operator
42 : * item is offsets of right and left operands.
43 : *
44 : * So, binary representation of sample expression above is:
45 : * (bottom arrows are next links, top lines are argument links)
46 : *
47 : * _____
48 : * _____ ___/____ \ __
49 : * _ /_ \ _____/__/____ \ \ __ _ /_ \
50 : * / / \ \ / / / \ \ \ / \ / / \ \
51 : * +(LR) $ .a $ [](* to *, * to *) 1 5 7 ?(A) >(LR) @ 3 .double() .type()
52 : * | | ^ | ^| ^| ^ ^
53 : * | |__| |__||________________________||___________________| |
54 : * |_______________________________________________________________________|
55 : *
56 : * Copyright (c) 2019-2023, PostgreSQL Global Development Group
57 : *
58 : * IDENTIFICATION
59 : * src/backend/utils/adt/jsonpath.c
60 : *
61 : *-------------------------------------------------------------------------
62 : */
63 :
64 : #include "postgres.h"
65 :
66 : #include "funcapi.h"
67 : #include "lib/stringinfo.h"
68 : #include "libpq/pqformat.h"
69 : #include "nodes/miscnodes.h"
70 : #include "miscadmin.h"
71 : #include "utils/builtins.h"
72 : #include "utils/json.h"
73 : #include "utils/jsonpath.h"
74 :
75 :
76 : static Datum jsonPathFromCstring(char *in, int len, struct Node *escontext);
77 : static char *jsonPathToCstring(StringInfo out, JsonPath *in,
78 : int estimated_len);
79 : static bool flattenJsonPathParseItem(StringInfo buf, int *result,
80 : struct Node *escontext,
81 : JsonPathParseItem *item,
82 : int nestingLevel, bool insideArraySubscript);
83 : static void alignStringInfoInt(StringInfo buf);
84 : static int32 reserveSpaceForItemPointer(StringInfo buf);
85 : static void printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
86 : bool printBracketes);
87 : static int operationPriority(JsonPathItemType op);
88 :
89 :
90 : /**************************** INPUT/OUTPUT ********************************/
91 :
92 : /*
93 : * jsonpath type input function
94 : */
95 : Datum
1485 akorotkov 96 GIC 2280 : jsonpath_in(PG_FUNCTION_ARGS)
97 : {
98 2280 : char *in = PG_GETARG_CSTRING(0);
1485 akorotkov 99 CBC 2280 : int len = strlen(in);
100 :
106 andrew 101 GNC 2280 : return jsonPathFromCstring(in, len, fcinfo->context);
1485 akorotkov 102 ECB : }
103 :
104 : /*
105 : * jsonpath type recv function
106 : *
107 : * The type is sent as text in binary mode, so this is almost the same
108 : * as the input function, but it's prefixed with a version number so we
109 : * can change the binary format sent in future if necessary. For now,
110 : * only version 1 is supported.
111 : */
112 : Datum
1485 akorotkov 113 UIC 0 : jsonpath_recv(PG_FUNCTION_ARGS)
114 : {
115 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
1485 akorotkov 116 UBC 0 : int version = pq_getmsgint(buf, 1);
117 : char *str;
1485 akorotkov 118 EUB : int nbytes;
119 :
1485 akorotkov 120 UIC 0 : if (version == JSONPATH_VERSION)
121 0 : str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
122 : else
1485 akorotkov 123 UBC 0 : elog(ERROR, "unsupported jsonpath version number: %d", version);
1485 akorotkov 124 EUB :
106 andrew 125 UNC 0 : return jsonPathFromCstring(str, nbytes, NULL);
1485 akorotkov 126 EUB : }
127 :
128 : /*
129 : * jsonpath type output function
130 : */
131 : Datum
1485 akorotkov 132 GIC 586 : jsonpath_out(PG_FUNCTION_ARGS)
133 : {
134 586 : JsonPath *in = PG_GETARG_JSONPATH_P(0);
1485 akorotkov 135 ECB :
1485 akorotkov 136 GIC 586 : PG_RETURN_CSTRING(jsonPathToCstring(NULL, in, VARSIZE(in)));
1485 akorotkov 137 ECB : }
138 :
139 : /*
140 : * jsonpath type send function
141 : *
142 : * Just send jsonpath as a version number, then a string of text
143 : */
144 : Datum
1485 akorotkov 145 UIC 0 : jsonpath_send(PG_FUNCTION_ARGS)
146 : {
147 0 : JsonPath *in = PG_GETARG_JSONPATH_P(0);
1485 akorotkov 148 EUB : StringInfoData buf;
149 : StringInfoData jtext;
1485 akorotkov 150 UBC 0 : int version = JSONPATH_VERSION;
151 :
1485 akorotkov 152 UIC 0 : initStringInfo(&jtext);
1485 akorotkov 153 UBC 0 : (void) jsonPathToCstring(&jtext, in, VARSIZE(in));
154 :
155 0 : pq_begintypsend(&buf);
156 0 : pq_sendint8(&buf, version);
1485 akorotkov 157 UIC 0 : pq_sendtext(&buf, jtext.data, jtext.len);
1485 akorotkov 158 UBC 0 : pfree(jtext.data);
1485 akorotkov 159 EUB :
1485 akorotkov 160 UBC 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
1485 akorotkov 161 EUB : }
162 :
163 : /*
164 : * Converts C-string to a jsonpath value.
165 : *
166 : * Uses jsonpath parser to turn string into an AST, then
167 : * flattenJsonPathParseItem() does second pass turning AST into binary
168 : * representation of jsonpath.
169 : */
170 : static Datum
106 andrew 171 GNC 2280 : jsonPathFromCstring(char *in, int len, struct Node *escontext)
172 : {
173 2280 : JsonPathParseResult *jsonpath = parsejsonpath(in, len, escontext);
1485 akorotkov 174 ECB : JsonPath *res;
175 : StringInfoData buf;
176 :
106 andrew 177 GNC 2130 : if (SOFT_ERROR_OCCURRED(escontext))
178 18 : return (Datum) 0;
179 :
1485 akorotkov 180 2112 : if (!jsonpath)
106 andrew 181 3 : ereturn(escontext, (Datum) 0,
182 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
183 : errmsg("invalid input syntax for type %s: \"%s\"", "jsonpath",
184 : in)));
185 :
106 andrew 186 GIC 2109 : initStringInfo(&buf);
187 2109 : enlargeStringInfo(&buf, 4 * len /* estimation */ );
188 :
106 andrew 189 CBC 2109 : appendStringInfoSpaces(&buf, JSONPATH_HDRSZ);
106 andrew 190 ECB :
106 andrew 191 GNC 2109 : if (!flattenJsonPathParseItem(&buf, NULL, escontext,
192 : jsonpath->expr, 0, false))
193 6 : return (Datum) 0;
1485 akorotkov 194 ECB :
1485 akorotkov 195 CBC 2094 : res = (JsonPath *) buf.data;
1485 akorotkov 196 GIC 2094 : SET_VARSIZE(res, buf.len);
1485 akorotkov 197 CBC 2094 : res->header = JSONPATH_VERSION;
1485 akorotkov 198 GIC 2094 : if (jsonpath->lax)
1485 akorotkov 199 CBC 1917 : res->header |= JSONPATH_LAX;
200 :
201 2094 : PG_RETURN_JSONPATH_P(res);
202 : }
1485 akorotkov 203 ECB :
204 : /*
205 : * Converts jsonpath value to a C-string.
206 : *
207 : * If 'out' argument is non-null, the resulting C-string is stored inside the
208 : * StringBuffer. The resulting string is always returned.
209 : */
210 : static char *
1485 akorotkov 211 GIC 586 : jsonPathToCstring(StringInfo out, JsonPath *in, int estimated_len)
212 : {
213 : StringInfoData buf;
214 : JsonPathItem v;
215 :
216 586 : if (!out)
217 : {
218 586 : out = &buf;
1485 akorotkov 219 CBC 586 : initStringInfo(out);
220 : }
1485 akorotkov 221 GIC 586 : enlargeStringInfo(out, estimated_len);
222 :
223 586 : if (!(in->header & JSONPATH_LAX))
100 peter 224 GNC 3 : appendStringInfoString(out, "strict ");
225 :
1485 akorotkov 226 CBC 586 : jspInit(&v, in);
227 586 : printJsonPathItem(out, &v, false, true);
228 :
229 586 : return out->data;
230 : }
1485 akorotkov 231 ECB :
232 : /*
233 : * Recursive function converting given jsonpath parse item and all its
234 : * children into a binary representation.
235 : */
236 : static bool
106 andrew 237 GNC 9843 : flattenJsonPathParseItem(StringInfo buf, int *result, struct Node *escontext,
238 : JsonPathParseItem *item, int nestingLevel,
239 : bool insideArraySubscript)
240 : {
241 : /* position from beginning of jsonpath data */
1485 akorotkov 242 GIC 9843 : int32 pos = buf->len - JSONPATH_HDRSZ;
243 : int32 chld;
244 : int32 next;
245 9843 : int argNestingLevel = 0;
1485 akorotkov 246 ECB :
1485 akorotkov 247 GIC 9843 : check_stack_depth();
248 9843 : CHECK_FOR_INTERRUPTS();
249 :
250 9843 : appendStringInfoChar(buf, (char) (item->type));
1485 akorotkov 251 ECB :
252 : /*
253 : * We align buffer to int32 because a series of int32 values often goes
254 : * after the header, and we want to read them directly by dereferencing
255 : * int32 pointer (see jspInitByBuffer()).
256 : */
1485 akorotkov 257 CBC 9843 : alignStringInfoInt(buf);
258 :
1485 akorotkov 259 ECB : /*
260 : * Reserve space for next item pointer. Actual value will be recorded
261 : * later, after next and children items processing.
262 : */
1485 akorotkov 263 GIC 9843 : next = reserveSpaceForItemPointer(buf);
264 :
265 9843 : switch (item->type)
1485 akorotkov 266 ECB : {
1485 akorotkov 267 GIC 1947 : case jpiString:
268 : case jpiVariable:
269 : case jpiKey:
100 peter 270 GNC 1947 : appendBinaryStringInfo(buf, &item->value.string.len,
271 : sizeof(item->value.string.len));
1485 akorotkov 272 CBC 1947 : appendBinaryStringInfo(buf, item->value.string.val,
1485 akorotkov 273 GIC 1947 : item->value.string.len);
1485 akorotkov 274 CBC 1947 : appendStringInfoChar(buf, '\0');
1485 akorotkov 275 GIC 1947 : break;
1485 akorotkov 276 CBC 870 : case jpiNumeric:
100 peter 277 GNC 870 : appendBinaryStringInfo(buf, item->value.numeric,
1485 akorotkov 278 GIC 870 : VARSIZE(item->value.numeric));
1485 akorotkov 279 CBC 870 : break;
1485 akorotkov 280 GIC 90 : case jpiBool:
100 peter 281 GNC 90 : appendBinaryStringInfo(buf, &item->value.boolean,
1485 akorotkov 282 ECB : sizeof(item->value.boolean));
1485 akorotkov 283 CBC 90 : break;
284 1272 : case jpiAnd:
1485 akorotkov 285 ECB : case jpiOr:
286 : case jpiEqual:
287 : case jpiNotEqual:
288 : case jpiLess:
289 : case jpiGreater:
290 : case jpiLessOrEqual:
291 : case jpiGreaterOrEqual:
292 : case jpiAdd:
293 : case jpiSub:
294 : case jpiMul:
295 : case jpiDiv:
296 : case jpiMod:
297 : case jpiStartsWith:
298 : {
299 : /*
300 : * First, reserve place for left/right arg's positions, then
301 : * record both args and sets actual position in reserved
302 : * places.
303 : */
1485 akorotkov 304 GIC 1272 : int32 left = reserveSpaceForItemPointer(buf);
305 1272 : int32 right = reserveSpaceForItemPointer(buf);
306 :
106 andrew 307 GNC 1272 : if (!item->value.args.left)
106 andrew 308 UNC 0 : chld = pos;
106 andrew 309 GNC 1272 : else if (! flattenJsonPathParseItem(buf, &chld, escontext,
310 : item->value.args.left,
311 : nestingLevel + argNestingLevel,
312 : insideArraySubscript))
313 6 : return false;
1485 akorotkov 314 GIC 1260 : *(int32 *) (buf->data + left) = chld - pos;
315 :
106 andrew 316 GNC 1260 : if (!item->value.args.right)
106 andrew 317 UNC 0 : chld = pos;
106 andrew 318 GNC 1260 : else if (! flattenJsonPathParseItem(buf, &chld, escontext,
319 : item->value.args.right,
320 : nestingLevel + argNestingLevel,
321 : insideArraySubscript))
106 andrew 322 UNC 0 : return false;
1485 akorotkov 323 GBC 1260 : *(int32 *) (buf->data + right) = chld - pos;
1485 akorotkov 324 ECB : }
1485 akorotkov 325 GIC 1260 : break;
326 60 : case jpiLikeRegex:
327 : {
1485 akorotkov 328 ECB : int32 offs;
329 :
1485 akorotkov 330 GIC 60 : appendBinaryStringInfo(buf,
100 peter 331 GNC 60 : &item->value.like_regex.flags,
1485 akorotkov 332 EUB : sizeof(item->value.like_regex.flags));
1485 akorotkov 333 CBC 60 : offs = reserveSpaceForItemPointer(buf);
1485 akorotkov 334 GIC 60 : appendBinaryStringInfo(buf,
100 peter 335 GNC 60 : &item->value.like_regex.patternlen,
336 : sizeof(item->value.like_regex.patternlen));
1485 akorotkov 337 GBC 60 : appendBinaryStringInfo(buf, item->value.like_regex.pattern,
1485 akorotkov 338 CBC 60 : item->value.like_regex.patternlen);
1485 akorotkov 339 GIC 60 : appendStringInfoChar(buf, '\0');
1485 akorotkov 340 ECB :
106 andrew 341 GNC 60 : if (! flattenJsonPathParseItem(buf, &chld, escontext,
342 : item->value.like_regex.expr,
343 : nestingLevel,
344 : insideArraySubscript))
106 andrew 345 UNC 0 : return false;
1485 akorotkov 346 GIC 60 : *(int32 *) (buf->data + offs) = chld - pos;
1485 akorotkov 347 ECB : }
1485 akorotkov 348 CBC 60 : break;
1485 akorotkov 349 GIC 819 : case jpiFilter:
1485 akorotkov 350 CBC 819 : argNestingLevel++;
1485 tgl 351 ECB : /* FALLTHROUGH */
1485 akorotkov 352 CBC 1455 : case jpiIsUnknown:
353 : case jpiNot:
1485 akorotkov 354 ECB : case jpiPlus:
355 : case jpiMinus:
356 : case jpiExists:
357 : case jpiDatetime:
358 : {
1485 akorotkov 359 GIC 1455 : int32 arg = reserveSpaceForItemPointer(buf);
360 :
106 andrew 361 GNC 1455 : if (!item->value.arg)
362 168 : chld = pos;
363 1287 : else if (! flattenJsonPathParseItem(buf, &chld, escontext,
364 : item->value.arg,
365 : nestingLevel + argNestingLevel,
366 : insideArraySubscript))
106 andrew 367 UNC 0 : return false;
1485 akorotkov 368 CBC 1452 : *(int32 *) (buf->data + arg) = chld - pos;
1485 akorotkov 369 ECB : }
1485 akorotkov 370 CBC 1452 : break;
1485 akorotkov 371 GIC 57 : case jpiNull:
1485 akorotkov 372 CBC 57 : break;
1485 akorotkov 373 GIC 1929 : case jpiRoot:
374 1929 : break;
375 561 : case jpiAnyArray:
376 : case jpiAnyKey:
377 561 : break;
378 954 : case jpiCurrent:
1485 akorotkov 379 CBC 954 : if (nestingLevel <= 0)
106 andrew 380 GNC 9 : ereturn(escontext, false,
1485 akorotkov 381 ECB : (errcode(ERRCODE_SYNTAX_ERROR),
382 : errmsg("@ is not allowed in root expressions")));
1485 akorotkov 383 CBC 945 : break;
1485 akorotkov 384 GIC 45 : case jpiLast:
385 45 : if (!insideArraySubscript)
106 andrew 386 GNC 6 : ereturn(escontext, false,
1485 akorotkov 387 EUB : (errcode(ERRCODE_SYNTAX_ERROR),
1485 akorotkov 388 ECB : errmsg("LAST is allowed only in array subscripts")));
1485 akorotkov 389 GIC 39 : break;
1485 akorotkov 390 CBC 168 : case jpiIndexArray:
1485 akorotkov 391 ECB : {
1485 akorotkov 392 CBC 168 : int32 nelems = item->value.array.nelems;
1485 akorotkov 393 ECB : int offset;
394 : int i;
395 :
100 peter 396 GNC 168 : appendBinaryStringInfo(buf, &nelems, sizeof(nelems));
1485 akorotkov 397 ECB :
1485 akorotkov 398 CBC 168 : offset = buf->len;
1485 akorotkov 399 ECB :
1485 akorotkov 400 CBC 168 : appendStringInfoSpaces(buf, sizeof(int32) * 2 * nelems);
401 :
1485 akorotkov 402 GIC 351 : for (i = 0; i < nelems; i++)
1485 akorotkov 403 ECB : {
404 : int32 *ppos;
405 : int32 topos;
406 : int32 frompos;
407 :
106 andrew 408 GNC 183 : if (! flattenJsonPathParseItem(buf, &frompos, escontext,
409 183 : item->value.array.elems[i].from,
410 : nestingLevel, true))
106 andrew 411 UNC 0 : return false;
106 andrew 412 GNC 183 : frompos -= pos;
1485 akorotkov 413 ECB :
1485 akorotkov 414 GIC 183 : if (item->value.array.elems[i].to)
415 : {
106 andrew 416 GNC 21 : if (! flattenJsonPathParseItem(buf, &topos, escontext,
417 21 : item->value.array.elems[i].to,
418 : nestingLevel, true))
106 andrew 419 UNC 0 : return false;
106 andrew 420 GNC 21 : topos -= pos;
421 : }
422 : else
1485 akorotkov 423 CBC 162 : topos = 0;
424 :
425 183 : ppos = (int32 *) &buf->data[offset + i * 2 * sizeof(int32)];
426 :
427 183 : ppos[0] = frompos;
1485 akorotkov 428 GIC 183 : ppos[1] = topos;
1485 akorotkov 429 ECB : }
430 : }
1485 akorotkov 431 GIC 168 : break;
432 177 : case jpiAny:
433 177 : appendBinaryStringInfo(buf,
100 peter 434 GNC 177 : &item->value.anybounds.first,
1485 akorotkov 435 ECB : sizeof(item->value.anybounds.first));
1485 akorotkov 436 CBC 177 : appendBinaryStringInfo(buf,
100 peter 437 GNC 177 : &item->value.anybounds.last,
1485 akorotkov 438 EUB : sizeof(item->value.anybounds.last));
1485 akorotkov 439 CBC 177 : break;
1485 akorotkov 440 GIC 258 : case jpiType:
1485 akorotkov 441 ECB : case jpiSize:
442 : case jpiAbs:
443 : case jpiFloor:
444 : case jpiCeiling:
445 : case jpiDouble:
1485 akorotkov 446 EUB : case jpiKeyValue:
1485 akorotkov 447 CBC 258 : break;
1485 akorotkov 448 UIC 0 : default:
449 0 : elog(ERROR, "unrecognized jsonpath item type: %d", item->type);
1485 akorotkov 450 ECB : }
451 :
1485 akorotkov 452 CBC 9813 : if (item->next)
453 : {
106 andrew 454 GNC 3651 : if (! flattenJsonPathParseItem(buf, &chld, escontext,
455 : item->next, nestingLevel,
456 : insideArraySubscript))
106 andrew 457 UNC 0 : return false;
106 andrew 458 GNC 3648 : chld -= pos;
1485 akorotkov 459 GIC 3648 : *(int32 *) (buf->data + next) = chld;
460 : }
1485 akorotkov 461 ECB :
106 andrew 462 GNC 9810 : if (result)
463 7716 : *result = pos;
464 9810 : return true;
1485 akorotkov 465 ECB : }
466 :
467 : /*
468 : * Align StringInfo to int by adding zero padding bytes
469 : */
470 : static void
1485 akorotkov 471 CBC 9843 : alignStringInfoInt(StringInfo buf)
1485 akorotkov 472 ECB : {
1485 akorotkov 473 GIC 9843 : switch (INTALIGN(buf->len) - buf->len)
474 : {
475 8649 : case 3:
476 8649 : appendStringInfoCharMacro(buf, 0);
477 : /* FALLTHROUGH */
478 : case 2:
1485 akorotkov 479 CBC 8817 : appendStringInfoCharMacro(buf, 0);
1485 tgl 480 EUB : /* FALLTHROUGH */
akorotkov 481 : case 1:
1485 akorotkov 482 GIC 9747 : appendStringInfoCharMacro(buf, 0);
483 : /* FALLTHROUGH */
1485 akorotkov 484 ECB : default:
1485 akorotkov 485 GIC 9843 : break;
1485 akorotkov 486 ECB : }
1485 akorotkov 487 GIC 9843 : }
488 :
1485 akorotkov 489 EUB : /*
1485 akorotkov 490 ECB : * Reserve space for int32 JsonPathItem pointer. Now zero pointer is written,
491 : * actual value will be recorded at '(int32 *) &buf->data[pos]' later.
492 : */
493 : static int32
1485 akorotkov 494 CBC 13902 : reserveSpaceForItemPointer(StringInfo buf)
1485 akorotkov 495 ECB : {
1485 akorotkov 496 CBC 13902 : int32 pos = buf->len;
1485 akorotkov 497 GIC 13902 : int32 ptr = 0;
498 :
100 peter 499 GNC 13902 : appendBinaryStringInfo(buf, &ptr, sizeof(ptr));
500 :
1485 akorotkov 501 GIC 13902 : return pos;
502 : }
1485 akorotkov 503 ECB :
504 : /*
505 : * Prints text representation of given jsonpath item and all its children.
506 : */
507 : static void
1485 akorotkov 508 CBC 2623 : printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
509 : bool printBracketes)
510 : {
1485 akorotkov 511 ECB : JsonPathItem elem;
512 : int i;
513 :
1485 akorotkov 514 CBC 2623 : check_stack_depth();
1485 akorotkov 515 GIC 2623 : CHECK_FOR_INTERRUPTS();
516 :
1485 akorotkov 517 CBC 2623 : switch (v->type)
518 : {
519 21 : case jpiNull:
1485 akorotkov 520 GIC 21 : appendStringInfoString(buf, "null");
521 21 : break;
522 532 : case jpiKey:
523 532 : if (inKey)
524 532 : appendStringInfoChar(buf, '.');
525 532 : escape_json(buf, jspGetString(v, NULL));
1485 akorotkov 526 CBC 532 : break;
1485 akorotkov 527 GIC 42 : case jpiString:
1485 akorotkov 528 CBC 42 : escape_json(buf, jspGetString(v, NULL));
529 42 : break;
1485 akorotkov 530 GIC 24 : case jpiVariable:
1485 akorotkov 531 CBC 24 : appendStringInfoChar(buf, '$');
1485 akorotkov 532 GIC 24 : escape_json(buf, jspGetString(v, NULL));
1485 akorotkov 533 CBC 24 : break;
1485 akorotkov 534 GIC 442 : case jpiNumeric:
377 peter 535 442 : if (jspHasNext(v))
536 42 : appendStringInfoChar(buf, '(');
1485 akorotkov 537 442 : appendStringInfoString(buf,
538 442 : DatumGetCString(DirectFunctionCall1(numeric_out,
539 : NumericGetDatum(jspGetNumeric(v)))));
377 peter 540 CBC 442 : if (jspHasNext(v))
377 peter 541 GIC 42 : appendStringInfoChar(buf, ')');
1485 akorotkov 542 442 : break;
543 6 : case jpiBool:
544 6 : if (jspGetBool(v))
100 peter 545 GNC 3 : appendStringInfoString(buf, "true");
1485 akorotkov 546 ECB : else
100 peter 547 GNC 3 : appendStringInfoString(buf, "false");
1485 akorotkov 548 GIC 6 : break;
1485 akorotkov 549 CBC 370 : case jpiAnd:
550 : case jpiOr:
1485 akorotkov 551 ECB : case jpiEqual:
552 : case jpiNotEqual:
553 : case jpiLess:
554 : case jpiGreater:
555 : case jpiLessOrEqual:
556 : case jpiGreaterOrEqual:
557 : case jpiAdd:
558 : case jpiSub:
559 : case jpiMul:
560 : case jpiDiv:
561 : case jpiMod:
562 : case jpiStartsWith:
1485 akorotkov 563 CBC 370 : if (printBracketes)
564 57 : appendStringInfoChar(buf, '(');
565 370 : jspGetLeftArg(v, &elem);
566 370 : printJsonPathItem(buf, &elem, false,
567 370 : operationPriority(elem.type) <=
568 370 : operationPriority(v->type));
569 370 : appendStringInfoChar(buf, ' ');
570 370 : appendStringInfoString(buf, jspOperationName(v->type));
1485 akorotkov 571 GIC 370 : appendStringInfoChar(buf, ' ');
1485 akorotkov 572 CBC 370 : jspGetRightArg(v, &elem);
573 370 : printJsonPathItem(buf, &elem, false,
574 370 : operationPriority(elem.type) <=
575 370 : operationPriority(v->type));
576 370 : if (printBracketes)
577 57 : appendStringInfoChar(buf, ')');
1485 akorotkov 578 GIC 370 : break;
1485 akorotkov 579 CBC 24 : case jpiLikeRegex:
580 24 : if (printBracketes)
1485 akorotkov 581 LBC 0 : appendStringInfoChar(buf, '(');
582 :
1485 akorotkov 583 GIC 24 : jspInitByBuffer(&elem, v->base, v->content.like_regex.expr);
584 24 : printJsonPathItem(buf, &elem, false,
585 24 : operationPriority(elem.type) <=
586 24 : operationPriority(v->type));
587 :
100 peter 588 GNC 24 : appendStringInfoString(buf, " like_regex ");
589 :
1485 akorotkov 590 GIC 24 : escape_json(buf, v->content.like_regex.pattern);
591 :
592 24 : if (v->content.like_regex.flags)
593 : {
100 peter 594 GNC 18 : appendStringInfoString(buf, " flag \"");
1485 akorotkov 595 ECB :
1485 akorotkov 596 CBC 18 : if (v->content.like_regex.flags & JSP_REGEX_ICASE)
597 15 : appendStringInfoChar(buf, 'i');
1300 tgl 598 18 : if (v->content.like_regex.flags & JSP_REGEX_DOTALL)
1485 akorotkov 599 9 : appendStringInfoChar(buf, 's');
600 18 : if (v->content.like_regex.flags & JSP_REGEX_MLINE)
601 6 : appendStringInfoChar(buf, 'm');
602 18 : if (v->content.like_regex.flags & JSP_REGEX_WSPACE)
603 3 : appendStringInfoChar(buf, 'x');
1390 604 18 : if (v->content.like_regex.flags & JSP_REGEX_QUOTE)
605 9 : appendStringInfoChar(buf, 'q');
1485 akorotkov 606 ECB :
1485 akorotkov 607 CBC 18 : appendStringInfoChar(buf, '"');
1485 akorotkov 608 ECB : }
609 :
1485 akorotkov 610 CBC 24 : if (printBracketes)
1485 akorotkov 611 LBC 0 : appendStringInfoChar(buf, ')');
1485 akorotkov 612 CBC 24 : break;
1485 akorotkov 613 GBC 24 : case jpiPlus:
614 : case jpiMinus:
1485 akorotkov 615 CBC 24 : if (printBracketes)
616 9 : appendStringInfoChar(buf, '(');
617 24 : appendStringInfoChar(buf, v->type == jpiPlus ? '+' : '-');
618 24 : jspGetArg(v, &elem);
1485 akorotkov 619 GIC 24 : printJsonPathItem(buf, &elem, false,
1485 akorotkov 620 CBC 24 : operationPriority(elem.type) <=
1485 akorotkov 621 GIC 24 : operationPriority(v->type));
1485 akorotkov 622 CBC 24 : if (printBracketes)
1485 akorotkov 623 GIC 9 : appendStringInfoChar(buf, ')');
1485 akorotkov 624 CBC 24 : break;
1485 akorotkov 625 GIC 253 : case jpiFilter:
100 peter 626 GNC 253 : appendStringInfoString(buf, "?(");
1485 akorotkov 627 GIC 253 : jspGetArg(v, &elem);
1485 akorotkov 628 CBC 253 : printJsonPathItem(buf, &elem, false, false);
629 253 : appendStringInfoChar(buf, ')');
630 253 : break;
631 6 : case jpiNot:
100 peter 632 GNC 6 : appendStringInfoString(buf, "!(");
1485 akorotkov 633 CBC 6 : jspGetArg(v, &elem);
634 6 : printJsonPathItem(buf, &elem, false, false);
635 6 : appendStringInfoChar(buf, ')');
636 6 : break;
637 3 : case jpiIsUnknown:
1485 akorotkov 638 GIC 3 : appendStringInfoChar(buf, '(');
1485 akorotkov 639 CBC 3 : jspGetArg(v, &elem);
1485 akorotkov 640 GIC 3 : printJsonPathItem(buf, &elem, false, false);
100 peter 641 GNC 3 : appendStringInfoString(buf, ") is unknown");
1485 akorotkov 642 CBC 3 : break;
1485 akorotkov 643 GBC 12 : case jpiExists:
100 peter 644 GNC 12 : appendStringInfoString(buf, "exists (");
1485 akorotkov 645 CBC 12 : jspGetArg(v, &elem);
1485 akorotkov 646 GIC 12 : printJsonPathItem(buf, &elem, false, false);
1485 akorotkov 647 CBC 12 : appendStringInfoChar(buf, ')');
648 12 : break;
649 289 : case jpiCurrent:
650 289 : Assert(!inKey);
651 289 : appendStringInfoChar(buf, '@');
652 289 : break;
653 427 : case jpiRoot:
654 427 : Assert(!inKey);
655 427 : appendStringInfoChar(buf, '$');
656 427 : break;
657 6 : case jpiLast:
100 peter 658 GNC 6 : appendStringInfoString(buf, "last");
1485 akorotkov 659 CBC 6 : break;
660 43 : case jpiAnyArray:
100 peter 661 GNC 43 : appendStringInfoString(buf, "[*]");
1485 akorotkov 662 CBC 43 : break;
663 6 : case jpiAnyKey:
664 6 : if (inKey)
665 6 : appendStringInfoChar(buf, '.');
666 6 : appendStringInfoChar(buf, '*');
667 6 : break;
668 30 : case jpiIndexArray:
669 30 : appendStringInfoChar(buf, '[');
670 69 : for (i = 0; i < v->content.array.nelems; i++)
1485 akorotkov 671 ECB : {
672 : JsonPathItem from;
673 : JsonPathItem to;
1485 akorotkov 674 CBC 39 : bool range = jspGetArraySubscript(v, &from, &to, i);
1485 akorotkov 675 ECB :
1485 akorotkov 676 CBC 39 : if (i)
677 9 : appendStringInfoChar(buf, ',');
1485 akorotkov 678 ECB :
1485 akorotkov 679 CBC 39 : printJsonPathItem(buf, &from, false, false);
1485 akorotkov 680 ECB :
1485 akorotkov 681 CBC 39 : if (range)
1485 akorotkov 682 ECB : {
100 peter 683 GNC 6 : appendStringInfoString(buf, " to ");
1485 akorotkov 684 CBC 6 : printJsonPathItem(buf, &to, false, false);
1485 akorotkov 685 ECB : }
686 : }
1485 akorotkov 687 CBC 30 : appendStringInfoChar(buf, ']');
688 30 : break;
689 24 : case jpiAny:
690 24 : if (inKey)
691 24 : appendStringInfoChar(buf, '.');
1485 akorotkov 692 ECB :
1485 akorotkov 693 CBC 24 : if (v->content.anybounds.first == 0 &&
694 6 : v->content.anybounds.last == PG_UINT32_MAX)
100 peter 695 GNC 3 : appendStringInfoString(buf, "**");
1485 akorotkov 696 CBC 21 : else if (v->content.anybounds.first == v->content.anybounds.last)
1485 akorotkov 697 ECB : {
1485 akorotkov 698 CBC 9 : if (v->content.anybounds.first == PG_UINT32_MAX)
906 drowley 699 3 : appendStringInfoString(buf, "**{last}");
1485 akorotkov 700 ECB : else
1485 akorotkov 701 CBC 6 : appendStringInfo(buf, "**{%u}",
1485 akorotkov 702 ECB : v->content.anybounds.first);
703 : }
1485 akorotkov 704 GIC 12 : else if (v->content.anybounds.first == PG_UINT32_MAX)
705 3 : appendStringInfo(buf, "**{last to %u}",
1485 akorotkov 706 ECB : v->content.anybounds.last);
1485 akorotkov 707 GIC 9 : else if (v->content.anybounds.last == PG_UINT32_MAX)
1485 akorotkov 708 CBC 3 : appendStringInfo(buf, "**{%u to last}",
1485 akorotkov 709 ECB : v->content.anybounds.first);
710 : else
1485 akorotkov 711 CBC 6 : appendStringInfo(buf, "**{%u to %u}",
712 : v->content.anybounds.first,
1485 akorotkov 713 ECB : v->content.anybounds.last);
1485 akorotkov 714 GIC 24 : break;
1485 akorotkov 715 CBC 15 : case jpiType:
100 peter 716 GNC 15 : appendStringInfoString(buf, ".type()");
1485 akorotkov 717 GIC 15 : break;
718 3 : case jpiSize:
100 peter 719 GNC 3 : appendStringInfoString(buf, ".size()");
1485 akorotkov 720 CBC 3 : break;
721 3 : case jpiAbs:
100 peter 722 GNC 3 : appendStringInfoString(buf, ".abs()");
1485 akorotkov 723 CBC 3 : break;
1485 akorotkov 724 GIC 3 : case jpiFloor:
100 peter 725 GNC 3 : appendStringInfoString(buf, ".floor()");
1485 akorotkov 726 CBC 3 : break;
727 3 : case jpiCeiling:
100 peter 728 GNC 3 : appendStringInfoString(buf, ".ceiling()");
1485 akorotkov 729 GIC 3 : break;
1485 akorotkov 730 CBC 3 : case jpiDouble:
100 peter 731 GNC 3 : appendStringInfoString(buf, ".double()");
1485 akorotkov 732 GIC 3 : break;
1292 akorotkov 733 CBC 6 : case jpiDatetime:
100 peter 734 GNC 6 : appendStringInfoString(buf, ".datetime(");
1292 akorotkov 735 GIC 6 : if (v->content.arg)
1292 akorotkov 736 ECB : {
1292 akorotkov 737 CBC 3 : jspGetArg(v, &elem);
1292 akorotkov 738 GIC 3 : printJsonPathItem(buf, &elem, false, false);
1292 akorotkov 739 ECB : }
1292 akorotkov 740 CBC 6 : appendStringInfoChar(buf, ')');
1292 akorotkov 741 GIC 6 : break;
1485 742 3 : case jpiKeyValue:
100 peter 743 GNC 3 : appendStringInfoString(buf, ".keyvalue()");
1485 akorotkov 744 GIC 3 : break;
1485 akorotkov 745 UIC 0 : default:
1485 akorotkov 746 LBC 0 : elog(ERROR, "unrecognized jsonpath item type: %d", v->type);
1485 akorotkov 747 ECB : }
748 :
1485 akorotkov 749 CBC 2623 : if (jspGetNext(v, &elem))
750 927 : printJsonPathItem(buf, &elem, true, true);
751 2623 : }
1485 akorotkov 752 ECB :
753 : const char *
1485 akorotkov 754 CBC 451 : jspOperationName(JsonPathItemType type)
1485 akorotkov 755 ECB : {
1485 akorotkov 756 CBC 451 : switch (type)
1485 akorotkov 757 ECB : {
1485 akorotkov 758 CBC 15 : case jpiAnd:
759 15 : return "&&";
760 27 : case jpiOr:
761 27 : return "||";
762 81 : case jpiEqual:
763 81 : return "==";
764 3 : case jpiNotEqual:
765 3 : return "!=";
766 150 : case jpiLess:
767 150 : return "<";
1485 akorotkov 768 GIC 19 : case jpiGreater:
1485 akorotkov 769 CBC 19 : return ">";
770 3 : case jpiLessOrEqual:
1485 akorotkov 771 GIC 3 : return "<=";
1485 akorotkov 772 CBC 15 : case jpiGreaterOrEqual:
773 15 : return ">=";
774 36 : case jpiPlus:
1485 akorotkov 775 ECB : case jpiAdd:
1485 akorotkov 776 CBC 36 : return "+";
1485 akorotkov 777 GBC 12 : case jpiMinus:
1485 akorotkov 778 EUB : case jpiSub:
1485 akorotkov 779 GIC 12 : return "-";
780 12 : case jpiMul:
1485 akorotkov 781 CBC 12 : return "*";
782 3 : case jpiDiv:
783 3 : return "/";
1485 akorotkov 784 GIC 3 : case jpiMod:
785 3 : return "%";
1485 akorotkov 786 CBC 6 : case jpiStartsWith:
1485 akorotkov 787 GIC 6 : return "starts with";
1485 akorotkov 788 LBC 0 : case jpiLikeRegex:
1485 akorotkov 789 UIC 0 : return "like_regex";
1485 akorotkov 790 LBC 0 : case jpiType:
791 0 : return "type";
1485 akorotkov 792 CBC 3 : case jpiSize:
793 3 : return "size";
794 9 : case jpiKeyValue:
795 9 : return "keyvalue";
796 30 : case jpiDouble:
797 30 : return "double";
798 3 : case jpiAbs:
799 3 : return "abs";
800 3 : case jpiFloor:
801 3 : return "floor";
802 3 : case jpiCeiling:
803 3 : return "ceiling";
1292 804 15 : case jpiDatetime:
805 15 : return "datetime";
1485 akorotkov 806 LBC 0 : default:
1485 akorotkov 807 UIC 0 : elog(ERROR, "unrecognized jsonpath item type: %d", type);
1485 akorotkov 808 ECB : return NULL;
809 : }
810 : }
811 :
812 : static int
1485 akorotkov 813 CBC 1576 : operationPriority(JsonPathItemType op)
1485 akorotkov 814 ECB : {
1485 akorotkov 815 CBC 1576 : switch (op)
1485 akorotkov 816 ECB : {
1485 akorotkov 817 CBC 57 : case jpiOr:
818 57 : return 0;
819 39 : case jpiAnd:
1485 akorotkov 820 GBC 39 : return 1;
821 617 : case jpiEqual:
1485 akorotkov 822 EUB : case jpiNotEqual:
823 : case jpiLess:
1485 akorotkov 824 ECB : case jpiGreater:
825 : case jpiLessOrEqual:
826 : case jpiGreaterOrEqual:
827 : case jpiStartsWith:
1485 akorotkov 828 CBC 617 : return 2;
829 90 : case jpiAdd:
1485 akorotkov 830 ECB : case jpiSub:
1485 akorotkov 831 CBC 90 : return 3;
832 33 : case jpiMul:
1485 akorotkov 833 ECB : case jpiDiv:
834 : case jpiMod:
1485 akorotkov 835 CBC 33 : return 4;
836 42 : case jpiPlus:
1485 akorotkov 837 ECB : case jpiMinus:
1485 akorotkov 838 GBC 42 : return 5;
839 698 : default:
1485 akorotkov 840 GIC 698 : return 6;
841 : }
842 : }
843 :
844 : /******************* Support functions for JsonPath *************************/
1485 akorotkov 845 ECB :
846 : /*
847 : * Support macros to read stored values
848 : */
849 :
850 : #define read_byte(v, b, p) do { \
851 : (v) = *(uint8*)((b) + (p)); \
852 : (p) += 1; \
853 : } while(0) \
854 :
855 : #define read_int32(v, b, p) do { \
856 : (v) = *(uint32*)((b) + (p)); \
857 : (p) += sizeof(int32); \
858 : } while(0) \
859 :
860 : #define read_int32_n(v, b, p, n) do { \
861 : (v) = (void *)((b) + (p)); \
862 : (p) += sizeof(int32) * (n); \
863 : } while(0) \
864 :
865 : /*
866 : * Read root node and fill root node representation
867 : */
868 : void
1485 akorotkov 869 GIC 96016 : jspInit(JsonPathItem *v, JsonPath *js)
1485 akorotkov 870 ECB : {
1485 akorotkov 871 CBC 96016 : Assert((js->header & ~JSONPATH_LAX) == JSONPATH_VERSION);
872 96016 : jspInitByBuffer(v, js->data, 0);
1485 akorotkov 873 GIC 96016 : }
874 :
875 : /*
876 : * Read node from buffer and fill its representation
877 : */
878 : void
879 324031 : jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
880 : {
881 324031 : v->base = base + pos;
882 :
883 324031 : read_byte(v->type, base, pos);
884 324031 : pos = INTALIGN((uintptr_t) (base + pos)) - (uintptr_t) base;
885 324031 : read_int32(v->nextPos, base, pos);
886 :
887 324031 : switch (v->type)
888 : {
889 117153 : case jpiNull:
890 : case jpiRoot:
891 : case jpiCurrent:
892 : case jpiAnyArray:
893 : case jpiAnyKey:
894 : case jpiType:
895 : case jpiSize:
896 : case jpiAbs:
897 : case jpiFloor:
898 : case jpiCeiling:
899 : case jpiDouble:
900 : case jpiKeyValue:
1485 akorotkov 901 ECB : case jpiLast:
1485 akorotkov 902 GIC 117153 : break;
1485 akorotkov 903 CBC 97906 : case jpiKey:
1485 akorotkov 904 ECB : case jpiString:
905 : case jpiVariable:
1485 akorotkov 906 GIC 97906 : read_int32(v->content.value.datalen, base, pos);
907 : /* FALLTHROUGH */
908 108830 : case jpiNumeric:
909 : case jpiBool:
910 108830 : v->content.value.data = base + pos;
1485 akorotkov 911 CBC 108830 : break;
1485 akorotkov 912 GIC 47371 : case jpiAnd:
1485 akorotkov 913 ECB : case jpiOr:
914 : case jpiAdd:
915 : case jpiSub:
916 : case jpiMul:
917 : case jpiDiv:
918 : case jpiMod:
919 : case jpiEqual:
920 : case jpiNotEqual:
921 : case jpiLess:
922 : case jpiGreater:
923 : case jpiLessOrEqual:
924 : case jpiGreaterOrEqual:
925 : case jpiStartsWith:
1485 akorotkov 926 GIC 47371 : read_int32(v->content.args.left, base, pos);
927 47371 : read_int32(v->content.args.right, base, pos);
928 47371 : break;
929 222 : case jpiLikeRegex:
930 222 : read_int32(v->content.like_regex.flags, base, pos);
931 222 : read_int32(v->content.like_regex.expr, base, pos);
932 222 : read_int32(v->content.like_regex.patternlen, base, pos);
933 222 : v->content.like_regex.pattern = base + pos;
1485 akorotkov 934 CBC 222 : break;
935 50104 : case jpiNot:
936 : case jpiExists:
937 : case jpiIsUnknown:
1485 akorotkov 938 ECB : case jpiPlus:
939 : case jpiMinus:
940 : case jpiFilter:
941 : case jpiDatetime:
1485 akorotkov 942 CBC 50104 : read_int32(v->content.arg, base, pos);
943 50104 : break;
944 174 : case jpiIndexArray:
1485 akorotkov 945 GIC 174 : read_int32(v->content.array.nelems, base, pos);
946 174 : read_int32_n(v->content.array.elems, base, pos,
947 : v->content.array.nelems * 2);
948 174 : break;
949 177 : case jpiAny:
950 177 : read_int32(v->content.anybounds.first, base, pos);
951 177 : read_int32(v->content.anybounds.last, base, pos);
952 177 : break;
1485 akorotkov 953 UIC 0 : default:
954 0 : elog(ERROR, "unrecognized jsonpath item type: %d", v->type);
955 : }
1485 akorotkov 956 GIC 324031 : }
957 :
1485 akorotkov 958 ECB : void
1485 akorotkov 959 CBC 50470 : jspGetArg(JsonPathItem *v, JsonPathItem *a)
1485 akorotkov 960 ECB : {
1485 akorotkov 961 CBC 50470 : Assert(v->type == jpiFilter ||
1485 akorotkov 962 ECB : v->type == jpiNot ||
963 : v->type == jpiIsUnknown ||
964 : v->type == jpiExists ||
965 : v->type == jpiPlus ||
1292 966 : v->type == jpiMinus ||
967 : v->type == jpiDatetime);
968 :
1485 akorotkov 969 GIC 50470 : jspInitByBuffer(a, v->base, v->content.arg);
970 50470 : }
971 :
972 : bool
973 210505 : jspGetNext(JsonPathItem *v, JsonPathItem *a)
1485 akorotkov 974 ECB : {
1485 akorotkov 975 CBC 210505 : if (jspHasNext(v))
1485 akorotkov 976 ECB : {
1485 akorotkov 977 CBC 94860 : Assert(v->type == jpiString ||
1485 akorotkov 978 ECB : v->type == jpiNumeric ||
979 : v->type == jpiBool ||
980 : v->type == jpiNull ||
981 : v->type == jpiKey ||
982 : v->type == jpiAny ||
983 : v->type == jpiAnyArray ||
984 : v->type == jpiAnyKey ||
1485 akorotkov 985 EUB : v->type == jpiIndexArray ||
986 : v->type == jpiFilter ||
987 : v->type == jpiCurrent ||
1485 akorotkov 988 ECB : v->type == jpiExists ||
989 : v->type == jpiRoot ||
990 : v->type == jpiVariable ||
991 : v->type == jpiLast ||
992 : v->type == jpiAdd ||
993 : v->type == jpiSub ||
994 : v->type == jpiMul ||
995 : v->type == jpiDiv ||
996 : v->type == jpiMod ||
997 : v->type == jpiPlus ||
998 : v->type == jpiMinus ||
999 : v->type == jpiEqual ||
1000 : v->type == jpiNotEqual ||
1001 : v->type == jpiGreater ||
1002 : v->type == jpiGreaterOrEqual ||
1003 : v->type == jpiLess ||
1004 : v->type == jpiLessOrEqual ||
1005 : v->type == jpiAnd ||
1006 : v->type == jpiOr ||
1007 : v->type == jpiNot ||
1008 : v->type == jpiIsUnknown ||
1009 : v->type == jpiType ||
1010 : v->type == jpiSize ||
1011 : v->type == jpiAbs ||
1012 : v->type == jpiFloor ||
1013 : v->type == jpiCeiling ||
1014 : v->type == jpiDouble ||
1015 : v->type == jpiDatetime ||
1016 : v->type == jpiKeyValue ||
1017 : v->type == jpiStartsWith);
1018 :
1485 akorotkov 1019 GIC 94860 : if (a)
1020 94860 : jspInitByBuffer(a, v->base, v->nextPos);
1021 94860 : return true;
1022 : }
1023 :
1024 115645 : return false;
1025 : }
1026 :
1027 : void
1028 47371 : jspGetLeftArg(JsonPathItem *v, JsonPathItem *a)
1029 : {
1030 47371 : Assert(v->type == jpiAnd ||
1031 : v->type == jpiOr ||
1032 : v->type == jpiEqual ||
1033 : v->type == jpiNotEqual ||
1034 : v->type == jpiLess ||
1035 : v->type == jpiGreater ||
1036 : v->type == jpiLessOrEqual ||
1037 : v->type == jpiGreaterOrEqual ||
1038 : v->type == jpiAdd ||
1039 : v->type == jpiSub ||
1040 : v->type == jpiMul ||
1041 : v->type == jpiDiv ||
1042 : v->type == jpiMod ||
1043 : v->type == jpiStartsWith);
1044 :
1045 47371 : jspInitByBuffer(a, v->base, v->content.args.left);
1046 47371 : }
1047 :
1048 : void
1049 34888 : jspGetRightArg(JsonPathItem *v, JsonPathItem *a)
1050 : {
1485 akorotkov 1051 CBC 34888 : Assert(v->type == jpiAnd ||
1485 akorotkov 1052 ECB : v->type == jpiOr ||
1053 : v->type == jpiEqual ||
1054 : v->type == jpiNotEqual ||
1055 : v->type == jpiLess ||
1056 : v->type == jpiGreater ||
1057 : v->type == jpiLessOrEqual ||
1058 : v->type == jpiGreaterOrEqual ||
1059 : v->type == jpiAdd ||
1060 : v->type == jpiSub ||
1061 : v->type == jpiMul ||
1062 : v->type == jpiDiv ||
1063 : v->type == jpiMod ||
1064 : v->type == jpiStartsWith);
1065 :
1485 akorotkov 1066 GIC 34888 : jspInitByBuffer(a, v->base, v->content.args.right);
1067 34888 : }
1068 :
1069 : bool
1070 717 : jspGetBool(JsonPathItem *v)
1071 : {
1072 717 : Assert(v->type == jpiBool);
1073 :
1074 717 : return (bool) *v->content.value.data;
1075 : }
1076 :
1485 akorotkov 1077 ECB : Numeric
1485 akorotkov 1078 CBC 10120 : jspGetNumeric(JsonPathItem *v)
1079 : {
1485 akorotkov 1080 GIC 10120 : Assert(v->type == jpiNumeric);
1485 akorotkov 1081 ECB :
1485 akorotkov 1082 GIC 10120 : return (Numeric) v->content.value.data;
1485 akorotkov 1083 ECB : }
1084 :
1085 : char *
1485 akorotkov 1086 GIC 97846 : jspGetString(JsonPathItem *v, int32 *len)
1087 : {
1088 97846 : Assert(v->type == jpiKey ||
1089 : v->type == jpiString ||
1090 : v->type == jpiVariable);
1091 :
1092 97846 : if (len)
1093 97248 : *len = v->content.value.datalen;
1094 97846 : return v->content.value.data;
1095 : }
1096 :
1097 : bool
1485 akorotkov 1098 CBC 183 : jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from, JsonPathItem *to,
1485 akorotkov 1099 ECB : int i)
1100 : {
1485 akorotkov 1101 GIC 183 : Assert(v->type == jpiIndexArray);
1485 akorotkov 1102 ECB :
1485 akorotkov 1103 GIC 183 : jspInitByBuffer(from, v->base, v->content.array.elems[i].from);
1485 akorotkov 1104 ECB :
1485 akorotkov 1105 GIC 183 : if (!v->content.array.elems[i].to)
1485 akorotkov 1106 CBC 162 : return false;
1107 :
1485 akorotkov 1108 GIC 21 : jspInitByBuffer(to, v->base, v->content.array.elems[i].to);
1109 :
1485 akorotkov 1110 CBC 21 : return true;
1111 : }
|