1 /*-------------------------------------------------------------------------
4 * lexical token lookup for reserved words in PostgreSQL
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.51 2002/06/30 09:34:13 meskes Exp $
13 *-------------------------------------------------------------------------
15 #include "postgres_fe.h"
24 * List of (keyword-name, keyword-token-value) pairs.
26 * !!WARNING!!: This list must be sorted, because binary
27 * search is used to locate entries.
29 static ScanKeyword ScanKeywords[] = {
31 {"abort", ABORT_TRANS},
32 {"absolute", ABSOLUTE},
37 {"aggregate", AGGREGATE},
40 {"analyse", ANALYSE}, /* British spelling */
46 {"assertion", ASSERTION},
47 {"assignment", ASSIGNMENT},
49 {"authorization", AUTHORIZATION},
50 {"backward", BACKWARD},
52 {"begin", BEGIN_TRANS},
67 {"character", CHARACTER},
68 {"characteristics", CHARACTERISTICS},
70 {"checkpoint", CHECKPOINT},
73 {"coalesce", COALESCE},
78 {"committed", COMMITTED},
79 {"constraint", CONSTRAINT},
80 {"constraints", CONSTRAINTS},
83 {"createdb", CREATEDB},
84 {"createuser", CREATEUSER},
86 {"current_date", CURRENT_DATE},
87 {"current_time", CURRENT_TIME},
88 {"current_timestamp", CURRENT_TIMESTAMP},
89 {"current_user", CURRENT_USER},
92 {"database", DATABASE},
98 {"deferrable", DEFERRABLE},
99 {"deferred", DEFERRED},
100 {"definer", DEFINER},
101 {"delete", DELETE_P},
102 {"delimiter", DELIMITER},
103 {"delimiters", DELIMITERS},
105 {"distinct", DISTINCT},
107 {"domain", DOMAIN_P},
112 {"encoding", ENCODING},
113 {"encrypted", ENCRYPTED},
117 {"exclusive", EXCLUSIVE},
118 {"execute", EXECUTE},
120 {"explain", EXPLAIN},
121 {"external", EXTERNAL},
122 {"extract", EXTRACT},
128 {"foreign", FOREIGN},
129 {"forward", FORWARD},
133 {"function", FUNCTION},
137 {"handler", HANDLER},
141 {"immediate", IMMEDIATE},
142 {"immutable", IMMUTABLE},
143 {"implicit", IMPLICIT},
145 {"increment", INCREMENT},
147 {"inherits", INHERITS},
148 {"initially", INITIALLY},
152 {"insensitive", INSENSITIVE},
154 {"instead", INSTEAD},
156 {"integer", INTEGER},
157 {"intersect", INTERSECT},
158 {"interval", INTERVAL},
160 {"invoker", INVOKER},
163 {"isolation", ISOLATION},
166 {"lancompiler", LANCOMPILER},
167 {"language", LANGUAGE},
168 {"leading", LEADING},
176 {"localtime", LOCALTIME},
177 {"localtimestamp", LOCALTIMESTAMP},
178 {"location", LOCATION},
181 {"maxvalue", MAXVALUE},
182 {"minute", MINUTE_P},
183 {"minvalue", MINVALUE},
188 {"national", NATIONAL},
189 {"natural", NATURAL},
194 {"nocreatedb", NOCREATEDB},
195 {"nocreateuser", NOCREATEUSER},
198 {"nothing", NOTHING},
200 {"notnull", NOTNULL},
203 {"numeric", NUMERIC},
211 {"operator", OPERATOR},
217 {"overlaps", OVERLAPS},
218 {"overlay", OVERLAY},
220 {"partial", PARTIAL},
221 {"password", PASSWORD},
223 {"pendant", PENDANT},
224 {"placing", PLACING},
225 {"position", POSITION},
226 {"precision", PRECISION},
227 {"primary", PRIMARY},
229 {"privileges", PRIVILEGES},
230 {"procedural", PROCEDURAL},
231 {"procedure", PROCEDURE},
234 {"references", REFERENCES},
235 {"reindex", REINDEX},
236 {"relative", RELATIVE},
238 {"replace", REPLACE},
240 {"restrict", RESTRICT},
241 {"returns", RETURNS},
244 {"rollback", ROLLBACK},
249 {"second", SECOND_P},
250 {"security", SECURITY},
252 {"sequence", SEQUENCE},
253 {"serializable", SERIALIZABLE},
254 {"session", SESSION},
255 {"session_user", SESSION_USER},
260 {"similar", SIMILAR},
262 {"smallint", SMALLINT},
266 {"statement", STATEMENT},
267 {"statistics", STATISTICS},
270 {"storage", STORAGE},
272 {"substring", SUBSTRING},
276 {"template", TEMPLATE},
277 {"temporary", TEMPORARY},
280 {"timestamp", TIMESTAMP},
283 {"trailing", TRAILING},
284 {"transaction", TRANSACTION},
285 {"trigger", TRIGGER},
288 {"truncate", TRUNCATE},
289 {"trusted", TRUSTED},
291 {"unencrypted", UNENCRYPTED},
294 {"unknown", UNKNOWN},
295 {"unlisten", UNLISTEN},
303 {"validator", VALIDATOR},
305 {"varchar", VARCHAR},
306 {"varying", VARYING},
307 {"verbose", VERBOSE},
308 {"version", VERSION},
310 {"volatile", VOLATILE},
314 {"without", WITHOUT},
322 * ScanKeywordLookup - see if a given word is a keyword
324 * Returns a pointer to the ScanKeyword table entry, or NULL if no match.
326 * The match is done case-insensitively. Note that we deliberately use a
327 * dumbed-down case conversion that will only translate 'A'-'Z' into 'a'-'z',
328 * even if we are in a locale where tolower() would produce more or different
329 * translations. This is to conform to the SQL99 spec, which says that
330 * keywords are to be matched in this way even though non-keyword identifiers
331 * receive a different case-normalization mapping.
334 ScanKeywordLookup(char *text)
338 char word[NAMEDATALEN];
343 /* We assume all keywords are shorter than NAMEDATALEN. */
344 if (len >= NAMEDATALEN)
348 * Apply an ASCII-only downcasing. We must not use tolower() since it
349 * may produce the wrong translation in some locales (eg, Turkish),
350 * and we don't trust isupper() very much either. In an ASCII-based
351 * encoding the tests against A and Z are sufficient, but we also
352 * check isupper() so that we will work correctly under EBCDIC. The
353 * actual case conversion step should work for either ASCII or EBCDIC.
355 for (i = 0; i < len; i++)
359 if (ch >= 'A' && ch <= 'Z' && isupper((unsigned char) ch))
366 * Now do a binary search using plain strcmp() comparison.
368 low = &ScanKeywords[0];
369 high = endof(ScanKeywords) - 1;
375 middle = low + (high - low) / 2;
376 difference = strcmp(middle->name, word);
379 else if (difference < 0)