| 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 | |