1 /*-------------------------------------------------------------------------
4 * lexical token lookup for reserved words in PostgreSQL
6 * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.80 2007/06/12 07:55:56 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[] = {
32 {"absolute", ABSOLUTE_P},
38 {"aggregate", AGGREGATE},
43 {"analyse", ANALYSE}, /* British spelling */
50 {"assertion", ASSERTION},
51 {"assignment", ASSIGNMENT},
52 {"asymmetric", ASYMMETRIC},
54 {"authorization", AUTHORIZATION},
55 {"backward", BACKWARD},
62 {"boolean", BOOLEAN_P},
68 {"cascaded", CASCADED},
73 {"character", CHARACTER},
74 {"characteristics", CHARACTERISTICS},
76 {"checkpoint", CHECKPOINT},
80 {"coalesce", COALESCE},
85 {"committed", COMMITTED},
86 {"concurrently", CONCURRENTLY},
87 {"concurrently", CONCURRENTLY},
88 {"connection", CONNECTION},
89 {"constraint", CONSTRAINT},
90 {"constraints", CONSTRAINTS},
91 {"content", CONTENT_P},
92 {"conversion", CONVERSION_P},
97 {"createdb", CREATEDB},
98 {"createrole", CREATEROLE},
99 {"createuser", CREATEUSER},
102 {"current", CURRENT_P},
103 {"current_date", CURRENT_DATE},
104 {"current_role", CURRENT_ROLE},
105 {"current_time", CURRENT_TIME},
106 {"current_timestamp", CURRENT_TIMESTAMP},
109 {"database", DATABASE},
111 {"deallocate", DEALLOCATE},
113 {"decimal", DECIMAL_P},
114 {"declare", DECLARE},
115 {"default", DEFAULT},
116 {"defaults", DEFAULTS},
117 {"deferrable", DEFERRABLE},
118 {"deferred", DEFERRED},
119 {"definer", DEFINER},
120 {"delete", DELETE_P},
121 {"delimiter", DELIMITER},
122 {"delimiters", DELIMITERS},
124 {"disable", DISABLE_P},
125 {"discard", DISCARD},
126 {"distinct", DISTINCT},
128 {"document", DOCUMENT_P},
129 {"domain", DOMAIN_P},
130 {"double", DOUBLE_P},
134 {"enable", ENABLE_P},
135 {"encoding", ENCODING},
136 {"encrypted", ENCRYPTED},
141 {"excluding", EXCLUDING},
142 {"exclusive", EXCLUSIVE},
143 {"execute", EXECUTE},
145 {"explain", EXPLAIN},
146 {"external", EXTERNAL},
147 {"extract", EXTRACT},
155 {"foreign", FOREIGN},
156 {"forward", FORWARD},
160 {"function", FUNCTION},
164 {"granted", GRANTED},
165 {"greatest", GREATEST},
167 {"handler", HANDLER},
169 {"header", HEADER_P},
174 {"immediate", IMMEDIATE},
175 {"immutable", IMMUTABLE},
176 {"implicit", IMPLICIT_P},
178 {"including", INCLUDING},
179 {"increment", INCREMENT},
181 {"indexes", INDEXES},
182 {"inherit", INHERIT},
183 {"inherits", INHERITS},
184 {"initially", INITIALLY},
188 {"insensitive", INSENSITIVE},
190 {"instead", INSTEAD},
192 {"integer", INTEGER},
193 {"intersect", INTERSECT},
194 {"interval", INTERVAL},
196 {"invoker", INVOKER},
199 {"isolation", ISOLATION},
202 {"lancompiler", LANCOMPILER},
203 {"language", LANGUAGE},
206 {"leading", LEADING},
215 {"location", LOCATION},
219 {"maxvalue", MAXVALUE},
220 {"minute", MINUTE_P},
221 {"minvalue", MINVALUE},
227 {"national", NATIONAL},
228 {"natural", NATURAL},
233 {"nocreatedb", NOCREATEDB},
234 {"nocreaterole", NOCREATEROLE},
235 {"nocreateuser", NOCREATEUSER},
236 {"noinherit", NOINHERIT},
237 {"nologin", NOLOGIN_P},
239 {"nosuperuser", NOSUPERUSER},
241 {"nothing", NOTHING},
243 {"notnull", NOTNULL},
248 {"numeric", NUMERIC},
249 {"object", OBJECT_P},
257 {"operator", OPERATOR},
263 {"overlaps", OVERLAPS},
266 {"partial", PARTIAL},
267 {"password", PASSWORD},
268 {"placing", PLACING},
270 {"position", POSITION},
271 {"precision", PRECISION},
272 {"prepare", PREPARE},
273 {"prepared", PREPARED},
274 {"preserve", PRESERVE},
275 {"primary", PRIMARY},
277 {"privileges", PRIVILEGES},
278 {"procedural", PROCEDURAL},
279 {"procedure", PROCEDURE},
283 {"reassign", REASSIGN},
284 {"recheck", RECHECK},
285 {"references", REFERENCES},
286 {"reindex", REINDEX},
287 {"relative", RELATIVE_P},
288 {"release", RELEASE},
290 {"repeatable", REPEATABLE},
291 {"replace", REPLACE},
292 {"replica", REPLICA},
294 {"restart", RESTART},
295 {"restrict", RESTRICT},
296 {"returning", RETURNING},
297 {"returns", RETURNS},
301 {"rollback", ROLLBACK},
305 {"savepoint", SAVEPOINT},
308 {"second", SECOND_P},
309 {"security", SECURITY},
311 {"sequence", SEQUENCE},
312 {"serializable", SERIALIZABLE},
313 {"session", SESSION},
314 {"session_user", SESSION_USER},
319 {"similar", SIMILAR},
321 {"smallint", SMALLINT},
324 {"standalone", STANDALONE_P},
326 {"statement", STATEMENT},
327 {"statistics", STATISTICS},
330 {"storage", STORAGE},
331 {"strict", STRICT_P},
333 {"substring", SUBSTRING},
334 {"superuser", SUPERUSER_P},
335 {"symmetric", SYMMETRIC},
337 {"system", SYSTEM_P},
339 {"tablespace", TABLESPACE},
341 {"template", TEMPLATE},
342 {"temporary", TEMPORARY},
345 {"timestamp", TIMESTAMP},
347 {"trailing", TRAILING},
348 {"transaction", TRANSACTION},
350 {"trigger", TRIGGER},
353 {"truncate", TRUNCATE},
354 {"trusted", TRUSTED},
356 {"uncommitted", UNCOMMITTED},
357 {"unencrypted", UNENCRYPTED},
360 {"unknown", UNKNOWN},
361 {"unlisten", UNLISTEN},
368 {"validator", VALIDATOR},
371 {"varchar", VARCHAR},
372 {"varying", VARYING},
373 {"verbose", VERBOSE},
374 {"version", VERSION_P},
376 {"volatile", VOLATILE},
379 {"whitespace", WHITESPACE_P},
381 {"without", WITHOUT},
385 {"xmlattributes", XMLATTRIBUTES},
386 {"xmlconcat", XMLCONCAT},
387 {"xmlelement", XMLELEMENT},
388 {"xmlforest", XMLFOREST},
389 {"xmlparse", XMLPARSE},
391 {"xmlroot", XMLROOT},
392 {"xmlserialize", XMLSERIALIZE},
399 * ScanKeywordLookup - see if a given word is a keyword
401 * Returns a pointer to the ScanKeyword table entry, or NULL if no match.
403 * The match is done case-insensitively. Note that we deliberately use a
404 * dumbed-down case conversion that will only translate 'A'-'Z' into 'a'-'z',
405 * even if we are in a locale where tolower() would produce more or different
406 * translations. This is to conform to the SQL99 spec, which says that
407 * keywords are to be matched in this way even though non-keyword identifiers
408 * receive a different case-normalization mapping.
411 ScanKeywordLookup(char *text)
415 char word[NAMEDATALEN];
420 /* We assume all keywords are shorter than NAMEDATALEN. */
421 if (len >= NAMEDATALEN)
425 * Apply an ASCII-only downcasing. We must not use tolower() since it may
426 * produce the wrong translation in some locales (eg, Turkish).
428 for (i = 0; i < len; i++)
432 if (ch >= 'A' && ch <= 'Z')
439 * Now do a binary search using plain strcmp() comparison.
441 low = &ScanKeywords[0];
442 high = endof(ScanKeywords) - 1;
448 middle = low + (high - low) / 2;
449 difference = strcmp(middle->name, word);
452 else if (difference < 0)