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