Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * jsonpath.h
4 : * Definitions for jsonpath datatype
5 : *
6 : * Copyright (c) 2019-2024, 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 "executor/tablefunc.h"
18 : #include "fmgr.h"
19 : #include "nodes/pg_list.h"
20 : #include "nodes/primnodes.h"
21 : #include "utils/jsonb.h"
22 :
23 : typedef struct
24 : {
25 : int32 vl_len_; /* varlena header (do not touch directly!) */
26 : uint32 header; /* version and flags (see below) */
27 : char data[FLEXIBLE_ARRAY_MEMBER];
28 : } JsonPath;
29 :
30 : #define JSONPATH_VERSION (0x01)
31 : #define JSONPATH_LAX (0x80000000)
32 : #define JSONPATH_HDRSZ (offsetof(JsonPath, data))
33 :
34 : static inline JsonPath *
35 197366 : DatumGetJsonPathP(Datum d)
36 : {
37 197366 : return (JsonPath *) PG_DETOAST_DATUM(d);
38 : }
39 :
40 : static inline JsonPath *
41 4068 : DatumGetJsonPathPCopy(Datum d)
42 : {
43 4068 : return (JsonPath *) PG_DETOAST_DATUM_COPY(d);
44 : }
45 :
46 : #define PG_GETARG_JSONPATH_P(x) DatumGetJsonPathP(PG_GETARG_DATUM(x))
47 : #define PG_GETARG_JSONPATH_P_COPY(x) DatumGetJsonPathPCopy(PG_GETARG_DATUM(x))
48 : #define PG_RETURN_JSONPATH_P(p) PG_RETURN_POINTER(p)
49 :
50 : #define jspIsScalar(type) ((type) >= jpiNull && (type) <= jpiBool)
51 :
52 : /*
53 : * All node's type of jsonpath expression
54 : *
55 : * These become part of the on-disk representation of the jsonpath type.
56 : * Therefore, to preserve pg_upgradability, the order must not be changed, and
57 : * new values must be added at the end.
58 : *
59 : * It is recommended that switch cases etc. in other parts of the code also
60 : * use this order, to maintain some consistency.
61 : */
62 : typedef enum JsonPathItemType
63 : {
64 : jpiNull = jbvNull, /* NULL literal */
65 : jpiString = jbvString, /* string literal */
66 : jpiNumeric = jbvNumeric, /* numeric literal */
67 : jpiBool = jbvBool, /* boolean literal: TRUE or FALSE */
68 : jpiAnd, /* predicate && predicate */
69 : jpiOr, /* predicate || predicate */
70 : jpiNot, /* ! predicate */
71 : jpiIsUnknown, /* (predicate) IS UNKNOWN */
72 : jpiEqual, /* expr == expr */
73 : jpiNotEqual, /* expr != expr */
74 : jpiLess, /* expr < expr */
75 : jpiGreater, /* expr > expr */
76 : jpiLessOrEqual, /* expr <= expr */
77 : jpiGreaterOrEqual, /* expr >= expr */
78 : jpiAdd, /* expr + expr */
79 : jpiSub, /* expr - expr */
80 : jpiMul, /* expr * expr */
81 : jpiDiv, /* expr / expr */
82 : jpiMod, /* expr % expr */
83 : jpiPlus, /* + expr */
84 : jpiMinus, /* - expr */
85 : jpiAnyArray, /* [*] */
86 : jpiAnyKey, /* .* */
87 : jpiIndexArray, /* [subscript, ...] */
88 : jpiAny, /* .** */
89 : jpiKey, /* .key */
90 : jpiCurrent, /* @ */
91 : jpiRoot, /* $ */
92 : jpiVariable, /* $variable */
93 : jpiFilter, /* ? (predicate) */
94 : jpiExists, /* EXISTS (expr) predicate */
95 : jpiType, /* .type() item method */
96 : jpiSize, /* .size() item method */
97 : jpiAbs, /* .abs() item method */
98 : jpiFloor, /* .floor() item method */
99 : jpiCeiling, /* .ceiling() item method */
100 : jpiDouble, /* .double() item method */
101 : jpiDatetime, /* .datetime() item method */
102 : jpiKeyValue, /* .keyvalue() item method */
103 : jpiSubscript, /* array subscript: 'expr' or 'expr TO expr' */
104 : jpiLast, /* LAST array subscript */
105 : jpiStartsWith, /* STARTS WITH predicate */
106 : jpiLikeRegex, /* LIKE_REGEX predicate */
107 : jpiBigint, /* .bigint() item method */
108 : jpiBoolean, /* .boolean() item method */
109 : jpiDate, /* .date() item method */
110 : jpiDecimal, /* .decimal() item method */
111 : jpiInteger, /* .integer() item method */
112 : jpiNumber, /* .number() item method */
113 : jpiStringFunc, /* .string() item method */
114 : jpiTime, /* .time() item method */
115 : jpiTimeTz, /* .time_tz() item method */
116 : jpiTimestamp, /* .timestamp() item method */
117 : jpiTimestampTz, /* .timestamp_tz() item method */
118 : } JsonPathItemType;
119 :
120 : /* XQuery regex mode flags for LIKE_REGEX predicate */
121 : #define JSP_REGEX_ICASE 0x01 /* i flag, case insensitive */
122 : #define JSP_REGEX_DOTALL 0x02 /* s flag, dot matches newline */
123 : #define JSP_REGEX_MLINE 0x04 /* m flag, ^/$ match at newlines */
124 : #define JSP_REGEX_WSPACE 0x08 /* x flag, ignore whitespace in pattern */
125 : #define JSP_REGEX_QUOTE 0x10 /* q flag, no special characters */
126 :
127 : /*
128 : * Support functions to parse/construct binary value.
129 : * Unlike many other representation of expression the first/main
130 : * node is not an operation but left operand of expression. That
131 : * allows to implement cheap follow-path descending in jsonb
132 : * structure and then execute operator with right operand
133 : */
134 :
135 : typedef struct JsonPathItem
136 : {
137 : JsonPathItemType type;
138 :
139 : /* position form base to next node */
140 : int32 nextPos;
141 :
142 : /*
143 : * pointer into JsonPath value to current node, all positions of current
144 : * are relative to this base
145 : */
146 : char *base;
147 :
148 : union
149 : {
150 : /* classic operator with two operands: and, or etc */
151 : struct
152 : {
153 : int32 left;
154 : int32 right;
155 : } args;
156 :
157 : /* any unary operation */
158 : int32 arg;
159 :
160 : /* storage for jpiIndexArray: indexes of array */
161 : struct
162 : {
163 : int32 nelems;
164 : struct
165 : {
166 : int32 from;
167 : int32 to;
168 : } *elems;
169 : } array;
170 :
171 : /* jpiAny: levels */
172 : struct
173 : {
174 : uint32 first;
175 : uint32 last;
176 : } anybounds;
177 :
178 : struct
179 : {
180 : char *data; /* for bool, numeric and string/key */
181 : int32 datalen; /* filled only for string/key */
182 : } value;
183 :
184 : struct
185 : {
186 : int32 expr;
187 : char *pattern;
188 : int32 patternlen;
189 : uint32 flags;
190 : } like_regex;
191 : } content;
192 : } JsonPathItem;
193 :
194 : #define jspHasNext(jsp) ((jsp)->nextPos > 0)
195 :
196 : extern void jspInit(JsonPathItem *v, JsonPath *js);
197 : extern void jspInitByBuffer(JsonPathItem *v, char *base, int32 pos);
198 : extern bool jspGetNext(JsonPathItem *v, JsonPathItem *a);
199 : extern void jspGetArg(JsonPathItem *v, JsonPathItem *a);
200 : extern void jspGetLeftArg(JsonPathItem *v, JsonPathItem *a);
201 : extern void jspGetRightArg(JsonPathItem *v, JsonPathItem *a);
202 : extern Numeric jspGetNumeric(JsonPathItem *v);
203 : extern bool jspGetBool(JsonPathItem *v);
204 : extern char *jspGetString(JsonPathItem *v, int32 *len);
205 : extern bool jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from,
206 : JsonPathItem *to, int i);
207 : extern bool jspIsMutable(JsonPath *path, List *varnames, List *varexprs);
208 :
209 : extern const char *jspOperationName(JsonPathItemType type);
210 :
211 : /*
212 : * Parsing support data structures.
213 : */
214 :
215 : typedef struct JsonPathParseItem JsonPathParseItem;
216 :
217 : struct JsonPathParseItem
218 : {
219 : JsonPathItemType type;
220 : JsonPathParseItem *next; /* next in path */
221 :
222 : union
223 : {
224 :
225 : /* classic operator with two operands: and, or etc */
226 : struct
227 : {
228 : JsonPathParseItem *left;
229 : JsonPathParseItem *right;
230 : } args;
231 :
232 : /* any unary operation */
233 : JsonPathParseItem *arg;
234 :
235 : /* storage for jpiIndexArray: indexes of array */
236 : struct
237 : {
238 : int nelems;
239 : struct
240 : {
241 : JsonPathParseItem *from;
242 : JsonPathParseItem *to;
243 : } *elems;
244 : } array;
245 :
246 : /* jpiAny: levels */
247 : struct
248 : {
249 : uint32 first;
250 : uint32 last;
251 : } anybounds;
252 :
253 : struct
254 : {
255 : JsonPathParseItem *expr;
256 : char *pattern; /* could not be not null-terminated */
257 : uint32 patternlen;
258 : uint32 flags;
259 : } like_regex;
260 :
261 : /* scalars */
262 : Numeric numeric;
263 : bool boolean;
264 : struct
265 : {
266 : uint32 len;
267 : char *val; /* could not be not null-terminated */
268 : } string;
269 : } value;
270 : };
271 :
272 : typedef struct JsonPathParseResult
273 : {
274 : JsonPathParseItem *expr;
275 : bool lax;
276 : } JsonPathParseResult;
277 :
278 : extern JsonPathParseResult *parsejsonpath(const char *str, int len,
279 : struct Node *escontext);
280 :
281 : extern bool jspConvertRegexFlags(uint32 xflags, int *result,
282 : struct Node *escontext);
283 :
284 : /*
285 : * Struct for details about external variables passed into jsonpath executor
286 : */
287 : typedef struct JsonPathVariable
288 : {
289 : char *name;
290 : int namelen; /* strlen(name) as cache for GetJsonPathVar() */
291 : Oid typid;
292 : int32 typmod;
293 : Datum value;
294 : bool isnull;
295 : } JsonPathVariable;
296 :
297 :
298 : /* SQL/JSON query functions */
299 : extern bool JsonPathExists(Datum jb, JsonPath *jp, bool *error, List *vars);
300 : extern Datum JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper,
301 : bool *empty, bool *error, List *vars,
302 : const char *column_name);
303 : extern JsonbValue *JsonPathValue(Datum jb, JsonPath *jp, bool *empty,
304 : bool *error, List *vars,
305 : const char *column_name);
306 :
307 : /* For JSON_TABLE() */
308 : extern PGDLLIMPORT const TableFuncRoutine JsonbTableRoutine;
309 :
310 : #endif
|