1 /*-------------------------------------------------------------------------
2  *
3  * jsonpath.h
4  *	Definitions for jsonpath datatype
5  *
6  * Copyright (c) 2019-2021, 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 "nodes/pg_list.h"
19 #include "utils/jsonb.h"
20 
21 typedef 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  */
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 	jpiDatetime,				/* .datetime() item method */
83 	jpiKeyValue,				/* .keyvalue() item method */
84 	jpiSubscript,				/* array subscript: 'expr' or 'expr TO expr' */
85 	jpiLast,					/* LAST array subscript */
86 	jpiStartsWith,				/* STARTS WITH predicate */
87 	jpiLikeRegex,				/* LIKE_REGEX predicate */
88 } JsonPathItemType;
89 
90 /* XQuery regex mode flags for LIKE_REGEX predicate */
91 #define JSP_REGEX_ICASE		0x01	/* i flag, case insensitive */
92 #define JSP_REGEX_DOTALL	0x02	/* s flag, dot matches newline */
93 #define JSP_REGEX_MLINE		0x04	/* m flag, ^/$ match at newlines */
94 #define JSP_REGEX_WSPACE	0x08	/* x flag, ignore whitespace in pattern */
95 #define JSP_REGEX_QUOTE		0x10	/* q flag, no special characters */
96 
97 /*
98  * Support functions to parse/construct binary value.
99  * Unlike many other representation of expression the first/main
100  * node is not an operation but left operand of expression. That
101  * allows to implement cheap follow-path descending in jsonb
102  * structure and then execute operator with right operand
103  */
104 
105 typedef struct JsonPathItem
106 {
107 	JsonPathItemType type;
108 
109 	/* position form base to next node */
110 	int32		nextPos;
111 
112 	/*
113 	 * pointer into JsonPath value to current node, all positions of current
114 	 * are relative to this base
115 	 */
116 	char	   *base;
117 
118 	union
119 	{
120 		/* classic operator with two operands: and, or etc */
121 		struct
122 		{
123 			int32		left;
124 			int32		right;
125 		}			args;
126 
127 		/* any unary operation */
128 		int32		arg;
129 
130 		/* storage for jpiIndexArray: indexes of array */
131 		struct
132 		{
133 			int32		nelems;
134 			struct
135 			{
136 				int32		from;
137 				int32		to;
138 			}		   *elems;
139 		}			array;
140 
141 		/* jpiAny: levels */
142 		struct
143 		{
144 			uint32		first;
145 			uint32		last;
146 		}			anybounds;
147 
148 		struct
149 		{
150 			char	   *data;	/* for bool, numeric and string/key */
151 			int32		datalen;	/* filled only for string/key */
152 		}			value;
153 
154 		struct
155 		{
156 			int32		expr;
157 			char	   *pattern;
158 			int32		patternlen;
159 			uint32		flags;
160 		}			like_regex;
161 	}			content;
162 } JsonPathItem;
163 
164 #define jspHasNext(jsp) ((jsp)->nextPos > 0)
165 
166 extern void jspInit(JsonPathItem *v, JsonPath *js);
167 extern void jspInitByBuffer(JsonPathItem *v, char *base, int32 pos);
168 extern bool jspGetNext(JsonPathItem *v, JsonPathItem *a);
169 extern void jspGetArg(JsonPathItem *v, JsonPathItem *a);
170 extern void jspGetLeftArg(JsonPathItem *v, JsonPathItem *a);
171 extern void jspGetRightArg(JsonPathItem *v, JsonPathItem *a);
172 extern Numeric jspGetNumeric(JsonPathItem *v);
173 extern bool jspGetBool(JsonPathItem *v);
174 extern char *jspGetString(JsonPathItem *v, int32 *len);
175 extern bool jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from,
176 								 JsonPathItem *to, int i);
177 
178 extern const char *jspOperationName(JsonPathItemType type);
179 
180 /*
181  * Parsing support data structures.
182  */
183 
184 typedef struct JsonPathParseItem JsonPathParseItem;
185 
186 struct JsonPathParseItem
187 {
188 	JsonPathItemType type;
189 	JsonPathParseItem *next;	/* next in path */
190 
191 	union
192 	{
193 
194 		/* classic operator with two operands: and, or etc */
195 		struct
196 		{
197 			JsonPathParseItem *left;
198 			JsonPathParseItem *right;
199 		}			args;
200 
201 		/* any unary operation */
202 		JsonPathParseItem *arg;
203 
204 		/* storage for jpiIndexArray: indexes of array */
205 		struct
206 		{
207 			int			nelems;
208 			struct
209 			{
210 				JsonPathParseItem *from;
211 				JsonPathParseItem *to;
212 			}		   *elems;
213 		}			array;
214 
215 		/* jpiAny: levels */
216 		struct
217 		{
218 			uint32		first;
219 			uint32		last;
220 		}			anybounds;
221 
222 		struct
223 		{
224 			JsonPathParseItem *expr;
225 			char	   *pattern;	/* could not be not null-terminated */
226 			uint32		patternlen;
227 			uint32		flags;
228 		}			like_regex;
229 
230 		/* scalars */
231 		Numeric numeric;
232 		bool		boolean;
233 		struct
234 		{
235 			uint32		len;
236 			char	   *val;	/* could not be not null-terminated */
237 		}			string;
238 	}			value;
239 };
240 
241 typedef struct JsonPathParseResult
242 {
243 	JsonPathParseItem *expr;
244 	bool		lax;
245 } JsonPathParseResult;
246 
247 extern JsonPathParseResult *parsejsonpath(const char *str, int len);
248 
249 extern int	jspConvertRegexFlags(uint32 xflags);
250 
251 #endif
252