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-2022, 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 
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 
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  */
249 
250  /*
251  * Reserve space for next item pointer. Actual value will be recorded
252  * later, after next and children items processing.
253  */
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));
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  */
297 
298  chld = !item->value.args.left ? pos :
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));
320  (char *) &item->value.like_regex.patternlen,
321  sizeof(item->value.like_regex.patternlen));
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  case jpiDatetime:
341  {
343 
344  chld = !item->value.arg ? pos :
346  nestingLevel + argNestingLevel,
347  insideArraySubscript);
348  *(int32 *) (buf->data + arg) = chld - pos;
349  }
350  break;
351  case jpiNull:
352  break;
353  case jpiRoot:
354  break;
355  case jpiAnyArray:
356  case jpiAnyKey:
357  break;
358  case jpiCurrent:
359  if (nestingLevel <= 0)
360  ereport(ERROR,
361  (errcode(ERRCODE_SYNTAX_ERROR),
362  errmsg("@ is not allowed in root expressions")));
363  break;
364  case jpiLast:
365  if (!insideArraySubscript)
366  ereport(ERROR,
367  (errcode(ERRCODE_SYNTAX_ERROR),
368  errmsg("LAST is allowed only in array subscripts")));
369  break;
370  case jpiIndexArray:
371  {
372  int32 nelems = item->value.array.nelems;
373  int offset;
374  int i;
375 
376  appendBinaryStringInfo(buf, (char *) &nelems, sizeof(nelems));
377 
378  offset = buf->len;
379 
380  appendStringInfoSpaces(buf, sizeof(int32) * 2 * nelems);
381 
382  for (i = 0; i < nelems; i++)
383  {
384  int32 *ppos;
385  int32 topos;
386  int32 frompos =
388  item->value.array.elems[i].from,
389  nestingLevel, true) - pos;
390 
391  if (item->value.array.elems[i].to)
393  item->value.array.elems[i].to,
394  nestingLevel, true) - pos;
395  else
396  topos = 0;
397 
398  ppos = (int32 *) &buf->data[offset + i * 2 * sizeof(int32)];
399 
400  ppos[0] = frompos;
401  ppos[1] = topos;
402  }
403  }
404  break;
405  case jpiAny:
407  (char *) &item->value.anybounds.first,
408  sizeof(item->value.anybounds.first));
410  (char *) &item->value.anybounds.last,
411  sizeof(item->value.anybounds.last));
412  break;
413  case jpiType:
414  case jpiSize:
415  case jpiAbs:
416  case jpiFloor:
417  case jpiCeiling:
418  case jpiDouble:
419  case jpiKeyValue:
420  break;
421  default:
422  elog(ERROR, "unrecognized jsonpath item type: %d", item->type);
423  }
424 
425  if (item->next)
426  {
427  chld = flattenJsonPathParseItem(buf, item->next, nestingLevel,
428  insideArraySubscript) - pos;
429  *(int32 *) (buf->data + next) = chld;
430  }
431 
432  return pos;
433 }
434 
435 /*
436  * Align StringInfo to int by adding zero padding bytes
437  */
438 static void
440 {
441  switch (INTALIGN(buf->len) - buf->len)
442  {
443  case 3:
445  /* FALLTHROUGH */
446  case 2:
448  /* FALLTHROUGH */
449  case 1:
451  /* FALLTHROUGH */
452  default:
453  break;
454  }
455 }
456 
457 /*
458  * Reserve space for int32 JsonPathItem pointer. Now zero pointer is written,
459  * actual value will be recorded at '(int32 *) &buf->data[pos]' later.
460  */
461 static int32
463 {
464  int32 pos = buf->len;
465  int32 ptr = 0;
466 
467  appendBinaryStringInfo(buf, (char *) &ptr, sizeof(ptr));
468 
469  return pos;
470 }
471 
472 /*
473  * Prints text representation of given jsonpath item and all its children.
474  */
475 static void
477  bool printBracketes)
478 {
479  JsonPathItem elem;
480  int i;
481 
484 
485  switch (v->type)
486  {
487  case jpiNull:
488  appendStringInfoString(buf, "null");
489  break;
490  case jpiKey:
491  if (inKey)
493  escape_json(buf, jspGetString(v, NULL));
494  break;
495  case jpiString:
496  escape_json(buf, jspGetString(v, NULL));
497  break;
498  case jpiVariable:
500  escape_json(buf, jspGetString(v, NULL));
501  break;
502  case jpiNumeric:
503  if (jspHasNext(v))
508  if (jspHasNext(v))
510  break;
511  case jpiBool:
512  if (jspGetBool(v))
513  appendBinaryStringInfo(buf, "true", 4);
514  else
515  appendBinaryStringInfo(buf, "false", 5);
516  break;
517  case jpiAnd:
518  case jpiOr:
519  case jpiEqual:
520  case jpiNotEqual:
521  case jpiLess:
522  case jpiGreater:
523  case jpiLessOrEqual:
524  case jpiGreaterOrEqual:
525  case jpiAdd:
526  case jpiSub:
527  case jpiMul:
528  case jpiDiv:
529  case jpiMod:
530  case jpiStartsWith:
531  if (printBracketes)
533  jspGetLeftArg(v, &elem);
534  printJsonPathItem(buf, &elem, false,
535  operationPriority(elem.type) <=
536  operationPriority(v->type));
540  jspGetRightArg(v, &elem);
541  printJsonPathItem(buf, &elem, false,
542  operationPriority(elem.type) <=
543  operationPriority(v->type));
544  if (printBracketes)
546  break;
547  case jpiLikeRegex:
548  if (printBracketes)
550 
551  jspInitByBuffer(&elem, v->base, v->content.like_regex.expr);
552  printJsonPathItem(buf, &elem, false,
553  operationPriority(elem.type) <=
554  operationPriority(v->type));
555 
556  appendBinaryStringInfo(buf, " like_regex ", 12);
557 
558  escape_json(buf, v->content.like_regex.pattern);
559 
560  if (v->content.like_regex.flags)
561  {
562  appendBinaryStringInfo(buf, " flag \"", 7);
563 
564  if (v->content.like_regex.flags & JSP_REGEX_ICASE)
566  if (v->content.like_regex.flags & JSP_REGEX_DOTALL)
568  if (v->content.like_regex.flags & JSP_REGEX_MLINE)
570  if (v->content.like_regex.flags & JSP_REGEX_WSPACE)
572  if (v->content.like_regex.flags & JSP_REGEX_QUOTE)
574 
576  }
577 
578  if (printBracketes)
580  break;
581  case jpiPlus:
582  case jpiMinus:
583  if (printBracketes)
585  appendStringInfoChar(buf, v->type == jpiPlus ? '+' : '-');
586  jspGetArg(v, &elem);
587  printJsonPathItem(buf, &elem, false,
588  operationPriority(elem.type) <=
589  operationPriority(v->type));
590  if (printBracketes)
592  break;
593  case jpiFilter:
594  appendBinaryStringInfo(buf, "?(", 2);
595  jspGetArg(v, &elem);
596  printJsonPathItem(buf, &elem, false, false);
598  break;
599  case jpiNot:
600  appendBinaryStringInfo(buf, "!(", 2);
601  jspGetArg(v, &elem);
602  printJsonPathItem(buf, &elem, false, false);
604  break;
605  case jpiIsUnknown:
607  jspGetArg(v, &elem);
608  printJsonPathItem(buf, &elem, false, false);
609  appendBinaryStringInfo(buf, ") is unknown", 12);
610  break;
611  case jpiExists:
612  appendBinaryStringInfo(buf, "exists (", 8);
613  jspGetArg(v, &elem);
614  printJsonPathItem(buf, &elem, false, false);
616  break;
617  case jpiCurrent:
618  Assert(!inKey);
620  break;
621  case jpiRoot:
622  Assert(!inKey);
624  break;
625  case jpiLast:
626  appendBinaryStringInfo(buf, "last", 4);
627  break;
628  case jpiAnyArray:
629  appendBinaryStringInfo(buf, "[*]", 3);
630  break;
631  case jpiAnyKey:
632  if (inKey)
635  break;
636  case jpiIndexArray:
638  for (i = 0; i < v->content.array.nelems; i++)
639  {
640  JsonPathItem from;
641  JsonPathItem to;
642  bool range = jspGetArraySubscript(v, &from, &to, i);
643 
644  if (i)
646 
647  printJsonPathItem(buf, &from, false, false);
648 
649  if (range)
650  {
651  appendBinaryStringInfo(buf, " to ", 4);
652  printJsonPathItem(buf, &to, false, false);
653  }
654  }
656  break;
657  case jpiAny:
658  if (inKey)
660 
661  if (v->content.anybounds.first == 0 &&
662  v->content.anybounds.last == PG_UINT32_MAX)
663  appendBinaryStringInfo(buf, "**", 2);
664  else if (v->content.anybounds.first == v->content.anybounds.last)
665  {
666  if (v->content.anybounds.first == PG_UINT32_MAX)
667  appendStringInfoString(buf, "**{last}");
668  else
669  appendStringInfo(buf, "**{%u}",
670  v->content.anybounds.first);
671  }
672  else if (v->content.anybounds.first == PG_UINT32_MAX)
673  appendStringInfo(buf, "**{last to %u}",
674  v->content.anybounds.last);
675  else if (v->content.anybounds.last == PG_UINT32_MAX)
676  appendStringInfo(buf, "**{%u to last}",
677  v->content.anybounds.first);
678  else
679  appendStringInfo(buf, "**{%u to %u}",
680  v->content.anybounds.first,
681  v->content.anybounds.last);
682  break;
683  case jpiType:
684  appendBinaryStringInfo(buf, ".type()", 7);
685  break;
686  case jpiSize:
687  appendBinaryStringInfo(buf, ".size()", 7);
688  break;
689  case jpiAbs:
690  appendBinaryStringInfo(buf, ".abs()", 6);
691  break;
692  case jpiFloor:
693  appendBinaryStringInfo(buf, ".floor()", 8);
694  break;
695  case jpiCeiling:
696  appendBinaryStringInfo(buf, ".ceiling()", 10);
697  break;
698  case jpiDouble:
699  appendBinaryStringInfo(buf, ".double()", 9);
700  break;
701  case jpiDatetime:
702  appendBinaryStringInfo(buf, ".datetime(", 10);
703  if (v->content.arg)
704  {
705  jspGetArg(v, &elem);
706  printJsonPathItem(buf, &elem, false, false);
707  }
709  break;
710  case jpiKeyValue:
711  appendBinaryStringInfo(buf, ".keyvalue()", 11);
712  break;
713  default:
714  elog(ERROR, "unrecognized jsonpath item type: %d", v->type);
715  }
716 
717  if (jspGetNext(v, &elem))
718  printJsonPathItem(buf, &elem, true, true);
719 }
720 
721 const char *
723 {
724  switch (type)
725  {
726  case jpiAnd:
727  return "&&";
728  case jpiOr:
729  return "||";
730  case jpiEqual:
731  return "==";
732  case jpiNotEqual:
733  return "!=";
734  case jpiLess:
735  return "<";
736  case jpiGreater:
737  return ">";
738  case jpiLessOrEqual:
739  return "<=";
740  case jpiGreaterOrEqual:
741  return ">=";
742  case jpiPlus:
743  case jpiAdd:
744  return "+";
745  case jpiMinus:
746  case jpiSub:
747  return "-";
748  case jpiMul:
749  return "*";
750  case jpiDiv:
751  return "/";
752  case jpiMod:
753  return "%";
754  case jpiStartsWith:
755  return "starts with";
756  case jpiLikeRegex:
757  return "like_regex";
758  case jpiType:
759  return "type";
760  case jpiSize:
761  return "size";
762  case jpiKeyValue:
763  return "keyvalue";
764  case jpiDouble:
765  return "double";
766  case jpiAbs:
767  return "abs";
768  case jpiFloor:
769  return "floor";
770  case jpiCeiling:
771  return "ceiling";
772  case jpiDatetime:
773  return "datetime";
774  default:
775  elog(ERROR, "unrecognized jsonpath item type: %d", type);
776  return NULL;
777  }
778 }
779 
780 static int
782 {
783  switch (op)
784  {
785  case jpiOr:
786  return 0;
787  case jpiAnd:
788  return 1;
789  case jpiEqual:
790  case jpiNotEqual:
791  case jpiLess:
792  case jpiGreater:
793  case jpiLessOrEqual:
794  case jpiGreaterOrEqual:
795  case jpiStartsWith:
796  return 2;
797  case jpiAdd:
798  case jpiSub:
799  return 3;
800  case jpiMul:
801  case jpiDiv:
802  case jpiMod:
803  return 4;
804  case jpiPlus:
805  case jpiMinus:
806  return 5;
807  default:
808  return 6;
809  }
810 }
811 
812 /******************* Support functions for JsonPath *************************/
813 
814 /*
815  * Support macros to read stored values
816  */
817 
818 #define read_byte(v, b, p) do { \
819  (v) = *(uint8*)((b) + (p)); \
820  (p) += 1; \
821 } while(0) \
822 
823 #define read_int32(v, b, p) do { \
824  (v) = *(uint32*)((b) + (p)); \
825  (p) += sizeof(int32); \
826 } while(0) \
827 
828 #define read_int32_n(v, b, p, n) do { \
829  (v) = (void *)((b) + (p)); \
830  (p) += sizeof(int32) * (n); \
831 } while(0) \
832 
833 /*
834  * Read root node and fill root node representation
835  */
836 void
838 {
840  jspInitByBuffer(v, js->data, 0);
841 }
842 
843 /*
844  * Read node from buffer and fill its representation
845  */
846 void
847 jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
848 {
849  v->base = base + pos;
850 
851  read_byte(v->type, base, pos);
852  pos = INTALIGN((uintptr_t) (base + pos)) - (uintptr_t) base;
853  read_int32(v->nextPos, base, pos);
854 
855  switch (v->type)
856  {
857  case jpiNull:
858  case jpiRoot:
859  case jpiCurrent:
860  case jpiAnyArray:
861  case jpiAnyKey:
862  case jpiType:
863  case jpiSize:
864  case jpiAbs:
865  case jpiFloor:
866  case jpiCeiling:
867  case jpiDouble:
868  case jpiKeyValue:
869  case jpiLast:
870  break;
871  case jpiKey:
872  case jpiString:
873  case jpiVariable:
874  read_int32(v->content.value.datalen, base, pos);
875  /* FALLTHROUGH */
876  case jpiNumeric:
877  case jpiBool:
878  v->content.value.data = base + pos;
879  break;
880  case jpiAnd:
881  case jpiOr:
882  case jpiAdd:
883  case jpiSub:
884  case jpiMul:
885  case jpiDiv:
886  case jpiMod:
887  case jpiEqual:
888  case jpiNotEqual:
889  case jpiLess:
890  case jpiGreater:
891  case jpiLessOrEqual:
892  case jpiGreaterOrEqual:
893  case jpiStartsWith:
894  read_int32(v->content.args.left, base, pos);
895  read_int32(v->content.args.right, base, pos);
896  break;
897  case jpiLikeRegex:
898  read_int32(v->content.like_regex.flags, base, pos);
899  read_int32(v->content.like_regex.expr, base, pos);
900  read_int32(v->content.like_regex.patternlen, base, pos);
901  v->content.like_regex.pattern = base + pos;
902  break;
903  case jpiNot:
904  case jpiExists:
905  case jpiIsUnknown:
906  case jpiPlus:
907  case jpiMinus:
908  case jpiFilter:
909  case jpiDatetime:
910  read_int32(v->content.arg, base, pos);
911  break;
912  case jpiIndexArray:
913  read_int32(v->content.array.nelems, base, pos);
914  read_int32_n(v->content.array.elems, base, pos,
915  v->content.array.nelems * 2);
916  break;
917  case jpiAny:
918  read_int32(v->content.anybounds.first, base, pos);
919  read_int32(v->content.anybounds.last, base, pos);
920  break;
921  default:
922  elog(ERROR, "unrecognized jsonpath item type: %d", v->type);
923  }
924 }
925 
926 void
928 {
929  Assert(v->type == jpiFilter ||
930  v->type == jpiNot ||
931  v->type == jpiIsUnknown ||
932  v->type == jpiExists ||
933  v->type == jpiPlus ||
934  v->type == jpiMinus ||
935  v->type == jpiDatetime);
936 
937  jspInitByBuffer(a, v->base, v->content.arg);
938 }
939 
940 bool
942 {
943  if (jspHasNext(v))
944  {
945  Assert(v->type == jpiString ||
946  v->type == jpiNumeric ||
947  v->type == jpiBool ||
948  v->type == jpiNull ||
949  v->type == jpiKey ||
950  v->type == jpiAny ||
951  v->type == jpiAnyArray ||
952  v->type == jpiAnyKey ||
953  v->type == jpiIndexArray ||
954  v->type == jpiFilter ||
955  v->type == jpiCurrent ||
956  v->type == jpiExists ||
957  v->type == jpiRoot ||
958  v->type == jpiVariable ||
959  v->type == jpiLast ||
960  v->type == jpiAdd ||
961  v->type == jpiSub ||
962  v->type == jpiMul ||
963  v->type == jpiDiv ||
964  v->type == jpiMod ||
965  v->type == jpiPlus ||
966  v->type == jpiMinus ||
967  v->type == jpiEqual ||
968  v->type == jpiNotEqual ||
969  v->type == jpiGreater ||
970  v->type == jpiGreaterOrEqual ||
971  v->type == jpiLess ||
972  v->type == jpiLessOrEqual ||
973  v->type == jpiAnd ||
974  v->type == jpiOr ||
975  v->type == jpiNot ||
976  v->type == jpiIsUnknown ||
977  v->type == jpiType ||
978  v->type == jpiSize ||
979  v->type == jpiAbs ||
980  v->type == jpiFloor ||
981  v->type == jpiCeiling ||
982  v->type == jpiDouble ||
983  v->type == jpiDatetime ||
984  v->type == jpiKeyValue ||
985  v->type == jpiStartsWith);
986 
987  if (a)
988  jspInitByBuffer(a, v->base, v->nextPos);
989  return true;
990  }
991 
992  return false;
993 }
994 
995 void
997 {
998  Assert(v->type == jpiAnd ||
999  v->type == jpiOr ||
1000  v->type == jpiEqual ||
1001  v->type == jpiNotEqual ||
1002  v->type == jpiLess ||
1003  v->type == jpiGreater ||
1004  v->type == jpiLessOrEqual ||
1005  v->type == jpiGreaterOrEqual ||
1006  v->type == jpiAdd ||
1007  v->type == jpiSub ||
1008  v->type == jpiMul ||
1009  v->type == jpiDiv ||
1010  v->type == jpiMod ||
1011  v->type == jpiStartsWith);
1012 
1013  jspInitByBuffer(a, v->base, v->content.args.left);
1014 }
1015 
1016 void
1018 {
1019  Assert(v->type == jpiAnd ||
1020  v->type == jpiOr ||
1021  v->type == jpiEqual ||
1022  v->type == jpiNotEqual ||
1023  v->type == jpiLess ||
1024  v->type == jpiGreater ||
1025  v->type == jpiLessOrEqual ||
1026  v->type == jpiGreaterOrEqual ||
1027  v->type == jpiAdd ||
1028  v->type == jpiSub ||
1029  v->type == jpiMul ||
1030  v->type == jpiDiv ||
1031  v->type == jpiMod ||
1032  v->type == jpiStartsWith);
1033 
1034  jspInitByBuffer(a, v->base, v->content.args.right);
1035 }
1036 
1037 bool
1039 {
1040  Assert(v->type == jpiBool);
1041 
1042  return (bool) *v->content.value.data;
1043 }
1044 
1045 Numeric
1047 {
1048  Assert(v->type == jpiNumeric);
1049 
1050  return (Numeric) v->content.value.data;
1051 }
1052 
1053 char *
1055 {
1056  Assert(v->type == jpiKey ||
1057  v->type == jpiString ||
1058  v->type == jpiVariable);
1059 
1060  if (len)
1061  *len = v->content.value.datalen;
1062  return v->content.value.data;
1063 }
1064 
1065 bool
1067  int i)
1068 {
1069  Assert(v->type == jpiIndexArray);
1070 
1071  jspInitByBuffer(from, v->base, v->content.array.elems[i].from);
1072 
1073  if (!v->content.array.elems[i].to)
1074  return false;
1075 
1076  jspInitByBuffer(to, v->base, v->content.array.elems[i].to);
1077 
1078  return true;
1079 }
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:735
static int32 next
Definition: blutils.c:219
#define INTALIGN(LEN)
Definition: c.h:744
#define PG_UINT32_MAX
Definition: c.h:526
signed int int32
Definition: c.h:430
int errcode(int sqlerrcode)
Definition: elog.c:735
int errmsg(const char *fmt,...)
Definition: elog.c:946
#define ERROR
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:145
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:362
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:277
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
int a
Definition: isn.c:69
int i
Definition: isn.c:73
void escape_json(StringInfo buf, const char *str)
Definition: json.c:1271
void jspGetLeftArg(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:996
void jspGetArg(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:927
Datum jsonpath_send(PG_FUNCTION_ARGS)
Definition: jsonpath.c:142
#define read_byte(v, b, p)
Definition: jsonpath.c:818
#define read_int32_n(v, b, p, n)
Definition: jsonpath.c:828
Datum jsonpath_out(PG_FUNCTION_ARGS)
Definition: jsonpath.c:129
static void alignStringInfoInt(StringInfo buf)
Definition: jsonpath.c:439
void jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
Definition: jsonpath.c:847
bool jspGetBool(JsonPathItem *v)
Definition: jsonpath.c:1038
void jspInit(JsonPathItem *v, JsonPath *js)
Definition: jsonpath.c:837
const char * jspOperationName(JsonPathItemType type)
Definition: jsonpath.c:722
Numeric jspGetNumeric(JsonPathItem *v)
Definition: jsonpath.c:1046
bool jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from, JsonPathItem *to, int i)
Definition: jsonpath.c:1066
static void printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey, bool printBracketes)
Definition: jsonpath.c:476
#define read_int32(v, b, p)
Definition: jsonpath.c:823
static int flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item, int nestingLevel, bool insideArraySubscript)
Definition: jsonpath.c:229
bool jspGetNext(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:941
static int operationPriority(JsonPathItemType op)
Definition: jsonpath.c:781
static Datum jsonPathFromCstring(char *in, int len)
Definition: jsonpath.c:168
Datum jsonpath_recv(PG_FUNCTION_ARGS)
Definition: jsonpath.c:110
Datum jsonpath_in(PG_FUNCTION_ARGS)
Definition: jsonpath.c:93
void jspGetRightArg(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:1017
char * jspGetString(JsonPathItem *v, int32 *len)
Definition: jsonpath.c:1054
static int32 reserveSpaceForItemPointer(StringInfo buf)
Definition: jsonpath.c:462
static char * jsonPathToCstring(StringInfo out, JsonPath *in, int estimated_len)
Definition: jsonpath.c:203
#define JSP_REGEX_WSPACE
Definition: jsonpath.h:104
#define JSP_REGEX_MLINE
Definition: jsonpath.h:103
#define PG_RETURN_JSONPATH_P(p)
Definition: jsonpath.h:46
#define JSP_REGEX_ICASE
Definition: jsonpath.h:101
#define jspHasNext(jsp)
Definition: jsonpath.h:174
#define PG_GETARG_JSONPATH_P(x)
Definition: jsonpath.h:44
#define JSONPATH_VERSION
Definition: jsonpath.h:28
JsonPathParseResult * parsejsonpath(const char *str, int len)
#define JSP_REGEX_DOTALL
Definition: jsonpath.h:102
JsonPathItemType
Definition: jsonpath.h:54
@ jpiAdd
Definition: jsonpath.h:69
@ jpiString
Definition: jsonpath.h:56
@ jpiAbs
Definition: jsonpath.h:88
@ jpiIndexArray
Definition: jsonpath.h:78
@ jpiAny
Definition: jsonpath.h:79
@ jpiDatetime
Definition: jsonpath.h:92
@ jpiBool
Definition: jsonpath.h:58
@ jpiType
Definition: jsonpath.h:86
@ jpiFloor
Definition: jsonpath.h:89
@ jpiAnyArray
Definition: jsonpath.h:76
@ jpiExists
Definition: jsonpath.h:85
@ jpiSize
Definition: jsonpath.h:87
@ jpiSub
Definition: jsonpath.h:70
@ jpiNotEqual
Definition: jsonpath.h:64
@ jpiMul
Definition: jsonpath.h:71
@ jpiVariable
Definition: jsonpath.h:83
@ jpiNot
Definition: jsonpath.h:61
@ jpiGreaterOrEqual
Definition: jsonpath.h:68
@ jpiPlus
Definition: jsonpath.h:74
@ jpiDouble
Definition: jsonpath.h:91
@ jpiGreater
Definition: jsonpath.h:66
@ jpiAnd
Definition: jsonpath.h:59
@ jpiStartsWith
Definition: jsonpath.h:96
@ jpiOr
Definition: jsonpath.h:60
@ jpiMod
Definition: jsonpath.h:73
@ jpiLikeRegex
Definition: jsonpath.h:97
@ jpiRoot
Definition: jsonpath.h:82
@ jpiFilter
Definition: jsonpath.h:84
@ jpiNull
Definition: jsonpath.h:55
@ jpiLess
Definition: jsonpath.h:65
@ jpiCurrent
Definition: jsonpath.h:81
@ jpiEqual
Definition: jsonpath.h:63
@ jpiKey
Definition: jsonpath.h:80
@ jpiDiv
Definition: jsonpath.h:72
@ jpiLast
Definition: jsonpath.h:95
@ jpiMinus
Definition: jsonpath.h:75
@ jpiLessOrEqual
Definition: jsonpath.h:67
@ jpiCeiling
Definition: jsonpath.h:90
@ jpiIsUnknown
Definition: jsonpath.h:62
@ jpiKeyValue
Definition: jsonpath.h:93
@ jpiNumeric
Definition: jsonpath.h:57
@ jpiAnyKey
Definition: jsonpath.h:77
#define JSONPATH_LAX
Definition: jsonpath.h:29
#define JSONPATH_HDRSZ
Definition: jsonpath.h:30
#define JSP_REGEX_QUOTE
Definition: jsonpath.h:105
Assert(fmt[strlen(fmt) - 1] !='\n')
void pfree(void *pointer)
Definition: mcxt.c:1306
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
static Datum NumericGetDatum(Numeric X)
Definition: numeric.h:72
void * arg
const void size_t len
static char * buf
Definition: pg_test_fsync.c:67
void check_stack_depth(void)
Definition: postgres.c:3440
static char * DatumGetCString(Datum X)
Definition: postgres.h:683
uintptr_t Datum
Definition: postgres.h:412
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:343
#define VARSIZE(PTR)
Definition: postgres.h:317
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:417
void pq_sendtext(StringInfo buf, const char *str, int slen)
Definition: pqformat.c:174
char * pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes)
Definition: pqformat.c:548
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:328
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:348
static void pq_sendint8(StringInfo buf, uint8 i)
Definition: pqformat.h:129
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
Definition: regc_locale.c:412
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void enlargeStringInfo(StringInfo str, int needed)
Definition: stringinfo.c:283
void appendBinaryStringInfo(StringInfo str, const char *data, int datalen)
Definition: stringinfo.c:227
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:206
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
StringInfoData * StringInfo
Definition: stringinfo.h:44
#define appendStringInfoCharMacro(str, ch)
Definition: stringinfo.h:128
struct JsonPathItem::@128::@133 like_regex
union JsonPathItem::@128 content
char * base
Definition: jsonpath.h:126
int32 nextPos
Definition: jsonpath.h:120
struct JsonPathItem::@128::@130 array
int32 arg
Definition: jsonpath.h:138
JsonPathItemType type
Definition: jsonpath.h:117
struct JsonPathItem::@128::@129 args
struct JsonPathItem::@128::@132 value
struct JsonPathItem::@128::@131 anybounds
JsonPathParseItem * arg
Definition: jsonpath.h:212
struct JsonPathParseItem::@135::@136 args
struct JsonPathParseItem::@135::@137 array
JsonPathParseItem * next
Definition: jsonpath.h:199
struct JsonPathParseItem::@135::@140 string
Numeric numeric
Definition: jsonpath.h:241
union JsonPathParseItem::@135 value
struct JsonPathParseItem::@135::@138 anybounds
struct JsonPathParseItem::@135::@139 like_regex
JsonPathItemType type
Definition: jsonpath.h:198
JsonPathParseItem * expr
Definition: jsonpath.h:253
char data[FLEXIBLE_ARRAY_MEMBER]
Definition: jsonpath.h:25
uint32 header
Definition: jsonpath.h:24