4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
12 ** A tokenizer for SQL
14 ** This file contains C code that splits an SQL input string up into
15 ** individual tokens and sends those tokens one-by-one over to the
16 ** parser for analysis.
29 ** All the keywords of the SQL language are stored as in a hash
30 ** table composed of instances of the following structure.
32 typedef struct Keyword Keyword
;
34 const WCHAR
*name
; /* The keyword name */
36 int tokenType
; /* The token value for this keyword */
39 #define MAX_TOKEN_LEN 11
41 static const WCHAR addW
[] = {'A','D','D'};
42 static const WCHAR alterW
[] = {'A','L','T','E','R'};
43 static const WCHAR andW
[] = {'A','N','D'};
44 static const WCHAR byW
[] = {'B','Y'};
45 static const WCHAR charW
[] = {'C','H','A','R'};
46 static const WCHAR characterW
[] = {'C','H','A','R','A','C','T','E','R'};
47 static const WCHAR createW
[] = {'C','R','E','A','T','E'};
48 static const WCHAR deleteW
[] = {'D','E','L','E','T','E'};
49 static const WCHAR distinctW
[] = {'D','I','S','T','I','N','C','T'};
50 static const WCHAR dropW
[] = {'D','R','O','P'};
51 static const WCHAR freeW
[] = {'F','R','E','E'};
52 static const WCHAR fromW
[] = {'F','R','O','M'};
53 static const WCHAR holdW
[] = {'H','O','L','D'};
54 static const WCHAR insertW
[] = {'I','N','S','E','R','T'};
55 static const WCHAR intW
[] = {'I','N','T'};
56 static const WCHAR integerW
[] = {'I','N','T','E','G','E','R'};
57 static const WCHAR intoW
[] = {'I','N','T','O'};
58 static const WCHAR isW
[] = {'I','S'};
59 static const WCHAR keyW
[] = {'K','E','Y'};
60 static const WCHAR likeW
[] = {'L','I','K','E'};
61 static const WCHAR localizableW
[] = {'L','O','C','A','L','I','Z','A','B','L','E'};
62 static const WCHAR longW
[] = {'L','O','N','G'};
63 static const WCHAR longcharW
[] = {'L','O','N','G','C','H','A','R'};
64 static const WCHAR notW
[] = {'N','O','T'};
65 static const WCHAR nullW
[] = {'N','U','L','L'};
66 static const WCHAR objectW
[] = {'O','B','J','E','C','T'};
67 static const WCHAR orW
[] = {'O','R'};
68 static const WCHAR orderW
[] = {'O','R','D','E','R'};
69 static const WCHAR primaryW
[] = {'P','R','I','M','A','R','Y'};
70 static const WCHAR selectW
[] = {'S','E','L','E','C','T'};
71 static const WCHAR setW
[] = {'S','E','T'};
72 static const WCHAR shortW
[] = {'S','H','O','R','T'};
73 static const WCHAR tableW
[] = {'T','A','B','L','E'};
74 static const WCHAR temporaryW
[] = {'T','E','M','P','O','R','A','R','Y'};
75 static const WCHAR updateW
[] = {'U','P','D','A','T','E'};
76 static const WCHAR valuesW
[] = {'V','A','L','U','E','S'};
77 static const WCHAR whereW
[] = {'W','H','E','R','E'};
80 ** These are the keywords
81 ** They MUST be in alphabetical order
83 static const Keyword aKeywordTable
[] = {
84 { addW
, ARRAY_SIZE(addW
), TK_ADD
},
85 { alterW
, ARRAY_SIZE(alterW
), TK_ALTER
},
86 { andW
, ARRAY_SIZE(andW
), TK_AND
},
87 { byW
, ARRAY_SIZE(byW
), TK_BY
},
88 { charW
, ARRAY_SIZE(charW
), TK_CHAR
},
89 { characterW
, ARRAY_SIZE(characterW
), TK_CHAR
},
90 { createW
, ARRAY_SIZE(createW
), TK_CREATE
},
91 { deleteW
, ARRAY_SIZE(deleteW
), TK_DELETE
},
92 { distinctW
, ARRAY_SIZE(distinctW
), TK_DISTINCT
},
93 { dropW
, ARRAY_SIZE(dropW
), TK_DROP
},
94 { freeW
, ARRAY_SIZE(freeW
), TK_FREE
},
95 { fromW
, ARRAY_SIZE(fromW
), TK_FROM
},
96 { holdW
, ARRAY_SIZE(holdW
), TK_HOLD
},
97 { insertW
, ARRAY_SIZE(insertW
), TK_INSERT
},
98 { intW
, ARRAY_SIZE(intW
), TK_INT
},
99 { integerW
, ARRAY_SIZE(integerW
), TK_INT
},
100 { intoW
, ARRAY_SIZE(intoW
), TK_INTO
},
101 { isW
, ARRAY_SIZE(isW
), TK_IS
},
102 { keyW
, ARRAY_SIZE(keyW
), TK_KEY
},
103 { likeW
, ARRAY_SIZE(likeW
), TK_LIKE
},
104 { localizableW
, ARRAY_SIZE(localizableW
), TK_LOCALIZABLE
},
105 { longW
, ARRAY_SIZE(longW
), TK_LONG
},
106 { longcharW
, ARRAY_SIZE(longcharW
), TK_LONGCHAR
},
107 { notW
, ARRAY_SIZE(notW
), TK_NOT
},
108 { nullW
, ARRAY_SIZE(nullW
), TK_NULL
},
109 { objectW
, ARRAY_SIZE(objectW
), TK_OBJECT
},
110 { orW
, ARRAY_SIZE(orW
), TK_OR
},
111 { orderW
, ARRAY_SIZE(orderW
), TK_ORDER
},
112 { primaryW
, ARRAY_SIZE(primaryW
), TK_PRIMARY
},
113 { selectW
, ARRAY_SIZE(selectW
), TK_SELECT
},
114 { setW
, ARRAY_SIZE(setW
), TK_SET
},
115 { shortW
, ARRAY_SIZE(shortW
), TK_SHORT
},
116 { tableW
, ARRAY_SIZE(tableW
), TK_TABLE
},
117 { temporaryW
, ARRAY_SIZE(temporaryW
), TK_TEMPORARY
},
118 { updateW
, ARRAY_SIZE(updateW
), TK_UPDATE
},
119 { valuesW
, ARRAY_SIZE(valuesW
), TK_VALUES
},
120 { whereW
, ARRAY_SIZE(whereW
), TK_WHERE
},
124 ** Comparison function for binary search.
126 static int __cdecl
compKeyword(const void *m1
, const void *m2
){
127 const Keyword
*k1
= m1
, *k2
= m2
;
128 int ret
, len
= min( k1
->len
, k2
->len
);
130 if ((ret
= wcsnicmp( k1
->name
, k2
->name
, len
))) return ret
;
131 if (k1
->len
< k2
->len
) return -1;
132 else if (k1
->len
> k2
->len
) return 1;
137 ** This function looks up an identifier to determine if it is a
138 ** keyword. If it is a keyword, the token code of that keyword is
139 ** returned. If the input is not a keyword, TK_ID is returned.
141 static int sqliteKeywordCode(const WCHAR
*z
, int n
){
144 if( n
>MAX_TOKEN_LEN
)
150 r
= bsearch( &key
, aKeywordTable
, ARRAY_SIZE(aKeywordTable
), sizeof(Keyword
), compKeyword
);
158 ** If X is a character that can be used in an identifier then
159 ** isIdChar[X] will be 1. Otherwise isIdChar[X] will be 0.
161 ** In this implementation, an identifier can be a string of
162 ** alphabetic characters, digits, and "_" plus any character
163 ** with the high-order bit set. The latter rule means that
164 ** any sequence of UTF-8 characters or characters taken from
165 ** an extended ISO8859 character set can form an identifier.
167 static const char isIdChar
[] = {
168 /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
169 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */
170 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */
171 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, /* 2x */
172 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */
173 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */
174 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */
175 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */
176 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */
177 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8x */
178 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9x */
179 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Ax */
180 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Bx */
181 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Cx */
182 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Dx */
183 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Ex */
184 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Fx */
188 ** WCHAR safe version of isdigit()
190 static inline int isDigit(WCHAR c
)
192 return c
>= '0' && c
<= '9';
196 ** WCHAR safe version of isspace(), except '\r'
198 static inline int isSpace(WCHAR c
)
200 return c
== ' ' || c
== '\t' || c
== '\n' || c
== '\f';
204 ** Return the length of the token that begins at z[0]. Return
205 ** -1 if the token is (or might be) incomplete. Store the token
206 ** type in *tokenType before returning.
208 int sqliteGetToken(const WCHAR
*z
, int *tokenType
, int *skip
){
213 case ' ': case '\t': case '\n': case '\f':
214 for(i
=1; isSpace(z
[i
]); i
++){}
215 *tokenType
= TK_SPACE
;
218 if( z
[1]==0 ) return -1;
219 *tokenType
= TK_MINUS
;
228 *tokenType
= TK_STAR
;
237 }else if( z
[1]=='>' ){
254 *tokenType
= TK_ILLEGAL
;
261 *tokenType
= TK_WILDCARD
;
264 *tokenType
= TK_COMMA
;
266 case '`': case '\'': {
276 *tokenType
= TK_STRING
;
280 if( !isDigit(z
[1]) ){
285 case '0': case '1': case '2': case '3': case '4':
286 case '5': case '6': case '7': case '8': case '9':
287 *tokenType
= TK_INTEGER
;
288 for(i
=1; isDigit(z
[i
]); i
++){}
291 for(i
=1; z
[i
] && z
[i
-1]!=']'; i
++){}
298 for(i
=1; isIdChar
[z
[i
]]; i
++){}
299 *tokenType
= sqliteKeywordCode(z
, i
);
300 if( *tokenType
== TK_ID
&& z
[i
] == '`' ) *skip
= 1;
303 *tokenType
= TK_ILLEGAL
;