251cced1f8
Various minor things done to project files Updated sample extension project file and updated makefile to the new unified version (more changes likely on the way) Updated regex project file and makefile --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401971
272 lines
8.6 KiB
C
272 lines
8.6 KiB
C
/*
|
|
** 2001 September 15
|
|
**
|
|
** The author disclaims copyright to this source code. In place of
|
|
** a legal notice, here is a blessing:
|
|
**
|
|
** May you do good and not evil.
|
|
** May you find forgiveness for yourself and forgive others.
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
*************************************************************************
|
|
** An tokenizer for SQL
|
|
**
|
|
** This file contains C code that implements the sqlite3_complete() API.
|
|
** This code used to be part of the tokenizer.c source file. But by
|
|
** separating it out, the code will be automatically omitted from
|
|
** static links that do not use it.
|
|
**
|
|
** $Id$
|
|
*/
|
|
#include "sqliteInt.h"
|
|
#ifndef SQLITE_OMIT_COMPLETE
|
|
|
|
/*
|
|
** This is defined in tokenize.c. We just have to import the definition.
|
|
*/
|
|
#ifndef SQLITE_AMALGAMATION
|
|
#ifdef SQLITE_ASCII
|
|
extern const char sqlite3IsAsciiIdChar[];
|
|
#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsAsciiIdChar[c-0x20]))
|
|
#endif
|
|
#ifdef SQLITE_EBCDIC
|
|
extern const char sqlite3IsEbcdicIdChar[];
|
|
#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
|
|
#endif
|
|
#endif /* SQLITE_AMALGAMATION */
|
|
|
|
|
|
/*
|
|
** Token types used by the sqlite3_complete() routine. See the header
|
|
** comments on that procedure for additional information.
|
|
*/
|
|
#define tkSEMI 0
|
|
#define tkWS 1
|
|
#define tkOTHER 2
|
|
#define tkEXPLAIN 3
|
|
#define tkCREATE 4
|
|
#define tkTEMP 5
|
|
#define tkTRIGGER 6
|
|
#define tkEND 7
|
|
|
|
/*
|
|
** Return TRUE if the given SQL string ends in a semicolon.
|
|
**
|
|
** Special handling is require for CREATE TRIGGER statements.
|
|
** Whenever the CREATE TRIGGER keywords are seen, the statement
|
|
** must end with ";END;".
|
|
**
|
|
** This implementation uses a state machine with 7 states:
|
|
**
|
|
** (0) START At the beginning or end of an SQL statement. This routine
|
|
** returns 1 if it ends in the START state and 0 if it ends
|
|
** in any other state.
|
|
**
|
|
** (1) NORMAL We are in the middle of statement which ends with a single
|
|
** semicolon.
|
|
**
|
|
** (2) EXPLAIN The keyword EXPLAIN has been seen at the beginning of
|
|
** a statement.
|
|
**
|
|
** (3) CREATE The keyword CREATE has been seen at the beginning of a
|
|
** statement, possibly preceeded by EXPLAIN and/or followed by
|
|
** TEMP or TEMPORARY
|
|
**
|
|
** (4) TRIGGER We are in the middle of a trigger definition that must be
|
|
** ended by a semicolon, the keyword END, and another semicolon.
|
|
**
|
|
** (5) SEMI We've seen the first semicolon in the ";END;" that occurs at
|
|
** the end of a trigger definition.
|
|
**
|
|
** (6) END We've seen the ";END" of the ";END;" that occurs at the end
|
|
** of a trigger difinition.
|
|
**
|
|
** Transitions between states above are determined by tokens extracted
|
|
** from the input. The following tokens are significant:
|
|
**
|
|
** (0) tkSEMI A semicolon.
|
|
** (1) tkWS Whitespace
|
|
** (2) tkOTHER Any other SQL token.
|
|
** (3) tkEXPLAIN The "explain" keyword.
|
|
** (4) tkCREATE The "create" keyword.
|
|
** (5) tkTEMP The "temp" or "temporary" keyword.
|
|
** (6) tkTRIGGER The "trigger" keyword.
|
|
** (7) tkEND The "end" keyword.
|
|
**
|
|
** Whitespace never causes a state transition and is always ignored.
|
|
**
|
|
** If we compile with SQLITE_OMIT_TRIGGER, all of the computation needed
|
|
** to recognize the end of a trigger can be omitted. All we have to do
|
|
** is look for a semicolon that is not part of an string or comment.
|
|
*/
|
|
int sqlite3_complete(const char *zSql){
|
|
u8 state = 0; /* Current state, using numbers defined in header comment */
|
|
u8 token; /* Value of the next token */
|
|
|
|
#ifndef SQLITE_OMIT_TRIGGER
|
|
/* A complex statement machine used to detect the end of a CREATE TRIGGER
|
|
** statement. This is the normal case.
|
|
*/
|
|
static const u8 trans[7][8] = {
|
|
/* Token: */
|
|
/* State: ** SEMI WS OTHER EXPLAIN CREATE TEMP TRIGGER END */
|
|
/* 0 START: */ { 0, 0, 1, 2, 3, 1, 1, 1, },
|
|
/* 1 NORMAL: */ { 0, 1, 1, 1, 1, 1, 1, 1, },
|
|
/* 2 EXPLAIN: */ { 0, 2, 1, 1, 3, 1, 1, 1, },
|
|
/* 3 CREATE: */ { 0, 3, 1, 1, 1, 3, 4, 1, },
|
|
/* 4 TRIGGER: */ { 5, 4, 4, 4, 4, 4, 4, 4, },
|
|
/* 5 SEMI: */ { 5, 5, 4, 4, 4, 4, 4, 6, },
|
|
/* 6 END: */ { 0, 6, 4, 4, 4, 4, 4, 4, },
|
|
};
|
|
#else
|
|
/* If triggers are not suppored by this compile then the statement machine
|
|
** used to detect the end of a statement is much simplier
|
|
*/
|
|
static const u8 trans[2][3] = {
|
|
/* Token: */
|
|
/* State: ** SEMI WS OTHER */
|
|
/* 0 START: */ { 0, 0, 1, },
|
|
/* 1 NORMAL: */ { 0, 1, 1, },
|
|
};
|
|
#endif /* SQLITE_OMIT_TRIGGER */
|
|
|
|
while( *zSql ){
|
|
switch( *zSql ){
|
|
case ';': { /* A semicolon */
|
|
token = tkSEMI;
|
|
break;
|
|
}
|
|
case ' ':
|
|
case '\r':
|
|
case '\t':
|
|
case '\n':
|
|
case '\f': { /* White space is ignored */
|
|
token = tkWS;
|
|
break;
|
|
}
|
|
case '/': { /* C-style comments */
|
|
if( zSql[1]!='*' ){
|
|
token = tkOTHER;
|
|
break;
|
|
}
|
|
zSql += 2;
|
|
while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; }
|
|
if( zSql[0]==0 ) return 0;
|
|
zSql++;
|
|
token = tkWS;
|
|
break;
|
|
}
|
|
case '-': { /* SQL-style comments from "--" to end of line */
|
|
if( zSql[1]!='-' ){
|
|
token = tkOTHER;
|
|
break;
|
|
}
|
|
while( *zSql && *zSql!='\n' ){ zSql++; }
|
|
if( *zSql==0 ) return state==0;
|
|
token = tkWS;
|
|
break;
|
|
}
|
|
case '[': { /* Microsoft-style identifiers in [...] */
|
|
zSql++;
|
|
while( *zSql && *zSql!=']' ){ zSql++; }
|
|
if( *zSql==0 ) return 0;
|
|
token = tkOTHER;
|
|
break;
|
|
}
|
|
case '`': /* Grave-accent quoted symbols used by MySQL */
|
|
case '"': /* single- and double-quoted strings */
|
|
case '\'': {
|
|
int c = *zSql;
|
|
zSql++;
|
|
while( *zSql && *zSql!=c ){ zSql++; }
|
|
if( *zSql==0 ) return 0;
|
|
token = tkOTHER;
|
|
break;
|
|
}
|
|
default: {
|
|
int c;
|
|
if( IdChar((u8)*zSql) ){
|
|
/* Keywords and unquoted identifiers */
|
|
int nId;
|
|
for(nId=1; IdChar(zSql[nId]); nId++){}
|
|
#ifdef SQLITE_OMIT_TRIGGER
|
|
token = tkOTHER;
|
|
#else
|
|
switch( *zSql ){
|
|
case 'c': case 'C': {
|
|
if( nId==6 && sqlite3StrNICmp(zSql, "create", 6)==0 ){
|
|
token = tkCREATE;
|
|
}else{
|
|
token = tkOTHER;
|
|
}
|
|
break;
|
|
}
|
|
case 't': case 'T': {
|
|
if( nId==7 && sqlite3StrNICmp(zSql, "trigger", 7)==0 ){
|
|
token = tkTRIGGER;
|
|
}else if( nId==4 && sqlite3StrNICmp(zSql, "temp", 4)==0 ){
|
|
token = tkTEMP;
|
|
}else if( nId==9 && sqlite3StrNICmp(zSql, "temporary", 9)==0 ){
|
|
token = tkTEMP;
|
|
}else{
|
|
token = tkOTHER;
|
|
}
|
|
break;
|
|
}
|
|
case 'e': case 'E': {
|
|
if( nId==3 && sqlite3StrNICmp(zSql, "end", 3)==0 ){
|
|
token = tkEND;
|
|
}else
|
|
#ifndef SQLITE_OMIT_EXPLAIN
|
|
if( nId==7 && sqlite3StrNICmp(zSql, "explain", 7)==0 ){
|
|
token = tkEXPLAIN;
|
|
}else
|
|
#endif
|
|
{
|
|
token = tkOTHER;
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
token = tkOTHER;
|
|
break;
|
|
}
|
|
}
|
|
#endif /* SQLITE_OMIT_TRIGGER */
|
|
zSql += nId-1;
|
|
}else{
|
|
/* Operators and special symbols */
|
|
token = tkOTHER;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
state = trans[state][token];
|
|
zSql++;
|
|
}
|
|
return state==0;
|
|
}
|
|
|
|
#ifndef SQLITE_OMIT_UTF16
|
|
/*
|
|
** This routine is the same as the sqlite3_complete() routine described
|
|
** above, except that the parameter is required to be UTF-16 encoded, not
|
|
** UTF-8.
|
|
*/
|
|
int sqlite3_complete16(const void *zSql){
|
|
sqlite3_value *pVal;
|
|
char const *zSql8;
|
|
int rc = SQLITE_NOMEM;
|
|
|
|
pVal = sqlite3ValueNew(0);
|
|
sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC);
|
|
zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8);
|
|
if( zSql8 ){
|
|
rc = sqlite3_complete(zSql8);
|
|
}
|
|
sqlite3ValueFree(pVal);
|
|
return sqlite3ApiExit(0, rc);
|
|
}
|
|
#endif /* SQLITE_OMIT_UTF16 */
|
|
#endif /* SQLITE_OMIT_COMPLETE */
|