1 /*-------------------------------------------------------------------------
4 * lexical token lookup for reserved words in postgres embedded SQL
9 *-------------------------------------------------------------------------
12 #include "postgres_fe.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},
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
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},
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.
83 DoLookup(const char *word
, const ScanKeyword
*low
, const ScanKeyword
*high
)
87 const ScanKeyword
*middle
;
90 middle
= low
+ (high
- low
) / 2;
91 difference
= strcmp(middle
->name
, word
);
94 else if (difference
< 0)
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.
116 ScanECPGKeywordLookup(const char *text
)
120 char word
[NAMEDATALEN
];
121 const ScanKeyword
*res
;
123 /* First check SQL symbols defined by the backend. */
125 res
= ScanKeywordLookup(text
);
130 /* We assume all keywords are shorter than NAMEDATALEN. */
131 if (len
>= NAMEDATALEN
)
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
++)
142 if (ch
>= 'A' && ch
<= 'Z')
149 * Now do a binary search using plain strcmp() comparison.
152 return DoLookup(word
, &ScanECPGKeywords
[0], endof(ScanECPGKeywords
) - 1);