diff --git a/manifest b/manifest index 8dcb6035d1..7039832c53 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Beginning\sto\sclean\sup\sthe\strigger\scode.\s\sStill\slots\sof\swork\sto\sdo.\s(CVS\s566) -D 2002-05-15T12:45:43 +C Fix\sfor\sticket\s#41:\sBetter\shandling\sof\sCREATE\sTRIGGER\sin\sthe\ssqlite_complete()\nfunction.\s(CVS\s567) +D 2002-05-15T14:17:45 F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0 @@ -28,13 +28,13 @@ F src/func.c a31dcba85bc2ecb9b752980289cf7e6cd0cafbce F src/hash.c cc259475e358baaf299b00a2c7370f2b03dda892 F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9 F src/insert.c 26ca700fb4055c34970ebac1d9a9a067bebef3b0 -F src/main.c 9e9ba7d8491928c46c6a70d9b7c30bbf7e60d499 +F src/main.c de486c893c0a34a91aa5660c3ab5ce3d08746eaf F src/md5.c 0ae1f3e2cac92d06fc6246d1b4b8f61a2fe66d3b F src/os.c 5ab8b6b4590d0c1ab8e96c67996c170e4462e0fc F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10 F src/pager.c ba5740104cc27b342cd43eebfdc44d60f64a3ded F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e -F src/parse.y 164789531d0c6a2c28fb4baded14afc1be4bd4aa +F src/parse.y 12d6f6c0d12c868b366e3758e62578e686623394 F src/printf.c d8032ee18b860c812eeff596c9bebfdacb7930fd F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe F src/select.c 1b623a7d826ec7c245bc542b665d61724da2a62d @@ -73,7 +73,7 @@ F test/intpkey.test 31b5f28b2c44273e6695cf36ab2e4133aee7753c F test/ioerr.test 57d9bffaca18b34f9e976f786eadc2591d6efc6a F test/limit.test a930f3eba2a7691c8397ccab33710b931589566a F test/lock.test 3fcfd46a73119f6a18094673328a32c7b3047a8f -F test/main.test e121fed34ebf67f595290776162e322b08470127 +F test/main.test c66b564554b770ee7fdbf6a66c0cd90329bc2c85 F test/malloc.test 70fdd0812e2a57eb746aaf015350f58bb8eee0b1 F test/minmax.test fb6ab400271ae1f5bc88617c2882f2f081ea8e6d F test/misc1.test a03214118429b40ca5548bc1fae0ebd5c34dabe6 @@ -134,7 +134,7 @@ F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P 690f9a163173c4c7af7e8e92e942cee4184c7974 -R 2c7fa77b8b0294150616cb3ad535e3be +P b10346818b25940c6dc85e94de8e36d20954161c +R 8c54c69d6079e01fd5f95accd48faacf U drh -Z 2f79a3bdfbaced77f180a80585eae438 +Z f5897975828e35ff1e0f4db008fa1bf2 diff --git a/manifest.uuid b/manifest.uuid index d6e41fb428..7dfc43d7e8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b10346818b25940c6dc85e94de8e36d20954161c \ No newline at end of file +f45c4b767a6b1451787836060235ff7499dea0de \ No newline at end of file diff --git a/src/main.c b/src/main.c index 3d277e8294..7ec9cd1ba7 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 /* ** This is the callback routine for the code that initializes the @@ -476,14 +477,22 @@ void sqlite_close(sqlite *db){ /* ** 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 @@ int sqlite_complete(const char *zSql){ } 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 b790746771..bc60a78b65 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) ::= OFFSET(X). {A = X;} 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 @@ trigger_cmd(A) ::= select(X). {A = sqliteTriggerSelectStep(X); } cmd ::= DROP TRIGGER ids(X). { sqliteDropTrigger(pParse,&X,0); } - diff --git a/test/main.test b/test/main.test index 4eceab0811..fdcfcbc0ce 100644 --- a/test/main.test +++ b/test/main.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is exercising the code in main.c. # -# $Id: main.test,v 1.10 2002/05/10 13:14:08 drh Exp $ +# $Id: main.test,v 1.11 2002/05/15 14:17:45 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -70,6 +70,95 @@ do_test main-1.14 { do_test main-1.15 { db complete {SELECT a-b FROM t1 } } {0} +do_test main-1.16 { + db complete { + CREATE TABLE abc(x,y); + } +} {1} +do_test main-1.17 { + db complete { + CREATE TRIGGER xyz AFTER DELETE abc BEGIN UPDATE pqr; + } +} {0} +do_test main-1.18 { + db complete { + CREATE TRIGGER xyz AFTER DELETE abc BEGIN UPDATE pqr; END; + } +} {1} +do_test main-1.19 { + db complete { + CREATE TRIGGER xyz AFTER DELETE abc BEGIN + UPDATE pqr; + unknown command; + } +} {0} +do_test main-1.20 { + db complete { + CREATE TRIGGER xyz AFTER DELETE backend BEGIN + UPDATE pqr; + } +} {0} +do_test main-1.21 { + db complete { + CREATE TRIGGER xyz AFTER DELETE end BEGIN + SELECT a, b FROM end; + } +} {0} +do_test main-1.22 { + db complete { + CREATE TRIGGER xyz AFTER DELETE end BEGIN + SELECT a, b FROM end; + END; + } +} {1} +do_test main-1.23 { + db complete { + CREATE TRIGGER xyz AFTER DELETE end BEGIN + SELECT a, b FROM end; + END; + SELECT a, b FROM end; + } +} {1} +do_test main-1.24 { + db complete { + CREATE TRIGGER xyz AFTER DELETE [;end;] BEGIN + UPDATE pqr; + } +} {0} +do_test main-1.25 { + db complete { + CREATE TRIGGER xyz AFTER DELETE backend BEGIN + UPDATE pqr SET a=[;end;];;; + } +} {0} +do_test main-1.26 { + db complete { + CREATE -- a comment + TRIGGER xyz AFTER DELETE backend BEGIN + UPDATE pqr SET a=5; + } +} {0} +do_test main-1.27 { + db complete { + CREATE -- a comment + TRIGGERX xyz AFTER DELETE backend BEGIN + UPDATE pqr SET a=5; + } +} {1} +do_test main-1.28 { + db complete { + CREATE TEMP TRIGGER xyz AFTER DELETE backend BEGIN + UPDATE pqr SET a=5; + } +} {1} +do_test main-1.29 { + db complete { + CREATE TRIGGER xyz AFTER DELETE backend BEGIN + UPDATE pqr SET a=5; + EXPLAIN select * from xyz; + } +} {0} + # Try to open a database with a corrupt database file. #