offset-based-keyword-lookup-7.patch
text/x-diff
Filename: offset-based-keyword-lookup-7.patch
Type: text/x-diff
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| contrib/pg_stat_statements/pg_stat_statements.c | 0 | 0 |
| src/backend/parser/parser.c | 0 | 0 |
| src/backend/parser/scan.l | 0 | 0 |
| src/backend/utils/adt/misc.c | 0 | 0 |
| src/backend/utils/adt/ruleutils.c | 0 | 0 |
| src/common/.gitignore | 0 | 0 |
| src/common/keywords.c | 0 | 0 |
| src/common/kwlookup.c | 0 | 0 |
| src/common/Makefile | 0 | 0 |
| src/fe_utils/string_utils.c | 0 | 0 |
| src/include/common/keywords.h | 0 | 0 |
| src/include/common/kwlookup.h | 0 | 0 |
| src/include/parser/kwlist.h | 0 | 0 |
| src/include/parser/scanner.h | 0 | 0 |
| src/interfaces/ecpg/preproc/c_keywords.c | 0 | 0 |
| src/interfaces/ecpg/preproc/c_kwlist.h | 0 | 0 |
| src/interfaces/ecpg/preproc/ecpg_keywords.c | 0 | 0 |
| src/interfaces/ecpg/preproc/ecpg_kwlist.h | 0 | 0 |
| src/interfaces/ecpg/preproc/.gitignore | 0 | 0 |
| src/interfaces/ecpg/preproc/keywords.c | 0 | 0 |
| src/interfaces/ecpg/preproc/Makefile | 0 | 0 |
| src/interfaces/ecpg/preproc/pgc.l | 0 | 0 |
| src/interfaces/ecpg/preproc/preproc_extern.h | 0 | 0 |
| src/pl/plpgsql/src/.gitignore | 0 | 0 |
| src/pl/plpgsql/src/Makefile | 0 | 0 |
| src/pl/plpgsql/src/pl_reserved_kwlist.h | 0 | 0 |
| src/pl/plpgsql/src/pl_scanner.c | 0 | 0 |
| src/pl/plpgsql/src/pl_unreserved_kwlist.h | 0 | 0 |
| src/tools/gen_keywordlist.pl | 0 | 0 |
| src/tools/msvc/clean.bat | 0 | 0 |
| src/tools/msvc/Solution.pm | 0 | 0 |
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index e8ef966..9131991 100644
*** a/contrib/pg_stat_statements/pg_stat_statements.c
--- b/contrib/pg_stat_statements/pg_stat_statements.c
*************** fill_in_constant_lengths(pgssJumbleState
*** 3075,3082 ****
/* initialize the flex scanner --- should match raw_parser() */
yyscanner = scanner_init(query,
&yyextra,
! ScanKeywords,
! NumScanKeywords);
/* we don't want to re-emit any escape string warnings */
yyextra.escape_string_warning = false;
--- 3075,3082 ----
/* initialize the flex scanner --- should match raw_parser() */
yyscanner = scanner_init(query,
&yyextra,
! &ScanKeywords,
! ScanKeywordTokens);
/* we don't want to re-emit any escape string warnings */
yyextra.escape_string_warning = false;
diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c
index 7e9b122..4c0c258 100644
*** a/src/backend/parser/parser.c
--- b/src/backend/parser/parser.c
*************** raw_parser(const char *str)
*** 41,47 ****
/* initialize the flex scanner */
yyscanner = scanner_init(str, &yyextra.core_yy_extra,
! ScanKeywords, NumScanKeywords);
/* base_yylex() only needs this much initialization */
yyextra.have_lookahead = false;
--- 41,47 ----
/* initialize the flex scanner */
yyscanner = scanner_init(str, &yyextra.core_yy_extra,
! &ScanKeywords, ScanKeywordTokens);
/* base_yylex() only needs this much initialization */
yyextra.have_lookahead = false;
diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index fbeb86f..e1cae85 100644
*** a/src/backend/parser/scan.l
--- b/src/backend/parser/scan.l
*************** bool escape_string_warning = true;
*** 67,72 ****
--- 67,87 ----
bool standard_conforming_strings = true;
/*
+ * Constant data exported from this file. This array maps from the
+ * zero-based keyword numbers returned by ScanKeywordLookup to the
+ * Bison token numbers needed by gram.y. This is exported because
+ * callers need to pass it to scanner_init, if they are using the
+ * standard keyword list ScanKeywords.
+ */
+ #define PG_KEYWORD(kwname, value, category) value,
+
+ const uint16 ScanKeywordTokens[] = {
+ #include "parser/kwlist.h"
+ };
+
+ #undef PG_KEYWORD
+
+ /*
* Set the type of YYSTYPE.
*/
#define YYSTYPE core_YYSTYPE
*************** other .
*** 504,521 ****
* We will pass this along as a normal character string,
* but preceded with an internally-generated "NCHAR".
*/
! const ScanKeyword *keyword;
SET_YYLLOC();
yyless(1); /* eat only 'n' this time */
! keyword = ScanKeywordLookup("nchar",
! yyextra->keywords,
! yyextra->num_keywords);
! if (keyword != NULL)
{
! yylval->keyword = keyword->name;
! return keyword->value;
}
else
{
--- 519,536 ----
* We will pass this along as a normal character string,
* but preceded with an internally-generated "NCHAR".
*/
! int kwnum;
SET_YYLLOC();
yyless(1); /* eat only 'n' this time */
! kwnum = ScanKeywordLookup("nchar",
! yyextra->keywordlist);
! if (kwnum >= 0)
{
! yylval->keyword = GetScanKeyword(kwnum,
! yyextra->keywordlist);
! return yyextra->keyword_tokens[kwnum];
}
else
{
*************** other .
*** 1021,1039 ****
{identifier} {
! const ScanKeyword *keyword;
char *ident;
SET_YYLLOC();
/* Is it a keyword? */
! keyword = ScanKeywordLookup(yytext,
! yyextra->keywords,
! yyextra->num_keywords);
! if (keyword != NULL)
{
! yylval->keyword = keyword->name;
! return keyword->value;
}
/*
--- 1036,1054 ----
{identifier} {
! int kwnum;
char *ident;
SET_YYLLOC();
/* Is it a keyword? */
! kwnum = ScanKeywordLookup(yytext,
! yyextra->keywordlist);
! if (kwnum >= 0)
{
! yylval->keyword = GetScanKeyword(kwnum,
! yyextra->keywordlist);
! return yyextra->keyword_tokens[kwnum];
}
/*
*************** scanner_yyerror(const char *message, cor
*** 1142,1149 ****
core_yyscan_t
scanner_init(const char *str,
core_yy_extra_type *yyext,
! const ScanKeyword *keywords,
! int num_keywords)
{
Size slen = strlen(str);
yyscan_t scanner;
--- 1157,1164 ----
core_yyscan_t
scanner_init(const char *str,
core_yy_extra_type *yyext,
! const ScanKeywordList *keywordlist,
! const uint16 *keyword_tokens)
{
Size slen = strlen(str);
yyscan_t scanner;
*************** scanner_init(const char *str,
*** 1153,1160 ****
core_yyset_extra(yyext, scanner);
! yyext->keywords = keywords;
! yyext->num_keywords = num_keywords;
yyext->backslash_quote = backslash_quote;
yyext->escape_string_warning = escape_string_warning;
--- 1168,1175 ----
core_yyset_extra(yyext, scanner);
! yyext->keywordlist = keywordlist;
! yyext->keyword_tokens = keyword_tokens;
yyext->backslash_quote = backslash_quote;
yyext->escape_string_warning = escape_string_warning;
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 7b69b82..746b7d2 100644
*** a/src/backend/utils/adt/misc.c
--- b/src/backend/utils/adt/misc.c
*************** pg_get_keywords(PG_FUNCTION_ARGS)
*** 417,431 ****
funcctx = SRF_PERCALL_SETUP();
! if (funcctx->call_cntr < NumScanKeywords)
{
char *values[3];
HeapTuple tuple;
/* cast-away-const is ugly but alternatives aren't much better */
! values[0] = unconstify(char *, ScanKeywords[funcctx->call_cntr].name);
! switch (ScanKeywords[funcctx->call_cntr].category)
{
case UNRESERVED_KEYWORD:
values[1] = "U";
--- 417,433 ----
funcctx = SRF_PERCALL_SETUP();
! if (funcctx->call_cntr < ScanKeywords.num_keywords)
{
char *values[3];
HeapTuple tuple;
/* cast-away-const is ugly but alternatives aren't much better */
! values[0] = unconstify(char *,
! GetScanKeyword(funcctx->call_cntr,
! &ScanKeywords));
! switch (ScanKeywordCategories[funcctx->call_cntr])
{
case UNRESERVED_KEYWORD:
values[1] = "U";
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 368eacf..77811f6 100644
*** a/src/backend/utils/adt/ruleutils.c
--- b/src/backend/utils/adt/ruleutils.c
*************** quote_identifier(const char *ident)
*** 10601,10611 ****
* Note: ScanKeywordLookup() does case-insensitive comparison, but
* that's fine, since we already know we have all-lower-case.
*/
! const ScanKeyword *keyword = ScanKeywordLookup(ident,
! ScanKeywords,
! NumScanKeywords);
! if (keyword != NULL && keyword->category != UNRESERVED_KEYWORD)
safe = false;
}
--- 10601,10609 ----
* Note: ScanKeywordLookup() does case-insensitive comparison, but
* that's fine, since we already know we have all-lower-case.
*/
! int kwnum = ScanKeywordLookup(ident, &ScanKeywords);
! if (kwnum >= 0 && ScanKeywordCategories[kwnum] != UNRESERVED_KEYWORD)
safe = false;
}
diff --git a/src/common/.gitignore b/src/common/.gitignore
index ...ffa3284 .
*** a/src/common/.gitignore
--- b/src/common/.gitignore
***************
*** 0 ****
--- 1 ----
+ /kwlist_d.h
diff --git a/src/common/Makefile b/src/common/Makefile
index ec8139f..317b071 100644
*** a/src/common/Makefile
--- b/src/common/Makefile
*************** override CPPFLAGS += -DVAL_LDFLAGS_EX="\
*** 41,51 ****
override CPPFLAGS += -DVAL_LDFLAGS_SL="\"$(LDFLAGS_SL)\""
override CPPFLAGS += -DVAL_LIBS="\"$(LIBS)\""
! override CPPFLAGS := -DFRONTEND $(CPPFLAGS)
LIBS += $(PTHREAD_LIBS)
OBJS_COMMON = base64.o config_info.o controldata_utils.o exec.o file_perm.o \
! ip.o keywords.o link-canary.o md5.o pg_lzcompress.o \
pgfnames.o psprintf.o relpath.o \
rmtree.o saslprep.o scram-common.o string.o unicode_norm.o \
username.o wait_error.o
--- 41,51 ----
override CPPFLAGS += -DVAL_LDFLAGS_SL="\"$(LDFLAGS_SL)\""
override CPPFLAGS += -DVAL_LIBS="\"$(LIBS)\""
! override CPPFLAGS := -DFRONTEND -I. -I$(top_srcdir)/src/common $(CPPFLAGS)
LIBS += $(PTHREAD_LIBS)
OBJS_COMMON = base64.o config_info.o controldata_utils.o exec.o file_perm.o \
! ip.o keywords.o kwlookup.o link-canary.o md5.o pg_lzcompress.o \
pgfnames.o psprintf.o relpath.o \
rmtree.o saslprep.o scram-common.o string.o unicode_norm.o \
username.o wait_error.o
*************** OBJS_SRV = $(OBJS_COMMON:%.o=%_srv.o)
*** 65,70 ****
--- 65,72 ----
all: libpgcommon.a libpgcommon_shlib.a libpgcommon_srv.a
+ distprep: kwlist_d.h
+
# libpgcommon is needed by some contrib
install: all installdirs
$(INSTALL_STLIB) libpgcommon.a '$(DESTDIR)$(libdir)/libpgcommon.a'
*************** libpgcommon_srv.a: $(OBJS_SRV)
*** 115,130 ****
%_srv.o: %.c %.o
$(CC) $(CFLAGS) $(subst -DFRONTEND,, $(CPPFLAGS)) -c $< -o $@
! # Dependencies of keywords.o need to be managed explicitly to make sure
! # that you don't get broken parsing code, even in a non-enable-depend build.
! # Note that gram.h isn't required for the frontend versions of keywords.o.
! $(top_builddir)/src/include/parser/gram.h: $(top_srcdir)/src/backend/parser/gram.y
! $(MAKE) -C $(top_builddir)/src/backend $(top_builddir)/src/include/parser/gram.h
! keywords.o: $(top_srcdir)/src/include/parser/kwlist.h
! keywords_shlib.o: $(top_srcdir)/src/include/parser/kwlist.h
! keywords_srv.o: $(top_builddir)/src/include/parser/gram.h $(top_srcdir)/src/include/parser/kwlist.h
! clean distclean maintainer-clean:
rm -f libpgcommon.a libpgcommon_shlib.a libpgcommon_srv.a
rm -f $(OBJS_FRONTEND) $(OBJS_SHLIB) $(OBJS_SRV)
--- 117,134 ----
%_srv.o: %.c %.o
$(CC) $(CFLAGS) $(subst -DFRONTEND,, $(CPPFLAGS)) -c $< -o $@
! # generate SQL keyword lookup table to be included into keywords*.o.
! kwlist_d.h: $(top_srcdir)/src/include/parser/kwlist.h $(top_srcdir)/src/tools/gen_keywordlist.pl
! $(PERL) $(top_srcdir)/src/tools/gen_keywordlist.pl --extern $<
! # Dependencies of keywords*.o need to be managed explicitly to make sure
! # that you don't get broken parsing code, even in a non-enable-depend build.
! keywords.o keywords_shlib.o keywords_srv.o: kwlist_d.h
! # kwlist_d.h is in the distribution tarball, so it is not cleaned here.
! clean distclean:
rm -f libpgcommon.a libpgcommon_shlib.a libpgcommon_srv.a
rm -f $(OBJS_FRONTEND) $(OBJS_SHLIB) $(OBJS_SRV)
+
+ maintainer-clean: distclean
+ rm -f kwlist_d.h
diff --git a/src/common/keywords.c b/src/common/keywords.c
index 6f99090..103166c 100644
*** a/src/common/keywords.c
--- b/src/common/keywords.c
***************
*** 1,7 ****
/*-------------------------------------------------------------------------
*
* keywords.c
! * lexical token lookup for key words in PostgreSQL
*
*
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
--- 1,7 ----
/*-------------------------------------------------------------------------
*
* keywords.c
! * PostgreSQL's list of SQL keywords
*
*
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
***************
*** 19,114 ****
#include "postgres_fe.h"
#endif
! #ifndef FRONTEND
!
! #include "parser/gramparse.h"
!
! #define PG_KEYWORD(a,b,c) {a,b,c},
- #else
! #include "common/keywords.h"
! /*
! * We don't need the token number for frontend uses, so leave it out to avoid
! * requiring backend headers that won't compile cleanly here.
! */
! #define PG_KEYWORD(a,b,c) {a,0,c},
! #endif /* FRONTEND */
! const ScanKeyword ScanKeywords[] = {
#include "parser/kwlist.h"
};
! const int NumScanKeywords = lengthof(ScanKeywords);
!
!
! /*
! * ScanKeywordLookup - see if a given word is a keyword
! *
! * The table to be searched is passed explicitly, so that this can be used
! * to search keyword lists other than the standard list appearing above.
! *
! * Returns a pointer to the ScanKeyword table entry, or NULL if no match.
! *
! * The match is done case-insensitively. Note that we deliberately use a
! * dumbed-down case conversion that will only translate 'A'-'Z' into 'a'-'z',
! * even if we are in a locale where tolower() would produce more or different
! * translations. This is to conform to the SQL99 spec, which says that
! * keywords are to be matched in this way even though non-keyword identifiers
! * receive a different case-normalization mapping.
! */
! const ScanKeyword *
! ScanKeywordLookup(const char *text,
! const ScanKeyword *keywords,
! int num_keywords)
! {
! int len,
! i;
! char word[NAMEDATALEN];
! const ScanKeyword *low;
! const ScanKeyword *high;
!
! len = strlen(text);
! /* We assume all keywords are shorter than NAMEDATALEN. */
! if (len >= NAMEDATALEN)
! return NULL;
!
! /*
! * Apply an ASCII-only downcasing. We must not use tolower() since it may
! * produce the wrong translation in some locales (eg, Turkish).
! */
! for (i = 0; i < len; i++)
! {
! char ch = text[i];
!
! if (ch >= 'A' && ch <= 'Z')
! ch += 'a' - 'A';
! word[i] = ch;
! }
! word[len] = '\0';
!
! /*
! * Now do a binary search using plain strcmp() comparison.
! */
! low = keywords;
! high = keywords + (num_keywords - 1);
! while (low <= high)
! {
! const ScanKeyword *middle;
! int difference;
!
! middle = low + (high - low) / 2;
! difference = strcmp(middle->name, word);
! if (difference == 0)
! return middle;
! else if (difference < 0)
! low = middle + 1;
! else
! high = middle - 1;
! }
!
! return NULL;
! }
--- 19,37 ----
#include "postgres_fe.h"
#endif
! #include "common/keywords.h"
! /* ScanKeywordList lookup data for SQL keywords */
! #include "kwlist_d.h"
! /* Keyword categories for SQL keywords */
+ #define PG_KEYWORD(kwname, value, category) category,
! const uint8 ScanKeywordCategories[SCANKEYWORDS_NUM_KEYWORDS] = {
#include "parser/kwlist.h"
};
! #undef PG_KEYWORD
diff --git a/src/common/kwlookup.c b/src/common/kwlookup.c
index ...db62623 .
*** a/src/common/kwlookup.c
--- b/src/common/kwlookup.c
***************
*** 0 ****
--- 1,91 ----
+ /*-------------------------------------------------------------------------
+ *
+ * kwlookup.c
+ * Key word lookup for PostgreSQL
+ *
+ *
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/common/kwlookup.c
+ *
+ *-------------------------------------------------------------------------
+ */
+ #include "c.h"
+
+ #include "common/kwlookup.h"
+
+
+ /*
+ * ScanKeywordLookup - see if a given word is a keyword
+ *
+ * The list of keywords to be matched against is passed as a ScanKeywordList.
+ *
+ * Returns the keyword number (0..N-1) of the keyword, or -1 if no match.
+ * Callers typically use the keyword number to index into information
+ * arrays, but that is no concern of this code.
+ *
+ * The match is done case-insensitively. Note that we deliberately use a
+ * dumbed-down case conversion that will only translate 'A'-'Z' into 'a'-'z',
+ * even if we are in a locale where tolower() would produce more or different
+ * translations. This is to conform to the SQL99 spec, which says that
+ * keywords are to be matched in this way even though non-keyword identifiers
+ * receive a different case-normalization mapping.
+ */
+ int
+ ScanKeywordLookup(const char *text,
+ const ScanKeywordList *keywords)
+ {
+ int len,
+ i;
+ char word[NAMEDATALEN];
+ const char *kw_string;
+ const uint16 *kw_offsets;
+ const uint16 *low;
+ const uint16 *high;
+
+ len = strlen(text);
+ /* We assume all keywords are shorter than NAMEDATALEN. */
+ if (len >= NAMEDATALEN)
+ return -1;
+
+ /*
+ * Apply an ASCII-only downcasing. We must not use tolower() since it may
+ * produce the wrong translation in some locales (eg, Turkish).
+ */
+ for (i = 0; i < len; i++)
+ {
+ char ch = text[i];
+
+ if (ch >= 'A' && ch <= 'Z')
+ ch += 'a' - 'A';
+ word[i] = ch;
+ }
+ word[len] = '\0';
+
+ /*
+ * Now do a binary search using plain strcmp() comparison.
+ */
+ kw_string = keywords->kw_string;
+ kw_offsets = keywords->kw_offsets;
+ low = kw_offsets;
+ high = kw_offsets + (keywords->num_keywords - 1);
+ while (low <= high)
+ {
+ const uint16 *middle;
+ int difference;
+
+ middle = low + (high - low) / 2;
+ difference = strcmp(kw_string + *middle, word);
+ if (difference == 0)
+ return middle - kw_offsets;
+ else if (difference < 0)
+ low = middle + 1;
+ else
+ high = middle - 1;
+ }
+
+ return -1;
+ }
diff --git a/src/fe_utils/string_utils.c b/src/fe_utils/string_utils.c
index 9b47b62..5c1732a 100644
*** a/src/fe_utils/string_utils.c
--- b/src/fe_utils/string_utils.c
*************** fmtId(const char *rawid)
*** 104,114 ****
* Note: ScanKeywordLookup() does case-insensitive comparison, but
* that's fine, since we already know we have all-lower-case.
*/
! const ScanKeyword *keyword = ScanKeywordLookup(rawid,
! ScanKeywords,
! NumScanKeywords);
! if (keyword != NULL && keyword->category != UNRESERVED_KEYWORD)
need_quotes = true;
}
--- 104,112 ----
* Note: ScanKeywordLookup() does case-insensitive comparison, but
* that's fine, since we already know we have all-lower-case.
*/
! int kwnum = ScanKeywordLookup(rawid, &ScanKeywords);
! if (kwnum >= 0 && ScanKeywordCategories[kwnum] != UNRESERVED_KEYWORD)
need_quotes = true;
}
diff --git a/src/include/common/keywords.h b/src/include/common/keywords.h
index 8f22f32..fb18858 100644
*** a/src/include/common/keywords.h
--- b/src/include/common/keywords.h
***************
*** 1,7 ****
/*-------------------------------------------------------------------------
*
* keywords.h
! * lexical token lookup for key words in PostgreSQL
*
*
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
--- 1,7 ----
/*-------------------------------------------------------------------------
*
* keywords.h
! * PostgreSQL's list of SQL keywords
*
*
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
***************
*** 14,44 ****
#ifndef KEYWORDS_H
#define KEYWORDS_H
/* Keyword categories --- should match lists in gram.y */
#define UNRESERVED_KEYWORD 0
#define COL_NAME_KEYWORD 1
#define TYPE_FUNC_NAME_KEYWORD 2
#define RESERVED_KEYWORD 3
-
- typedef struct ScanKeyword
- {
- const char *name; /* in lower case */
- int16 value; /* grammar's token code */
- int16 category; /* see codes above */
- } ScanKeyword;
-
#ifndef FRONTEND
! extern PGDLLIMPORT const ScanKeyword ScanKeywords[];
! extern PGDLLIMPORT const int NumScanKeywords;
#else
! extern const ScanKeyword ScanKeywords[];
! extern const int NumScanKeywords;
#endif
-
- extern const ScanKeyword *ScanKeywordLookup(const char *text,
- const ScanKeyword *keywords,
- int num_keywords);
-
#endif /* KEYWORDS_H */
--- 14,33 ----
#ifndef KEYWORDS_H
#define KEYWORDS_H
+ #include "common/kwlookup.h"
+
/* Keyword categories --- should match lists in gram.y */
#define UNRESERVED_KEYWORD 0
#define COL_NAME_KEYWORD 1
#define TYPE_FUNC_NAME_KEYWORD 2
#define RESERVED_KEYWORD 3
#ifndef FRONTEND
! extern PGDLLIMPORT const ScanKeywordList ScanKeywords;
! extern PGDLLIMPORT const uint8 ScanKeywordCategories[];
#else
! extern const ScanKeywordList ScanKeywords;
! extern const uint8 ScanKeywordCategories[];
#endif
#endif /* KEYWORDS_H */
diff --git a/src/include/common/kwlookup.h b/src/include/common/kwlookup.h
index ...3098df3 .
*** a/src/include/common/kwlookup.h
--- b/src/include/common/kwlookup.h
***************
*** 0 ****
--- 1,39 ----
+ /*-------------------------------------------------------------------------
+ *
+ * kwlookup.h
+ * Key word lookup for PostgreSQL
+ *
+ *
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/common/kwlookup.h
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef KWLOOKUP_H
+ #define KWLOOKUP_H
+
+ /*
+ * This struct contains the data needed by ScanKeywordLookup to perform a
+ * search within a set of keywords. The contents are typically generated by
+ * src/tools/gen_keywordlist.pl from a header containing PG_KEYWORD macros.
+ */
+ typedef struct ScanKeywordList
+ {
+ const char *kw_string; /* all keywords in order, separated by \0 */
+ const uint16 *kw_offsets; /* offsets to the start of each keyword */
+ int num_keywords; /* number of keywords */
+ } ScanKeywordList;
+
+
+ extern int ScanKeywordLookup(const char *text, const ScanKeywordList *keywords);
+
+ /* Code that wants to retrieve the text of the N'th keyword should use this. */
+ static inline const char *
+ GetScanKeyword(int n, const ScanKeywordList *keywords)
+ {
+ return keywords->kw_string + keywords->kw_offsets[n];
+ }
+
+ #endif /* KWLOOKUP_H */
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 0256d53..b8902d3 100644
*** a/src/include/parser/kwlist.h
--- b/src/include/parser/kwlist.h
***************
*** 2,8 ****
*
* kwlist.h
*
! * The keyword list is kept in its own source file for possible use by
* automatic tools. The exact representation of a keyword is determined
* by the PG_KEYWORD macro, which is not defined in this file; it can
* be defined by the caller for special purposes.
--- 2,8 ----
*
* kwlist.h
*
! * The keyword lists are kept in their own source files for use by
* automatic tools. The exact representation of a keyword is determined
* by the PG_KEYWORD macro, which is not defined in this file; it can
* be defined by the caller for special purposes.
diff --git a/src/include/parser/scanner.h b/src/include/parser/scanner.h
index 009550f..91e1c83 100644
*** a/src/include/parser/scanner.h
--- b/src/include/parser/scanner.h
*************** typedef struct core_yy_extra_type
*** 73,82 ****
Size scanbuflen;
/*
! * The keyword list to use.
*/
! const ScanKeyword *keywords;
! int num_keywords;
/*
* Scanner settings to use. These are initialized from the corresponding
--- 73,82 ----
Size scanbuflen;
/*
! * The keyword list to use, and the associated grammar token codes.
*/
! const ScanKeywordList *keywordlist;
! const uint16 *keyword_tokens;
/*
* Scanner settings to use. These are initialized from the corresponding
*************** typedef struct core_yy_extra_type
*** 116,126 ****
typedef void *core_yyscan_t;
/* Entry points in parser/scan.l */
extern core_yyscan_t scanner_init(const char *str,
core_yy_extra_type *yyext,
! const ScanKeyword *keywords,
! int num_keywords);
extern void scanner_finish(core_yyscan_t yyscanner);
extern int core_yylex(core_YYSTYPE *lvalp, YYLTYPE *llocp,
core_yyscan_t yyscanner);
--- 116,129 ----
typedef void *core_yyscan_t;
+ /* Constant data exported from parser/scan.l */
+ extern PGDLLIMPORT const uint16 ScanKeywordTokens[];
+
/* Entry points in parser/scan.l */
extern core_yyscan_t scanner_init(const char *str,
core_yy_extra_type *yyext,
! const ScanKeywordList *keywordlist,
! const uint16 *keyword_tokens);
extern void scanner_finish(core_yyscan_t yyscanner);
extern int core_yylex(core_YYSTYPE *lvalp, YYLTYPE *llocp,
core_yyscan_t yyscanner);
diff --git a/src/interfaces/ecpg/preproc/.gitignore b/src/interfaces/ecpg/preproc/.gitignore
index 38ae2fe..958a826 100644
*** a/src/interfaces/ecpg/preproc/.gitignore
--- b/src/interfaces/ecpg/preproc/.gitignore
***************
*** 2,6 ****
--- 2,8 ----
/preproc.c
/preproc.h
/pgc.c
+ /c_kwlist_d.h
+ /ecpg_kwlist_d.h
/typename.c
/ecpg
diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile
index 69ddd8e..9b145a1 100644
*** a/src/interfaces/ecpg/preproc/Makefile
--- b/src/interfaces/ecpg/preproc/Makefile
*************** OBJS= preproc.o pgc.o type.o ecpg.o outp
*** 28,33 ****
--- 28,35 ----
keywords.o c_keywords.o ecpg_keywords.o typename.o descriptor.o variable.o \
$(WIN32RES)
+ GEN_KEYWORDLIST = $(top_srcdir)/src/tools/gen_keywordlist.pl
+
# Suppress parallel build to avoid a bug in GNU make 3.82
# (see comments in ../Makefile)
ifeq ($(MAKE_VERSION),3.82)
*************** preproc.y: ../../../backend/parser/gram.
*** 53,61 ****
$(PERL) $(srcdir)/parse.pl $(srcdir) < $< > $@
$(PERL) $(srcdir)/check_rules.pl $(srcdir) $<
ecpg_keywords.o c_keywords.o keywords.o preproc.o pgc.o parser.o: preproc.h
! distprep: preproc.y preproc.c preproc.h pgc.c
install: all installdirs
$(INSTALL_PROGRAM) ecpg$(X) '$(DESTDIR)$(bindir)'
--- 55,73 ----
$(PERL) $(srcdir)/parse.pl $(srcdir) < $< > $@
$(PERL) $(srcdir)/check_rules.pl $(srcdir) $<
+ # generate keyword headers
+ c_kwlist_d.h: c_kwlist.h $(GEN_KEYWORDLIST)
+ $(PERL) $(GEN_KEYWORDLIST) --varname ScanCKeywords $<
+
+ ecpg_kwlist_d.h: ecpg_kwlist.h $(GEN_KEYWORDLIST)
+ $(PERL) $(GEN_KEYWORDLIST) --varname ScanECPGKeywords $<
+
+ # Force these dependencies to be known even without dependency info built:
ecpg_keywords.o c_keywords.o keywords.o preproc.o pgc.o parser.o: preproc.h
+ ecpg_keywords.o: ecpg_kwlist_d.h
+ c_keywords.o: c_kwlist_d.h
! distprep: preproc.y preproc.c preproc.h pgc.c c_kwlist_d.h ecpg_kwlist_d.h
install: all installdirs
$(INSTALL_PROGRAM) ecpg$(X) '$(DESTDIR)$(bindir)'
*************** installdirs:
*** 66,77 ****
uninstall:
rm -f '$(DESTDIR)$(bindir)/ecpg$(X)'
clean distclean:
rm -f *.o ecpg$(X)
rm -f typename.c
- # `make distclean' must not remove preproc.y, preproc.c, preproc.h, or pgc.c
- # since we want to ship those files in the distribution for people with
- # inadequate tools. Instead, `make maintainer-clean' will remove them.
maintainer-clean: distclean
! rm -f preproc.y preproc.c preproc.h pgc.c
--- 78,88 ----
uninstall:
rm -f '$(DESTDIR)$(bindir)/ecpg$(X)'
+ # preproc.y, preproc.c, preproc.h, pgc.c, c_kwlist_d.h, and ecpg_kwlist_d.h
+ # are in the distribution tarball, so they are not cleaned here.
clean distclean:
rm -f *.o ecpg$(X)
rm -f typename.c
maintainer-clean: distclean
! rm -f preproc.y preproc.c preproc.h pgc.c c_kwlist_d.h ecpg_kwlist_d.h
diff --git a/src/interfaces/ecpg/preproc/c_keywords.c b/src/interfaces/ecpg/preproc/c_keywords.c
index c367dbf..521992f 100644
*** a/src/interfaces/ecpg/preproc/c_keywords.c
--- b/src/interfaces/ecpg/preproc/c_keywords.c
***************
*** 14,85 ****
#include "preproc_extern.h"
#include "preproc.h"
! /*
! * List of (keyword-name, keyword-token-value) pairs.
! *
! * !!WARNING!!: This list must be sorted, because binary
! * search is used to locate entries.
! */
! static const ScanKeyword ScanCKeywords[] = {
! /* name, value, category */
! /*
! * category is not needed in ecpg, it is only here so we can share the
! * data structure with the backend
! */
! {"VARCHAR", VARCHAR, 0},
! {"auto", S_AUTO, 0},
! {"bool", SQL_BOOL, 0},
! {"char", CHAR_P, 0},
! {"const", S_CONST, 0},
! {"enum", ENUM_P, 0},
! {"extern", S_EXTERN, 0},
! {"float", FLOAT_P, 0},
! {"hour", HOUR_P, 0},
! {"int", INT_P, 0},
! {"long", SQL_LONG, 0},
! {"minute", MINUTE_P, 0},
! {"month", MONTH_P, 0},
! {"register", S_REGISTER, 0},
! {"second", SECOND_P, 0},
! {"short", SQL_SHORT, 0},
! {"signed", SQL_SIGNED, 0},
! {"static", S_STATIC, 0},
! {"struct", SQL_STRUCT, 0},
! {"to", TO, 0},
! {"typedef", S_TYPEDEF, 0},
! {"union", UNION, 0},
! {"unsigned", SQL_UNSIGNED, 0},
! {"varchar", VARCHAR, 0},
! {"volatile", S_VOLATILE, 0},
! {"year", YEAR_P, 0},
};
/*
* Do a binary search using plain strcmp() comparison. This is much like
* ScanKeywordLookup(), except we want case-sensitive matching.
*/
! const ScanKeyword *
ScanCKeywordLookup(const char *text)
{
! const ScanKeyword *low = &ScanCKeywords[0];
! const ScanKeyword *high = &ScanCKeywords[lengthof(ScanCKeywords) - 1];
while (low <= high)
{
! const ScanKeyword *middle;
int difference;
middle = low + (high - low) / 2;
! difference = strcmp(middle->name, text);
if (difference == 0)
! return middle;
else if (difference < 0)
low = middle + 1;
else
high = middle - 1;
}
! return NULL;
}
--- 14,67 ----
#include "preproc_extern.h"
#include "preproc.h"
! /* ScanKeywordList lookup data for C keywords */
! #include "c_kwlist_d.h"
! /* Token codes for C keywords */
! #define PG_KEYWORD(kwname, value) value,
!
! static const uint16 ScanCKeywordTokens[] = {
! #include "c_kwlist.h"
};
+ #undef PG_KEYWORD
+
/*
+ * ScanCKeywordLookup - see if a given word is a keyword
+ *
+ * Returns the token value of the keyword, or -1 if no match.
+ *
* Do a binary search using plain strcmp() comparison. This is much like
* ScanKeywordLookup(), except we want case-sensitive matching.
*/
! int
ScanCKeywordLookup(const char *text)
{
! const char *kw_string;
! const uint16 *kw_offsets;
! const uint16 *low;
! const uint16 *high;
!
! kw_string = ScanCKeywords.kw_string;
! kw_offsets = ScanCKeywords.kw_offsets;
! low = kw_offsets;
! high = kw_offsets + (ScanCKeywords.num_keywords - 1);
while (low <= high)
{
! const uint16 *middle;
int difference;
middle = low + (high - low) / 2;
! difference = strcmp(kw_string + *middle, text);
if (difference == 0)
! return ScanCKeywordTokens[middle - kw_offsets];
else if (difference < 0)
low = middle + 1;
else
high = middle - 1;
}
! return -1;
}
diff --git a/src/interfaces/ecpg/preproc/c_kwlist.h b/src/interfaces/ecpg/preproc/c_kwlist.h
index ...4545505 .
*** a/src/interfaces/ecpg/preproc/c_kwlist.h
--- b/src/interfaces/ecpg/preproc/c_kwlist.h
***************
*** 0 ****
--- 1,53 ----
+ /*-------------------------------------------------------------------------
+ *
+ * c_kwlist.h
+ *
+ * The keyword lists are kept in their own source files for use by
+ * automatic tools. The exact representation of a keyword is determined
+ * by the PG_KEYWORD macro, which is not defined in this file; it can
+ * be defined by the caller for special purposes.
+ *
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/interfaces/ecpg/preproc/c_kwlist.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+ /* There is deliberately not an #ifndef C_KWLIST_H here. */
+
+ /*
+ * List of (keyword-name, keyword-token-value) pairs.
+ *
+ * !!WARNING!!: This list must be sorted by ASCII name, because binary
+ * search is used to locate entries.
+ */
+
+ /* name, value */
+ PG_KEYWORD("VARCHAR", VARCHAR)
+ PG_KEYWORD("auto", S_AUTO)
+ PG_KEYWORD("bool", SQL_BOOL)
+ PG_KEYWORD("char", CHAR_P)
+ PG_KEYWORD("const", S_CONST)
+ PG_KEYWORD("enum", ENUM_P)
+ PG_KEYWORD("extern", S_EXTERN)
+ PG_KEYWORD("float", FLOAT_P)
+ PG_KEYWORD("hour", HOUR_P)
+ PG_KEYWORD("int", INT_P)
+ PG_KEYWORD("long", SQL_LONG)
+ PG_KEYWORD("minute", MINUTE_P)
+ PG_KEYWORD("month", MONTH_P)
+ PG_KEYWORD("register", S_REGISTER)
+ PG_KEYWORD("second", SECOND_P)
+ PG_KEYWORD("short", SQL_SHORT)
+ PG_KEYWORD("signed", SQL_SIGNED)
+ PG_KEYWORD("static", S_STATIC)
+ PG_KEYWORD("struct", SQL_STRUCT)
+ PG_KEYWORD("to", TO)
+ PG_KEYWORD("typedef", S_TYPEDEF)
+ PG_KEYWORD("union", UNION)
+ PG_KEYWORD("unsigned", SQL_UNSIGNED)
+ PG_KEYWORD("varchar", VARCHAR)
+ PG_KEYWORD("volatile", S_VOLATILE)
+ PG_KEYWORD("year", YEAR_P)
diff --git a/src/interfaces/ecpg/preproc/ecpg_keywords.c b/src/interfaces/ecpg/preproc/ecpg_keywords.c
index 37c97e1..4839c37 100644
*** a/src/interfaces/ecpg/preproc/ecpg_keywords.c
--- b/src/interfaces/ecpg/preproc/ecpg_keywords.c
***************
*** 16,97 ****
#include "preproc_extern.h"
#include "preproc.h"
! /*
! * List of (keyword-name, keyword-token-value) pairs.
! *
! * !!WARNING!!: This list must be sorted, because binary
! * search is used to locate entries.
! */
! static const ScanKeyword ECPGScanKeywords[] = {
! /* name, value, category */
! /*
! * category is not needed in ecpg, it is only here so we can share the
! * data structure with the backend
! */
! {"allocate", SQL_ALLOCATE, 0},
! {"autocommit", SQL_AUTOCOMMIT, 0},
! {"bool", SQL_BOOL, 0},
! {"break", SQL_BREAK, 0},
! {"cardinality", SQL_CARDINALITY, 0},
! {"connect", SQL_CONNECT, 0},
! {"count", SQL_COUNT, 0},
! {"datetime_interval_code", SQL_DATETIME_INTERVAL_CODE, 0},
! {"datetime_interval_precision", SQL_DATETIME_INTERVAL_PRECISION, 0},
! {"describe", SQL_DESCRIBE, 0},
! {"descriptor", SQL_DESCRIPTOR, 0},
! {"disconnect", SQL_DISCONNECT, 0},
! {"found", SQL_FOUND, 0},
! {"free", SQL_FREE, 0},
! {"get", SQL_GET, 0},
! {"go", SQL_GO, 0},
! {"goto", SQL_GOTO, 0},
! {"identified", SQL_IDENTIFIED, 0},
! {"indicator", SQL_INDICATOR, 0},
! {"key_member", SQL_KEY_MEMBER, 0},
! {"length", SQL_LENGTH, 0},
! {"long", SQL_LONG, 0},
! {"nullable", SQL_NULLABLE, 0},
! {"octet_length", SQL_OCTET_LENGTH, 0},
! {"open", SQL_OPEN, 0},
! {"output", SQL_OUTPUT, 0},
! {"reference", SQL_REFERENCE, 0},
! {"returned_length", SQL_RETURNED_LENGTH, 0},
! {"returned_octet_length", SQL_RETURNED_OCTET_LENGTH, 0},
! {"scale", SQL_SCALE, 0},
! {"section", SQL_SECTION, 0},
! {"short", SQL_SHORT, 0},
! {"signed", SQL_SIGNED, 0},
! {"sqlerror", SQL_SQLERROR, 0},
! {"sqlprint", SQL_SQLPRINT, 0},
! {"sqlwarning", SQL_SQLWARNING, 0},
! {"stop", SQL_STOP, 0},
! {"struct", SQL_STRUCT, 0},
! {"unsigned", SQL_UNSIGNED, 0},
! {"var", SQL_VAR, 0},
! {"whenever", SQL_WHENEVER, 0},
};
/*
* ScanECPGKeywordLookup - see if a given word is a keyword
*
! * Returns a pointer to the ScanKeyword table entry, or NULL if no match.
* Keywords are matched using the same case-folding rules as in the backend.
*/
! const ScanKeyword *
ScanECPGKeywordLookup(const char *text)
{
! const ScanKeyword *res;
/* First check SQL symbols defined by the backend. */
! res = ScanKeywordLookup(text, SQLScanKeywords, NumSQLScanKeywords);
! if (res)
! return res;
/* Try ECPG-specific keywords. */
! res = ScanKeywordLookup(text, ECPGScanKeywords, lengthof(ECPGScanKeywords));
! if (res)
! return res;
! return NULL;
}
--- 16,55 ----
#include "preproc_extern.h"
#include "preproc.h"
! /* ScanKeywordList lookup data for ECPG keywords */
! #include "ecpg_kwlist_d.h"
! /* Token codes for ECPG keywords */
! #define PG_KEYWORD(kwname, value) value,
!
! static const uint16 ECPGScanKeywordTokens[] = {
! #include "ecpg_kwlist.h"
};
+ #undef PG_KEYWORD
+
+
/*
* ScanECPGKeywordLookup - see if a given word is a keyword
*
! * Returns the token value of the keyword, or -1 if no match.
! *
* Keywords are matched using the same case-folding rules as in the backend.
*/
! int
ScanECPGKeywordLookup(const char *text)
{
! int kwnum;
/* First check SQL symbols defined by the backend. */
! kwnum = ScanKeywordLookup(text, &ScanKeywords);
! if (kwnum >= 0)
! return SQLScanKeywordTokens[kwnum];
/* Try ECPG-specific keywords. */
! kwnum = ScanKeywordLookup(text, &ScanECPGKeywords);
! if (kwnum >= 0)
! return ECPGScanKeywordTokens[kwnum];
! return -1;
}
diff --git a/src/interfaces/ecpg/preproc/ecpg_kwlist.h b/src/interfaces/ecpg/preproc/ecpg_kwlist.h
index ...97ef254 .
*** a/src/interfaces/ecpg/preproc/ecpg_kwlist.h
--- b/src/interfaces/ecpg/preproc/ecpg_kwlist.h
***************
*** 0 ****
--- 1,68 ----
+ /*-------------------------------------------------------------------------
+ *
+ * ecpg_kwlist.h
+ *
+ * The keyword lists are kept in their own source files for use by
+ * automatic tools. The exact representation of a keyword is determined
+ * by the PG_KEYWORD macro, which is not defined in this file; it can
+ * be defined by the caller for special purposes.
+ *
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/interfaces/ecpg/preproc/ecpg_kwlist.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+ /* There is deliberately not an #ifndef ECPG_KWLIST_H here. */
+
+ /*
+ * List of (keyword-name, keyword-token-value) pairs.
+ *
+ * !!WARNING!!: This list must be sorted by ASCII name, because binary
+ * search is used to locate entries.
+ */
+
+ /* name, value */
+ PG_KEYWORD("allocate", SQL_ALLOCATE)
+ PG_KEYWORD("autocommit", SQL_AUTOCOMMIT)
+ PG_KEYWORD("bool", SQL_BOOL)
+ PG_KEYWORD("break", SQL_BREAK)
+ PG_KEYWORD("cardinality", SQL_CARDINALITY)
+ PG_KEYWORD("connect", SQL_CONNECT)
+ PG_KEYWORD("count", SQL_COUNT)
+ PG_KEYWORD("datetime_interval_code", SQL_DATETIME_INTERVAL_CODE)
+ PG_KEYWORD("datetime_interval_precision", SQL_DATETIME_INTERVAL_PRECISION)
+ PG_KEYWORD("describe", SQL_DESCRIBE)
+ PG_KEYWORD("descriptor", SQL_DESCRIPTOR)
+ PG_KEYWORD("disconnect", SQL_DISCONNECT)
+ PG_KEYWORD("found", SQL_FOUND)
+ PG_KEYWORD("free", SQL_FREE)
+ PG_KEYWORD("get", SQL_GET)
+ PG_KEYWORD("go", SQL_GO)
+ PG_KEYWORD("goto", SQL_GOTO)
+ PG_KEYWORD("identified", SQL_IDENTIFIED)
+ PG_KEYWORD("indicator", SQL_INDICATOR)
+ PG_KEYWORD("key_member", SQL_KEY_MEMBER)
+ PG_KEYWORD("length", SQL_LENGTH)
+ PG_KEYWORD("long", SQL_LONG)
+ PG_KEYWORD("nullable", SQL_NULLABLE)
+ PG_KEYWORD("octet_length", SQL_OCTET_LENGTH)
+ PG_KEYWORD("open", SQL_OPEN)
+ PG_KEYWORD("output", SQL_OUTPUT)
+ PG_KEYWORD("reference", SQL_REFERENCE)
+ PG_KEYWORD("returned_length", SQL_RETURNED_LENGTH)
+ PG_KEYWORD("returned_octet_length", SQL_RETURNED_OCTET_LENGTH)
+ PG_KEYWORD("scale", SQL_SCALE)
+ PG_KEYWORD("section", SQL_SECTION)
+ PG_KEYWORD("short", SQL_SHORT)
+ PG_KEYWORD("signed", SQL_SIGNED)
+ PG_KEYWORD("sqlerror", SQL_SQLERROR)
+ PG_KEYWORD("sqlprint", SQL_SQLPRINT)
+ PG_KEYWORD("sqlwarning", SQL_SQLWARNING)
+ PG_KEYWORD("stop", SQL_STOP)
+ PG_KEYWORD("struct", SQL_STRUCT)
+ PG_KEYWORD("unsigned", SQL_UNSIGNED)
+ PG_KEYWORD("var", SQL_VAR)
+ PG_KEYWORD("whenever", SQL_WHENEVER)
diff --git a/src/interfaces/ecpg/preproc/keywords.c b/src/interfaces/ecpg/preproc/keywords.c
index 12409e9..0380409 100644
*** a/src/interfaces/ecpg/preproc/keywords.c
--- b/src/interfaces/ecpg/preproc/keywords.c
***************
*** 17,40 ****
/*
* This is much trickier than it looks. We are #include'ing kwlist.h
! * but the "value" numbers that go into the table are from preproc.h
! * not the backend's gram.h. Therefore this table will recognize all
! * keywords known to the backend, but will supply the token numbers used
* by ecpg's grammar, which is what we need. The ecpg grammar must
* define all the same token names the backend does, else we'll get
* undefined-symbol failures in this compile.
*/
- #include "common/keywords.h"
-
#include "preproc_extern.h"
#include "preproc.h"
! #define PG_KEYWORD(a,b,c) {a,b,c},
!
! const ScanKeyword SQLScanKeywords[] = {
#include "parser/kwlist.h"
};
! const int NumSQLScanKeywords = lengthof(SQLScanKeywords);
--- 17,38 ----
/*
* This is much trickier than it looks. We are #include'ing kwlist.h
! * but the token numbers that go into the table are from preproc.h
! * not the backend's gram.h. Therefore this token table will match
! * the ScanKeywords table supplied from common/keywords.c, including all
! * keywords known to the backend, but it will supply the token numbers used
* by ecpg's grammar, which is what we need. The ecpg grammar must
* define all the same token names the backend does, else we'll get
* undefined-symbol failures in this compile.
*/
#include "preproc_extern.h"
#include "preproc.h"
+ #define PG_KEYWORD(kwname, value, category) value,
! const uint16 SQLScanKeywordTokens[] = {
#include "parser/kwlist.h"
};
! #undef PG_KEYWORD
diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l
index a60564c..3131f5f 100644
*** a/src/interfaces/ecpg/preproc/pgc.l
--- b/src/interfaces/ecpg/preproc/pgc.l
*************** cppline {space}*#([^i][A-Za-z]*|{if}|{
*** 920,938 ****
}
{identifier} {
- const ScanKeyword *keyword;
-
if (!isdefine())
{
/* Is it an SQL/ECPG keyword? */
! keyword = ScanECPGKeywordLookup(yytext);
! if (keyword != NULL)
! return keyword->value;
/* Is it a C keyword? */
! keyword = ScanCKeywordLookup(yytext);
! if (keyword != NULL)
! return keyword->value;
/*
* None of the above. Return it as an identifier.
--- 920,938 ----
}
{identifier} {
if (!isdefine())
{
+ int kwvalue;
+
/* Is it an SQL/ECPG keyword? */
! kwvalue = ScanECPGKeywordLookup(yytext);
! if (kwvalue >= 0)
! return kwvalue;
/* Is it a C keyword? */
! kwvalue = ScanCKeywordLookup(yytext);
! if (kwvalue >= 0)
! return kwvalue;
/*
* None of the above. Return it as an identifier.
*************** cppline {space}*#([^i][A-Za-z]*|{if}|{
*** 1010,1021 ****
return CPP_LINE;
}
<C>{identifier} {
- const ScanKeyword *keyword;
-
/*
* Try to detect a function name:
* look for identifiers at the global scope
! * keep the last identifier before the first '(' and '{' */
if (braces_open == 0 && parenths_open == 0)
{
if (current_function)
--- 1010,1020 ----
return CPP_LINE;
}
<C>{identifier} {
/*
* Try to detect a function name:
* look for identifiers at the global scope
! * keep the last identifier before the first '(' and '{'
! */
if (braces_open == 0 && parenths_open == 0)
{
if (current_function)
*************** cppline {space}*#([^i][A-Za-z]*|{if}|{
*** 1026,1034 ****
/* however, some defines have to be taken care of for compatibility */
if ((!INFORMIX_MODE || !isinformixdefine()) && !isdefine())
{
! keyword = ScanCKeywordLookup(yytext);
! if (keyword != NULL)
! return keyword->value;
else
{
base_yylval.str = mm_strdup(yytext);
--- 1025,1035 ----
/* however, some defines have to be taken care of for compatibility */
if ((!INFORMIX_MODE || !isinformixdefine()) && !isdefine())
{
! int kwvalue;
!
! kwvalue = ScanCKeywordLookup(yytext);
! if (kwvalue >= 0)
! return kwvalue;
else
{
base_yylval.str = mm_strdup(yytext);
diff --git a/src/interfaces/ecpg/preproc/preproc_extern.h b/src/interfaces/ecpg/preproc/preproc_extern.h
index 13eda67..9746780 100644
*** a/src/interfaces/ecpg/preproc/preproc_extern.h
--- b/src/interfaces/ecpg/preproc/preproc_extern.h
*************** extern struct when when_error,
*** 59,66 ****
extern struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH];
/* Globals from keywords.c */
! extern const ScanKeyword SQLScanKeywords[];
! extern const int NumSQLScanKeywords;
/* functions */
--- 59,65 ----
extern struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH];
/* Globals from keywords.c */
! extern const uint16 SQLScanKeywordTokens[];
/* functions */
*************** extern void check_indicator(struct ECPGt
*** 102,109 ****
extern void remove_typedefs(int);
extern void remove_variables(int);
extern struct variable *new_variable(const char *, struct ECPGtype *, int);
! extern const ScanKeyword *ScanCKeywordLookup(const char *);
! extern const ScanKeyword *ScanECPGKeywordLookup(const char *text);
extern void parser_init(void);
extern int filtered_base_yylex(void);
--- 101,108 ----
extern void remove_typedefs(int);
extern void remove_variables(int);
extern struct variable *new_variable(const char *, struct ECPGtype *, int);
! extern int ScanCKeywordLookup(const char *text);
! extern int ScanECPGKeywordLookup(const char *text);
extern void parser_init(void);
extern int filtered_base_yylex(void);
diff --git a/src/pl/plpgsql/src/.gitignore b/src/pl/plpgsql/src/.gitignore
index ff6ac96..3ab9a22 100644
*** a/src/pl/plpgsql/src/.gitignore
--- b/src/pl/plpgsql/src/.gitignore
***************
*** 1,5 ****
--- 1,7 ----
/pl_gram.c
/pl_gram.h
+ /pl_reserved_kwlist_d.h
+ /pl_unreserved_kwlist_d.h
/plerrcodes.h
/log/
/results/
diff --git a/src/pl/plpgsql/src/Makefile b/src/pl/plpgsql/src/Makefile
index 25a5a9d..9dd4a74 100644
*** a/src/pl/plpgsql/src/Makefile
--- b/src/pl/plpgsql/src/Makefile
*************** REGRESS_OPTS = --dbname=$(PL_TESTDB)
*** 29,34 ****
--- 29,36 ----
REGRESS = plpgsql_call plpgsql_control plpgsql_domain plpgsql_record \
plpgsql_cache plpgsql_transaction plpgsql_varprops
+ GEN_KEYWORDLIST = $(top_srcdir)/src/tools/gen_keywordlist.pl
+
all: all-lib
# Shared library stuff
*************** uninstall-headers:
*** 61,66 ****
--- 63,69 ----
# Force these dependencies to be known even without dependency info built:
pl_gram.o pl_handler.o pl_comp.o pl_exec.o pl_funcs.o pl_scanner.o: plpgsql.h pl_gram.h plerrcodes.h
+ pl_scanner.o: pl_reserved_kwlist_d.h pl_unreserved_kwlist_d.h
# See notes in src/backend/parser/Makefile about the following two rules
pl_gram.h: pl_gram.c
*************** pl_gram.c: BISONFLAGS += -d
*** 72,77 ****
--- 75,87 ----
plerrcodes.h: $(top_srcdir)/src/backend/utils/errcodes.txt generate-plerrcodes.pl
$(PERL) $(srcdir)/generate-plerrcodes.pl $< > $@
+ # generate keyword headers for the scanner
+ pl_reserved_kwlist_d.h: pl_reserved_kwlist.h $(GEN_KEYWORDLIST)
+ $(PERL) $(GEN_KEYWORDLIST) --varname ReservedPLKeywords $<
+
+ pl_unreserved_kwlist_d.h: pl_unreserved_kwlist.h $(GEN_KEYWORDLIST)
+ $(PERL) $(GEN_KEYWORDLIST) --varname UnreservedPLKeywords $<
+
check: submake
$(pg_regress_check) $(REGRESS_OPTS) $(REGRESS)
*************** submake:
*** 84,96 ****
$(MAKE) -C $(top_builddir)/src/test/regress pg_regress$(X)
! distprep: pl_gram.h pl_gram.c plerrcodes.h
! # pl_gram.c, pl_gram.h and plerrcodes.h are in the distribution tarball,
! # so they are not cleaned here.
clean distclean: clean-lib
rm -f $(OBJS)
rm -rf $(pg_regress_clean_files)
maintainer-clean: distclean
! rm -f pl_gram.c pl_gram.h plerrcodes.h
--- 94,107 ----
$(MAKE) -C $(top_builddir)/src/test/regress pg_regress$(X)
! distprep: pl_gram.h pl_gram.c plerrcodes.h pl_reserved_kwlist_d.h pl_unreserved_kwlist_d.h
! # pl_gram.c, pl_gram.h, plerrcodes.h, pl_reserved_kwlist_d.h, and
! # pl_unreserved_kwlist_d.h are in the distribution tarball, so they
! # are not cleaned here.
clean distclean: clean-lib
rm -f $(OBJS)
rm -rf $(pg_regress_clean_files)
maintainer-clean: distclean
! rm -f pl_gram.c pl_gram.h plerrcodes.h pl_reserved_kwlist_d.h pl_unreserved_kwlist_d.h
diff --git a/src/pl/plpgsql/src/pl_reserved_kwlist.h b/src/pl/plpgsql/src/pl_reserved_kwlist.h
index ...5c2e0c1 .
*** a/src/pl/plpgsql/src/pl_reserved_kwlist.h
--- b/src/pl/plpgsql/src/pl_reserved_kwlist.h
***************
*** 0 ****
--- 1,53 ----
+ /*-------------------------------------------------------------------------
+ *
+ * pl_reserved_kwlist.h
+ *
+ * The keyword lists are kept in their own source files for use by
+ * automatic tools. The exact representation of a keyword is determined
+ * by the PG_KEYWORD macro, which is not defined in this file; it can
+ * be defined by the caller for special purposes.
+ *
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/pl/plpgsql/src/pl_reserved_kwlist.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+ /* There is deliberately not an #ifndef PL_RESERVED_KWLIST_H here. */
+
+ /*
+ * List of (keyword-name, keyword-token-value) pairs.
+ *
+ * Be careful not to put the same word in both lists.
+ *
+ * !!WARNING!!: This list must be sorted by ASCII name, because binary
+ * search is used to locate entries.
+ */
+
+ /* name, value */
+ PG_KEYWORD("all", K_ALL)
+ PG_KEYWORD("begin", K_BEGIN)
+ PG_KEYWORD("by", K_BY)
+ PG_KEYWORD("case", K_CASE)
+ PG_KEYWORD("declare", K_DECLARE)
+ PG_KEYWORD("else", K_ELSE)
+ PG_KEYWORD("end", K_END)
+ PG_KEYWORD("execute", K_EXECUTE)
+ PG_KEYWORD("for", K_FOR)
+ PG_KEYWORD("foreach", K_FOREACH)
+ PG_KEYWORD("from", K_FROM)
+ PG_KEYWORD("if", K_IF)
+ PG_KEYWORD("in", K_IN)
+ PG_KEYWORD("into", K_INTO)
+ PG_KEYWORD("loop", K_LOOP)
+ PG_KEYWORD("not", K_NOT)
+ PG_KEYWORD("null", K_NULL)
+ PG_KEYWORD("or", K_OR)
+ PG_KEYWORD("strict", K_STRICT)
+ PG_KEYWORD("then", K_THEN)
+ PG_KEYWORD("to", K_TO)
+ PG_KEYWORD("using", K_USING)
+ PG_KEYWORD("when", K_WHEN)
+ PG_KEYWORD("while", K_WHILE)
diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c
index 8340628..c260438 100644
*** a/src/pl/plpgsql/src/pl_scanner.c
--- b/src/pl/plpgsql/src/pl_scanner.c
***************
*** 22,37 ****
#include "pl_gram.h" /* must be after parser/scanner.h */
- #define PG_KEYWORD(a,b,c) {a,b,c},
-
-
/* Klugy flag to tell scanner how to look up identifiers */
IdentifierLookup plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
/*
* A word about keywords:
*
! * We keep reserved and unreserved keywords in separate arrays. The
* reserved keywords are passed to the core scanner, so they will be
* recognized before (and instead of) any variable name. Unreserved words
* are checked for separately, usually after determining that the identifier
--- 22,36 ----
#include "pl_gram.h" /* must be after parser/scanner.h */
/* Klugy flag to tell scanner how to look up identifiers */
IdentifierLookup plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
/*
* A word about keywords:
*
! * We keep reserved and unreserved keywords in separate headers. Be careful
! * not to put the same word in both headers. Also be sure that pl_gram.y's
! * unreserved_keyword production agrees with the unreserved header. The
* reserved keywords are passed to the core scanner, so they will be
* recognized before (and instead of) any variable name. Unreserved words
* are checked for separately, usually after determining that the identifier
*************** IdentifierLookup plpgsql_IdentifierLooku
*** 57,186 ****
* BEGIN BY DECLARE EXECUTE FOREACH IF LOOP STRICT WHILE
*/
! /*
! * Lists of keyword (name, token-value, category) entries.
! *
! * !!WARNING!!: These lists must be sorted by ASCII name, because binary
! * search is used to locate entries.
! *
! * Be careful not to put the same word in both lists. Also be sure that
! * pl_gram.y's unreserved_keyword production agrees with the second list.
! */
! static const ScanKeyword reserved_keywords[] = {
! PG_KEYWORD("all", K_ALL, RESERVED_KEYWORD)
! PG_KEYWORD("begin", K_BEGIN, RESERVED_KEYWORD)
! PG_KEYWORD("by", K_BY, RESERVED_KEYWORD)
! PG_KEYWORD("case", K_CASE, RESERVED_KEYWORD)
! PG_KEYWORD("declare", K_DECLARE, RESERVED_KEYWORD)
! PG_KEYWORD("else", K_ELSE, RESERVED_KEYWORD)
! PG_KEYWORD("end", K_END, RESERVED_KEYWORD)
! PG_KEYWORD("execute", K_EXECUTE, RESERVED_KEYWORD)
! PG_KEYWORD("for", K_FOR, RESERVED_KEYWORD)
! PG_KEYWORD("foreach", K_FOREACH, RESERVED_KEYWORD)
! PG_KEYWORD("from", K_FROM, RESERVED_KEYWORD)
! PG_KEYWORD("if", K_IF, RESERVED_KEYWORD)
! PG_KEYWORD("in", K_IN, RESERVED_KEYWORD)
! PG_KEYWORD("into", K_INTO, RESERVED_KEYWORD)
! PG_KEYWORD("loop", K_LOOP, RESERVED_KEYWORD)
! PG_KEYWORD("not", K_NOT, RESERVED_KEYWORD)
! PG_KEYWORD("null", K_NULL, RESERVED_KEYWORD)
! PG_KEYWORD("or", K_OR, RESERVED_KEYWORD)
! PG_KEYWORD("strict", K_STRICT, RESERVED_KEYWORD)
! PG_KEYWORD("then", K_THEN, RESERVED_KEYWORD)
! PG_KEYWORD("to", K_TO, RESERVED_KEYWORD)
! PG_KEYWORD("using", K_USING, RESERVED_KEYWORD)
! PG_KEYWORD("when", K_WHEN, RESERVED_KEYWORD)
! PG_KEYWORD("while", K_WHILE, RESERVED_KEYWORD)
! };
! static const int num_reserved_keywords = lengthof(reserved_keywords);
! static const ScanKeyword unreserved_keywords[] = {
! PG_KEYWORD("absolute", K_ABSOLUTE, UNRESERVED_KEYWORD)
! PG_KEYWORD("alias", K_ALIAS, UNRESERVED_KEYWORD)
! PG_KEYWORD("array", K_ARRAY, UNRESERVED_KEYWORD)
! PG_KEYWORD("assert", K_ASSERT, UNRESERVED_KEYWORD)
! PG_KEYWORD("backward", K_BACKWARD, UNRESERVED_KEYWORD)
! PG_KEYWORD("call", K_CALL, UNRESERVED_KEYWORD)
! PG_KEYWORD("close", K_CLOSE, UNRESERVED_KEYWORD)
! PG_KEYWORD("collate", K_COLLATE, UNRESERVED_KEYWORD)
! PG_KEYWORD("column", K_COLUMN, UNRESERVED_KEYWORD)
! PG_KEYWORD("column_name", K_COLUMN_NAME, UNRESERVED_KEYWORD)
! PG_KEYWORD("commit", K_COMMIT, UNRESERVED_KEYWORD)
! PG_KEYWORD("constant", K_CONSTANT, UNRESERVED_KEYWORD)
! PG_KEYWORD("constraint", K_CONSTRAINT, UNRESERVED_KEYWORD)
! PG_KEYWORD("constraint_name", K_CONSTRAINT_NAME, UNRESERVED_KEYWORD)
! PG_KEYWORD("continue", K_CONTINUE, UNRESERVED_KEYWORD)
! PG_KEYWORD("current", K_CURRENT, UNRESERVED_KEYWORD)
! PG_KEYWORD("cursor", K_CURSOR, UNRESERVED_KEYWORD)
! PG_KEYWORD("datatype", K_DATATYPE, UNRESERVED_KEYWORD)
! PG_KEYWORD("debug", K_DEBUG, UNRESERVED_KEYWORD)
! PG_KEYWORD("default", K_DEFAULT, UNRESERVED_KEYWORD)
! PG_KEYWORD("detail", K_DETAIL, UNRESERVED_KEYWORD)
! PG_KEYWORD("diagnostics", K_DIAGNOSTICS, UNRESERVED_KEYWORD)
! PG_KEYWORD("do", K_DO, UNRESERVED_KEYWORD)
! PG_KEYWORD("dump", K_DUMP, UNRESERVED_KEYWORD)
! PG_KEYWORD("elseif", K_ELSIF, UNRESERVED_KEYWORD)
! PG_KEYWORD("elsif", K_ELSIF, UNRESERVED_KEYWORD)
! PG_KEYWORD("errcode", K_ERRCODE, UNRESERVED_KEYWORD)
! PG_KEYWORD("error", K_ERROR, UNRESERVED_KEYWORD)
! PG_KEYWORD("exception", K_EXCEPTION, UNRESERVED_KEYWORD)
! PG_KEYWORD("exit", K_EXIT, UNRESERVED_KEYWORD)
! PG_KEYWORD("fetch", K_FETCH, UNRESERVED_KEYWORD)
! PG_KEYWORD("first", K_FIRST, UNRESERVED_KEYWORD)
! PG_KEYWORD("forward", K_FORWARD, UNRESERVED_KEYWORD)
! PG_KEYWORD("get", K_GET, UNRESERVED_KEYWORD)
! PG_KEYWORD("hint", K_HINT, UNRESERVED_KEYWORD)
! PG_KEYWORD("import", K_IMPORT, UNRESERVED_KEYWORD)
! PG_KEYWORD("info", K_INFO, UNRESERVED_KEYWORD)
! PG_KEYWORD("insert", K_INSERT, UNRESERVED_KEYWORD)
! PG_KEYWORD("is", K_IS, UNRESERVED_KEYWORD)
! PG_KEYWORD("last", K_LAST, UNRESERVED_KEYWORD)
! PG_KEYWORD("log", K_LOG, UNRESERVED_KEYWORD)
! PG_KEYWORD("message", K_MESSAGE, UNRESERVED_KEYWORD)
! PG_KEYWORD("message_text", K_MESSAGE_TEXT, UNRESERVED_KEYWORD)
! PG_KEYWORD("move", K_MOVE, UNRESERVED_KEYWORD)
! PG_KEYWORD("next", K_NEXT, UNRESERVED_KEYWORD)
! PG_KEYWORD("no", K_NO, UNRESERVED_KEYWORD)
! PG_KEYWORD("notice", K_NOTICE, UNRESERVED_KEYWORD)
! PG_KEYWORD("open", K_OPEN, UNRESERVED_KEYWORD)
! PG_KEYWORD("option", K_OPTION, UNRESERVED_KEYWORD)
! PG_KEYWORD("perform", K_PERFORM, UNRESERVED_KEYWORD)
! PG_KEYWORD("pg_context", K_PG_CONTEXT, UNRESERVED_KEYWORD)
! PG_KEYWORD("pg_datatype_name", K_PG_DATATYPE_NAME, UNRESERVED_KEYWORD)
! PG_KEYWORD("pg_exception_context", K_PG_EXCEPTION_CONTEXT, UNRESERVED_KEYWORD)
! PG_KEYWORD("pg_exception_detail", K_PG_EXCEPTION_DETAIL, UNRESERVED_KEYWORD)
! PG_KEYWORD("pg_exception_hint", K_PG_EXCEPTION_HINT, UNRESERVED_KEYWORD)
! PG_KEYWORD("print_strict_params", K_PRINT_STRICT_PARAMS, UNRESERVED_KEYWORD)
! PG_KEYWORD("prior", K_PRIOR, UNRESERVED_KEYWORD)
! PG_KEYWORD("query", K_QUERY, UNRESERVED_KEYWORD)
! PG_KEYWORD("raise", K_RAISE, UNRESERVED_KEYWORD)
! PG_KEYWORD("relative", K_RELATIVE, UNRESERVED_KEYWORD)
! PG_KEYWORD("reset", K_RESET, UNRESERVED_KEYWORD)
! PG_KEYWORD("return", K_RETURN, UNRESERVED_KEYWORD)
! PG_KEYWORD("returned_sqlstate", K_RETURNED_SQLSTATE, UNRESERVED_KEYWORD)
! PG_KEYWORD("reverse", K_REVERSE, UNRESERVED_KEYWORD)
! PG_KEYWORD("rollback", K_ROLLBACK, UNRESERVED_KEYWORD)
! PG_KEYWORD("row_count", K_ROW_COUNT, UNRESERVED_KEYWORD)
! PG_KEYWORD("rowtype", K_ROWTYPE, UNRESERVED_KEYWORD)
! PG_KEYWORD("schema", K_SCHEMA, UNRESERVED_KEYWORD)
! PG_KEYWORD("schema_name", K_SCHEMA_NAME, UNRESERVED_KEYWORD)
! PG_KEYWORD("scroll", K_SCROLL, UNRESERVED_KEYWORD)
! PG_KEYWORD("set", K_SET, UNRESERVED_KEYWORD)
! PG_KEYWORD("slice", K_SLICE, UNRESERVED_KEYWORD)
! PG_KEYWORD("sqlstate", K_SQLSTATE, UNRESERVED_KEYWORD)
! PG_KEYWORD("stacked", K_STACKED, UNRESERVED_KEYWORD)
! PG_KEYWORD("table", K_TABLE, UNRESERVED_KEYWORD)
! PG_KEYWORD("table_name", K_TABLE_NAME, UNRESERVED_KEYWORD)
! PG_KEYWORD("type", K_TYPE, UNRESERVED_KEYWORD)
! PG_KEYWORD("use_column", K_USE_COLUMN, UNRESERVED_KEYWORD)
! PG_KEYWORD("use_variable", K_USE_VARIABLE, UNRESERVED_KEYWORD)
! PG_KEYWORD("variable_conflict", K_VARIABLE_CONFLICT, UNRESERVED_KEYWORD)
! PG_KEYWORD("warning", K_WARNING, UNRESERVED_KEYWORD)
};
! static const int num_unreserved_keywords = lengthof(unreserved_keywords);
/*
* This macro must recognize all tokens that can immediately precede a
--- 56,77 ----
* BEGIN BY DECLARE EXECUTE FOREACH IF LOOP STRICT WHILE
*/
! /* ScanKeywordList lookup data for PL/pgSQL keywords */
! #include "pl_reserved_kwlist_d.h"
! #include "pl_unreserved_kwlist_d.h"
! /* Token codes for PL/pgSQL keywords */
! #define PG_KEYWORD(kwname, value) value,
! static const uint16 ReservedPLKeywordTokens[] = {
! #include "pl_reserved_kwlist.h"
! };
! static const uint16 UnreservedPLKeywordTokens[] = {
! #include "pl_unreserved_kwlist.h"
};
! #undef PG_KEYWORD
/*
* This macro must recognize all tokens that can immediately precede a
*************** plpgsql_yylex(void)
*** 256,262 ****
{
int tok1;
TokenAuxData aux1;
! const ScanKeyword *kw;
tok1 = internal_yylex(&aux1);
if (tok1 == IDENT || tok1 == PARAM)
--- 147,153 ----
{
int tok1;
TokenAuxData aux1;
! int kwnum;
tok1 = internal_yylex(&aux1);
if (tok1 == IDENT || tok1 == PARAM)
*************** plpgsql_yylex(void)
*** 333,344 ****
&aux1.lval.word))
tok1 = T_DATUM;
else if (!aux1.lval.word.quoted &&
! (kw = ScanKeywordLookup(aux1.lval.word.ident,
! unreserved_keywords,
! num_unreserved_keywords)))
{
! aux1.lval.keyword = kw->name;
! tok1 = kw->value;
}
else
tok1 = T_WORD;
--- 224,235 ----
&aux1.lval.word))
tok1 = T_DATUM;
else if (!aux1.lval.word.quoted &&
! (kwnum = ScanKeywordLookup(aux1.lval.word.ident,
! &UnreservedPLKeywords)) >= 0)
{
! aux1.lval.keyword = GetScanKeyword(kwnum,
! &UnreservedPLKeywords);
! tok1 = UnreservedPLKeywordTokens[kwnum];
}
else
tok1 = T_WORD;
*************** plpgsql_yylex(void)
*** 375,386 ****
&aux1.lval.word))
tok1 = T_DATUM;
else if (!aux1.lval.word.quoted &&
! (kw = ScanKeywordLookup(aux1.lval.word.ident,
! unreserved_keywords,
! num_unreserved_keywords)))
{
! aux1.lval.keyword = kw->name;
! tok1 = kw->value;
}
else
tok1 = T_WORD;
--- 266,277 ----
&aux1.lval.word))
tok1 = T_DATUM;
else if (!aux1.lval.word.quoted &&
! (kwnum = ScanKeywordLookup(aux1.lval.word.ident,
! &UnreservedPLKeywords)) >= 0)
{
! aux1.lval.keyword = GetScanKeyword(kwnum,
! &UnreservedPLKeywords);
! tok1 = UnreservedPLKeywordTokens[kwnum];
}
else
tok1 = T_WORD;
*************** plpgsql_token_is_unreserved_keyword(int
*** 497,505 ****
{
int i;
! for (i = 0; i < num_unreserved_keywords; i++)
{
! if (unreserved_keywords[i].value == token)
return true;
}
return false;
--- 388,396 ----
{
int i;
! for (i = 0; i < lengthof(UnreservedPLKeywordTokens); i++)
{
! if (UnreservedPLKeywordTokens[i] == token)
return true;
}
return false;
*************** plpgsql_scanner_init(const char *str)
*** 696,702 ****
{
/* Start up the core scanner */
yyscanner = scanner_init(str, &core_yy,
! reserved_keywords, num_reserved_keywords);
/*
* scanorig points to the original string, which unlike the scanner's
--- 587,593 ----
{
/* Start up the core scanner */
yyscanner = scanner_init(str, &core_yy,
! &ReservedPLKeywords, ReservedPLKeywordTokens);
/*
* scanorig points to the original string, which unlike the scanner's
diff --git a/src/pl/plpgsql/src/pl_unreserved_kwlist.h b/src/pl/plpgsql/src/pl_unreserved_kwlist.h
index ...ef2aea0 .
*** a/src/pl/plpgsql/src/pl_unreserved_kwlist.h
--- b/src/pl/plpgsql/src/pl_unreserved_kwlist.h
***************
*** 0 ****
--- 1,111 ----
+ /*-------------------------------------------------------------------------
+ *
+ * pl_unreserved_kwlist.h
+ *
+ * The keyword lists are kept in their own source files for use by
+ * automatic tools. The exact representation of a keyword is determined
+ * by the PG_KEYWORD macro, which is not defined in this file; it can
+ * be defined by the caller for special purposes.
+ *
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/pl/plpgsql/src/pl_unreserved_kwlist.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+ /* There is deliberately not an #ifndef PL_UNRESERVED_KWLIST_H here. */
+
+ /*
+ * List of (keyword-name, keyword-token-value) pairs.
+ *
+ * Be careful not to put the same word in both lists. Also be sure that
+ * pl_gram.y's unreserved_keyword production agrees with this list.
+ *
+ * !!WARNING!!: This list must be sorted by ASCII name, because binary
+ * search is used to locate entries.
+ */
+
+ /* name, value */
+ PG_KEYWORD("absolute", K_ABSOLUTE)
+ PG_KEYWORD("alias", K_ALIAS)
+ PG_KEYWORD("array", K_ARRAY)
+ PG_KEYWORD("assert", K_ASSERT)
+ PG_KEYWORD("backward", K_BACKWARD)
+ PG_KEYWORD("call", K_CALL)
+ PG_KEYWORD("close", K_CLOSE)
+ PG_KEYWORD("collate", K_COLLATE)
+ PG_KEYWORD("column", K_COLUMN)
+ PG_KEYWORD("column_name", K_COLUMN_NAME)
+ PG_KEYWORD("commit", K_COMMIT)
+ PG_KEYWORD("constant", K_CONSTANT)
+ PG_KEYWORD("constraint", K_CONSTRAINT)
+ PG_KEYWORD("constraint_name", K_CONSTRAINT_NAME)
+ PG_KEYWORD("continue", K_CONTINUE)
+ PG_KEYWORD("current", K_CURRENT)
+ PG_KEYWORD("cursor", K_CURSOR)
+ PG_KEYWORD("datatype", K_DATATYPE)
+ PG_KEYWORD("debug", K_DEBUG)
+ PG_KEYWORD("default", K_DEFAULT)
+ PG_KEYWORD("detail", K_DETAIL)
+ PG_KEYWORD("diagnostics", K_DIAGNOSTICS)
+ PG_KEYWORD("do", K_DO)
+ PG_KEYWORD("dump", K_DUMP)
+ PG_KEYWORD("elseif", K_ELSIF)
+ PG_KEYWORD("elsif", K_ELSIF)
+ PG_KEYWORD("errcode", K_ERRCODE)
+ PG_KEYWORD("error", K_ERROR)
+ PG_KEYWORD("exception", K_EXCEPTION)
+ PG_KEYWORD("exit", K_EXIT)
+ PG_KEYWORD("fetch", K_FETCH)
+ PG_KEYWORD("first", K_FIRST)
+ PG_KEYWORD("forward", K_FORWARD)
+ PG_KEYWORD("get", K_GET)
+ PG_KEYWORD("hint", K_HINT)
+ PG_KEYWORD("import", K_IMPORT)
+ PG_KEYWORD("info", K_INFO)
+ PG_KEYWORD("insert", K_INSERT)
+ PG_KEYWORD("is", K_IS)
+ PG_KEYWORD("last", K_LAST)
+ PG_KEYWORD("log", K_LOG)
+ PG_KEYWORD("message", K_MESSAGE)
+ PG_KEYWORD("message_text", K_MESSAGE_TEXT)
+ PG_KEYWORD("move", K_MOVE)
+ PG_KEYWORD("next", K_NEXT)
+ PG_KEYWORD("no", K_NO)
+ PG_KEYWORD("notice", K_NOTICE)
+ PG_KEYWORD("open", K_OPEN)
+ PG_KEYWORD("option", K_OPTION)
+ PG_KEYWORD("perform", K_PERFORM)
+ PG_KEYWORD("pg_context", K_PG_CONTEXT)
+ PG_KEYWORD("pg_datatype_name", K_PG_DATATYPE_NAME)
+ PG_KEYWORD("pg_exception_context", K_PG_EXCEPTION_CONTEXT)
+ PG_KEYWORD("pg_exception_detail", K_PG_EXCEPTION_DETAIL)
+ PG_KEYWORD("pg_exception_hint", K_PG_EXCEPTION_HINT)
+ PG_KEYWORD("print_strict_params", K_PRINT_STRICT_PARAMS)
+ PG_KEYWORD("prior", K_PRIOR)
+ PG_KEYWORD("query", K_QUERY)
+ PG_KEYWORD("raise", K_RAISE)
+ PG_KEYWORD("relative", K_RELATIVE)
+ PG_KEYWORD("reset", K_RESET)
+ PG_KEYWORD("return", K_RETURN)
+ PG_KEYWORD("returned_sqlstate", K_RETURNED_SQLSTATE)
+ PG_KEYWORD("reverse", K_REVERSE)
+ PG_KEYWORD("rollback", K_ROLLBACK)
+ PG_KEYWORD("row_count", K_ROW_COUNT)
+ PG_KEYWORD("rowtype", K_ROWTYPE)
+ PG_KEYWORD("schema", K_SCHEMA)
+ PG_KEYWORD("schema_name", K_SCHEMA_NAME)
+ PG_KEYWORD("scroll", K_SCROLL)
+ PG_KEYWORD("set", K_SET)
+ PG_KEYWORD("slice", K_SLICE)
+ PG_KEYWORD("sqlstate", K_SQLSTATE)
+ PG_KEYWORD("stacked", K_STACKED)
+ PG_KEYWORD("table", K_TABLE)
+ PG_KEYWORD("table_name", K_TABLE_NAME)
+ PG_KEYWORD("type", K_TYPE)
+ PG_KEYWORD("use_column", K_USE_COLUMN)
+ PG_KEYWORD("use_variable", K_USE_VARIABLE)
+ PG_KEYWORD("variable_conflict", K_VARIABLE_CONFLICT)
+ PG_KEYWORD("warning", K_WARNING)
diff --git a/src/tools/gen_keywordlist.pl b/src/tools/gen_keywordlist.pl
index ...eb5ed65 .
*** a/src/tools/gen_keywordlist.pl
--- b/src/tools/gen_keywordlist.pl
***************
*** 0 ****
--- 1,148 ----
+ #----------------------------------------------------------------------
+ #
+ # gen_keywordlist.pl
+ # Perl script that transforms a list of keywords into a ScanKeywordList
+ # data structure that can be passed to ScanKeywordLookup().
+ #
+ # The input is a C header file containing a series of macro calls
+ # PG_KEYWORD("keyword", ...)
+ # Lines not starting with PG_KEYWORD are ignored. The keywords are
+ # implicitly numbered 0..N-1 in order of appearance in the header file.
+ # Currently, the keywords are required to appear in ASCII order.
+ #
+ # The output is a C header file that defines a "const ScanKeywordList"
+ # variable named according to the -v switch ("ScanKeywords" by default).
+ # The variable is marked "static" unless the -e switch is given.
+ #
+ #
+ # Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
+ # Portions Copyright (c) 1994, Regents of the University of California
+ #
+ # src/tools/gen_keywordlist.pl
+ #
+ #----------------------------------------------------------------------
+
+ use strict;
+ use warnings;
+ use Getopt::Long;
+
+ my $output_path = '';
+ my $extern = 0;
+ my $varname = 'ScanKeywords';
+
+ GetOptions(
+ 'output:s' => \$output_path,
+ 'extern' => \$extern,
+ 'varname:s' => \$varname) || usage();
+
+ my $kw_input_file = shift @ARGV || die "No input file.\n";
+
+ # Make sure output_path ends in a slash if needed.
+ if ($output_path ne '' && substr($output_path, -1) ne '/')
+ {
+ $output_path .= '/';
+ }
+
+ $kw_input_file =~ /(\w+)\.h$/ || die "Input file must be named something.h.\n";
+ my $base_filename = $1 . '_d';
+ my $kw_def_file = $output_path . $base_filename . '.h';
+
+ open(my $kif, '<', $kw_input_file) || die "$kw_input_file: $!\n";
+ open(my $kwdef, '>', $kw_def_file) || die "$kw_def_file: $!\n";
+
+ # Opening boilerplate for keyword definition header.
+ printf $kwdef <<EOM, $base_filename, uc $base_filename, uc $base_filename;
+ /*-------------------------------------------------------------------------
+ *
+ * %s.h
+ * List of keywords represented as a ScanKeywordList.
+ *
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * NOTES
+ * ******************************
+ * *** DO NOT EDIT THIS FILE! ***
+ * ******************************
+ *
+ * It has been GENERATED by src/tools/gen_keywordlist.pl
+ *
+ *-------------------------------------------------------------------------
+ */
+
+ #ifndef %s_H
+ #define %s_H
+
+ #include "common/kwlookup.h"
+
+ EOM
+
+ # Parse input file for keyword names.
+ my @keywords;
+ while (<$kif>)
+ {
+ if (/^PG_KEYWORD\("(\w+)"/)
+ {
+ push @keywords, $1;
+ }
+ }
+
+ # Error out if the keyword names are not in ASCII order.
+ for my $i (0..$#keywords - 1)
+ {
+ die qq|The keyword "$keywords[$i + 1]" is out of order in $kw_input_file\n|
+ if ($keywords[$i] cmp $keywords[$i + 1]) >= 0;
+ }
+
+ # Emit the string containing all the keywords.
+
+ printf $kwdef qq|static const char %s_kw_string[] =\n\t"|, $varname;
+ print $kwdef join qq|\\0"\n\t"|, @keywords;
+ print $kwdef qq|";\n\n|;
+
+ # Emit an array of numerical offsets which will be used to index into the
+ # keyword string.
+
+ printf $kwdef "static const uint16 %s_kw_offsets[] = {\n", $varname;
+
+ my $offset = 0;
+ foreach my $name (@keywords)
+ {
+ print $kwdef "\t$offset,\n";
+
+ # Calculate the cumulative offset of the next keyword,
+ # taking into account the null terminator.
+ $offset += length($name) + 1;
+ }
+
+ print $kwdef "};\n\n";
+
+ # Emit a macro defining the number of keywords.
+
+ printf $kwdef "#define %s_NUM_KEYWORDS %d\n\n", uc $varname, scalar @keywords;
+
+ # Emit the struct that wraps all this lookup info into one variable.
+
+ print $kwdef "static " if !$extern;
+ printf $kwdef "const ScanKeywordList %s = {\n", $varname;
+ printf $kwdef qq|\t%s_kw_string,\n|, $varname;
+ printf $kwdef qq|\t%s_kw_offsets,\n|, $varname;
+ printf $kwdef qq|\t%s_NUM_KEYWORDS\n|, uc $varname;
+ print $kwdef "};\n\n";
+
+ printf $kwdef "#endif\t\t\t\t\t\t\t/* %s_H */\n", uc $base_filename;
+
+
+ sub usage
+ {
+ die <<EOM;
+ Usage: gen_keywordlist.pl [--output/-o <path>] [--varname/-v <varname>] [--extern/-e] input_file
+ --output Output directory (default '.')
+ --varname Name for ScanKeywordList variable (default 'ScanKeywords')
+ --extern Allow the ScanKeywordList variable to be globally visible
+
+ gen_keywordlist.pl transforms a list of keywords into a ScanKeywordList.
+ The output filename is derived from the input file by inserting _d,
+ for example kwlist_d.h is produced from kwlist.h.
+ EOM
+ }
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index eb2346b..937bf18 100644
*** a/src/tools/msvc/Solution.pm
--- b/src/tools/msvc/Solution.pm
*************** sub GenerateFiles
*** 410,415 ****
--- 410,451 ----
}
if (IsNewer(
+ 'src/common/kwlist_d.h',
+ 'src/include/parser/kwlist.h'))
+ {
+ print "Generating kwlist_d.h...\n";
+ system('perl src/tools/gen_keywordlist.pl --extern -o src/common src/include/parser/kwlist.h');
+ }
+
+ if (IsNewer(
+ 'src/pl/plpgsql/src/pl_reserved_kwlist_d.h',
+ 'src/pl/plpgsql/src/pl_reserved_kwlist.h')
+ || IsNewer(
+ 'src/pl/plpgsql/src/pl_unreserved_kwlist_d.h',
+ 'src/pl/plpgsql/src/pl_unreserved_kwlist.h'))
+ {
+ print "Generating pl_reserved_kwlist_d.h and pl_unreserved_kwlist_d.h...\n";
+ chdir('src/pl/plpgsql/src');
+ system('perl ../../../tools/gen_keywordlist.pl --varname ReservedPLKeywords pl_reserved_kwlist.h');
+ system('perl ../../../tools/gen_keywordlist.pl --varname UnreservedPLKeywords pl_unreserved_kwlist.h');
+ chdir('../../../..');
+ }
+
+ if (IsNewer(
+ 'src/interfaces/ecpg/preproc/c_kwlist_d.h',
+ 'src/interfaces/ecpg/preproc/c_kwlist.h')
+ || IsNewer(
+ 'src/interfaces/ecpg/preproc/ecpg_kwlist_d.h',
+ 'src/interfaces/ecpg/preproc/ecpg_kwlist.h'))
+ {
+ print "Generating c_kwlist_d.h and ecpg_kwlist_d.h...\n";
+ chdir('src/interfaces/ecpg/preproc');
+ system('perl ../../../tools/gen_keywordlist.pl --varname ScanCKeywords c_kwlist.h');
+ system('perl ../../../tools/gen_keywordlist.pl --varname ScanECPGKeywords ecpg_kwlist.h');
+ chdir('../../../..');
+ }
+
+ if (IsNewer(
'src/interfaces/ecpg/preproc/preproc.y',
'src/backend/parser/gram.y'))
{
diff --git a/src/tools/msvc/clean.bat b/src/tools/msvc/clean.bat
index 7a23a2b..069d6eb 100755
*** a/src/tools/msvc/clean.bat
--- b/src/tools/msvc/clean.bat
*************** if %DIST%==1 if exist src\pl\tcl\pltcler
*** 64,69 ****
--- 64,74 ----
if %DIST%==1 if exist src\backend\utils\sort\qsort_tuple.c del /q src\backend\utils\sort\qsort_tuple.c
if %DIST%==1 if exist src\bin\psql\sql_help.c del /q src\bin\psql\sql_help.c
if %DIST%==1 if exist src\bin\psql\sql_help.h del /q src\bin\psql\sql_help.h
+ if %DIST%==1 if exist src\common\kwlist_d.h del /q src\common\kwlist_d.h
+ if %DIST%==1 if exist src\pl\plpgsql\src\pl_reserved_kwlist_d.h del /q src\pl\plpgsql\src\pl_reserved_kwlist_d.h
+ if %DIST%==1 if exist src\pl\plpgsql\src\pl_unreserved_kwlist_d.h del /q src\pl\plpgsql\src\pl_unreserved_kwlist_d.h
+ if %DIST%==1 if exist src\interfaces\ecpg\preproc\c_kwlist_d.h del /q src\interfaces\ecpg\preproc\c_kwlist_d.h
+ if %DIST%==1 if exist src\interfaces\ecpg\preproc\ecpg_kwlist_d.h del /q src\interfaces\ecpg\preproc\ecpg_kwlist_d.h
if %DIST%==1 if exist src\interfaces\ecpg\preproc\preproc.y del /q src\interfaces\ecpg\preproc\preproc.y
if %DIST%==1 if exist src\backend\catalog\postgres.bki del /q src\backend\catalog\postgres.bki
if %DIST%==1 if exist src\backend\catalog\postgres.description del /q src\backend\catalog\postgres.description