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);
 }
-