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 | |
21 | typedef struct |
22 | { |
23 | int32 vl_len_; /* varlena header (do not touch directly!) */ |
24 | uint32 ; /* 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 | */ |
43 | typedef 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 | |
104 | typedef 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 | |
165 | extern void jspInit(JsonPathItem *v, JsonPath *js); |
166 | extern void jspInitByBuffer(JsonPathItem *v, char *base, int32 pos); |
167 | extern bool jspGetNext(JsonPathItem *v, JsonPathItem *a); |
168 | extern void jspGetArg(JsonPathItem *v, JsonPathItem *a); |
169 | extern void jspGetLeftArg(JsonPathItem *v, JsonPathItem *a); |
170 | extern void jspGetRightArg(JsonPathItem *v, JsonPathItem *a); |
171 | extern Numeric jspGetNumeric(JsonPathItem *v); |
172 | extern bool jspGetBool(JsonPathItem *v); |
173 | extern char *jspGetString(JsonPathItem *v, int32 *len); |
174 | extern bool jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from, |
175 | JsonPathItem *to, int i); |
176 | |
177 | extern const char *jspOperationName(JsonPathItemType type); |
178 | |
179 | /* |
180 | * Parsing support data structures. |
181 | */ |
182 | |
183 | typedef struct JsonPathParseItem JsonPathParseItem; |
184 | |
185 | struct 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 | |
240 | typedef struct JsonPathParseResult |
241 | { |
242 | JsonPathParseItem *expr; |
243 | bool lax; |
244 | } JsonPathParseResult; |
245 | |
246 | extern JsonPathParseResult *parsejsonpath(const char *str, int len); |
247 | |
248 | extern int jspConvertRegexFlags(uint32 xflags); |
249 | |
250 | #endif |
251 | |