]> granicus.if.org Git - postgresql/blob - src/backend/parser/keywords.c
I attach a version of my toast-slicing patch, against current CVS
[postgresql] / src / backend / parser / keywords.c
1 /*-------------------------------------------------------------------------
2  *
3  * keywords.c
4  *        lexical token lookup for reserved words in PostgreSQL
5  *
6  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.101 2002/03/05 05:33:15 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include <ctype.h>
18
19 #include "nodes/parsenodes.h"
20 #include "parser/keywords.h"
21 #include "parser/parse.h"
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         {"at", AT},
47         {"authorization", AUTHORIZATION},
48         {"backward", BACKWARD},
49         {"before", BEFORE},
50         {"begin", BEGIN_TRANS},
51         {"between", BETWEEN},
52         {"binary", BINARY},
53         {"bit", BIT},
54         {"both", BOTH},
55         {"by", BY},
56         {"cache", CACHE},
57         {"cascade", CASCADE},
58         {"case", CASE},
59         {"cast", CAST},
60         {"chain", CHAIN},
61         {"char", CHAR},
62         {"character", CHARACTER},
63         {"characteristics", CHARACTERISTICS},
64         {"check", CHECK},
65         {"checkpoint", CHECKPOINT},
66         {"close", CLOSE},
67         {"cluster", CLUSTER},
68         {"coalesce", COALESCE},
69         {"collate", COLLATE},
70         {"column", COLUMN},
71         {"comment", COMMENT},
72         {"commit", COMMIT},
73         {"committed", COMMITTED},
74         {"constraint", CONSTRAINT},
75         {"constraints", CONSTRAINTS},
76         {"copy", COPY},
77         {"create", CREATE},
78         {"createdb", CREATEDB},
79         {"createuser", CREATEUSER},
80         {"cross", CROSS},
81         {"current_date", CURRENT_DATE},
82         {"current_time", CURRENT_TIME},
83         {"current_timestamp", CURRENT_TIMESTAMP},
84         {"current_user", CURRENT_USER},
85         {"cursor", CURSOR},
86         {"cycle", CYCLE},
87         {"database", DATABASE},
88         {"day", DAY_P},
89         {"dec", DEC},
90         {"decimal", DECIMAL},
91         {"declare", DECLARE},
92         {"default", DEFAULT},
93         {"deferrable", DEFERRABLE},
94         {"deferred", DEFERRED},
95         {"delete", DELETE},
96         {"delimiters", DELIMITERS},
97         {"desc", DESC},
98         {"distinct", DISTINCT},
99         {"do", DO},
100         {"double", DOUBLE},
101         {"drop", DROP},
102         {"each", EACH},
103         {"else", ELSE},
104         {"encoding", ENCODING},
105         {"encrypted", ENCRYPTED},
106         {"end", END_TRANS},
107         {"escape", ESCAPE},
108         {"except", EXCEPT},
109         {"exclusive", EXCLUSIVE},
110         {"execute", EXECUTE},
111         {"exists", EXISTS},
112         {"explain", EXPLAIN},
113         {"extract", EXTRACT},
114         {"false", FALSE_P},
115         {"fetch", FETCH},
116         {"float", FLOAT},
117         {"for", FOR},
118         {"force", FORCE},
119         {"foreign", FOREIGN},
120         {"forward", FORWARD},
121         {"freeze", FREEZE},
122         {"from", FROM},
123         {"full", FULL},
124         {"function", FUNCTION},
125         {"global", GLOBAL},
126         {"grant", GRANT},
127         {"group", GROUP},
128         {"handler", HANDLER},
129         {"having", HAVING},
130         {"hour", HOUR_P},
131         {"ilike", ILIKE},
132         {"immediate", IMMEDIATE},
133         {"in", IN},
134         {"increment", INCREMENT},
135         {"index", INDEX},
136         {"inherits", INHERITS},
137         {"initially", INITIALLY},
138         {"inner", INNER_P},
139         {"inout", INOUT},
140         {"insensitive", INSENSITIVE},
141         {"insert", INSERT},
142         {"instead", INSTEAD},
143         {"intersect", INTERSECT},
144         {"interval", INTERVAL},
145         {"into", INTO},
146         {"is", IS},
147         {"isnull", ISNULL},
148         {"isolation", ISOLATION},
149         {"join", JOIN},
150         {"key", KEY},
151         {"lancompiler", LANCOMPILER},
152         {"language", LANGUAGE},
153         {"leading", LEADING},
154         {"left", LEFT},
155         {"level", LEVEL},
156         {"like", LIKE},
157         {"limit", LIMIT},
158         {"listen", LISTEN},
159         {"load", LOAD},
160         {"local", LOCAL},
161         {"location", LOCATION},
162         {"lock", LOCK_P},
163         {"match", MATCH},
164         {"maxvalue", MAXVALUE},
165         {"minute", MINUTE_P},
166         {"minvalue", MINVALUE},
167         {"mode", MODE},
168         {"month", MONTH_P},
169         {"move", MOVE},
170         {"names", NAMES},
171         {"national", NATIONAL},
172         {"natural", NATURAL},
173         {"nchar", NCHAR},
174         {"new", NEW},
175         {"next", NEXT},
176         {"no", NO},
177         {"nocreatedb", NOCREATEDB},
178         {"nocreateuser", NOCREATEUSER},
179         {"none", NONE},
180         {"not", NOT},
181         {"nothing", NOTHING},
182         {"notify", NOTIFY},
183         {"notnull", NOTNULL},
184         {"null", NULL_P},
185         {"nullif", NULLIF},
186         {"numeric", NUMERIC},
187         {"of", OF},
188         {"off", OFF},
189         {"offset", OFFSET},
190         {"oids", OIDS},
191         {"old", OLD},
192         {"on", ON},
193         {"only", ONLY},
194         {"operator", OPERATOR},
195         {"option", OPTION},
196         {"or", OR},
197         {"order", ORDER},
198         {"out", OUT},
199         {"outer", OUTER_P},
200         {"overlaps", OVERLAPS},
201         {"owner", OWNER},
202         {"partial", PARTIAL},
203         {"password", PASSWORD},
204         {"path", PATH_P},
205         {"pendant", PENDANT},
206         {"position", POSITION},
207         {"precision", PRECISION},
208         {"primary", PRIMARY},
209         {"prior", PRIOR},
210         {"privileges", PRIVILEGES},
211         {"procedural", PROCEDURAL},
212         {"procedure", PROCEDURE},
213         {"public", PUBLIC},
214         {"read", READ},
215         {"references", REFERENCES},
216         {"reindex", REINDEX},
217         {"relative", RELATIVE},
218         {"rename", RENAME},
219         {"replace", REPLACE},
220         {"reset", RESET},
221         {"restrict", RESTRICT},
222         {"returns", RETURNS},
223         {"revoke", REVOKE},
224         {"right", RIGHT},
225         {"rollback", ROLLBACK},
226         {"row", ROW},
227         {"rule", RULE},
228         {"schema", SCHEMA},
229         {"scroll", SCROLL},
230         {"second", SECOND_P},
231         {"select", SELECT},
232         {"sequence", SEQUENCE},
233         {"serializable", SERIALIZABLE},
234         {"session", SESSION},
235         {"session_user", SESSION_USER},
236         {"set", SET},
237         {"setof", SETOF},
238         {"share", SHARE},
239         {"show", SHOW},
240         {"some", SOME},
241         {"start", START},
242         {"statement", STATEMENT},
243         {"statistics", STATISTICS},
244         {"stdin", STDIN},
245         {"stdout", STDOUT},
246         {"storage", STORAGE},
247         {"substring", SUBSTRING},
248         {"sysid", SYSID},
249         {"table", TABLE},
250         {"temp", TEMP},
251         {"template", TEMPLATE},
252         {"temporary", TEMPORARY},
253         {"then", THEN},
254         {"time", TIME},
255         {"timestamp", TIMESTAMP},
256         {"to", TO},
257         {"toast", TOAST},
258         {"trailing", TRAILING},
259         {"transaction", TRANSACTION},
260         {"trigger", TRIGGER},
261         {"trim", TRIM},
262         {"true", TRUE_P},
263         {"truncate", TRUNCATE},
264         {"trusted", TRUSTED},
265         {"type", TYPE_P},
266         {"unencrypted", UNENCRYPTED},
267         {"union", UNION},
268         {"unique", UNIQUE},
269         {"unknown", UNKNOWN},
270         {"unlisten", UNLISTEN},
271         {"until", UNTIL},
272         {"update", UPDATE},
273         {"usage", USAGE},
274         {"user", USER},
275         {"using", USING},
276         {"vacuum", VACUUM},
277         {"valid", VALID},
278         {"values", VALUES},
279         {"varchar", VARCHAR},
280         {"varying", VARYING},
281         {"verbose", VERBOSE},
282         {"version", VERSION},
283         {"view", VIEW},
284         {"when", WHEN},
285         {"where", WHERE},
286         {"with", WITH},
287         {"without", WITHOUT},
288         {"work", WORK},
289         {"year", YEAR_P},
290         {"zone", ZONE},
291 };
292
293 /*
294  * ScanKeywordLookup - see if a given word is a keyword
295  *
296  * Returns a pointer to the ScanKeyword table entry, or NULL if no match.
297  *
298  * The match is done case-insensitively.  Note that we deliberately use a
299  * dumbed-down case conversion that will only translate 'A'-'Z' into 'a'-'z',
300  * even if we are in a locale where tolower() would produce more or different
301  * translations.  This is to conform to the SQL99 spec, which says that
302  * keywords are to be matched in this way even though non-keyword identifiers
303  * receive a different case-normalization mapping.
304  */
305 ScanKeyword *
306 ScanKeywordLookup(char *text)
307 {
308         int                     len,
309                                 i;
310         char            word[NAMEDATALEN];
311         ScanKeyword *low;
312         ScanKeyword *high;
313
314         len = strlen(text);
315         /* We assume all keywords are shorter than NAMEDATALEN. */
316         if (len >= NAMEDATALEN)
317                 return NULL;
318
319         /*
320          * Apply an ASCII-only downcasing.      We must not use tolower() since it
321          * may produce the wrong translation in some locales (eg, Turkish),
322          * and we don't trust isupper() very much either.  In an ASCII-based
323          * encoding the tests against A and Z are sufficient, but we also
324          * check isupper() so that we will work correctly under EBCDIC.  The
325          * actual case conversion step should work for either ASCII or EBCDIC.
326          */
327         for (i = 0; i < len; i++)
328         {
329                 char            ch = text[i];
330
331                 if (ch >= 'A' && ch <= 'Z' && isupper((unsigned char) ch))
332                         ch += 'a' - 'A';
333                 word[i] = ch;
334         }
335         word[len] = '\0';
336
337         /*
338          * Now do a binary search using plain strcmp() comparison.
339          */
340         low = &ScanKeywords[0];
341         high = endof(ScanKeywords) - 1;
342         while (low <= high)
343         {
344                 ScanKeyword *middle;
345                 int                     difference;
346
347                 middle = low + (high - low) / 2;
348                 difference = strcmp(middle->name, word);
349                 if (difference == 0)
350                         return middle;
351                 else if (difference < 0)
352                         low = middle + 1;
353                 else
354                         high = middle - 1;
355         }
356
357         return NULL;
358 }
359
360
361 /*
362  * This does the reverse mapping from token number to string.
363  */
364 const char *
365 TokenString(int token)
366 {
367     int i = 0;
368     static char buf[NAMEDATALEN];
369
370     while (i < sizeof(ScanKeywords))
371     {
372         if (ScanKeywords[i].value == token)
373         {
374             int k;
375
376             /* uppercase */
377             for (k = 0; k < NAMEDATALEN; k++)
378                 if (ScanKeywords[i].name[k] >= 'a'
379                     && ScanKeywords[i].name[k] <= 'z')
380                     buf[k] = ScanKeywords[i].name[k] + ('A' - 'a');
381                 else
382                     buf[k] = ScanKeywords[i].name[k];
383
384             return buf;
385         }
386
387         i++;
388     }
389
390     return NULL;
391 }