Fix for ticket #41: Better handling of CREATE TRIGGER in the sqlite_complete()
function. (CVS 567)
FossilOrigin-Name: f45c4b767a6b1451787836060235ff7499dea0de
diff --git a/src/main.c b/src/main.c
index 3d277e8..7ec9cd1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,10 +14,11 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
-** $Id: main.c,v 1.73 2002/05/15 11:44:14 drh Exp $
+** $Id: main.c,v 1.74 2002/05/15 14:17:45 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
+#include <ctype.h>
/*
** This is the callback routine for the code that initializes the
@@ -476,14 +477,22 @@
/*
** 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;".
*/
int sqlite_complete(const char *zSql){
- int isComplete = 0;
+ int isComplete = 1;
+ int requireEnd = 0;
+ int seenText = 0;
int seenCreate = 0;
while( *zSql ){
switch( *zSql ){
case ';': {
isComplete = 1;
+ seenText = 1;
+ seenCreate = 0;
break;
}
case ' ':
@@ -494,53 +503,88 @@
}
case '[': {
isComplete = 0;
+ seenText = 1;
+ seenCreate = 0;
zSql++;
while( *zSql && *zSql!=']' ){ zSql++; }
if( *zSql==0 ) return 0;
break;
}
+ case '"':
case '\'': {
+ int c = *zSql;
isComplete = 0;
+ seenText = 1;
+ seenCreate = 0;
zSql++;
- while( *zSql && *zSql!='\'' ){ zSql++; }
- if( *zSql==0 ) return 0;
- break;
- }
- case '"': {
- isComplete = 0;
- zSql++;
- while( *zSql && *zSql!='"' ){ zSql++; }
+ while( *zSql && *zSql!=c ){ zSql++; }
if( *zSql==0 ) return 0;
break;
}
case '-': {
if( zSql[1]!='-' ){
isComplete = 0;
+ seenCreate = 0;
break;
}
while( *zSql && *zSql!='\n' ){ zSql++; }
- if( *zSql==0 ) return isComplete;
+ if( *zSql==0 ) return seenText && isComplete && requireEnd==0;
+ break;
+ }
+ case 'c':
+ case 'C': {
+ seenText = 1;
+ if( !isComplete ) break;
+ isComplete = 0;
+ if( sqliteStrNICmp(zSql, "create", 6)!=0 ) break;
+ if( !isspace(zSql[6]) ) break;
+ zSql += 5;
+ seenCreate = 1;
+ while( isspace(zSql[1]) ) zSql++;
+ if( sqliteStrNICmp(&zSql[1],"trigger", 7)!=0 ) break;
+ zSql += 7;
+ requireEnd++;
+ break;
+ }
+ case 't':
+ case 'T': {
+ seenText = 1;
+ if( !seenCreate ) break;
+ seenCreate = 0;
+ isComplete = 0;
+ if( sqliteStrNICmp(zSql, "trigger", 7)!=0 ) break;
+ if( !isspace(zSql[7]) ) break;
+ zSql += 6;
+ requireEnd++;
+ break;
+ }
+ case 'e':
+ case 'E': {
+ seenCreate = 0;
+ seenText = 1;
+ if( !isComplete ) break;
+ isComplete = 0;
+ if( requireEnd==0 ) break;
+ if( sqliteStrNICmp(zSql, "end", 3)!=0 ) break;
+ zSql += 2;
+ while( isspace(zSql[1]) ) zSql++;
+ if( zSql[1]==';' ){
+ zSql++;
+ isComplete = 1;
+ requireEnd--;
+ }
break;
}
default: {
- if (seenCreate && !sqliteStrNICmp(zSql, "trigger", 7)){
- while (sqliteStrNICmp(zSql, "end", 3)){
- if (!*++zSql) return 0;
- }
- }
- if (!sqliteStrNICmp(zSql, "create", 6)) {
- zSql = zSql + 5;
- seenCreate = 1;
- }else{
- seenCreate = 0;
- }
+ seenCreate = 0;
+ seenText = 1;
isComplete = 0;
break;
}
}
zSql++;
}
- return isComplete;
+ return seenText && isComplete && requireEnd==0;
}
/*
diff --git a/src/parse.y b/src/parse.y
index b790746..bc60a78 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -14,7 +14,7 @@
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
-** @(#) $Id: parse.y,v 1.64 2002/05/15 08:30:14 danielk1977 Exp $
+** @(#) $Id: parse.y,v 1.65 2002/05/15 14:17:45 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
@@ -120,6 +120,7 @@
id(A) ::= PRAGMA(X). {A = X;}
id(A) ::= REPLACE(X). {A = X;}
id(A) ::= TEMP(X). {A = X;}
+id(A) ::= TRIGGER(X). {A = X;}
id(A) ::= VACUUM(X). {A = X;}
id(A) ::= VIEW(X). {A = X;}
@@ -692,4 +693,3 @@
cmd ::= DROP TRIGGER ids(X). {
sqliteDropTrigger(pParse,&X,0);
}
-