1/*-------------------------------------------------------------------------
2 *
3 * jsonpath.h
4 * Definitions for jsonpath datatype
5 *
6 * Copyright (c) 2019, PostgreSQL Global Development Group
7 *
8 * IDENTIFICATION
9 * src/include/utils/jsonpath.h
10 *
11 *-------------------------------------------------------------------------
12 */
13
14#ifndef JSONPATH_H
15#define JSONPATH_H
16
17#include "fmgr.h"
18#include "utils/jsonb.h"
19#include "nodes/pg_list.h"
20
21typedef struct
22{
23 int32 vl_len_; /* varlena header (do not touch directly!) */
24 uint32 header; /* version and flags (see below) */
25 char data[FLEXIBLE_ARRAY_MEMBER];
26} JsonPath;
27
28#define JSONPATH_VERSION (0x01)
29#define JSONPATH_LAX (0x80000000)
30#define JSONPATH_HDRSZ (offsetof(JsonPath, data))
31
32#define DatumGetJsonPathP(d) ((JsonPath *) DatumGetPointer(PG_DETOAST_DATUM(d)))
33#define DatumGetJsonPathPCopy(d) ((JsonPath *) DatumGetPointer(PG_DETOAST_DATUM_COPY(d)))
34#define PG_GETARG_JSONPATH_P(x) DatumGetJsonPathP(PG_GETARG_DATUM(x))
35#define PG_GETARG_JSONPATH_P_COPY(x) DatumGetJsonPathPCopy(PG_GETARG_DATUM(x))
36#define PG_RETURN_JSONPATH_P(p) PG_RETURN_POINTER(p)
37
38#define jspIsScalar(type) ((type) >= jpiNull && (type) <= jpiBool)
39
40/*
41 * All node's type of jsonpath expression
42 */
43typedef enum JsonPathItemType
44{
45 jpiNull = jbvNull, /* NULL literal */
46 jpiString = jbvString, /* string literal */
47 jpiNumeric = jbvNumeric, /* numeric literal */
48 jpiBool = jbvBool, /* boolean literal: TRUE or FALSE */
49 jpiAnd, /* predicate && predicate */
50 jpiOr, /* predicate || predicate */
51 jpiNot, /* ! predicate */
52 jpiIsUnknown, /* (predicate) IS UNKNOWN */
53 jpiEqual, /* expr == expr */
54 jpiNotEqual, /* expr != expr */
55 jpiLess, /* expr < expr */
56 jpiGreater, /* expr > expr */
57 jpiLessOrEqual, /* expr <= expr */
58 jpiGreaterOrEqual, /* expr >= expr */
59 jpiAdd, /* expr + expr */
60 jpiSub, /* expr - expr */
61 jpiMul, /* expr * expr */
62 jpiDiv, /* expr / expr */
63 jpiMod, /* expr % expr */
64 jpiPlus, /* + expr */
65 jpiMinus, /* - expr */
66 jpiAnyArray, /* [*] */
67 jpiAnyKey, /* .* */
68 jpiIndexArray, /* [subscript, ...] */
69 jpiAny, /* .** */
70 jpiKey, /* .key */
71 jpiCurrent, /* @ */
72 jpiRoot, /* $ */
73 jpiVariable, /* $variable */
74 jpiFilter, /* ? (predicate) */
75 jpiExists, /* EXISTS (expr) predicate */
76 jpiType, /* .type() item method */
77 jpiSize, /* .size() item method */
78 jpiAbs, /* .abs() item method */
79 jpiFloor, /* .floor() item method */
80 jpiCeiling, /* .ceiling() item method */
81 jpiDouble, /* .double() item method */
82 jpiKeyValue, /* .keyvalue() item method */
83 jpiSubscript, /* array subscript: 'expr' or 'expr TO expr' */
84 jpiLast, /* LAST array subscript */
85 jpiStartsWith, /* STARTS WITH predicate */
86 jpiLikeRegex, /* LIKE_REGEX predicate */
87} JsonPathItemType;
88
89/* XQuery regex mode flags for LIKE_REGEX predicate */
90#define JSP_REGEX_ICASE 0x01 /* i flag, case insensitive */
91#define JSP_REGEX_DOTALL 0x02 /* s flag, dot matches newline */
92#define JSP_REGEX_MLINE 0x04 /* m flag, ^/$ match at newlines */
93#define JSP_REGEX_WSPACE 0x08 /* x flag, ignore whitespace in pattern */
94#define JSP_REGEX_QUOTE 0x10 /* q flag, no special characters */
95
96/*
97 * Support functions to parse/construct binary value.
98 * Unlike many other representation of expression the first/main
99 * node is not an operation but left operand of expression. That
100 * allows to implement cheap follow-path descending in jsonb
101 * structure and then execute operator with right operand
102 */
103
104typedef struct JsonPathItem
105{
106 JsonPathItemType type;
107
108 /* position form base to next node */
109 int32 nextPos;
110
111 /*
112 * pointer into JsonPath value to current node, all positions of current
113 * are relative to this base
114 */
115 char *base;
116
117 union
118 {
119 /* classic operator with two operands: and, or etc */
120 struct
121 {
122 int32 left;
123 int32 right;
124 } args;
125
126 /* any unary operation */
127 int32 arg;
128
129 /* storage for jpiIndexArray: indexes of array */
130 struct
131 {
132 int32 nelems;
133 struct
134 {
135 int32 from;
136 int32 to;
137 } *elems;
138 } array;
139
140 /* jpiAny: levels */
141 struct
142 {
143 uint32 first;
144 uint32 last;
145 } anybounds;
146
147 struct
148 {
149 char *data; /* for bool, numeric and string/key */
150 int32 datalen; /* filled only for string/key */
151 } value;
152
153 struct
154 {
155 int32 expr;
156 char *pattern;
157 int32 patternlen;
158 uint32 flags;
159 } like_regex;
160 } content;
161} JsonPathItem;
162
163#define jspHasNext(jsp) ((jsp)->nextPos > 0)
164
165extern void jspInit(JsonPathItem *v, JsonPath *js);
166extern void jspInitByBuffer(JsonPathItem *v, char *base, int32 pos);
167extern bool jspGetNext(JsonPathItem *v, JsonPathItem *a);
168extern void jspGetArg(JsonPathItem *v, JsonPathItem *a);
169extern void jspGetLeftArg(JsonPathItem *v, JsonPathItem *a);
170extern void jspGetRightArg(JsonPathItem *v, JsonPathItem *a);
171extern Numeric jspGetNumeric(JsonPathItem *v);
172extern bool jspGetBool(JsonPathItem *v);
173extern char *jspGetString(JsonPathItem *v, int32 *len);
174extern bool jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from,
175 JsonPathItem *to, int i);
176
177extern const char *jspOperationName(JsonPathItemType type);
178
179/*
180 * Parsing support data structures.
181 */
182
183typedef struct JsonPathParseItem JsonPathParseItem;
184
185struct JsonPathParseItem
186{
187 JsonPathItemType type;
188 JsonPathParseItem *next; /* next in path */
189
190 union
191 {
192
193 /* classic operator with two operands: and, or etc */
194 struct
195 {
196 JsonPathParseItem *left;
197 JsonPathParseItem *right;
198 } args;
199
200 /* any unary operation */
201 JsonPathParseItem *arg;
202
203 /* storage for jpiIndexArray: indexes of array */
204 struct
205 {
206 int nelems;
207 struct
208 {
209 JsonPathParseItem *from;
210 JsonPathParseItem *to;
211 } *elems;
212 } array;
213
214 /* jpiAny: levels */
215 struct
216 {
217 uint32 first;
218 uint32 last;
219 } anybounds;
220
221 struct
222 {
223 JsonPathParseItem *expr;
224 char *pattern; /* could not be not null-terminated */
225 uint32 patternlen;
226 uint32 flags;
227 } like_regex;
228
229 /* scalars */
230 Numeric numeric;
231 bool boolean;
232 struct
233 {
234 uint32 len;
235 char *val; /* could not be not null-terminated */
236 } string;
237 } value;
238};
239
240typedef struct JsonPathParseResult
241{
242 JsonPathParseItem *expr;
243 bool lax;
244} JsonPathParseResult;
245
246extern JsonPathParseResult *parsejsonpath(const char *str, int len);
247
248extern int jspConvertRegexFlags(uint32 xflags);
249
250#endif
251