/src/postgres/src/include/utils/jsonpath.h
Line | Count | Source |
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 | 0 | #define JSONPATH_VERSION (0x01) |
31 | 0 | #define JSONPATH_LAX (0x80000000) |
32 | 0 | #define JSONPATH_HDRSZ (offsetof(JsonPath, data)) |
33 | | |
34 | | static inline JsonPath * |
35 | | DatumGetJsonPathP(Datum d) |
36 | 0 | { |
37 | 0 | return (JsonPath *) PG_DETOAST_DATUM(d); |
38 | 0 | } Unexecuted instantiation: execExpr.c:DatumGetJsonPathP Unexecuted instantiation: execExprInterp.c:DatumGetJsonPathP Unexecuted instantiation: nodeTableFuncscan.c:DatumGetJsonPathP Unexecuted instantiation: clauses.c:DatumGetJsonPathP Unexecuted instantiation: jsonb_gin.c:DatumGetJsonPathP Unexecuted instantiation: jsonpath.c:DatumGetJsonPathP Unexecuted instantiation: jsonpath_exec.c:DatumGetJsonPathP Unexecuted instantiation: jsonpath_gram.c:DatumGetJsonPathP Unexecuted instantiation: jsonpath_scan.c:DatumGetJsonPathP |
39 | | |
40 | | static inline JsonPath * |
41 | | DatumGetJsonPathPCopy(Datum d) |
42 | 0 | { |
43 | 0 | return (JsonPath *) PG_DETOAST_DATUM_COPY(d); |
44 | 0 | } Unexecuted instantiation: execExpr.c:DatumGetJsonPathPCopy Unexecuted instantiation: execExprInterp.c:DatumGetJsonPathPCopy Unexecuted instantiation: nodeTableFuncscan.c:DatumGetJsonPathPCopy Unexecuted instantiation: clauses.c:DatumGetJsonPathPCopy Unexecuted instantiation: jsonb_gin.c:DatumGetJsonPathPCopy Unexecuted instantiation: jsonpath.c:DatumGetJsonPathPCopy Unexecuted instantiation: jsonpath_exec.c:DatumGetJsonPathPCopy Unexecuted instantiation: jsonpath_gram.c:DatumGetJsonPathPCopy Unexecuted instantiation: jsonpath_scan.c:DatumGetJsonPathPCopy |
45 | | |
46 | 0 | #define PG_GETARG_JSONPATH_P(x) DatumGetJsonPathP(PG_GETARG_DATUM(x)) |
47 | 0 | #define PG_GETARG_JSONPATH_P_COPY(x) DatumGetJsonPathPCopy(PG_GETARG_DATUM(x)) |
48 | 0 | #define PG_RETURN_JSONPATH_P(p) PG_RETURN_POINTER(p) |
49 | | |
50 | 0 | #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 | 0 | #define JSP_REGEX_ICASE 0x01 /* i flag, case insensitive */ |
130 | 0 | #define JSP_REGEX_DOTALL 0x02 /* s flag, dot matches newline */ |
131 | 0 | #define JSP_REGEX_MLINE 0x04 /* m flag, ^/$ match at newlines */ |
132 | 0 | #define JSP_REGEX_WSPACE 0x08 /* x flag, ignore whitespace in pattern */ |
133 | 0 | #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 | 0 | #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 |