Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Make explicit the restrictions on UPDATE, DELETE, and INSERT statement syntax within triggers. Ticket #3947. (CVS 6840) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
c8bf40df7be728b11bb633516d1988c6 |
User & Date: | drh 2009-07-03 15:37:28.000 |
Context
2009-07-03
| ||
16:25 | Simplify the way the read-uncommitted flag is handled to facilitate test coverage. (CVS 6841) (check-in: e2112d6160 user: danielk1977 tags: trunk) | |
15:37 | Make explicit the restrictions on UPDATE, DELETE, and INSERT statement syntax within triggers. Ticket #3947. (CVS 6840) (check-in: c8bf40df7b user: drh tags: trunk) | |
12:57 | Test the result of pthread_create() and do not call pthread_join() if the thread creation failed. Ticket #3933. (CVS 6839) (check-in: 304c5110ad user: drh tags: trunk) | |
Changes
Changes to src/parse.y.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** 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. ** | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** 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.285 2009/07/03 15:37:28 drh Exp $ */ // All token codes are small integers with #defines that begin with "TK_" %token_prefix TK_ // The type of the data attached to each token is Token. This is also the // default type for non-terminals. |
︙ | ︙ | |||
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 | A = Y; } trigger_cmd_list(A) ::= trigger_cmd(X) SEMI. { assert( X!=0 ); X->pLast = X; A = X; } %type trigger_cmd {TriggerStep*} %destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);} // UPDATE | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | | | | | | 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 | A = Y; } trigger_cmd_list(A) ::= trigger_cmd(X) SEMI. { assert( X!=0 ); X->pLast = X; A = X; } // Disallow qualified table names on INSERT, UPDATE, and DELETE statements // within a trigger. The table to INSERT, UPDATE, or DELETE is always in // the same database as the table that the trigger fires on. // %type trnm {Token} trnm(A) ::= nm(X). {A = X;} trnm(A) ::= nm DOT nm(X). { A = X; sqlite3ErrorMsg(pParse, "qualified table names are not allowed on INSERT, UPDATE, and DELETE " "statements within triggers"); } // Disallow the INDEX BY and NOT INDEXED clauses on UPDATE and DELETE // statements within triggers. We make a specific error message for this // since it is an exception to the default grammar rules. // tridxby ::= . tridxby ::= INDEXED BY nm. { sqlite3ErrorMsg(pParse, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " "within triggers"); } tridxby ::= NOT INDEXED. { sqlite3ErrorMsg(pParse, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " "within triggers"); } %type trigger_cmd {TriggerStep*} %destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);} // UPDATE trigger_cmd(A) ::= UPDATE orconf(R) trnm(X) tridxby SET setlist(Y) where_opt(Z). { A = sqlite3TriggerUpdateStep(pParse->db, &X, Y, Z, R); } // INSERT trigger_cmd(A) ::= insert_cmd(R) INTO trnm(X) inscollist_opt(F) VALUES LP itemlist(Y) RP. {A = sqlite3TriggerInsertStep(pParse->db, &X, F, Y, 0, R);} trigger_cmd(A) ::= insert_cmd(R) INTO trnm(X) inscollist_opt(F) select(S). {A = sqlite3TriggerInsertStep(pParse->db, &X, F, 0, S, R);} // DELETE trigger_cmd(A) ::= DELETE FROM trnm(X) tridxby where_opt(Y). {A = sqlite3TriggerDeleteStep(pParse->db, &X, Y);} // SELECT trigger_cmd(A) ::= select(X). {A = sqlite3TriggerSelectStep(pParse->db, X); } // The special RAISE expression that may occur in trigger programs expr(A) ::= RAISE(X) LP IGNORE RP(Y). { |
︙ | ︙ |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.891 2009/07/03 15:37:28 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build |
︙ | ︙ | |||
2137 2138 2139 2140 2141 2142 2143 | * Otherwise NULL. * pExprList -> A list of the columns to update and the expressions to update * them to. See sqlite3Update() documentation of "pChanges" * argument. * */ struct TriggerStep { | | | < | < | | | < | | 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 | * Otherwise NULL. * pExprList -> A list of the columns to update and the expressions to update * them to. See sqlite3Update() documentation of "pChanges" * argument. * */ struct TriggerStep { u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */ u8 orconf; /* OE_Rollback etc. */ Trigger *pTrig; /* The trigger that this step is a part of */ Select *pSelect; /* SELECT statment or RHS of INSERT INTO .. SELECT ... */ Token target; /* Target table for DELETE, UPDATE, INSERT */ Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */ ExprList *pExprList; /* SET clause for UPDATE. VALUES clause for INSERT */ IdList *pIdList; /* Column names for INSERT */ TriggerStep *pNext; /* Next in the link-list */ TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */ }; /* * An instance of struct TriggerStack stores information required during code * generation of a single trigger program. While the trigger program is being |
︙ | ︙ |
Changes to test/trigger1.test.
︙ | ︙ | |||
635 636 637 638 639 640 641 642 | } catchsql { UPDATE tA SET a = 'abc' } } {1 {datatype mismatch}} do_test trigger1-15.2 { catchsql { INSERT INTO tA VALUES('abc', 2, 3) } } {1 {datatype mismatch}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 | } catchsql { UPDATE tA SET a = 'abc' } } {1 {datatype mismatch}} do_test trigger1-15.2 { catchsql { INSERT INTO tA VALUES('abc', 2, 3) } } {1 {datatype mismatch}} # Ticket #3947: Do not allow qualified table names on INSERT, UPDATE, and # DELETE statements within triggers. Actually, this has never been allowed # by the grammar. But the error message is confusing: one simply gets a # "syntax error". That has now been changed to give a full error message. # do_test trigger1-16.1 { db eval { CREATE TABLE t16(a,b,c); CREATE INDEX t16a ON t16(a); CREATE INDEX t16b ON t16(b); } catchsql { CREATE TRIGGER main.t16err1 AFTER INSERT ON tA BEGIN INSERT INTO main.t16 VALUES(1,2,3); END; } } {1 {qualified table names are not allowed on INSERT, UPDATE, and DELETE statements within triggers}} do_test trigger1-16.2 { catchsql { CREATE TRIGGER main.t16err2 AFTER INSERT ON tA BEGIN UPDATE main.t16 SET rowid=rowid+1; END; } } {1 {qualified table names are not allowed on INSERT, UPDATE, and DELETE statements within triggers}} do_test trigger1-16.3 { catchsql { CREATE TRIGGER main.t16err3 AFTER INSERT ON tA BEGIN DELETE FROM main.t16; END; } } {1 {qualified table names are not allowed on INSERT, UPDATE, and DELETE statements within triggers}} do_test trigger1-16.4 { catchsql { CREATE TRIGGER main.t16err4 AFTER INSERT ON tA BEGIN UPDATE t16 NOT INDEXED SET rowid=rowid+1; END; } } {1 {the NOT INDEXED clause is not allowed on UPDATE or DELETE statements within triggers}} do_test trigger1-16.5 { catchsql { CREATE TRIGGER main.t16err5 AFTER INSERT ON tA BEGIN UPDATE t16 INDEXED BY t16a SET rowid=rowid+1 WHERE a=1; END; } } {1 {the INDEXED BY clause is not allowed on UPDATE or DELETE statements within triggers}} do_test trigger1-16.6 { catchsql { CREATE TRIGGER main.t16err6 AFTER INSERT ON tA BEGIN DELETE FROM t16 NOT INDEXED WHERE a=123; END; } } {1 {the NOT INDEXED clause is not allowed on UPDATE or DELETE statements within triggers}} do_test trigger1-16.7 { catchsql { CREATE TRIGGER main.t16err7 AFTER INSERT ON tA BEGIN DELETE FROM t16 INDEXED BY t16a WHERE a=123; END; } } {1 {the INDEXED BY clause is not allowed on UPDATE or DELETE statements within triggers}} finish_test |