source: trunk/src/3rdparty/sqlite/tokenize.c@ 205

Last change on this file since 205 was 205, checked in by rudi, 14 years ago

Added SQLite 2.8.17 sources. This allows to build at least one of the sql drivers / plugins.

File size: 20.7 KB
Line 
1/*
2** 2001 September 15
3**
4** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
6**
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.
10**
11*************************************************************************
12** An tokenizer for SQL
13**
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.
17**
18** $Id: tokenize.c,v 1.68 2004/02/14 23:59:58 drh Exp $
19*/
20#include "sqliteInt.h"
21#include "os.h"
22#include <ctype.h>
23#include <stdlib.h>
24
25/*
26** All the keywords of the SQL language are stored as in a hash
27** table composed of instances of the following structure.
28*/
29typedef struct Keyword Keyword;
30struct Keyword {
31 char *zName; /* The keyword name */
32 u8 tokenType; /* Token value for this keyword */
33 u8 len; /* Length of this keyword */
34 u8 iNext; /* Index in aKeywordTable[] of next with same hash */
35};
36
37/*
38** These are the keywords
39*/
40static Keyword aKeywordTable[] = {
41 { "ABORT", TK_ABORT, },
42 { "AFTER", TK_AFTER, },
43 { "ALL", TK_ALL, },
44 { "AND", TK_AND, },
45 { "AS", TK_AS, },
46 { "ASC", TK_ASC, },
47 { "ATTACH", TK_ATTACH, },
48 { "BEFORE", TK_BEFORE, },
49 { "BEGIN", TK_BEGIN, },
50 { "BETWEEN", TK_BETWEEN, },
51 { "BY", TK_BY, },
52 { "CASCADE", TK_CASCADE, },
53 { "CASE", TK_CASE, },
54 { "CHECK", TK_CHECK, },
55 { "CLUSTER", TK_CLUSTER, },
56 { "COLLATE", TK_COLLATE, },
57 { "COMMIT", TK_COMMIT, },
58 { "CONFLICT", TK_CONFLICT, },
59 { "CONSTRAINT", TK_CONSTRAINT, },
60 { "COPY", TK_COPY, },
61 { "CREATE", TK_CREATE, },
62 { "CROSS", TK_JOIN_KW, },
63 { "DATABASE", TK_DATABASE, },
64 { "DEFAULT", TK_DEFAULT, },
65 { "DEFERRED", TK_DEFERRED, },
66 { "DEFERRABLE", TK_DEFERRABLE, },
67 { "DELETE", TK_DELETE, },
68 { "DELIMITERS", TK_DELIMITERS, },
69 { "DESC", TK_DESC, },
70 { "DETACH", TK_DETACH, },
71 { "DISTINCT", TK_DISTINCT, },
72 { "DROP", TK_DROP, },
73 { "END", TK_END, },
74 { "EACH", TK_EACH, },
75 { "ELSE", TK_ELSE, },
76 { "EXCEPT", TK_EXCEPT, },
77 { "EXPLAIN", TK_EXPLAIN, },
78 { "FAIL", TK_FAIL, },
79 { "FOR", TK_FOR, },
80 { "FOREIGN", TK_FOREIGN, },
81 { "FROM", TK_FROM, },
82 { "FULL", TK_JOIN_KW, },
83 { "GLOB", TK_GLOB, },
84 { "GROUP", TK_GROUP, },
85 { "HAVING", TK_HAVING, },
86 { "IGNORE", TK_IGNORE, },
87 { "IMMEDIATE", TK_IMMEDIATE, },
88 { "IN", TK_IN, },
89 { "INDEX", TK_INDEX, },
90 { "INITIALLY", TK_INITIALLY, },
91 { "INNER", TK_JOIN_KW, },
92 { "INSERT", TK_INSERT, },
93 { "INSTEAD", TK_INSTEAD, },
94 { "INTERSECT", TK_INTERSECT, },
95 { "INTO", TK_INTO, },
96 { "IS", TK_IS, },
97 { "ISNULL", TK_ISNULL, },
98 { "JOIN", TK_JOIN, },
99 { "KEY", TK_KEY, },
100 { "LEFT", TK_JOIN_KW, },
101 { "LIKE", TK_LIKE, },
102 { "LIMIT", TK_LIMIT, },
103 { "MATCH", TK_MATCH, },
104 { "NATURAL", TK_JOIN_KW, },
105 { "NOT", TK_NOT, },
106 { "NOTNULL", TK_NOTNULL, },
107 { "NULL", TK_NULL, },
108 { "OF", TK_OF, },
109 { "OFFSET", TK_OFFSET, },
110 { "ON", TK_ON, },
111 { "OR", TK_OR, },
112 { "ORDER", TK_ORDER, },
113 { "OUTER", TK_JOIN_KW, },
114 { "PRAGMA", TK_PRAGMA, },
115 { "PRIMARY", TK_PRIMARY, },
116 { "RAISE", TK_RAISE, },
117 { "REFERENCES", TK_REFERENCES, },
118 { "REPLACE", TK_REPLACE, },
119 { "RESTRICT", TK_RESTRICT, },
120 { "RIGHT", TK_JOIN_KW, },
121 { "ROLLBACK", TK_ROLLBACK, },
122 { "ROW", TK_ROW, },
123 { "SELECT", TK_SELECT, },
124 { "SET", TK_SET, },
125 { "STATEMENT", TK_STATEMENT, },
126 { "TABLE", TK_TABLE, },
127 { "TEMP", TK_TEMP, },
128 { "TEMPORARY", TK_TEMP, },
129 { "THEN", TK_THEN, },
130 { "TRANSACTION", TK_TRANSACTION, },
131 { "TRIGGER", TK_TRIGGER, },
132 { "UNION", TK_UNION, },
133 { "UNIQUE", TK_UNIQUE, },
134 { "UPDATE", TK_UPDATE, },
135 { "USING", TK_USING, },
136 { "VACUUM", TK_VACUUM, },
137 { "VALUES", TK_VALUES, },
138 { "VIEW", TK_VIEW, },
139 { "WHEN", TK_WHEN, },
140 { "WHERE", TK_WHERE, },
141};
142
143/*
144** This is the hash table
145*/
146#define KEY_HASH_SIZE 101
147static u8 aiHashTable[KEY_HASH_SIZE];
148
149
150/*
151** This function looks up an identifier to determine if it is a
152** keyword. If it is a keyword, the token code of that keyword is
153** returned. If the input is not a keyword, TK_ID is returned.
154*/
155int sqliteKeywordCode(const char *z, int n){
156 int h, i;
157 Keyword *p;
158 static char needInit = 1;
159 if( needInit ){
160 /* Initialize the keyword hash table */
161 sqliteOsEnterMutex();
162 if( needInit ){
163 int nk;
164 nk = sizeof(aKeywordTable)/sizeof(aKeywordTable[0]);
165 for(i=0; i<nk; i++){
166 aKeywordTable[i].len = strlen(aKeywordTable[i].zName);
167 h = sqliteHashNoCase(aKeywordTable[i].zName, aKeywordTable[i].len);
168 h %= KEY_HASH_SIZE;
169 aKeywordTable[i].iNext = aiHashTable[h];
170 aiHashTable[h] = i+1;
171 }
172 needInit = 0;
173 }
174 sqliteOsLeaveMutex();
175 }
176 h = sqliteHashNoCase(z, n) % KEY_HASH_SIZE;
177 for(i=aiHashTable[h]; i; i=p->iNext){
178 p = &aKeywordTable[i-1];
179 if( p->len==n && sqliteStrNICmp(p->zName, z, n)==0 ){
180 return p->tokenType;
181 }
182 }
183 return TK_ID;
184}
185
186
187/*
188** If X is a character that can be used in an identifier and
189** X&0x80==0 then isIdChar[X] will be 1. If X&0x80==0x80 then
190** X is always an identifier character. (Hence all UTF-8
191** characters can be part of an identifier). isIdChar[X] will
192** be 0 for every character in the lower 128 ASCII characters
193** that cannot be used as part of an identifier.
194**
195** In this implementation, an identifier can be a string of
196** alphabetic characters, digits, and "_" plus any character
197** with the high-order bit set. The latter rule means that
198** any sequence of UTF-8 characters or characters taken from
199** an extended ISO8859 character set can form an identifier.
200*/
201static const char isIdChar[] = {
202/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
203 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */
204 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */
205 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */
206 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */
207 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */
208 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */
209 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */
210 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */
211};
212
213
214/*
215** Return the length of the token that begins at z[0].
216** Store the token type in *tokenType before returning.
217*/
218static int sqliteGetToken(const unsigned char *z, int *tokenType){
219 int i;
220 switch( *z ){
221 case ' ': case '\t': case '\n': case '\f': case '\r': {
222 for(i=1; isspace(z[i]); i++){}
223 *tokenType = TK_SPACE;
224 return i;
225 }
226 case '-': {
227 if( z[1]=='-' ){
228 for(i=2; z[i] && z[i]!='\n'; i++){}
229 *tokenType = TK_COMMENT;
230 return i;
231 }
232 *tokenType = TK_MINUS;
233 return 1;
234 }
235 case '(': {
236 *tokenType = TK_LP;
237 return 1;
238 }
239 case ')': {
240 *tokenType = TK_RP;
241 return 1;
242 }
243 case ';': {
244 *tokenType = TK_SEMI;
245 return 1;
246 }
247 case '+': {
248 *tokenType = TK_PLUS;
249 return 1;
250 }
251 case '*': {
252 *tokenType = TK_STAR;
253 return 1;
254 }
255 case '/': {
256 if( z[1]!='*' || z[2]==0 ){
257 *tokenType = TK_SLASH;
258 return 1;
259 }
260 for(i=3; z[i] && (z[i]!='/' || z[i-1]!='*'); i++){}
261 if( z[i] ) i++;
262 *tokenType = TK_COMMENT;
263 return i;
264 }
265 case '%': {
266 *tokenType = TK_REM;
267 return 1;
268 }
269 case '=': {
270 *tokenType = TK_EQ;
271 return 1 + (z[1]=='=');
272 }
273 case '<': {
274 if( z[1]=='=' ){
275 *tokenType = TK_LE;
276 return 2;
277 }else if( z[1]=='>' ){
278 *tokenType = TK_NE;
279 return 2;
280 }else if( z[1]=='<' ){
281 *tokenType = TK_LSHIFT;
282 return 2;
283 }else{
284 *tokenType = TK_LT;
285 return 1;
286 }
287 }
288 case '>': {
289 if( z[1]=='=' ){
290 *tokenType = TK_GE;
291 return 2;
292 }else if( z[1]=='>' ){
293 *tokenType = TK_RSHIFT;
294 return 2;
295 }else{
296 *tokenType = TK_GT;
297 return 1;
298 }
299 }
300 case '!': {
301 if( z[1]!='=' ){
302 *tokenType = TK_ILLEGAL;
303 return 2;
304 }else{
305 *tokenType = TK_NE;
306 return 2;
307 }
308 }
309 case '|': {
310 if( z[1]!='|' ){
311 *tokenType = TK_BITOR;
312 return 1;
313 }else{
314 *tokenType = TK_CONCAT;
315 return 2;
316 }
317 }
318 case ',': {
319 *tokenType = TK_COMMA;
320 return 1;
321 }
322 case '&': {
323 *tokenType = TK_BITAND;
324 return 1;
325 }
326 case '~': {
327 *tokenType = TK_BITNOT;
328 return 1;
329 }
330 case '\'': case '"': {
331 int delim = z[0];
332 for(i=1; z[i]; i++){
333 if( z[i]==delim ){
334 if( z[i+1]==delim ){
335 i++;
336 }else{
337 break;
338 }
339 }
340 }
341 if( z[i] ) i++;
342 *tokenType = TK_STRING;
343 return i;
344 }
345 case '.': {
346 *tokenType = TK_DOT;
347 return 1;
348 }
349 case '0': case '1': case '2': case '3': case '4':
350 case '5': case '6': case '7': case '8': case '9': {
351 *tokenType = TK_INTEGER;
352 for(i=1; isdigit(z[i]); i++){}
353 if( z[i]=='.' && isdigit(z[i+1]) ){
354 i += 2;
355 while( isdigit(z[i]) ){ i++; }
356 *tokenType = TK_FLOAT;
357 }
358 if( (z[i]=='e' || z[i]=='E') &&
359 ( isdigit(z[i+1])
360 || ((z[i+1]=='+' || z[i+1]=='-') && isdigit(z[i+2]))
361 )
362 ){
363 i += 2;
364 while( isdigit(z[i]) ){ i++; }
365 *tokenType = TK_FLOAT;
366 }
367 return i;
368 }
369 case '[': {
370 for(i=1; z[i] && z[i-1]!=']'; i++){}
371 *tokenType = TK_ID;
372 return i;
373 }
374 case '?': {
375 *tokenType = TK_VARIABLE;
376 return 1;
377 }
378 default: {
379 if( (*z&0x80)==0 && !isIdChar[*z] ){
380 break;
381 }
382 for(i=1; (z[i]&0x80)!=0 || isIdChar[z[i]]; i++){}
383 *tokenType = sqliteKeywordCode((char*)z, i);
384 return i;
385 }
386 }
387 *tokenType = TK_ILLEGAL;
388 return 1;
389}
390
391/*
392** Run the parser on the given SQL string. The parser structure is
393** passed in. An SQLITE_ status code is returned. If an error occurs
394** and pzErrMsg!=NULL then an error message might be written into
395** memory obtained from malloc() and *pzErrMsg made to point to that
396** error message. Or maybe not.
397*/
398int sqliteRunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
399 int nErr = 0;
400 int i;
401 void *pEngine;
402 int tokenType;
403 int lastTokenParsed = -1;
404 sqlite *db = pParse->db;
405 extern void *sqliteParserAlloc(void*(*)(int));
406 extern void sqliteParserFree(void*, void(*)(void*));
407 extern int sqliteParser(void*, int, Token, Parse*);
408
409 db->flags &= ~SQLITE_Interrupt;
410 pParse->rc = SQLITE_OK;
411 i = 0;
412 pEngine = sqliteParserAlloc((void*(*)(int))malloc);
413 if( pEngine==0 ){
414 sqliteSetString(pzErrMsg, "out of memory", (char*)0);
415 return 1;
416 }
417 pParse->sLastToken.dyn = 0;
418 pParse->zTail = zSql;
419 while( sqlite_malloc_failed==0 && zSql[i]!=0 ){
420 assert( i>=0 );
421 pParse->sLastToken.z = &zSql[i];
422 assert( pParse->sLastToken.dyn==0 );
423 pParse->sLastToken.n = sqliteGetToken((unsigned char*)&zSql[i], &tokenType);
424 i += pParse->sLastToken.n;
425 switch( tokenType ){
426 case TK_SPACE:
427 case TK_COMMENT: {
428 if( (db->flags & SQLITE_Interrupt)!=0 ){
429 pParse->rc = SQLITE_INTERRUPT;
430 sqliteSetString(pzErrMsg, "interrupt", (char*)0);
431 goto abort_parse;
432 }
433 break;
434 }
435 case TK_ILLEGAL: {
436 sqliteSetNString(pzErrMsg, "unrecognized token: \"", -1,
437 pParse->sLastToken.z, pParse->sLastToken.n, "\"", 1, 0);
438 nErr++;
439 goto abort_parse;
440 }
441 case TK_SEMI: {
442 pParse->zTail = &zSql[i];
443 /* Fall thru into the default case */
444 }
445 default: {
446 sqliteParser(pEngine, tokenType, pParse->sLastToken, pParse);
447 lastTokenParsed = tokenType;
448 if( pParse->rc!=SQLITE_OK ){
449 goto abort_parse;
450 }
451 break;
452 }
453 }
454 }
455abort_parse:
456 if( zSql[i]==0 && nErr==0 && pParse->rc==SQLITE_OK ){
457 if( lastTokenParsed!=TK_SEMI ){
458 sqliteParser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
459 pParse->zTail = &zSql[i];
460 }
461 sqliteParser(pEngine, 0, pParse->sLastToken, pParse);
462 }
463 sqliteParserFree(pEngine, free);
464 if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
465 sqliteSetString(&pParse->zErrMsg, sqlite_error_string(pParse->rc),
466 (char*)0);
467 }
468 if( pParse->zErrMsg ){
469 if( pzErrMsg && *pzErrMsg==0 ){
470 *pzErrMsg = pParse->zErrMsg;
471 }else{
472 sqliteFree(pParse->zErrMsg);
473 }
474 pParse->zErrMsg = 0;
475 if( !nErr ) nErr++;
476 }
477 if( pParse->pVdbe && pParse->nErr>0 ){
478 sqliteVdbeDelete(pParse->pVdbe);
479 pParse->pVdbe = 0;
480 }
481 if( pParse->pNewTable ){
482 sqliteDeleteTable(pParse->db, pParse->pNewTable);
483 pParse->pNewTable = 0;
484 }
485 if( pParse->pNewTrigger ){
486 sqliteDeleteTrigger(pParse->pNewTrigger);
487 pParse->pNewTrigger = 0;
488 }
489 if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){
490 pParse->rc = SQLITE_ERROR;
491 }
492 return nErr;
493}
494
495/*
496** Token types used by the sqlite_complete() routine. See the header
497** comments on that procedure for additional information.
498*/
499#define tkEXPLAIN 0
500#define tkCREATE 1
501#define tkTEMP 2
502#define tkTRIGGER 3
503#define tkEND 4
504#define tkSEMI 5
505#define tkWS 6
506#define tkOTHER 7
507
508/*
509** Return TRUE if the given SQL string ends in a semicolon.
510**
511** Special handling is require for CREATE TRIGGER statements.
512** Whenever the CREATE TRIGGER keywords are seen, the statement
513** must end with ";END;".
514**
515** This implementation uses a state machine with 7 states:
516**
517** (0) START At the beginning or end of an SQL statement. This routine
518** returns 1 if it ends in the START state and 0 if it ends
519** in any other state.
520**
521** (1) EXPLAIN The keyword EXPLAIN has been seen at the beginning of
522** a statement.
523**
524** (2) CREATE The keyword CREATE has been seen at the beginning of a
525** statement, possibly preceeded by EXPLAIN and/or followed by
526** TEMP or TEMPORARY
527**
528** (3) NORMAL We are in the middle of statement which ends with a single
529** semicolon.
530**
531** (4) TRIGGER We are in the middle of a trigger definition that must be
532** ended by a semicolon, the keyword END, and another semicolon.
533**
534** (5) SEMI We've seen the first semicolon in the ";END;" that occurs at
535** the end of a trigger definition.
536**
537** (6) END We've seen the ";END" of the ";END;" that occurs at the end
538** of a trigger difinition.
539**
540** Transitions between states above are determined by tokens extracted
541** from the input. The following tokens are significant:
542**
543** (0) tkEXPLAIN The "explain" keyword.
544** (1) tkCREATE The "create" keyword.
545** (2) tkTEMP The "temp" or "temporary" keyword.
546** (3) tkTRIGGER The "trigger" keyword.
547** (4) tkEND The "end" keyword.
548** (5) tkSEMI A semicolon.
549** (6) tkWS Whitespace
550** (7) tkOTHER Any other SQL token.
551**
552** Whitespace never causes a state transition and is always ignored.
553*/
554int sqlite_complete(const char *zSql){
555 u8 state = 0; /* Current state, using numbers defined in header comment */
556 u8 token; /* Value of the next token */
557
558 /* The following matrix defines the transition from one state to another
559 ** according to what token is seen. trans[state][token] returns the
560 ** next state.
561 */
562 static const u8 trans[7][8] = {
563 /* Token: */
564 /* State: ** EXPLAIN CREATE TEMP TRIGGER END SEMI WS OTHER */
565 /* 0 START: */ { 1, 2, 3, 3, 3, 0, 0, 3, },
566 /* 1 EXPLAIN: */ { 3, 2, 3, 3, 3, 0, 1, 3, },
567 /* 2 CREATE: */ { 3, 3, 2, 4, 3, 0, 2, 3, },
568 /* 3 NORMAL: */ { 3, 3, 3, 3, 3, 0, 3, 3, },
569 /* 4 TRIGGER: */ { 4, 4, 4, 4, 4, 5, 4, 4, },
570 /* 5 SEMI: */ { 4, 4, 4, 4, 6, 5, 5, 4, },
571 /* 6 END: */ { 4, 4, 4, 4, 4, 0, 6, 4, },
572 };
573
574 while( *zSql ){
575 switch( *zSql ){
576 case ';': { /* A semicolon */
577 token = tkSEMI;
578 break;
579 }
580 case ' ':
581 case '\r':
582 case '\t':
583 case '\n':
584 case '\f': { /* White space is ignored */
585 token = tkWS;
586 break;
587 }
588 case '/': { /* C-style comments */
589 if( zSql[1]!='*' ){
590 token = tkOTHER;
591 break;
592 }
593 zSql += 2;
594 while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; }
595 if( zSql[0]==0 ) return 0;
596 zSql++;
597 token = tkWS;
598 break;
599 }
600 case '-': { /* SQL-style comments from "--" to end of line */
601 if( zSql[1]!='-' ){
602 token = tkOTHER;
603 break;
604 }
605 while( *zSql && *zSql!='\n' ){ zSql++; }
606 if( *zSql==0 ) return state==0;
607 token = tkWS;
608 break;
609 }
610 case '[': { /* Microsoft-style identifiers in [...] */
611 zSql++;
612 while( *zSql && *zSql!=']' ){ zSql++; }
613 if( *zSql==0 ) return 0;
614 token = tkOTHER;
615 break;
616 }
617 case '"': /* single- and double-quoted strings */
618 case '\'': {
619 int c = *zSql;
620 zSql++;
621 while( *zSql && *zSql!=c ){ zSql++; }
622 if( *zSql==0 ) return 0;
623 token = tkOTHER;
624 break;
625 }
626 default: {
627 if( isIdChar[(u8)*zSql] ){
628 /* Keywords and unquoted identifiers */
629 int nId;
630 for(nId=1; isIdChar[(u8)zSql[nId]]; nId++){}
631 switch( *zSql ){
632 case 'c': case 'C': {
633 if( nId==6 && sqliteStrNICmp(zSql, "create", 6)==0 ){
634 token = tkCREATE;
635 }else{
636 token = tkOTHER;
637 }
638 break;
639 }
640 case 't': case 'T': {
641 if( nId==7 && sqliteStrNICmp(zSql, "trigger", 7)==0 ){
642 token = tkTRIGGER;
643 }else if( nId==4 && sqliteStrNICmp(zSql, "temp", 4)==0 ){
644 token = tkTEMP;
645 }else if( nId==9 && sqliteStrNICmp(zSql, "temporary", 9)==0 ){
646 token = tkTEMP;
647 }else{
648 token = tkOTHER;
649 }
650 break;
651 }
652 case 'e': case 'E': {
653 if( nId==3 && sqliteStrNICmp(zSql, "end", 3)==0 ){
654 token = tkEND;
655 }else if( nId==7 && sqliteStrNICmp(zSql, "explain", 7)==0 ){
656 token = tkEXPLAIN;
657 }else{
658 token = tkOTHER;
659 }
660 break;
661 }
662 default: {
663 token = tkOTHER;
664 break;
665 }
666 }
667 zSql += nId-1;
668 }else{
669 /* Operators and special symbols */
670 token = tkOTHER;
671 }
672 break;
673 }
674 }
675 state = trans[state][token];
676 zSql++;
677 }
678 return state==0;
679}
Note: See TracBrowser for help on using the repository browser.