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-2024, 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);
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
97 {
98  char *in = PG_GETARG_CSTRING(0);
99  int len = strlen(in);
100 
101  return jsonPathFromCstring(in, len, fcinfo->context);
102 }
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
114 {
116  int version = pq_getmsgint(buf, 1);
117  char *str;
118  int nbytes;
119 
120  if (version == JSONPATH_VERSION)
121  str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
122  else
123  elog(ERROR, "unsupported jsonpath version number: %d", version);
124 
125  return jsonPathFromCstring(str, nbytes, NULL);
126 }
127 
128 /*
129  * jsonpath type output function
130  */
131 Datum
133 {
135 
137 }
138 
139 /*
140  * jsonpath type send function
141  *
142  * Just send jsonpath as a version number, then a string of text
143  */
144 Datum
146 {
149  StringInfoData jtext;
150  int version = JSONPATH_VERSION;
151 
152  initStringInfo(&jtext);
153  (void) jsonPathToCstring(&jtext, in, VARSIZE(in));
154 
156  pq_sendint8(&buf, version);
157  pq_sendtext(&buf, jtext.data, jtext.len);
158  pfree(jtext.data);
159 
161 }
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
171 jsonPathFromCstring(char *in, int len, struct Node *escontext)
172 {
173  JsonPathParseResult *jsonpath = parsejsonpath(in, len, escontext);
174  JsonPath *res;
176 
177  if (SOFT_ERROR_OCCURRED(escontext))
178  return (Datum) 0;
179 
180  if (!jsonpath)
181  ereturn(escontext, (Datum) 0,
182  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
183  errmsg("invalid input syntax for type %s: \"%s\"", "jsonpath",
184  in)));
185 
187  enlargeStringInfo(&buf, 4 * len /* estimation */ );
188 
190 
191  if (!flattenJsonPathParseItem(&buf, NULL, escontext,
192  jsonpath->expr, 0, false))
193  return (Datum) 0;
194 
195  res = (JsonPath *) buf.data;
196  SET_VARSIZE(res, buf.len);
197  res->header = JSONPATH_VERSION;
198  if (jsonpath->lax)
199  res->header |= JSONPATH_LAX;
200 
202 }
203 
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 *
211 jsonPathToCstring(StringInfo out, JsonPath *in, int estimated_len)
212 {
214  JsonPathItem v;
215 
216  if (!out)
217  {
218  out = &buf;
219  initStringInfo(out);
220  }
221  enlargeStringInfo(out, estimated_len);
222 
223  if (!(in->header & JSONPATH_LAX))
224  appendStringInfoString(out, "strict ");
225 
226  jspInit(&v, in);
227  printJsonPathItem(out, &v, false, true);
228 
229  return out->data;
230 }
231 
232 /*
233  * Recursive function converting given jsonpath parse item and all its
234  * children into a binary representation.
235  */
236 static bool
237 flattenJsonPathParseItem(StringInfo buf, int *result, struct Node *escontext,
238  JsonPathParseItem *item, int nestingLevel,
239  bool insideArraySubscript)
240 {
241  /* position from beginning of jsonpath data */
242  int32 pos = buf->len - JSONPATH_HDRSZ;
243  int32 chld;
244  int32 next;
245  int argNestingLevel = 0;
246 
249 
250  appendStringInfoChar(buf, (char) (item->type));
251 
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  */
258 
259  /*
260  * Reserve space for next item pointer. Actual value will be recorded
261  * later, after next and children items processing.
262  */
264 
265  switch (item->type)
266  {
267  case jpiString:
268  case jpiVariable:
269  case jpiKey:
271  sizeof(item->value.string.len));
273  item->value.string.len);
274  appendStringInfoChar(buf, '\0');
275  break;
276  case jpiNumeric:
278  VARSIZE(item->value.numeric));
279  break;
280  case jpiBool:
282  sizeof(item->value.boolean));
283  break;
284  case jpiAnd:
285  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  case jpiDecimal:
299  {
300  /*
301  * First, reserve place for left/right arg's positions, then
302  * record both args and sets actual position in reserved
303  * places.
304  */
307 
308  if (!item->value.args.left)
309  chld = pos;
310  else if (!flattenJsonPathParseItem(buf, &chld, escontext,
311  item->value.args.left,
312  nestingLevel + argNestingLevel,
313  insideArraySubscript))
314  return false;
315  *(int32 *) (buf->data + left) = chld - pos;
316 
317  if (!item->value.args.right)
318  chld = pos;
319  else if (!flattenJsonPathParseItem(buf, &chld, escontext,
320  item->value.args.right,
321  nestingLevel + argNestingLevel,
322  insideArraySubscript))
323  return false;
324  *(int32 *) (buf->data + right) = chld - pos;
325  }
326  break;
327  case jpiLikeRegex:
328  {
329  int32 offs;
330 
332  &item->value.like_regex.flags,
333  sizeof(item->value.like_regex.flags));
336  &item->value.like_regex.patternlen,
337  sizeof(item->value.like_regex.patternlen));
339  item->value.like_regex.patternlen);
340  appendStringInfoChar(buf, '\0');
341 
342  if (!flattenJsonPathParseItem(buf, &chld, escontext,
343  item->value.like_regex.expr,
344  nestingLevel,
345  insideArraySubscript))
346  return false;
347  *(int32 *) (buf->data + offs) = chld - pos;
348  }
349  break;
350  case jpiFilter:
351  argNestingLevel++;
352  /* FALLTHROUGH */
353  case jpiIsUnknown:
354  case jpiNot:
355  case jpiPlus:
356  case jpiMinus:
357  case jpiExists:
358  case jpiDatetime:
359  case jpiTime:
360  case jpiTimeTz:
361  case jpiTimestamp:
362  case jpiTimestampTz:
363  {
365 
366  if (!item->value.arg)
367  chld = pos;
368  else if (!flattenJsonPathParseItem(buf, &chld, escontext,
369  item->value.arg,
370  nestingLevel + argNestingLevel,
371  insideArraySubscript))
372  return false;
373  *(int32 *) (buf->data + arg) = chld - pos;
374  }
375  break;
376  case jpiNull:
377  break;
378  case jpiRoot:
379  break;
380  case jpiAnyArray:
381  case jpiAnyKey:
382  break;
383  case jpiCurrent:
384  if (nestingLevel <= 0)
385  ereturn(escontext, false,
386  (errcode(ERRCODE_SYNTAX_ERROR),
387  errmsg("@ is not allowed in root expressions")));
388  break;
389  case jpiLast:
390  if (!insideArraySubscript)
391  ereturn(escontext, false,
392  (errcode(ERRCODE_SYNTAX_ERROR),
393  errmsg("LAST is allowed only in array subscripts")));
394  break;
395  case jpiIndexArray:
396  {
397  int32 nelems = item->value.array.nelems;
398  int offset;
399  int i;
400 
401  appendBinaryStringInfo(buf, &nelems, sizeof(nelems));
402 
403  offset = buf->len;
404 
405  appendStringInfoSpaces(buf, sizeof(int32) * 2 * nelems);
406 
407  for (i = 0; i < nelems; i++)
408  {
409  int32 *ppos;
410  int32 topos;
411  int32 frompos;
412 
413  if (!flattenJsonPathParseItem(buf, &frompos, escontext,
414  item->value.array.elems[i].from,
415  nestingLevel, true))
416  return false;
417  frompos -= pos;
418 
419  if (item->value.array.elems[i].to)
420  {
421  if (!flattenJsonPathParseItem(buf, &topos, escontext,
422  item->value.array.elems[i].to,
423  nestingLevel, true))
424  return false;
425  topos -= pos;
426  }
427  else
428  topos = 0;
429 
430  ppos = (int32 *) &buf->data[offset + i * 2 * sizeof(int32)];
431 
432  ppos[0] = frompos;
433  ppos[1] = topos;
434  }
435  }
436  break;
437  case jpiAny:
439  &item->value.anybounds.first,
440  sizeof(item->value.anybounds.first));
442  &item->value.anybounds.last,
443  sizeof(item->value.anybounds.last));
444  break;
445  case jpiType:
446  case jpiSize:
447  case jpiAbs:
448  case jpiFloor:
449  case jpiCeiling:
450  case jpiDouble:
451  case jpiKeyValue:
452  case jpiBigint:
453  case jpiBoolean:
454  case jpiDate:
455  case jpiInteger:
456  case jpiNumber:
457  case jpiStringFunc:
458  break;
459  default:
460  elog(ERROR, "unrecognized jsonpath item type: %d", item->type);
461  }
462 
463  if (item->next)
464  {
465  if (!flattenJsonPathParseItem(buf, &chld, escontext,
466  item->next, nestingLevel,
467  insideArraySubscript))
468  return false;
469  chld -= pos;
470  *(int32 *) (buf->data + next) = chld;
471  }
472 
473  if (result)
474  *result = pos;
475  return true;
476 }
477 
478 /*
479  * Align StringInfo to int by adding zero padding bytes
480  */
481 static void
483 {
484  switch (INTALIGN(buf->len) - buf->len)
485  {
486  case 3:
488  /* FALLTHROUGH */
489  case 2:
491  /* FALLTHROUGH */
492  case 1:
494  /* FALLTHROUGH */
495  default:
496  break;
497  }
498 }
499 
500 /*
501  * Reserve space for int32 JsonPathItem pointer. Now zero pointer is written,
502  * actual value will be recorded at '(int32 *) &buf->data[pos]' later.
503  */
504 static int32
506 {
507  int32 pos = buf->len;
508  int32 ptr = 0;
509 
510  appendBinaryStringInfo(buf, &ptr, sizeof(ptr));
511 
512  return pos;
513 }
514 
515 /*
516  * Prints text representation of given jsonpath item and all its children.
517  */
518 static void
520  bool printBracketes)
521 {
522  JsonPathItem elem;
523  int i;
524 
527 
528  switch (v->type)
529  {
530  case jpiNull:
531  appendStringInfoString(buf, "null");
532  break;
533  case jpiString:
534  escape_json(buf, jspGetString(v, NULL));
535  break;
536  case jpiNumeric:
537  if (jspHasNext(v))
542  if (jspHasNext(v))
544  break;
545  case jpiBool:
546  if (jspGetBool(v))
547  appendStringInfoString(buf, "true");
548  else
549  appendStringInfoString(buf, "false");
550  break;
551  case jpiAnd:
552  case jpiOr:
553  case jpiEqual:
554  case jpiNotEqual:
555  case jpiLess:
556  case jpiGreater:
557  case jpiLessOrEqual:
558  case jpiGreaterOrEqual:
559  case jpiAdd:
560  case jpiSub:
561  case jpiMul:
562  case jpiDiv:
563  case jpiMod:
564  case jpiStartsWith:
565  if (printBracketes)
567  jspGetLeftArg(v, &elem);
568  printJsonPathItem(buf, &elem, false,
569  operationPriority(elem.type) <=
570  operationPriority(v->type));
574  jspGetRightArg(v, &elem);
575  printJsonPathItem(buf, &elem, false,
576  operationPriority(elem.type) <=
577  operationPriority(v->type));
578  if (printBracketes)
580  break;
581  case jpiNot:
583  jspGetArg(v, &elem);
584  printJsonPathItem(buf, &elem, false, false);
586  break;
587  case jpiIsUnknown:
589  jspGetArg(v, &elem);
590  printJsonPathItem(buf, &elem, false, false);
591  appendStringInfoString(buf, ") is unknown");
592  break;
593  case jpiPlus:
594  case jpiMinus:
595  if (printBracketes)
597  appendStringInfoChar(buf, v->type == jpiPlus ? '+' : '-');
598  jspGetArg(v, &elem);
599  printJsonPathItem(buf, &elem, false,
600  operationPriority(elem.type) <=
601  operationPriority(v->type));
602  if (printBracketes)
604  break;
605  case jpiAnyArray:
606  appendStringInfoString(buf, "[*]");
607  break;
608  case jpiAnyKey:
609  if (inKey)
612  break;
613  case jpiIndexArray:
615  for (i = 0; i < v->content.array.nelems; i++)
616  {
617  JsonPathItem from;
618  JsonPathItem to;
619  bool range = jspGetArraySubscript(v, &from, &to, i);
620 
621  if (i)
623 
624  printJsonPathItem(buf, &from, false, false);
625 
626  if (range)
627  {
628  appendStringInfoString(buf, " to ");
629  printJsonPathItem(buf, &to, false, false);
630  }
631  }
633  break;
634  case jpiAny:
635  if (inKey)
637 
638  if (v->content.anybounds.first == 0 &&
639  v->content.anybounds.last == PG_UINT32_MAX)
641  else if (v->content.anybounds.first == v->content.anybounds.last)
642  {
643  if (v->content.anybounds.first == PG_UINT32_MAX)
644  appendStringInfoString(buf, "**{last}");
645  else
646  appendStringInfo(buf, "**{%u}",
647  v->content.anybounds.first);
648  }
649  else if (v->content.anybounds.first == PG_UINT32_MAX)
650  appendStringInfo(buf, "**{last to %u}",
651  v->content.anybounds.last);
652  else if (v->content.anybounds.last == PG_UINT32_MAX)
653  appendStringInfo(buf, "**{%u to last}",
654  v->content.anybounds.first);
655  else
656  appendStringInfo(buf, "**{%u to %u}",
657  v->content.anybounds.first,
658  v->content.anybounds.last);
659  break;
660  case jpiKey:
661  if (inKey)
663  escape_json(buf, jspGetString(v, NULL));
664  break;
665  case jpiCurrent:
666  Assert(!inKey);
668  break;
669  case jpiRoot:
670  Assert(!inKey);
672  break;
673  case jpiVariable:
675  escape_json(buf, jspGetString(v, NULL));
676  break;
677  case jpiFilter:
679  jspGetArg(v, &elem);
680  printJsonPathItem(buf, &elem, false, false);
682  break;
683  case jpiExists:
684  appendStringInfoString(buf, "exists (");
685  jspGetArg(v, &elem);
686  printJsonPathItem(buf, &elem, false, false);
688  break;
689  case jpiType:
690  appendStringInfoString(buf, ".type()");
691  break;
692  case jpiSize:
693  appendStringInfoString(buf, ".size()");
694  break;
695  case jpiAbs:
696  appendStringInfoString(buf, ".abs()");
697  break;
698  case jpiFloor:
699  appendStringInfoString(buf, ".floor()");
700  break;
701  case jpiCeiling:
702  appendStringInfoString(buf, ".ceiling()");
703  break;
704  case jpiDouble:
705  appendStringInfoString(buf, ".double()");
706  break;
707  case jpiDatetime:
708  appendStringInfoString(buf, ".datetime(");
709  if (v->content.arg)
710  {
711  jspGetArg(v, &elem);
712  printJsonPathItem(buf, &elem, false, false);
713  }
715  break;
716  case jpiKeyValue:
717  appendStringInfoString(buf, ".keyvalue()");
718  break;
719  case jpiLast:
720  appendStringInfoString(buf, "last");
721  break;
722  case jpiLikeRegex:
723  if (printBracketes)
725 
726  jspInitByBuffer(&elem, v->base, v->content.like_regex.expr);
727  printJsonPathItem(buf, &elem, false,
728  operationPriority(elem.type) <=
729  operationPriority(v->type));
730 
731  appendStringInfoString(buf, " like_regex ");
732 
733  escape_json(buf, v->content.like_regex.pattern);
734 
735  if (v->content.like_regex.flags)
736  {
737  appendStringInfoString(buf, " flag \"");
738 
739  if (v->content.like_regex.flags & JSP_REGEX_ICASE)
741  if (v->content.like_regex.flags & JSP_REGEX_DOTALL)
743  if (v->content.like_regex.flags & JSP_REGEX_MLINE)
745  if (v->content.like_regex.flags & JSP_REGEX_WSPACE)
747  if (v->content.like_regex.flags & JSP_REGEX_QUOTE)
749 
751  }
752 
753  if (printBracketes)
755  break;
756  case jpiBigint:
757  appendStringInfoString(buf, ".bigint()");
758  break;
759  case jpiBoolean:
760  appendStringInfoString(buf, ".boolean()");
761  break;
762  case jpiDate:
763  appendStringInfoString(buf, ".date()");
764  break;
765  case jpiDecimal:
766  appendStringInfoString(buf, ".decimal(");
767  if (v->content.args.left)
768  {
769  jspGetLeftArg(v, &elem);
770  printJsonPathItem(buf, &elem, false, false);
771  }
772  if (v->content.args.right)
773  {
775  jspGetRightArg(v, &elem);
776  printJsonPathItem(buf, &elem, false, false);
777  }
779  break;
780  case jpiInteger:
781  appendStringInfoString(buf, ".integer()");
782  break;
783  case jpiNumber:
784  appendStringInfoString(buf, ".number()");
785  break;
786  case jpiStringFunc:
787  appendStringInfoString(buf, ".string()");
788  break;
789  case jpiTime:
790  appendStringInfoString(buf, ".time(");
791  if (v->content.arg)
792  {
793  jspGetArg(v, &elem);
794  printJsonPathItem(buf, &elem, false, false);
795  }
797  break;
798  case jpiTimeTz:
799  appendStringInfoString(buf, ".time_tz(");
800  if (v->content.arg)
801  {
802  jspGetArg(v, &elem);
803  printJsonPathItem(buf, &elem, false, false);
804  }
806  break;
807  case jpiTimestamp:
808  appendStringInfoString(buf, ".timestamp(");
809  if (v->content.arg)
810  {
811  jspGetArg(v, &elem);
812  printJsonPathItem(buf, &elem, false, false);
813  }
815  break;
816  case jpiTimestampTz:
817  appendStringInfoString(buf, ".timestamp_tz(");
818  if (v->content.arg)
819  {
820  jspGetArg(v, &elem);
821  printJsonPathItem(buf, &elem, false, false);
822  }
824  break;
825  default:
826  elog(ERROR, "unrecognized jsonpath item type: %d", v->type);
827  }
828 
829  if (jspGetNext(v, &elem))
830  printJsonPathItem(buf, &elem, true, true);
831 }
832 
833 const char *
835 {
836  switch (type)
837  {
838  case jpiAnd:
839  return "&&";
840  case jpiOr:
841  return "||";
842  case jpiEqual:
843  return "==";
844  case jpiNotEqual:
845  return "!=";
846  case jpiLess:
847  return "<";
848  case jpiGreater:
849  return ">";
850  case jpiLessOrEqual:
851  return "<=";
852  case jpiGreaterOrEqual:
853  return ">=";
854  case jpiAdd:
855  case jpiPlus:
856  return "+";
857  case jpiSub:
858  case jpiMinus:
859  return "-";
860  case jpiMul:
861  return "*";
862  case jpiDiv:
863  return "/";
864  case jpiMod:
865  return "%";
866  case jpiType:
867  return "type";
868  case jpiSize:
869  return "size";
870  case jpiAbs:
871  return "abs";
872  case jpiFloor:
873  return "floor";
874  case jpiCeiling:
875  return "ceiling";
876  case jpiDouble:
877  return "double";
878  case jpiDatetime:
879  return "datetime";
880  case jpiKeyValue:
881  return "keyvalue";
882  case jpiStartsWith:
883  return "starts with";
884  case jpiLikeRegex:
885  return "like_regex";
886  case jpiBigint:
887  return "bigint";
888  case jpiBoolean:
889  return "boolean";
890  case jpiDate:
891  return "date";
892  case jpiDecimal:
893  return "decimal";
894  case jpiInteger:
895  return "integer";
896  case jpiNumber:
897  return "number";
898  case jpiStringFunc:
899  return "string";
900  case jpiTime:
901  return "time";
902  case jpiTimeTz:
903  return "time_tz";
904  case jpiTimestamp:
905  return "timestamp";
906  case jpiTimestampTz:
907  return "timestamp_tz";
908  default:
909  elog(ERROR, "unrecognized jsonpath item type: %d", type);
910  return NULL;
911  }
912 }
913 
914 static int
916 {
917  switch (op)
918  {
919  case jpiOr:
920  return 0;
921  case jpiAnd:
922  return 1;
923  case jpiEqual:
924  case jpiNotEqual:
925  case jpiLess:
926  case jpiGreater:
927  case jpiLessOrEqual:
928  case jpiGreaterOrEqual:
929  case jpiStartsWith:
930  return 2;
931  case jpiAdd:
932  case jpiSub:
933  return 3;
934  case jpiMul:
935  case jpiDiv:
936  case jpiMod:
937  return 4;
938  case jpiPlus:
939  case jpiMinus:
940  return 5;
941  default:
942  return 6;
943  }
944 }
945 
946 /******************* Support functions for JsonPath *************************/
947 
948 /*
949  * Support macros to read stored values
950  */
951 
952 #define read_byte(v, b, p) do { \
953  (v) = *(uint8*)((b) + (p)); \
954  (p) += 1; \
955 } while(0) \
956 
957 #define read_int32(v, b, p) do { \
958  (v) = *(uint32*)((b) + (p)); \
959  (p) += sizeof(int32); \
960 } while(0) \
961 
962 #define read_int32_n(v, b, p, n) do { \
963  (v) = (void *)((b) + (p)); \
964  (p) += sizeof(int32) * (n); \
965 } while(0) \
966 
967 /*
968  * Read root node and fill root node representation
969  */
970 void
972 {
974  jspInitByBuffer(v, js->data, 0);
975 }
976 
977 /*
978  * Read node from buffer and fill its representation
979  */
980 void
981 jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
982 {
983  v->base = base + pos;
984 
985  read_byte(v->type, base, pos);
986  pos = INTALIGN((uintptr_t) (base + pos)) - (uintptr_t) base;
987  read_int32(v->nextPos, base, pos);
988 
989  switch (v->type)
990  {
991  case jpiNull:
992  case jpiRoot:
993  case jpiCurrent:
994  case jpiAnyArray:
995  case jpiAnyKey:
996  case jpiType:
997  case jpiSize:
998  case jpiAbs:
999  case jpiFloor:
1000  case jpiCeiling:
1001  case jpiDouble:
1002  case jpiKeyValue:
1003  case jpiLast:
1004  case jpiBigint:
1005  case jpiBoolean:
1006  case jpiDate:
1007  case jpiInteger:
1008  case jpiNumber:
1009  case jpiStringFunc:
1010  break;
1011  case jpiString:
1012  case jpiKey:
1013  case jpiVariable:
1014  read_int32(v->content.value.datalen, base, pos);
1015  /* FALLTHROUGH */
1016  case jpiNumeric:
1017  case jpiBool:
1018  v->content.value.data = base + pos;
1019  break;
1020  case jpiAnd:
1021  case jpiOr:
1022  case jpiEqual:
1023  case jpiNotEqual:
1024  case jpiLess:
1025  case jpiGreater:
1026  case jpiLessOrEqual:
1027  case jpiGreaterOrEqual:
1028  case jpiAdd:
1029  case jpiSub:
1030  case jpiMul:
1031  case jpiDiv:
1032  case jpiMod:
1033  case jpiStartsWith:
1034  case jpiDecimal:
1035  read_int32(v->content.args.left, base, pos);
1036  read_int32(v->content.args.right, base, pos);
1037  break;
1038  case jpiNot:
1039  case jpiIsUnknown:
1040  case jpiExists:
1041  case jpiPlus:
1042  case jpiMinus:
1043  case jpiFilter:
1044  case jpiDatetime:
1045  case jpiTime:
1046  case jpiTimeTz:
1047  case jpiTimestamp:
1048  case jpiTimestampTz:
1049  read_int32(v->content.arg, base, pos);
1050  break;
1051  case jpiIndexArray:
1052  read_int32(v->content.array.nelems, base, pos);
1053  read_int32_n(v->content.array.elems, base, pos,
1054  v->content.array.nelems * 2);
1055  break;
1056  case jpiAny:
1057  read_int32(v->content.anybounds.first, base, pos);
1058  read_int32(v->content.anybounds.last, base, pos);
1059  break;
1060  case jpiLikeRegex:
1061  read_int32(v->content.like_regex.flags, base, pos);
1062  read_int32(v->content.like_regex.expr, base, pos);
1063  read_int32(v->content.like_regex.patternlen, base, pos);
1064  v->content.like_regex.pattern = base + pos;
1065  break;
1066  default:
1067  elog(ERROR, "unrecognized jsonpath item type: %d", v->type);
1068  }
1069 }
1070 
1071 void
1073 {
1074  Assert(v->type == jpiNot ||
1075  v->type == jpiIsUnknown ||
1076  v->type == jpiPlus ||
1077  v->type == jpiMinus ||
1078  v->type == jpiFilter ||
1079  v->type == jpiExists ||
1080  v->type == jpiDatetime ||
1081  v->type == jpiTime ||
1082  v->type == jpiTimeTz ||
1083  v->type == jpiTimestamp ||
1084  v->type == jpiTimestampTz);
1085 
1086  jspInitByBuffer(a, v->base, v->content.arg);
1087 }
1088 
1089 bool
1091 {
1092  if (jspHasNext(v))
1093  {
1094  Assert(v->type == jpiNull ||
1095  v->type == jpiString ||
1096  v->type == jpiNumeric ||
1097  v->type == jpiBool ||
1098  v->type == jpiAnd ||
1099  v->type == jpiOr ||
1100  v->type == jpiNot ||
1101  v->type == jpiIsUnknown ||
1102  v->type == jpiEqual ||
1103  v->type == jpiNotEqual ||
1104  v->type == jpiLess ||
1105  v->type == jpiGreater ||
1106  v->type == jpiLessOrEqual ||
1107  v->type == jpiGreaterOrEqual ||
1108  v->type == jpiAdd ||
1109  v->type == jpiSub ||
1110  v->type == jpiMul ||
1111  v->type == jpiDiv ||
1112  v->type == jpiMod ||
1113  v->type == jpiPlus ||
1114  v->type == jpiMinus ||
1115  v->type == jpiAnyArray ||
1116  v->type == jpiAnyKey ||
1117  v->type == jpiIndexArray ||
1118  v->type == jpiAny ||
1119  v->type == jpiKey ||
1120  v->type == jpiCurrent ||
1121  v->type == jpiRoot ||
1122  v->type == jpiVariable ||
1123  v->type == jpiFilter ||
1124  v->type == jpiExists ||
1125  v->type == jpiType ||
1126  v->type == jpiSize ||
1127  v->type == jpiAbs ||
1128  v->type == jpiFloor ||
1129  v->type == jpiCeiling ||
1130  v->type == jpiDouble ||
1131  v->type == jpiDatetime ||
1132  v->type == jpiKeyValue ||
1133  v->type == jpiLast ||
1134  v->type == jpiStartsWith ||
1135  v->type == jpiLikeRegex ||
1136  v->type == jpiBigint ||
1137  v->type == jpiBoolean ||
1138  v->type == jpiDate ||
1139  v->type == jpiDecimal ||
1140  v->type == jpiInteger ||
1141  v->type == jpiNumber ||
1142  v->type == jpiStringFunc ||
1143  v->type == jpiTime ||
1144  v->type == jpiTimeTz ||
1145  v->type == jpiTimestamp ||
1146  v->type == jpiTimestampTz);
1147 
1148  if (a)
1149  jspInitByBuffer(a, v->base, v->nextPos);
1150  return true;
1151  }
1152 
1153  return false;
1154 }
1155 
1156 void
1158 {
1159  Assert(v->type == jpiAnd ||
1160  v->type == jpiOr ||
1161  v->type == jpiEqual ||
1162  v->type == jpiNotEqual ||
1163  v->type == jpiLess ||
1164  v->type == jpiGreater ||
1165  v->type == jpiLessOrEqual ||
1166  v->type == jpiGreaterOrEqual ||
1167  v->type == jpiAdd ||
1168  v->type == jpiSub ||
1169  v->type == jpiMul ||
1170  v->type == jpiDiv ||
1171  v->type == jpiMod ||
1172  v->type == jpiStartsWith ||
1173  v->type == jpiDecimal);
1174 
1175  jspInitByBuffer(a, v->base, v->content.args.left);
1176 }
1177 
1178 void
1180 {
1181  Assert(v->type == jpiAnd ||
1182  v->type == jpiOr ||
1183  v->type == jpiEqual ||
1184  v->type == jpiNotEqual ||
1185  v->type == jpiLess ||
1186  v->type == jpiGreater ||
1187  v->type == jpiLessOrEqual ||
1188  v->type == jpiGreaterOrEqual ||
1189  v->type == jpiAdd ||
1190  v->type == jpiSub ||
1191  v->type == jpiMul ||
1192  v->type == jpiDiv ||
1193  v->type == jpiMod ||
1194  v->type == jpiStartsWith ||
1195  v->type == jpiDecimal);
1196 
1197  jspInitByBuffer(a, v->base, v->content.args.right);
1198 }
1199 
1200 bool
1202 {
1203  Assert(v->type == jpiBool);
1204 
1205  return (bool) *v->content.value.data;
1206 }
1207 
1208 Numeric
1210 {
1211  Assert(v->type == jpiNumeric);
1212 
1213  return (Numeric) v->content.value.data;
1214 }
1215 
1216 char *
1218 {
1219  Assert(v->type == jpiKey ||
1220  v->type == jpiString ||
1221  v->type == jpiVariable);
1222 
1223  if (len)
1224  *len = v->content.value.datalen;
1225  return v->content.value.data;
1226 }
1227 
1228 bool
1230  int i)
1231 {
1232  Assert(v->type == jpiIndexArray);
1233 
1234  jspInitByBuffer(from, v->base, v->content.array.elems[i].from);
1235 
1236  if (!v->content.array.elems[i].to)
1237  return false;
1238 
1239  jspInitByBuffer(to, v->base, v->content.array.elems[i].to);
1240 
1241  return true;
1242 }
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:806
static int32 next
Definition: blutils.c:221
#define INTALIGN(LEN)
Definition: c.h:797
#define PG_UINT32_MAX
Definition: c.h:579
signed int int32
Definition: c.h:483
int errcode(int sqlerrcode)
Definition: elog.c:860
int errmsg(const char *fmt,...)
Definition: elog.c:1075
#define ereturn(context, dummy_value,...)
Definition: elog.h:276
#define ERROR
Definition: elog.h:39
#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:1549
void jspGetLeftArg(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:1157
void jspGetArg(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:1072
static Datum jsonPathFromCstring(char *in, int len, struct Node *escontext)
Definition: jsonpath.c:171
Datum jsonpath_send(PG_FUNCTION_ARGS)
Definition: jsonpath.c:145
#define read_byte(v, b, p)
Definition: jsonpath.c:952
#define read_int32_n(v, b, p, n)
Definition: jsonpath.c:962
Datum jsonpath_out(PG_FUNCTION_ARGS)
Definition: jsonpath.c:132
static void alignStringInfoInt(StringInfo buf)
Definition: jsonpath.c:482
void jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
Definition: jsonpath.c:981
bool jspGetBool(JsonPathItem *v)
Definition: jsonpath.c:1201
void jspInit(JsonPathItem *v, JsonPath *js)
Definition: jsonpath.c:971
static bool flattenJsonPathParseItem(StringInfo buf, int *result, struct Node *escontext, JsonPathParseItem *item, int nestingLevel, bool insideArraySubscript)
Definition: jsonpath.c:237
const char * jspOperationName(JsonPathItemType type)
Definition: jsonpath.c:834
Numeric jspGetNumeric(JsonPathItem *v)
Definition: jsonpath.c:1209
bool jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from, JsonPathItem *to, int i)
Definition: jsonpath.c:1229
static void printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey, bool printBracketes)
Definition: jsonpath.c:519
#define read_int32(v, b, p)
Definition: jsonpath.c:957
bool jspGetNext(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:1090
static int operationPriority(JsonPathItemType op)
Definition: jsonpath.c:915
Datum jsonpath_recv(PG_FUNCTION_ARGS)
Definition: jsonpath.c:113
Datum jsonpath_in(PG_FUNCTION_ARGS)
Definition: jsonpath.c:96
void jspGetRightArg(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:1179
char * jspGetString(JsonPathItem *v, int32 *len)
Definition: jsonpath.c:1217
static int32 reserveSpaceForItemPointer(StringInfo buf)
Definition: jsonpath.c:505
static char * jsonPathToCstring(StringInfo out, JsonPath *in, int estimated_len)
Definition: jsonpath.c:211
#define JSP_REGEX_WSPACE
Definition: jsonpath.h:122
#define JSP_REGEX_MLINE
Definition: jsonpath.h:121
#define PG_RETURN_JSONPATH_P(p)
Definition: jsonpath.h:46
#define JSP_REGEX_ICASE
Definition: jsonpath.h:119
JsonPathParseResult * parsejsonpath(const char *str, int len, struct Node *escontext)
#define jspHasNext(jsp)
Definition: jsonpath.h:192
#define PG_GETARG_JSONPATH_P(x)
Definition: jsonpath.h:44
#define JSONPATH_VERSION
Definition: jsonpath.h:28
#define JSP_REGEX_DOTALL
Definition: jsonpath.h:120
JsonPathItemType
Definition: jsonpath.h:61
@ jpiAdd
Definition: jsonpath.h:76
@ jpiString
Definition: jsonpath.h:63
@ jpiAbs
Definition: jsonpath.h:95
@ jpiIndexArray
Definition: jsonpath.h:85
@ jpiAny
Definition: jsonpath.h:86
@ jpiDatetime
Definition: jsonpath.h:99
@ jpiBigint
Definition: jsonpath.h:105
@ jpiBool
Definition: jsonpath.h:65
@ jpiType
Definition: jsonpath.h:93
@ jpiFloor
Definition: jsonpath.h:96
@ jpiAnyArray
Definition: jsonpath.h:83
@ jpiExists
Definition: jsonpath.h:92
@ jpiSize
Definition: jsonpath.h:94
@ jpiSub
Definition: jsonpath.h:77
@ jpiNotEqual
Definition: jsonpath.h:71
@ jpiMul
Definition: jsonpath.h:78
@ jpiVariable
Definition: jsonpath.h:90
@ jpiTimeTz
Definition: jsonpath.h:113
@ jpiNot
Definition: jsonpath.h:68
@ jpiDate
Definition: jsonpath.h:107
@ jpiGreaterOrEqual
Definition: jsonpath.h:75
@ jpiPlus
Definition: jsonpath.h:81
@ jpiDouble
Definition: jsonpath.h:98
@ jpiGreater
Definition: jsonpath.h:73
@ jpiNumber
Definition: jsonpath.h:110
@ jpiAnd
Definition: jsonpath.h:66
@ jpiStartsWith
Definition: jsonpath.h:103
@ jpiOr
Definition: jsonpath.h:67
@ jpiMod
Definition: jsonpath.h:80
@ jpiTimestamp
Definition: jsonpath.h:114
@ jpiLikeRegex
Definition: jsonpath.h:104
@ jpiTimestampTz
Definition: jsonpath.h:115
@ jpiInteger
Definition: jsonpath.h:109
@ jpiRoot
Definition: jsonpath.h:89
@ jpiFilter
Definition: jsonpath.h:91
@ jpiNull
Definition: jsonpath.h:62
@ jpiLess
Definition: jsonpath.h:72
@ jpiCurrent
Definition: jsonpath.h:88
@ jpiEqual
Definition: jsonpath.h:70
@ jpiKey
Definition: jsonpath.h:87
@ jpiDiv
Definition: jsonpath.h:79
@ jpiTime
Definition: jsonpath.h:112
@ jpiLast
Definition: jsonpath.h:102
@ jpiMinus
Definition: jsonpath.h:82
@ jpiLessOrEqual
Definition: jsonpath.h:74
@ jpiCeiling
Definition: jsonpath.h:97
@ jpiIsUnknown
Definition: jsonpath.h:69
@ jpiKeyValue
Definition: jsonpath.h:100
@ jpiNumeric
Definition: jsonpath.h:64
@ jpiBoolean
Definition: jsonpath.h:106
@ jpiStringFunc
Definition: jsonpath.h:111
@ jpiDecimal
Definition: jsonpath.h:108
@ jpiAnyKey
Definition: jsonpath.h:84
#define JSONPATH_LAX
Definition: jsonpath.h:29
#define JSONPATH_HDRSZ
Definition: jsonpath.h:30
#define JSP_REGEX_QUOTE
Definition: jsonpath.h:123
Assert(fmt[strlen(fmt) - 1] !='\n')
void pfree(void *pointer)
Definition: mcxt.c:1431
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
#define SOFT_ERROR_OCCURRED(escontext)
Definition: miscnodes.h:52
static Datum NumericGetDatum(Numeric X)
Definition: numeric.h:72
void * arg
const void size_t len
static char * buf
Definition: pg_test_fsync.c:73
void check_stack_depth(void)
Definition: postgres.c:3523
static char * DatumGetCString(Datum X)
Definition: postgres.h:335
uintptr_t Datum
Definition: postgres.h:64
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:418
void pq_sendtext(StringInfo buf, const char *str, int slen)
Definition: pqformat.c:175
char * pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes)
Definition: pqformat.c:549
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:329
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:349
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:97
void enlargeStringInfo(StringInfo str, int needed)
Definition: stringinfo.c:289
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:233
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:212
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:182
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
StringInfoData * StringInfo
Definition: stringinfo.h:54
#define appendStringInfoCharMacro(str, ch)
Definition: stringinfo.h:203
struct JsonPathItem::@131::@134 anybounds
struct JsonPathItem::@131::@136 like_regex
char * base
Definition: jsonpath.h:144
int32 nextPos
Definition: jsonpath.h:138
int32 arg
Definition: jsonpath.h:156
JsonPathItemType type
Definition: jsonpath.h:135
struct JsonPathItem::@131::@133 array
struct JsonPathItem::@131::@135 value
union JsonPathItem::@131 content
struct JsonPathItem::@131::@132 args
JsonPathParseItem * arg
Definition: jsonpath.h:230
struct JsonPathParseItem::@138::@141 anybounds
struct JsonPathParseItem::@138::@140 array
JsonPathParseItem * next
Definition: jsonpath.h:217
struct JsonPathParseItem::@138::@143 string
Numeric numeric
Definition: jsonpath.h:259
struct JsonPathParseItem::@138::@139 args
struct JsonPathParseItem::@138::@142 like_regex
JsonPathItemType type
Definition: jsonpath.h:216
union JsonPathParseItem::@138 value
JsonPathParseItem * expr
Definition: jsonpath.h:271
char data[FLEXIBLE_ARRAY_MEMBER]
Definition: jsonpath.h:25
uint32 header
Definition: jsonpath.h:24
Definition: nodes.h:129
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305
#define VARSIZE(PTR)
Definition: varatt.h:279
const char * type