diff options
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/Makefile | 14 | ||||
| -rw-r--r-- | src/common/keywords.c | 114 |
2 files changed, 126 insertions, 2 deletions
diff --git a/src/common/Makefile b/src/common/Makefile index f7a4a4d099a..72b73697a8c 100644 --- a/src/common/Makefile +++ b/src/common/Makefile @@ -36,8 +36,9 @@ override CPPFLAGS += -DVAL_LDFLAGS_EX="\"$(LDFLAGS_EX)\"" override CPPFLAGS += -DVAL_LDFLAGS_SL="\"$(LDFLAGS_SL)\"" override CPPFLAGS += -DVAL_LIBS="\"$(LIBS)\"" -OBJS_COMMON = config_info.o controldata_utils.o exec.o pg_lzcompress.o \ - pgfnames.o psprintf.o relpath.o rmtree.o string.o username.o wait_error.o +OBJS_COMMON = config_info.o controldata_utils.o exec.o keywords.o \ + pg_lzcompress.o pgfnames.o psprintf.o relpath.o rmtree.o \ + string.o username.o wait_error.o OBJS_FRONTEND = $(OBJS_COMMON) fe_memutils.o restricted_token.o @@ -83,5 +84,14 @@ $(OBJS_SRV): | submake-errcodes submake-errcodes: $(MAKE) -C ../backend submake-errcodes +# 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 version 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_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_srv.a $(OBJS_FRONTEND) $(OBJS_SRV) diff --git a/src/common/keywords.c b/src/common/keywords.c new file mode 100644 index 00000000000..485dd02e89d --- /dev/null +++ b/src/common/keywords.c @@ -0,0 +1,114 @@ +/*------------------------------------------------------------------------- + * + * keywords.c + * lexical token lookup for key words in PostgreSQL + * + * + * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/keywords.c + * + *------------------------------------------------------------------------- + */ +#ifndef FRONTEND +#include "postgres.h" +#else +#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; +} |
