Fix xslt_process() to ensure that it inserts a NULL terminator after the
[PostgreSQL.git] / src / interfaces / ecpg / preproc / ecpg_keywords.c
blob9a7fde718160ae58ff0c822a8710a8e4065405f4
1 /*-------------------------------------------------------------------------
3 * ecpg_keywords.c
4 * lexical token lookup for reserved words in postgres embedded SQL
6 * IDENTIFICATION
7 * $PostgreSQL$
9 *-------------------------------------------------------------------------
12 #include "postgres_fe.h"
14 #include <ctype.h>
16 #include "extern.h"
17 #include "preproc.h"
20 * List of (keyword-name, keyword-token-value) pairs.
22 * !!WARNING!!: This list must be sorted, because binary
23 * search is used to locate entries.
25 static const ScanKeyword ScanECPGKeywords[] = {
26 /* name, value, category */
29 * category is not needed in ecpg, it is only here so we can share the
30 * data structure with the backend
32 {"allocate", SQL_ALLOCATE, 0},
33 {"autocommit", SQL_AUTOCOMMIT, 0},
34 {"bool", SQL_BOOL, 0},
35 {"break", SQL_BREAK, 0},
36 {"call", SQL_CALL, 0},
37 {"cardinality", SQL_CARDINALITY, 0},
38 {"connect", SQL_CONNECT, 0},
39 {"count", SQL_COUNT, 0},
40 {"datetime_interval_code", SQL_DATETIME_INTERVAL_CODE, 0},
41 {"datetime_interval_precision", SQL_DATETIME_INTERVAL_PRECISION, 0},
42 {"describe", SQL_DESCRIBE, 0},
43 {"descriptor", SQL_DESCRIPTOR, 0},
44 {"disconnect", SQL_DISCONNECT, 0},
45 {"found", SQL_FOUND, 0},
46 {"free", SQL_FREE, 0},
47 {"get", SQL_GET, 0},
48 {"go", SQL_GO, 0},
49 {"goto", SQL_GOTO, 0},
50 {"identified", SQL_IDENTIFIED, 0},
51 {"indicator", SQL_INDICATOR, 0},
52 {"key_member", SQL_KEY_MEMBER, 0},
53 {"length", SQL_LENGTH, 0},
54 {"long", SQL_LONG, 0},
55 {"nullable", SQL_NULLABLE, 0},
56 {"octet_length", SQL_OCTET_LENGTH, 0},
57 {"open", SQL_OPEN, 0},
58 {"output", SQL_OUTPUT, 0},
59 {"reference", SQL_REFERENCE, 0},
60 {"returned_length", SQL_RETURNED_LENGTH, 0},
61 {"returned_octet_length", SQL_RETURNED_OCTET_LENGTH, 0},
62 {"scale", SQL_SCALE, 0},
63 {"section", SQL_SECTION, 0},
64 {"short", SQL_SHORT, 0},
65 {"signed", SQL_SIGNED, 0},
66 {"sql", SQL_SQL, 0}, /* strange thing, used for into sql descriptor
67 * MYDESC; */
68 {"sqlerror", SQL_SQLERROR, 0},
69 {"sqlprint", SQL_SQLPRINT, 0},
70 {"sqlwarning", SQL_SQLWARNING, 0},
71 {"stop", SQL_STOP, 0},
72 {"struct", SQL_STRUCT, 0},
73 {"unsigned", SQL_UNSIGNED, 0},
74 {"var", SQL_VAR, 0},
75 {"whenever", SQL_WHENEVER, 0},
78 /* This is all taken from src/backend/parser/keyword.c and adjusted for our needs. */
80 * Do a binary search using plain strcmp() comparison.
82 const ScanKeyword *
83 DoLookup(const char *word, const ScanKeyword *low, const ScanKeyword *high)
85 while (low <= high)
87 const ScanKeyword *middle;
88 int difference;
90 middle = low + (high - low) / 2;
91 difference = strcmp(middle->name, word);
92 if (difference == 0)
93 return middle;
94 else if (difference < 0)
95 low = middle + 1;
96 else
97 high = middle - 1;
100 return NULL;
104 * ScanECPGKeywordLookup - see if a given word is a keyword
106 * Returns a pointer to the ScanKeyword table entry, or NULL if no match.
108 * The match is done case-insensitively. Note that we deliberately use a
109 * dumbed-down case conversion that will only translate 'A'-'Z' into 'a'-'z',
110 * even if we are in a locale where tolower() would produce more or different
111 * translations. This is to conform to the SQL99 spec, which says that
112 * keywords are to be matched in this way even though non-keyword identifiers
113 * receive a different case-normalization mapping.
115 const ScanKeyword *
116 ScanECPGKeywordLookup(const char *text)
118 int len,
120 char word[NAMEDATALEN];
121 const ScanKeyword *res;
123 /* First check SQL symbols defined by the backend. */
125 res = ScanKeywordLookup(text);
126 if (res)
127 return res;
129 len = strlen(text);
130 /* We assume all keywords are shorter than NAMEDATALEN. */
131 if (len >= NAMEDATALEN)
132 return NULL;
135 * Apply an ASCII-only downcasing. We must not use tolower() since it may
136 * produce the wrong translation in some locales (eg, Turkish).
138 for (i = 0; i < len; i++)
140 char ch = text[i];
142 if (ch >= 'A' && ch <= 'Z')
143 ch += 'a' - 'A';
144 word[i] = ch;
146 word[len] = '\0';
149 * Now do a binary search using plain strcmp() comparison.
152 return DoLookup(word, &ScanECPGKeywords[0], endof(ScanECPGKeywords) - 1);