mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Get rid of jsonpath_gram.h and jsonpath_scanner.h
Jsonpath grammar and scanner are both quite small. It doesn't worth complexity to compile them separately. This commit makes grammar and scanner be compiled at once. Therefore, jsonpath_gram.h and jsonpath_gram.h are no longer needed. This commit also does some reorganization of code in jsonpath_gram.y. Discussion: https://postgr.es/m/d47b2023-3ecb-5f04-d253-d557547cf74f%402ndQuadrant.com
This commit is contained in:
@ -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"
|
||||
|
Reference in New Issue
Block a user