]> granicus.if.org Git - postgresql/blob - src/interfaces/ecpg/preproc/keywords.c
Committing parser changes. Note, however, that the development bison seems ot have...
[postgresql] / src / interfaces / ecpg / preproc / keywords.c
1 /*-------------------------------------------------------------------------
2  *
3  * keywords.c
4  *        lexical token lookup for reserved words in PostgreSQL
5  *
6  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.51 2002/06/30 09:34:13 meskes Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres_fe.h"
16
17 #include <ctype.h>
18
19 #include "extern.h"
20 #include "preproc.h"
21
22
23 /*
24  * List of (keyword-name, keyword-token-value) pairs.
25  *
26  * !!WARNING!!: This list must be sorted, because binary
27  *               search is used to locate entries.
28  */
29 static ScanKeyword ScanKeywords[] = {
30         /* name, value */
31         {"abort", ABORT_TRANS},
32         {"absolute", ABSOLUTE},
33         {"access", ACCESS},
34         {"action", ACTION},
35         {"add", ADD},
36         {"after", AFTER},
37         {"aggregate", AGGREGATE},
38         {"all", ALL},
39         {"alter", ALTER},
40         {"analyse", ANALYSE},           /* British spelling */
41         {"analyze", ANALYZE},
42         {"and", AND},
43         {"any", ANY},
44         {"as", AS},
45         {"asc", ASC},
46         {"assertion", ASSERTION},
47         {"assignment", ASSIGNMENT},
48         {"at", AT},
49         {"authorization", AUTHORIZATION},
50         {"backward", BACKWARD},
51         {"before", BEFORE},
52         {"begin", BEGIN_TRANS},
53         {"between", BETWEEN},
54         {"bigint", BIGINT},
55         {"binary", BINARY},
56         {"bit", BIT},
57         {"boolean", BOOLEAN},
58         {"both", BOTH},
59         {"by", BY},
60         {"cache", CACHE},
61         {"called", CALLED},
62         {"cascade", CASCADE},
63         {"case", CASE},
64         {"cast", CAST},
65         {"chain", CHAIN},
66         {"char", CHAR_P},
67         {"character", CHARACTER},
68         {"characteristics", CHARACTERISTICS},
69         {"check", CHECK},
70         {"checkpoint", CHECKPOINT},
71         {"close", CLOSE},
72         {"cluster", CLUSTER},
73         {"coalesce", COALESCE},
74         {"collate", COLLATE},
75         {"column", COLUMN},
76         {"comment", COMMENT},
77         {"commit", COMMIT},
78         {"committed", COMMITTED},
79         {"constraint", CONSTRAINT},
80         {"constraints", CONSTRAINTS},
81         {"copy", COPY},
82         {"create", CREATE},
83         {"createdb", CREATEDB},
84         {"createuser", CREATEUSER},
85         {"cross", CROSS},
86         {"current_date", CURRENT_DATE},
87         {"current_time", CURRENT_TIME},
88         {"current_timestamp", CURRENT_TIMESTAMP},
89         {"current_user", CURRENT_USER},
90         {"cursor", CURSOR},
91         {"cycle", CYCLE},
92         {"database", DATABASE},
93         {"day", DAY_P},
94         {"dec", DEC},
95         {"decimal", DECIMAL},
96         {"declare", DECLARE},
97         {"default", DEFAULT},
98         {"deferrable", DEFERRABLE},
99         {"deferred", DEFERRED},
100         {"definer", DEFINER},
101         {"delete", DELETE_P},
102         {"delimiter", DELIMITER},
103         {"delimiters", DELIMITERS},
104         {"desc", DESC},
105         {"distinct", DISTINCT},
106         {"do", DO},
107         {"domain", DOMAIN_P},
108         {"double", DOUBLE},
109         {"drop", DROP},
110         {"each", EACH},
111         {"else", ELSE},
112         {"encoding", ENCODING},
113         {"encrypted", ENCRYPTED},
114         {"end", END_TRANS},
115         {"escape", ESCAPE},
116         {"except", EXCEPT},
117         {"exclusive", EXCLUSIVE},
118         {"execute", EXECUTE},
119         {"exists", EXISTS},
120         {"explain", EXPLAIN},
121         {"external", EXTERNAL},
122         {"extract", EXTRACT},
123         {"false", FALSE_P},
124         {"fetch", FETCH},
125         {"float", FLOAT_P},
126         {"for", FOR},
127         {"force", FORCE},
128         {"foreign", FOREIGN},
129         {"forward", FORWARD},
130         {"freeze", FREEZE},
131         {"from", FROM},
132         {"full", FULL},
133         {"function", FUNCTION},
134         {"global", GLOBAL},
135         {"grant", GRANT},
136         {"group", GROUP_P},
137         {"handler", HANDLER},
138         {"having", HAVING},
139         {"hour", HOUR_P},
140         {"ilike", ILIKE},
141         {"immediate", IMMEDIATE},
142         {"immutable", IMMUTABLE},
143         {"implicit", IMPLICIT},
144         {"in", IN_P},
145         {"increment", INCREMENT},
146         {"index", INDEX},
147         {"inherits", INHERITS},
148         {"initially", INITIALLY},
149         {"inner", INNER_P},
150         {"inout", INOUT},
151         {"input", INPUT},
152         {"insensitive", INSENSITIVE},
153         {"insert", INSERT},
154         {"instead", INSTEAD},
155         {"int", INT},
156         {"integer", INTEGER},
157         {"intersect", INTERSECT},
158         {"interval", INTERVAL},
159         {"into", INTO},
160         {"invoker", INVOKER},
161         {"is", IS},
162         {"isnull", ISNULL},
163         {"isolation", ISOLATION},
164         {"join", JOIN},
165         {"key", KEY},
166         {"lancompiler", LANCOMPILER},
167         {"language", LANGUAGE},
168         {"leading", LEADING},
169         {"left", LEFT},
170         {"level", LEVEL},
171         {"like", LIKE},
172         {"limit", LIMIT},
173         {"listen", LISTEN},
174         {"load", LOAD},
175         {"local", LOCAL},
176         {"localtime", LOCALTIME},
177         {"localtimestamp", LOCALTIMESTAMP},
178         {"location", LOCATION},
179         {"lock", LOCK_P},
180         {"match", MATCH},
181         {"maxvalue", MAXVALUE},
182         {"minute", MINUTE_P},
183         {"minvalue", MINVALUE},
184         {"mode", MODE},
185         {"month", MONTH_P},
186         {"move", MOVE},
187         {"names", NAMES},
188         {"national", NATIONAL},
189         {"natural", NATURAL},
190         {"nchar", NCHAR},
191         {"new", NEW},
192         {"next", NEXT},
193         {"no", NO},
194         {"nocreatedb", NOCREATEDB},
195         {"nocreateuser", NOCREATEUSER},
196         {"none", NONE},
197         {"not", NOT},
198         {"nothing", NOTHING},
199         {"notify", NOTIFY},
200         {"notnull", NOTNULL},
201         {"null", NULL_P},
202         {"nullif", NULLIF},
203         {"numeric", NUMERIC},
204         {"of", OF},
205         {"off", OFF},
206         {"offset", OFFSET},
207         {"oids", OIDS},
208         {"old", OLD},
209         {"on", ON},
210         {"only", ONLY},
211         {"operator", OPERATOR},
212         {"option", OPTION},
213         {"or", OR},
214         {"order", ORDER},
215         {"out", OUT_P},
216         {"outer", OUTER_P},
217         {"overlaps", OVERLAPS},
218         {"overlay", OVERLAY},
219         {"owner", OWNER},
220         {"partial", PARTIAL},
221         {"password", PASSWORD},
222         {"path", PATH_P},
223         {"pendant", PENDANT},
224         {"placing", PLACING},
225         {"position", POSITION},
226         {"precision", PRECISION},
227         {"primary", PRIMARY},
228         {"prior", PRIOR},
229         {"privileges", PRIVILEGES},
230         {"procedural", PROCEDURAL},
231         {"procedure", PROCEDURE},
232         {"read", READ},
233         {"real", REAL},
234         {"references", REFERENCES},
235         {"reindex", REINDEX},
236         {"relative", RELATIVE},
237         {"rename", RENAME},
238         {"replace", REPLACE},
239         {"reset", RESET},
240         {"restrict", RESTRICT},
241         {"returns", RETURNS},
242         {"revoke", REVOKE},
243         {"right", RIGHT},
244         {"rollback", ROLLBACK},
245         {"row", ROW},
246         {"rule", RULE},
247         {"schema", SCHEMA},
248         {"scroll", SCROLL},
249         {"second", SECOND_P},
250         {"security", SECURITY},
251         {"select", SELECT},
252         {"sequence", SEQUENCE},
253         {"serializable", SERIALIZABLE},
254         {"session", SESSION},
255         {"session_user", SESSION_USER},
256         {"set", SET},
257         {"setof", SETOF},
258         {"share", SHARE},
259         {"show", SHOW},
260         {"similar", SIMILAR},
261         {"simple", SIMPLE},
262         {"smallint", SMALLINT},
263         {"some", SOME},
264         {"stable", STABLE},
265         {"start", START},
266         {"statement", STATEMENT},
267         {"statistics", STATISTICS},
268         {"stdin", STDIN},
269         {"stdout", STDOUT},
270         {"storage", STORAGE},
271         {"strict", STRICT},
272         {"substring", SUBSTRING},
273         {"sysid", SYSID},
274         {"table", TABLE},
275         {"temp", TEMP},
276         {"template", TEMPLATE},
277         {"temporary", TEMPORARY},
278         {"then", THEN},
279         {"time", TIME},
280         {"timestamp", TIMESTAMP},
281         {"to", TO},
282         {"toast", TOAST},
283         {"trailing", TRAILING},
284         {"transaction", TRANSACTION},
285         {"trigger", TRIGGER},
286         {"trim", TRIM},
287         {"true", TRUE_P},
288         {"truncate", TRUNCATE},
289         {"trusted", TRUSTED},
290         {"type", TYPE_P},
291         {"unencrypted", UNENCRYPTED},
292         {"union", UNION},
293         {"unique", UNIQUE},
294         {"unknown", UNKNOWN},
295         {"unlisten", UNLISTEN},
296         {"until", UNTIL},
297         {"update", UPDATE},
298         {"usage", USAGE},
299         {"user", USER},
300         {"using", USING},
301         {"vacuum", VACUUM},
302         {"valid", VALID},
303         {"validator", VALIDATOR},
304         {"values", VALUES},
305         {"varchar", VARCHAR},
306         {"varying", VARYING},
307         {"verbose", VERBOSE},
308         {"version", VERSION},
309         {"view", VIEW},
310         {"volatile", VOLATILE},
311         {"when", WHEN},
312         {"where", WHERE},
313         {"with", WITH},
314         {"without", WITHOUT},
315         {"work", WORK},
316         {"write", WRITE},
317         {"year", YEAR_P},
318         {"zone", ZONE},
319 };
320
321 /*
322  * ScanKeywordLookup - see if a given word is a keyword
323  *
324  * Returns a pointer to the ScanKeyword table entry, or NULL if no match.
325  *
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.
332  */
333 ScanKeyword *
334 ScanKeywordLookup(char *text)
335 {
336         int                     len,
337                                 i;
338         char            word[NAMEDATALEN];
339         ScanKeyword *low;
340         ScanKeyword *high;
341
342         len = strlen(text);
343         /* We assume all keywords are shorter than NAMEDATALEN. */
344         if (len >= NAMEDATALEN)
345                 return NULL;
346
347         /*
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.
354          */
355         for (i = 0; i < len; i++)
356         {
357                 char            ch = text[i];
358
359                 if (ch >= 'A' && ch <= 'Z' && isupper((unsigned char) ch))
360                         ch += 'a' - 'A';
361                 word[i] = ch;
362         }
363         word[len] = '\0';
364
365         /*
366          * Now do a binary search using plain strcmp() comparison.
367          */
368         low = &ScanKeywords[0];
369         high = endof(ScanKeywords) - 1;
370         while (low <= high)
371         {
372                 ScanKeyword *middle;
373                 int                     difference;
374
375                 middle = low + (high - low) / 2;
376                 difference = strcmp(middle->name, word);
377                 if (difference == 0)
378                         return middle;
379                 else if (difference < 0)
380                         low = middle + 1;
381                 else
382                         high = middle - 1;
383         }
384
385         return NULL;
386 }