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