diff --git a/src/backend/Makefile b/src/backend/Makefile index ecbfa875af..b03d5e510f 100644 --- a/src/backend/Makefile +++ b/src/backend/Makefile @@ -136,9 +136,6 @@ parser/gram.h: parser/gram.y storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl storage/lmgr/lwlocknames.txt $(MAKE) -C storage/lmgr lwlocknames.h lwlocknames.c -utils/adt/jsonpath_gram.h: utils/adt/jsonpath_gram.y - $(MAKE) -C utils/adt jsonpath_gram.h - # run this unconditionally to avoid needing to know its dependencies here: submake-catalog-headers: $(MAKE) -C catalog distprep generated-header-symlinks @@ -162,7 +159,7 @@ submake-utils-headers: .PHONY: generated-headers -generated-headers: $(top_builddir)/src/include/parser/gram.h $(top_builddir)/src/include/storage/lwlocknames.h $(top_builddir)/src/include/utils/jsonpath_gram.h submake-catalog-headers submake-utils-headers +generated-headers: $(top_builddir)/src/include/parser/gram.h $(top_builddir)/src/include/storage/lwlocknames.h submake-catalog-headers submake-utils-headers $(top_builddir)/src/include/parser/gram.h: parser/gram.h prereqdir=`cd '$(dir $<)' >/dev/null && pwd` && \ @@ -174,11 +171,6 @@ $(top_builddir)/src/include/storage/lwlocknames.h: storage/lmgr/lwlocknames.h cd '$(dir $@)' && rm -f $(notdir $@) && \ $(LN_S) "$$prereqdir/$(notdir $<)" . -$(top_builddir)/src/include/utils/jsonpath_gram.h: utils/adt/jsonpath_gram.h - prereqdir=`cd '$(dir $<)' >/dev/null && pwd` && \ - cd '$(dir $@)' && rm -f $(notdir $@) && \ - $(LN_S) "$$prereqdir/$(notdir $<)" . - utils/probes.o: utils/probes.d $(SUBDIROBJS) $(DTRACE) $(DTRACEFLAGS) -C -G -s $(call expand_subsys,$^) -o $@ @@ -193,7 +185,7 @@ distprep: $(MAKE) -C replication repl_gram.c repl_scanner.c syncrep_gram.c syncrep_scanner.c $(MAKE) -C storage/lmgr lwlocknames.h lwlocknames.c $(MAKE) -C utils distprep - $(MAKE) -C utils/adt jsonpath_gram.c jsonpath_gram.h jsonpath_scan.c + $(MAKE) -C utils/adt jsonpath_gram.c jsonpath_scan.c $(MAKE) -C utils/misc guc-file.c $(MAKE) -C utils/sort qsort_tuple.c @@ -316,7 +308,6 @@ maintainer-clean: distclean storage/lmgr/lwlocknames.c \ storage/lmgr/lwlocknames.h \ utils/adt/jsonpath_gram.c \ - utils/adt/jsonpath_gram.h \ utils/adt/jsonpath_scan.c \ utils/misc/guc-file.c \ utils/sort/qsort_tuple.c diff --git a/src/backend/utils/adt/.gitignore b/src/backend/utils/adt/.gitignore index 7fab054407..48cf941a52 100644 --- a/src/backend/utils/adt/.gitignore +++ b/src/backend/utils/adt/.gitignore @@ -1,3 +1,2 @@ -/jsonpath_gram.h /jsonpath_gram.c /jsonpath_scan.c diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile index 07857543a5..b64ab4ed88 100644 --- a/src/backend/utils/adt/Makefile +++ b/src/backend/utils/adt/Makefile @@ -17,7 +17,7 @@ OBJS = acl.o amutils.o arrayfuncs.o array_expanded.o array_selfuncs.o \ float.o format_type.o formatting.o genfile.o \ geo_ops.o geo_selfuncs.o geo_spgist.o inet_cidr_ntop.o inet_net_pton.o \ int.o int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \ - jsonfuncs.o jsonpath_gram.o jsonpath_scan.o jsonpath.o jsonpath_exec.o \ + jsonfuncs.o jsonpath_gram.o jsonpath.o jsonpath_exec.o \ like.o like_support.o lockfuncs.o mac.o mac8.o misc.o name.o \ network.o network_gist.o network_selfuncs.o network_spgist.o \ numeric.o numutils.o oid.o oracle_compat.o \ @@ -33,26 +33,13 @@ OBJS = acl.o amutils.o arrayfuncs.o array_expanded.o array_selfuncs.o \ txid.o uuid.o varbit.o varchar.o varlena.o version.o \ windowfuncs.o xid.o xml.o -# There is no correct way to write a rule that generates two files. -# See comment in src/backend/parser/Makefile for the explanation of -# the trick used here. - -jsonpath_gram.h: jsonpath_gram.c - touch $@ - -jsonpath_gram.c: BISONFLAGS += -d - jsonpath_scan.c: FLEXFLAGS = -CF -p -p - # Force these dependencies to be known even without dependency info built: -jsonpath_gram.o jsonpath_scan.o jsonpath_parser.o: jsonpath_gram.h - -# jsonpath_gram.c, jsonpath_gram.h, and jsonpath_scan.c are in the -# distribution tarball, so they are not cleaned here. -clean distclean maintainer-clean: - rm -f lex.backup +jsonpath_gram.o: jsonpath_scan.c +# jsonpath_gram.c and jsonpath_scan.c are in the distribution tarball, +# so they are not cleaned here. like.o: like.c like_match.c diff --git a/src/backend/utils/adt/jsonpath_gram.y b/src/backend/utils/adt/jsonpath_gram.y index 66b8c279ee..47ebb2a0e0 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" diff --git a/src/backend/utils/adt/jsonpath_scan.l b/src/backend/utils/adt/jsonpath_scan.l index e7aa1feb75..02cb54ee7f 100644 --- a/src/backend/utils/adt/jsonpath_scan.l +++ b/src/backend/utils/adt/jsonpath_scan.l @@ -1,3 +1,4 @@ +%{ /*------------------------------------------------------------------------- * * jsonpath_scan.l @@ -11,12 +12,10 @@ *------------------------------------------------------------------------- */ -%{ #include "postgres.h" #include "mb/pg_wchar.h" #include "nodes/pg_list.h" -#include "utils/jsonpath_scanner.h" static JsonPathString scanstring; @@ -46,7 +45,6 @@ fprintf_to_ereport(const char *fmt, const char *msg) ereport(ERROR, (errmsg_internal("%s", msg))); } -#define yyerror jsonpath_yyerror %} %option 8bit diff --git a/src/include/Makefile b/src/include/Makefile index 652f6dc6cc..c557375ae3 100644 --- a/src/include/Makefile +++ b/src/include/Makefile @@ -54,7 +54,7 @@ install: all installdirs cp $(srcdir)/$$dir/*.h '$(DESTDIR)$(includedir_server)'/$$dir/ || exit; \ done ifeq ($(vpath_build),yes) - for file in catalog/schemapg.h catalog/pg_*_d.h parser/gram.h storage/lwlocknames.h utils/probes.h utils/jsonpath_gram.h; do \ + for file in catalog/schemapg.h catalog/pg_*_d.h parser/gram.h storage/lwlocknames.h utils/probes.h; do \ cp $$file '$(DESTDIR)$(includedir_server)'/$$file || exit; \ done endif @@ -78,7 +78,7 @@ uninstall: clean: rm -f utils/fmgroids.h utils/fmgrprotos.h utils/errcodes.h utils/header-stamp - rm -f parser/gram.h storage/lwlocknames.h utils/probes.h utils/jsonpath_gram.h + rm -f parser/gram.h storage/lwlocknames.h utils/probes.h rm -f catalog/schemapg.h catalog/pg_*_d.h catalog/header-stamp distclean maintainer-clean: clean diff --git a/src/include/utils/.gitignore b/src/include/utils/.gitignore index e0705e1aa7..05cfa7a8d6 100644 --- a/src/include/utils/.gitignore +++ b/src/include/utils/.gitignore @@ -3,4 +3,3 @@ /probes.h /errcodes.h /header-stamp -/jsonpath_gram.h diff --git a/src/include/utils/jsonpath_scanner.h b/src/include/utils/jsonpath_scanner.h deleted file mode 100644 index 1c567717e8..0000000000 --- a/src/include/utils/jsonpath_scanner.h +++ /dev/null @@ -1,32 +0,0 @@ -/*------------------------------------------------------------------------- - * - * jsonpath_scanner.h - * Definitions for jsonpath scanner & parser - * - * Portions Copyright (c) 2019, PostgreSQL Global Development Group - * - * src/include/utils/jsonpath_scanner.h - * - *------------------------------------------------------------------------- - */ - -#ifndef JSONPATH_SCANNER_H -#define JSONPATH_SCANNER_H - -/* struct JsonPathString is shared between scan and gram */ -typedef struct JsonPathString -{ - char *val; - int len; - int total; -} JsonPathString; - -#include "utils/jsonpath.h" -#include "utils/jsonpath_gram.h" - -/* flex 2.5.4 doesn't bother with a decl for this */ -extern int jsonpath_yylex(YYSTYPE *yylval_param); -extern int jsonpath_yyparse(JsonPathParseResult **result); -extern void jsonpath_yyerror(JsonPathParseResult **result, const char *message); - -#endif diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm index 90a8d69e99..2ea224d770 100644 --- a/src/tools/msvc/Solution.pm +++ b/src/tools/msvc/Solution.pm @@ -327,24 +327,6 @@ sub GenerateFiles ); } - if (IsNewer( - 'src/backend/utils/adt/jsonpath_gram.h', - 'src/backend/utils/adt/jsonpath_gram.y')) - { - print "Generating jsonpath_gram.h...\n"; - chdir('src/backend/utils/adt'); - system('perl ../../../tools/msvc/pgbison.pl jsonpath_gram.y'); - chdir('../../../..'); - } - - if (IsNewer( - 'src/include/utils/jsonpath_gram.h', - 'src/backend/utils/adt/jsonpath_gram.h')) - { - copyFile('src/backend/utils/adt/jsonpath_gram.h', - 'src/include/utils/jsonpath_gram.h'); - } - if ($self->{options}->{python} && IsNewer( 'src/pl/plpython/spiexceptions.h',