| OLD | NEW |
| (Empty) |
| 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 implements the sqlite3_complete() API. | |
| 15 ** This code used to be part of the tokenizer.c source file. But by | |
| 16 ** separating it out, the code will be automatically omitted from | |
| 17 ** static links that do not use it. | |
| 18 ** | |
| 19 ** $Id: complete.c,v 1.8 2009/04/28 04:46:42 drh Exp $ | |
| 20 */ | |
| 21 #include "sqliteInt.h" | |
| 22 #ifndef SQLITE_OMIT_COMPLETE | |
| 23 | |
| 24 /* | |
| 25 ** This is defined in tokenize.c. We just have to import the definition. | |
| 26 */ | |
| 27 #ifndef SQLITE_AMALGAMATION | |
| 28 #ifdef SQLITE_ASCII | |
| 29 extern const char sqlite3IsAsciiIdChar[]; | |
| 30 #define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsAsciiIdChar[c-0x20])) | |
| 31 #endif | |
| 32 #ifdef SQLITE_EBCDIC | |
| 33 extern const char sqlite3IsEbcdicIdChar[]; | |
| 34 #define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40])) | |
| 35 #endif | |
| 36 #endif /* SQLITE_AMALGAMATION */ | |
| 37 | |
| 38 | |
| 39 /* | |
| 40 ** Token types used by the sqlite3_complete() routine. See the header | |
| 41 ** comments on that procedure for additional information. | |
| 42 */ | |
| 43 #define tkSEMI 0 | |
| 44 #define tkWS 1 | |
| 45 #define tkOTHER 2 | |
| 46 #define tkEXPLAIN 3 | |
| 47 #define tkCREATE 4 | |
| 48 #define tkTEMP 5 | |
| 49 #define tkTRIGGER 6 | |
| 50 #define tkEND 7 | |
| 51 | |
| 52 /* | |
| 53 ** Return TRUE if the given SQL string ends in a semicolon. | |
| 54 ** | |
| 55 ** Special handling is require for CREATE TRIGGER statements. | |
| 56 ** Whenever the CREATE TRIGGER keywords are seen, the statement | |
| 57 ** must end with ";END;". | |
| 58 ** | |
| 59 ** This implementation uses a state machine with 7 states: | |
| 60 ** | |
| 61 ** (0) START At the beginning or end of an SQL statement. This routine | |
| 62 ** returns 1 if it ends in the START state and 0 if it ends | |
| 63 ** in any other state. | |
| 64 ** | |
| 65 ** (1) NORMAL We are in the middle of statement which ends with a single | |
| 66 ** semicolon. | |
| 67 ** | |
| 68 ** (2) EXPLAIN The keyword EXPLAIN has been seen at the beginning of | |
| 69 ** a statement. | |
| 70 ** | |
| 71 ** (3) CREATE The keyword CREATE has been seen at the beginning of a | |
| 72 ** statement, possibly preceeded by EXPLAIN and/or followed by | |
| 73 ** TEMP or TEMPORARY | |
| 74 ** | |
| 75 ** (4) TRIGGER We are in the middle of a trigger definition that must be | |
| 76 ** ended by a semicolon, the keyword END, and another semicolon. | |
| 77 ** | |
| 78 ** (5) SEMI We've seen the first semicolon in the ";END;" that occurs at | |
| 79 ** the end of a trigger definition. | |
| 80 ** | |
| 81 ** (6) END We've seen the ";END" of the ";END;" that occurs at the end | |
| 82 ** of a trigger difinition. | |
| 83 ** | |
| 84 ** Transitions between states above are determined by tokens extracted | |
| 85 ** from the input. The following tokens are significant: | |
| 86 ** | |
| 87 ** (0) tkSEMI A semicolon. | |
| 88 ** (1) tkWS Whitespace | |
| 89 ** (2) tkOTHER Any other SQL token. | |
| 90 ** (3) tkEXPLAIN The "explain" keyword. | |
| 91 ** (4) tkCREATE The "create" keyword. | |
| 92 ** (5) tkTEMP The "temp" or "temporary" keyword. | |
| 93 ** (6) tkTRIGGER The "trigger" keyword. | |
| 94 ** (7) tkEND The "end" keyword. | |
| 95 ** | |
| 96 ** Whitespace never causes a state transition and is always ignored. | |
| 97 ** | |
| 98 ** If we compile with SQLITE_OMIT_TRIGGER, all of the computation needed | |
| 99 ** to recognize the end of a trigger can be omitted. All we have to do | |
| 100 ** is look for a semicolon that is not part of an string or comment. | |
| 101 */ | |
| 102 int sqlite3_complete(const char *zSql){ | |
| 103 u8 state = 0; /* Current state, using numbers defined in header comment */ | |
| 104 u8 token; /* Value of the next token */ | |
| 105 | |
| 106 #ifndef SQLITE_OMIT_TRIGGER | |
| 107 /* A complex statement machine used to detect the end of a CREATE TRIGGER | |
| 108 ** statement. This is the normal case. | |
| 109 */ | |
| 110 static const u8 trans[7][8] = { | |
| 111 /* Token: */ | |
| 112 /* State: ** SEMI WS OTHER EXPLAIN CREATE TEMP TRIGGER END */ | |
| 113 /* 0 START: */ { 0, 0, 1, 2, 3, 1, 1, 1, }, | |
| 114 /* 1 NORMAL: */ { 0, 1, 1, 1, 1, 1, 1, 1, }, | |
| 115 /* 2 EXPLAIN: */ { 0, 2, 2, 1, 3, 1, 1, 1, }, | |
| 116 /* 3 CREATE: */ { 0, 3, 1, 1, 1, 3, 4, 1, }, | |
| 117 /* 4 TRIGGER: */ { 5, 4, 4, 4, 4, 4, 4, 4, }, | |
| 118 /* 5 SEMI: */ { 5, 5, 4, 4, 4, 4, 4, 6, }, | |
| 119 /* 6 END: */ { 0, 6, 4, 4, 4, 4, 4, 4, }, | |
| 120 }; | |
| 121 #else | |
| 122 /* If triggers are not suppored by this compile then the statement machine | |
| 123 ** used to detect the end of a statement is much simplier | |
| 124 */ | |
| 125 static const u8 trans[2][3] = { | |
| 126 /* Token: */ | |
| 127 /* State: ** SEMI WS OTHER */ | |
| 128 /* 0 START: */ { 0, 0, 1, }, | |
| 129 /* 1 NORMAL: */ { 0, 1, 1, }, | |
| 130 }; | |
| 131 #endif /* SQLITE_OMIT_TRIGGER */ | |
| 132 | |
| 133 while( *zSql ){ | |
| 134 switch( *zSql ){ | |
| 135 case ';': { /* A semicolon */ | |
| 136 token = tkSEMI; | |
| 137 break; | |
| 138 } | |
| 139 case ' ': | |
| 140 case '\r': | |
| 141 case '\t': | |
| 142 case '\n': | |
| 143 case '\f': { /* White space is ignored */ | |
| 144 token = tkWS; | |
| 145 break; | |
| 146 } | |
| 147 case '/': { /* C-style comments */ | |
| 148 if( zSql[1]!='*' ){ | |
| 149 token = tkOTHER; | |
| 150 break; | |
| 151 } | |
| 152 zSql += 2; | |
| 153 while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; } | |
| 154 if( zSql[0]==0 ) return 0; | |
| 155 zSql++; | |
| 156 token = tkWS; | |
| 157 break; | |
| 158 } | |
| 159 case '-': { /* SQL-style comments from "--" to end of line */ | |
| 160 if( zSql[1]!='-' ){ | |
| 161 token = tkOTHER; | |
| 162 break; | |
| 163 } | |
| 164 while( *zSql && *zSql!='\n' ){ zSql++; } | |
| 165 if( *zSql==0 ) return state==0; | |
| 166 token = tkWS; | |
| 167 break; | |
| 168 } | |
| 169 case '[': { /* Microsoft-style identifiers in [...] */ | |
| 170 zSql++; | |
| 171 while( *zSql && *zSql!=']' ){ zSql++; } | |
| 172 if( *zSql==0 ) return 0; | |
| 173 token = tkOTHER; | |
| 174 break; | |
| 175 } | |
| 176 case '`': /* Grave-accent quoted symbols used by MySQL */ | |
| 177 case '"': /* single- and double-quoted strings */ | |
| 178 case '\'': { | |
| 179 int c = *zSql; | |
| 180 zSql++; | |
| 181 while( *zSql && *zSql!=c ){ zSql++; } | |
| 182 if( *zSql==0 ) return 0; | |
| 183 token = tkOTHER; | |
| 184 break; | |
| 185 } | |
| 186 default: { | |
| 187 int c; | |
| 188 if( IdChar((u8)*zSql) ){ | |
| 189 /* Keywords and unquoted identifiers */ | |
| 190 int nId; | |
| 191 for(nId=1; IdChar(zSql[nId]); nId++){} | |
| 192 #ifdef SQLITE_OMIT_TRIGGER | |
| 193 token = tkOTHER; | |
| 194 #else | |
| 195 switch( *zSql ){ | |
| 196 case 'c': case 'C': { | |
| 197 if( nId==6 && sqlite3StrNICmp(zSql, "create", 6)==0 ){ | |
| 198 token = tkCREATE; | |
| 199 }else{ | |
| 200 token = tkOTHER; | |
| 201 } | |
| 202 break; | |
| 203 } | |
| 204 case 't': case 'T': { | |
| 205 if( nId==7 && sqlite3StrNICmp(zSql, "trigger", 7)==0 ){ | |
| 206 token = tkTRIGGER; | |
| 207 }else if( nId==4 && sqlite3StrNICmp(zSql, "temp", 4)==0 ){ | |
| 208 token = tkTEMP; | |
| 209 }else if( nId==9 && sqlite3StrNICmp(zSql, "temporary", 9)==0 ){ | |
| 210 token = tkTEMP; | |
| 211 }else{ | |
| 212 token = tkOTHER; | |
| 213 } | |
| 214 break; | |
| 215 } | |
| 216 case 'e': case 'E': { | |
| 217 if( nId==3 && sqlite3StrNICmp(zSql, "end", 3)==0 ){ | |
| 218 token = tkEND; | |
| 219 }else | |
| 220 #ifndef SQLITE_OMIT_EXPLAIN | |
| 221 if( nId==7 && sqlite3StrNICmp(zSql, "explain", 7)==0 ){ | |
| 222 token = tkEXPLAIN; | |
| 223 }else | |
| 224 #endif | |
| 225 { | |
| 226 token = tkOTHER; | |
| 227 } | |
| 228 break; | |
| 229 } | |
| 230 default: { | |
| 231 token = tkOTHER; | |
| 232 break; | |
| 233 } | |
| 234 } | |
| 235 #endif /* SQLITE_OMIT_TRIGGER */ | |
| 236 zSql += nId-1; | |
| 237 }else{ | |
| 238 /* Operators and special symbols */ | |
| 239 token = tkOTHER; | |
| 240 } | |
| 241 break; | |
| 242 } | |
| 243 } | |
| 244 state = trans[state][token]; | |
| 245 zSql++; | |
| 246 } | |
| 247 return state==0; | |
| 248 } | |
| 249 | |
| 250 #ifndef SQLITE_OMIT_UTF16 | |
| 251 /* | |
| 252 ** This routine is the same as the sqlite3_complete() routine described | |
| 253 ** above, except that the parameter is required to be UTF-16 encoded, not | |
| 254 ** UTF-8. | |
| 255 */ | |
| 256 int sqlite3_complete16(const void *zSql){ | |
| 257 sqlite3_value *pVal; | |
| 258 char const *zSql8; | |
| 259 int rc = SQLITE_NOMEM; | |
| 260 | |
| 261 #ifndef SQLITE_OMIT_AUTOINIT | |
| 262 rc = sqlite3_initialize(); | |
| 263 if( rc ) return rc; | |
| 264 #endif | |
| 265 pVal = sqlite3ValueNew(0); | |
| 266 sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC); | |
| 267 zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8); | |
| 268 if( zSql8 ){ | |
| 269 rc = sqlite3_complete(zSql8); | |
| 270 }else{ | |
| 271 rc = SQLITE_NOMEM; | |
| 272 } | |
| 273 sqlite3ValueFree(pVal); | |
| 274 return sqlite3ApiExit(0, rc); | |
| 275 } | |
| 276 #endif /* SQLITE_OMIT_UTF16 */ | |
| 277 #endif /* SQLITE_OMIT_COMPLETE */ | |
| OLD | NEW |