Index: src/parse.y ================================================================== --- src/parse.y +++ src/parse.y @@ -12,11 +12,11 @@ ** This file contains SQLite's grammar for SQL. Process this file ** using the lemon parser generator to generate C code that runs ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.66 2002/05/21 11:38:12 drh Exp $ +** @(#) $Id: parse.y,v 1.67 2002/05/23 00:30:31 drh Exp $ */ %token_prefix TK_ %token_type {Token} %default_type {Token} %extra_argument {Parse *pParse} @@ -122,10 +122,11 @@ id(A) ::= OF(X). {A = X;} id(A) ::= OFFSET(X). {A = X;} id(A) ::= PRAGMA(X). {A = X;} id(A) ::= REPLACE(X). {A = X;} id(A) ::= ROW(X). {A = X;} +id(A) ::= STATEMENT(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;} Index: src/tokenize.c ================================================================== --- src/tokenize.c +++ src/tokenize.c @@ -13,11 +13,11 @@ ** ** This file contains C code that splits an SQL input string up into ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** -** $Id: tokenize.c,v 1.41 2002/05/15 08:30:14 danielk1977 Exp $ +** $Id: tokenize.c,v 1.42 2002/05/23 00:30:31 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include #include @@ -98,10 +98,11 @@ { "REPLACE", 0, TK_REPLACE, 0 }, { "ROLLBACK", 0, TK_ROLLBACK, 0 }, { "ROW", 0, TK_ROW, 0 }, { "SELECT", 0, TK_SELECT, 0 }, { "SET", 0, TK_SET, 0 }, + { "STATEMENT", 0, TK_STATEMENT, 0 }, { "TABLE", 0, TK_TABLE, 0 }, { "TEMP", 0, TK_TEMP, 0 }, { "TEMPORARY", 0, TK_TEMP, 0 }, { "THEN", 0, TK_THEN, 0 }, { "TRANSACTION", 0, TK_TRANSACTION, 0 }, Index: src/trigger.c ================================================================== --- src/trigger.c +++ src/trigger.c @@ -57,10 +57,16 @@ if( !tab ){ sqliteSetNString(&pParse->zErrMsg, "no such table: ", -1, pTableName->z, pTableName->n, 0); pParse->nErr++; goto trigger_cleanup; + } + if( sqliteStrICmp(tab->zName, MASTER_NAME)==0 ){ + sqliteSetString(&pParse->zErrMsg, "cannot create trigger on system " + "table: " MASTER_NAME, 0); + pParse->nErr++; + goto trigger_cleanup; } } /* Build the Trigger object */ nt = (Trigger*)sqliteMalloc(sizeof(Trigger)); Index: test/trigger1.test ================================================================== --- test/trigger1.test +++ test/trigger1.test @@ -100,14 +100,21 @@ END; SELECT count(*) FROM sqlite_master WHERE name = 'temp_trig'; } } {0} +do_test trig_cd-1.9 { + catchsql { + CREATE TRIGGER tr1 AFTER UPDATE ON sqlite_master BEGIN + SELECT * FROM sqlite_master; + END; + } +} {1 {cannot create trigger on system table: sqlite_master}} + catchsql { DROP TABLE temp_table; } catchsql { DROP TABLE t1; } finish_test - Index: test/trigger2.test ================================================================== --- test/trigger2.test +++ test/trigger2.test @@ -539,11 +539,12 @@ execsql { DROP TABLE tbl; } # 7. Triggers on views -execsql { +do_test trig-7.1 { + execsql { CREATE TABLE ab(a, b); CREATE TABLE cd(c, d); INSERT INTO ab VALUES (1, 2); INSERT INTO ab VALUES (0, 0); INSERT INTO cd VALUES (3, 4); @@ -577,13 +578,14 @@ END; CREATE TRIGGER after_insert AFTER INSERT ON abcd BEGIN INSERT INTO tlog VALUES(NULL, 0, 0, 0, 0, new.a, new.b, new.c, new.d); END; -} + } +} {} -do_test trig-7 { +do_test trig-7.2 { execsql { UPDATE abcd SET a = 100, b = 5*5 WHERE a = 1; DELETE FROM abcd WHERE a = 1; INSERT INTO abcd VALUES(10, 20, 30, 40); SELECT * FROM tlog; @@ -592,6 +594,5 @@ 2 1 2 3 4 100 25 3 4 \ 3 1 2 3 4 0 0 0 0 4 1 2 3 4 0 0 0 0 \ 5 0 0 0 0 10 20 30 40 6 0 0 0 0 10 20 30 40 ] finish_test -