diff options
Diffstat (limited to 'src/backend/utils/adt/jsonpath_gram.y')
-rw-r--r-- | src/backend/utils/adt/jsonpath_gram.y | 485 |
1 files changed, 259 insertions, 226 deletions
diff --git a/src/backend/utils/adt/jsonpath_gram.y b/src/backend/utils/adt/jsonpath_gram.y index 66b8c279ee5..47ebb2a0e09 100644 --- a/src/backend/utils/adt/jsonpath_gram.y +++ b/src/backend/utils/adt/jsonpath_gram.y @@ -1,3 +1,4 @@ +%{ /*------------------------------------------------------------------------- * * jsonpath_gram.y @@ -11,7 +12,6 @@ *------------------------------------------------------------------------- */ -%{ #include "postgres.h" #include "catalog/pg_collation.h" @@ -21,7 +21,37 @@ #include "regex/regex.h" #include "utils/builtins.h" #include "utils/jsonpath.h" -#include "utils/jsonpath_scanner.h" + +/* struct JsonPathString is shared between scan and gram */ +typedef struct JsonPathString +{ + char *val; + int len; + int total; +} JsonPathString; + +union YYSTYPE; + +/* flex 2.5.4 doesn't bother with a decl for this */ +int jsonpath_yylex(union YYSTYPE *yylval_param); +int jsonpath_yyparse(JsonPathParseResult **result); +void jsonpath_yyerror(JsonPathParseResult **result, const char *message); + +static JsonPathParseItem *makeItemType(int type); +static JsonPathParseItem *makeItemString(JsonPathString *s); +static JsonPathParseItem *makeItemVariable(JsonPathString *s); +static JsonPathParseItem *makeItemKey(JsonPathString *s); +static JsonPathParseItem *makeItemNumeric(JsonPathString *s); +static JsonPathParseItem *makeItemBool(bool val); +static JsonPathParseItem *makeItemBinary(int type, JsonPathParseItem *la, + JsonPathParseItem *ra); +static JsonPathParseItem *makeItemUnary(int type, JsonPathParseItem *a); +static JsonPathParseItem *makeItemList(List *list); +static JsonPathParseItem *makeIndexArray(List *list); +static JsonPathParseItem *makeAny(int first, int last); +static JsonPathParseItem *makeItemLikeRegex(JsonPathParseItem *expr, + JsonPathString *pattern, + JsonPathString *flags); /* * Bison doesn't allocate anything that needs to live across parser calls, @@ -34,230 +64,6 @@ #define YYMALLOC palloc #define YYFREE pfree -static JsonPathParseItem* -makeItemType(int type) -{ - JsonPathParseItem* v = palloc(sizeof(*v)); - - CHECK_FOR_INTERRUPTS(); - - v->type = type; - v->next = NULL; - - return v; -} - -static JsonPathParseItem* -makeItemString(JsonPathString *s) -{ - JsonPathParseItem *v; - - if (s == NULL) - { - v = makeItemType(jpiNull); - } - else - { - v = makeItemType(jpiString); - v->value.string.val = s->val; - v->value.string.len = s->len; - } - - return v; -} - -static JsonPathParseItem* -makeItemVariable(JsonPathString *s) -{ - JsonPathParseItem *v; - - v = makeItemType(jpiVariable); - v->value.string.val = s->val; - v->value.string.len = s->len; - - return v; -} - -static JsonPathParseItem* -makeItemKey(JsonPathString *s) -{ - JsonPathParseItem *v; - - v = makeItemString(s); - v->type = jpiKey; - - return v; -} - -static JsonPathParseItem* -makeItemNumeric(JsonPathString *s) -{ - JsonPathParseItem *v; - - v = makeItemType(jpiNumeric); - v->value.numeric = - DatumGetNumeric(DirectFunctionCall3(numeric_in, - CStringGetDatum(s->val), 0, -1)); - - return v; -} - -static JsonPathParseItem* -makeItemBool(bool val) { - JsonPathParseItem *v = makeItemType(jpiBool); - - v->value.boolean = val; - - return v; -} - -static JsonPathParseItem* -makeItemBinary(int type, JsonPathParseItem* la, JsonPathParseItem *ra) -{ - JsonPathParseItem *v = makeItemType(type); - - v->value.args.left = la; - v->value.args.right = ra; - - return v; -} - -static JsonPathParseItem* -makeItemUnary(int type, JsonPathParseItem* a) -{ - JsonPathParseItem *v; - - if (type == jpiPlus && a->type == jpiNumeric && !a->next) - return a; - - if (type == jpiMinus && a->type == jpiNumeric && !a->next) - { - v = makeItemType(jpiNumeric); - v->value.numeric = - DatumGetNumeric(DirectFunctionCall1(numeric_uminus, - NumericGetDatum(a->value.numeric))); - return v; - } - - v = makeItemType(type); - - v->value.arg = a; - - return v; -} - -static JsonPathParseItem* -makeItemList(List *list) -{ - JsonPathParseItem *head, *end; - ListCell *cell = list_head(list); - - head = end = (JsonPathParseItem *) lfirst(cell); - - if (!lnext(cell)) - return head; - - /* append items to the end of already existing list */ - while (end->next) - end = end->next; - - for_each_cell(cell, lnext(cell)) - { - JsonPathParseItem *c = (JsonPathParseItem *) lfirst(cell); - - end->next = c; - end = c; - } - - return head; -} - -static JsonPathParseItem* -makeIndexArray(List *list) -{ - JsonPathParseItem *v = makeItemType(jpiIndexArray); - ListCell *cell; - int i = 0; - - Assert(list_length(list) > 0); - v->value.array.nelems = list_length(list); - - v->value.array.elems = palloc(sizeof(v->value.array.elems[0]) * - v->value.array.nelems); - - foreach(cell, list) - { - JsonPathParseItem *jpi = lfirst(cell); - - Assert(jpi->type == jpiSubscript); - - v->value.array.elems[i].from = jpi->value.args.left; - v->value.array.elems[i++].to = jpi->value.args.right; - } - - return v; -} - -static JsonPathParseItem* -makeAny(int first, int last) -{ - JsonPathParseItem *v = makeItemType(jpiAny); - - v->value.anybounds.first = (first >= 0) ? first : PG_UINT32_MAX; - v->value.anybounds.last = (last >= 0) ? last : PG_UINT32_MAX; - - return v; -} - -static JsonPathParseItem * -makeItemLikeRegex(JsonPathParseItem *expr, JsonPathString *pattern, - JsonPathString *flags) -{ - JsonPathParseItem *v = makeItemType(jpiLikeRegex); - int i; - int cflags = REG_ADVANCED; - - v->value.like_regex.expr = expr; - v->value.like_regex.pattern = pattern->val; - v->value.like_regex.patternlen = pattern->len; - v->value.like_regex.flags = 0; - - for (i = 0; flags && i < flags->len; i++) - { - switch (flags->val[i]) - { - case 'i': - v->value.like_regex.flags |= JSP_REGEX_ICASE; - cflags |= REG_ICASE; - break; - case 's': - v->value.like_regex.flags &= ~JSP_REGEX_MLINE; - v->value.like_regex.flags |= JSP_REGEX_SLINE; - cflags |= REG_NEWLINE; - break; - case 'm': - v->value.like_regex.flags &= ~JSP_REGEX_SLINE; - v->value.like_regex.flags |= JSP_REGEX_MLINE; - cflags &= ~REG_NEWLINE; - break; - case 'x': - v->value.like_regex.flags |= JSP_REGEX_WSPACE; - cflags |= REG_EXPANDED; - break; - default: - yyerror(NULL, "unrecognized flag of LIKE_REGEX predicate"); - break; - } - } - - /* check regex validity */ - (void) RE_compile_and_cache(cstring_to_text_with_len(pattern->val, - pattern->len), - cflags, DEFAULT_COLLATION_OID); - - return v; -} - %} /* BISON Declarations */ @@ -478,3 +284,230 @@ method: | KEYVALUE_P { $$ = jpiKeyValue; } ; %% + +static JsonPathParseItem* +makeItemType(int type) +{ + JsonPathParseItem* v = palloc(sizeof(*v)); + + CHECK_FOR_INTERRUPTS(); + + v->type = type; + v->next = NULL; + + return v; +} + +static JsonPathParseItem* +makeItemString(JsonPathString *s) +{ + JsonPathParseItem *v; + + if (s == NULL) + { + v = makeItemType(jpiNull); + } + else + { + v = makeItemType(jpiString); + v->value.string.val = s->val; + v->value.string.len = s->len; + } + + return v; +} + +static JsonPathParseItem * +makeItemVariable(JsonPathString *s) +{ + JsonPathParseItem *v; + + v = makeItemType(jpiVariable); + v->value.string.val = s->val; + v->value.string.len = s->len; + + return v; +} + +static JsonPathParseItem * +makeItemKey(JsonPathString *s) +{ + JsonPathParseItem *v; + + v = makeItemString(s); + v->type = jpiKey; + + return v; +} + +static JsonPathParseItem * +makeItemNumeric(JsonPathString *s) +{ + JsonPathParseItem *v; + + v = makeItemType(jpiNumeric); + v->value.numeric = + DatumGetNumeric(DirectFunctionCall3(numeric_in, + CStringGetDatum(s->val), 0, -1)); + + return v; +} + +static JsonPathParseItem * +makeItemBool(bool val) +{ + JsonPathParseItem *v = makeItemType(jpiBool); + + v->value.boolean = val; + + return v; +} + +static JsonPathParseItem * +makeItemBinary(int type, JsonPathParseItem* la, JsonPathParseItem *ra) +{ + JsonPathParseItem *v = makeItemType(type); + + v->value.args.left = la; + v->value.args.right = ra; + + return v; +} + +static JsonPathParseItem * +makeItemUnary(int type, JsonPathParseItem* a) +{ + JsonPathParseItem *v; + + if (type == jpiPlus && a->type == jpiNumeric && !a->next) + return a; + + if (type == jpiMinus && a->type == jpiNumeric && !a->next) + { + v = makeItemType(jpiNumeric); + v->value.numeric = + DatumGetNumeric(DirectFunctionCall1(numeric_uminus, + NumericGetDatum(a->value.numeric))); + return v; + } + + v = makeItemType(type); + + v->value.arg = a; + + return v; +} + +static JsonPathParseItem * +makeItemList(List *list) +{ + JsonPathParseItem *head, *end; + ListCell *cell = list_head(list); + + head = end = (JsonPathParseItem *) lfirst(cell); + + if (!lnext(cell)) + return head; + + /* append items to the end of already existing list */ + while (end->next) + end = end->next; + + for_each_cell(cell, lnext(cell)) + { + JsonPathParseItem *c = (JsonPathParseItem *) lfirst(cell); + + end->next = c; + end = c; + } + + return head; +} + +static JsonPathParseItem * +makeIndexArray(List *list) +{ + JsonPathParseItem *v = makeItemType(jpiIndexArray); + ListCell *cell; + int i = 0; + + Assert(list_length(list) > 0); + v->value.array.nelems = list_length(list); + + v->value.array.elems = palloc(sizeof(v->value.array.elems[0]) * + v->value.array.nelems); + + foreach(cell, list) + { + JsonPathParseItem *jpi = lfirst(cell); + + Assert(jpi->type == jpiSubscript); + + v->value.array.elems[i].from = jpi->value.args.left; + v->value.array.elems[i++].to = jpi->value.args.right; + } + + return v; +} + +static JsonPathParseItem * +makeAny(int first, int last) +{ + JsonPathParseItem *v = makeItemType(jpiAny); + + v->value.anybounds.first = (first >= 0) ? first : PG_UINT32_MAX; + v->value.anybounds.last = (last >= 0) ? last : PG_UINT32_MAX; + + return v; +} + +static JsonPathParseItem * +makeItemLikeRegex(JsonPathParseItem *expr, JsonPathString *pattern, + JsonPathString *flags) +{ + JsonPathParseItem *v = makeItemType(jpiLikeRegex); + int i; + int cflags = REG_ADVANCED; + + v->value.like_regex.expr = expr; + v->value.like_regex.pattern = pattern->val; + v->value.like_regex.patternlen = pattern->len; + v->value.like_regex.flags = 0; + + for (i = 0; flags && i < flags->len; i++) + { + switch (flags->val[i]) + { + case 'i': + v->value.like_regex.flags |= JSP_REGEX_ICASE; + cflags |= REG_ICASE; + break; + case 's': + v->value.like_regex.flags &= ~JSP_REGEX_MLINE; + v->value.like_regex.flags |= JSP_REGEX_SLINE; + cflags |= REG_NEWLINE; + break; + case 'm': + v->value.like_regex.flags &= ~JSP_REGEX_SLINE; + v->value.like_regex.flags |= JSP_REGEX_MLINE; + cflags &= ~REG_NEWLINE; + break; + case 'x': + v->value.like_regex.flags |= JSP_REGEX_WSPACE; + cflags |= REG_EXPANDED; + break; + default: + yyerror(NULL, "unrecognized flag of LIKE_REGEX predicate"); + break; + } + } + + /* check regex validity */ + (void) RE_compile_and_cache(cstring_to_text_with_len(pattern->val, + pattern->len), + cflags, DEFAULT_COLLATION_OID); + + return v; +} + +#include "jsonpath_scan.c" |