Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * jsonpath.h
4 : * Definitions for jsonpath datatype
5 : *
6 : * Copyright (c) 2019-2026, 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 131929 : DatumGetJsonPathP(Datum d)
36 : {
37 131929 : return (JsonPath *) PG_DETOAST_DATUM(d);
38 : }
39 :
40 : static inline JsonPath *
41 3040 : DatumGetJsonPathPCopy(Datum d)
42 : {
43 3040 : 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 : jpiStrReplace, /* .replace() item method */
119 : jpiStrLower, /* .lower() item method */
120 : jpiStrUpper, /* .upper() item method */
121 : jpiStrLtrim, /* .ltrim() item method */
122 : jpiStrRtrim, /* .rtrim() item method */
123 : jpiStrBtrim, /* .btrim() item method */
124 : jpiStrInitcap, /* .initcap() item method */
125 : jpiStrSplitPart, /* .split_part() item method */
126 : } JsonPathItemType;
127 :
128 : /* XQuery regex mode flags for LIKE_REGEX predicate */
129 : #define JSP_REGEX_ICASE 0x01 /* i flag, case insensitive */
130 : #define JSP_REGEX_DOTALL 0x02 /* s flag, dot matches newline */
131 : #define JSP_REGEX_MLINE 0x04 /* m flag, ^/$ match at newlines */
132 : #define JSP_REGEX_WSPACE 0x08 /* x flag, ignore whitespace in pattern */
133 : #define JSP_REGEX_QUOTE 0x10 /* q flag, no special characters */
134 :
135 : /*
136 : * Support functions to parse/construct binary value.
137 : * Unlike many other representation of expression the first/main
138 : * node is not an operation but left operand of expression. That
139 : * allows to implement cheap follow-path descending in jsonb
140 : * structure and then execute operator with right operand
141 : */
142 :
143 : typedef struct JsonPathItem
144 : {
145 : JsonPathItemType type;
146 :
147 : /* position form base to next node */
148 : int32 nextPos;
149 :
150 : /*
151 : * pointer into JsonPath value to current node, all positions of current
152 : * are relative to this base
153 : */
154 : char *base;
155 :
156 : union
157 : {
158 : /* classic operator with two operands: and, or etc */
159 : struct
160 : {
161 : int32 left;
162 : int32 right;
163 : } args;
164 :
165 : /* any unary operation */
166 : int32 arg;
167 :
168 : /* storage for jpiIndexArray: indexes of array */
169 : struct
170 : {
171 : int32 nelems;
172 : struct
173 : {
174 : int32 from;
175 : int32 to;
176 : } *elems;
177 : } array;
178 :
179 : /* jpiAny: levels */
180 : struct
181 : {
182 : uint32 first;
183 : uint32 last;
184 : } anybounds;
185 :
186 : struct
187 : {
188 : char *data; /* for bool, numeric and string/key */
189 : int32 datalen; /* filled only for string/key */
190 : } value;
191 :
192 : struct
193 : {
194 : int32 expr;
195 : char *pattern;
196 : int32 patternlen;
197 : uint32 flags;
198 : } like_regex;
199 : } content;
200 : } JsonPathItem;
201 :
202 : #define jspHasNext(jsp) ((jsp)->nextPos > 0)
203 :
204 : extern void jspInit(JsonPathItem *v, JsonPath *js);
205 : extern void jspInitByBuffer(JsonPathItem *v, char *base, int32 pos);
206 : extern bool jspGetNext(JsonPathItem *v, JsonPathItem *a);
207 : extern void jspGetArg(JsonPathItem *v, JsonPathItem *a);
208 : extern void jspGetLeftArg(JsonPathItem *v, JsonPathItem *a);
209 : extern void jspGetRightArg(JsonPathItem *v, JsonPathItem *a);
210 : extern Numeric jspGetNumeric(JsonPathItem *v);
211 : extern bool jspGetBool(JsonPathItem *v);
212 : extern char *jspGetString(JsonPathItem *v, int32 *len);
213 : extern bool jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from,
214 : JsonPathItem *to, int i);
215 : extern bool jspIsMutable(JsonPath *path, List *varnames, List *varexprs);
216 :
217 : extern const char *jspOperationName(JsonPathItemType type);
218 :
219 : /*
220 : * Parsing support data structures.
221 : */
222 :
223 : typedef struct JsonPathParseItem JsonPathParseItem;
224 :
225 : struct JsonPathParseItem
226 : {
227 : JsonPathItemType type;
228 : JsonPathParseItem *next; /* next in path */
229 :
230 : union
231 : {
232 :
233 : /* classic operator with two operands: and, or etc */
234 : struct
235 : {
236 : JsonPathParseItem *left;
237 : JsonPathParseItem *right;
238 : } args;
239 :
240 : /* any unary operation */
241 : JsonPathParseItem *arg;
242 :
243 : /* storage for jpiIndexArray: indexes of array */
244 : struct
245 : {
246 : int nelems;
247 : struct
248 : {
249 : JsonPathParseItem *from;
250 : JsonPathParseItem *to;
251 : } *elems;
252 : } array;
253 :
254 : /* jpiAny: levels */
255 : struct
256 : {
257 : uint32 first;
258 : uint32 last;
259 : } anybounds;
260 :
261 : struct
262 : {
263 : JsonPathParseItem *expr;
264 : char *pattern; /* could not be not null-terminated */
265 : uint32 patternlen;
266 : uint32 flags;
267 : } like_regex;
268 :
269 : /* scalars */
270 : Numeric numeric;
271 : bool boolean;
272 : struct
273 : {
274 : uint32 len;
275 : char *val; /* could not be not null-terminated */
276 : } string;
277 : } value;
278 : };
279 :
280 : typedef struct JsonPathParseResult
281 : {
282 : JsonPathParseItem *expr;
283 : bool lax;
284 : } JsonPathParseResult;
285 :
286 : extern JsonPathParseResult *parsejsonpath(const char *str, int len,
287 : struct Node *escontext);
288 :
289 : extern bool jspConvertRegexFlags(uint32 xflags, int *result,
290 : struct Node *escontext);
291 :
292 : /*
293 : * Struct for details about external variables passed into jsonpath executor
294 : */
295 : typedef struct JsonPathVariable
296 : {
297 : char *name;
298 : int namelen; /* strlen(name) as cache for GetJsonPathVar() */
299 : Oid typid;
300 : int32 typmod;
301 : Datum value;
302 : bool isnull;
303 : } JsonPathVariable;
304 :
305 :
306 : /* SQL/JSON query functions */
307 : extern bool JsonPathExists(Datum jb, JsonPath *jp, bool *error, List *vars);
308 : extern Datum JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper,
309 : bool *empty, bool *error, List *vars,
310 : const char *column_name);
311 : extern JsonbValue *JsonPathValue(Datum jb, JsonPath *jp, bool *empty,
312 : bool *error, List *vars,
313 : const char *column_name);
314 :
315 : /* For JSON_TABLE() */
316 : extern PGDLLIMPORT const TableFuncRoutine JsonbTableRoutine;
317 :
318 : #endif
|