diff options
Diffstat (limited to 'src/interfaces/ecpg/preproc/ecpg_keywords.c')
| -rw-r--r-- | src/interfaces/ecpg/preproc/ecpg_keywords.c | 60 |
1 files changed, 54 insertions, 6 deletions
diff --git a/src/interfaces/ecpg/preproc/ecpg_keywords.c b/src/interfaces/ecpg/preproc/ecpg_keywords.c index 740b7d9cd3..c65730d9a3 100644 --- a/src/interfaces/ecpg/preproc/ecpg_keywords.c +++ b/src/interfaces/ecpg/preproc/ecpg_keywords.c @@ -1,8 +1,11 @@ /*------------------------------------------------------------------------- * - * keywords.c + * ecpg_keywords.c * lexical token lookup for reserved words in postgres embedded SQL * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/ecpg_keywords.c,v 1.22 2001/02/21 18:53:47 tgl Exp $ + * *------------------------------------------------------------------------- */ #include "postgres_fe.h" @@ -12,6 +15,7 @@ #include "extern.h" #include "preproc.h" + /* * List of (keyword-name, keyword-token-value) pairs. * @@ -73,18 +77,62 @@ static ScanKeyword ScanKeywords[] = { {"whenever", SQL_WHENEVER}, }; +/* + * ScanECPGKeywordLookup - see if a given word is a keyword + * + * 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. + */ ScanKeyword * ScanECPGKeywordLookup(char *text) { - ScanKeyword *low = &ScanKeywords[0]; - ScanKeyword *high = endof(ScanKeywords) - 1; - ScanKeyword *middle; - int difference; + int len, + i; + char word[NAMEDATALEN]; + ScanKeyword *low; + 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), + * and we don't trust isupper() very much either. In an ASCII-based + * encoding the tests against A and Z are sufficient, but we also check + * isupper() so that we will work correctly under EBCDIC. The actual + * case conversion step should work for either ASCII or EBCDIC. + */ + for (i = 0; i < len; i++) + { + char ch = text[i]; + + if (ch >= 'A' && ch <= 'Z' && isupper((unsigned char) ch)) + ch += 'a' - 'A'; + word[i] = ch; + } + word[len] = '\0'; + + /* + * Now do a binary search using plain strcmp() comparison. + */ + low = &ScanKeywords[0]; + high = endof(ScanKeywords) - 1; while (low <= high) { + ScanKeyword *middle; + int difference; + middle = low + (high - low) / 2; - difference = strcmp(middle->name, text); + difference = strcmp(middle->name, word); if (difference == 0) return middle; else if (difference < 0) |
