Optimize trigger compilation to avoid populating the OLD.* and NEW.* pseudo-tables with data that will never be used. Some testing to come. (CVS 4651)
FossilOrigin-Name: e08a33ed7255c22ce2805363f44a1d7770acb2dd
This commit is contained in:
parent
8ea1cfaa9a
commit
8f2c54e6e2
27
manifest
27
manifest
@ -1,5 +1,5 @@
|
|||||||
C Silence\sa\sharmless\sunitialised\svariable\swarning\sin\sbtree.c.\sTicket\s#2862.\s(CVS\s4650)
|
C Optimize\strigger\scompilation\sto\savoid\spopulating\sthe\sOLD.*\sand\sNEW.*\spseudo-tables\swith\sdata\sthat\swill\snever\sbe\sused.\sSome\stesting\sto\scome.\s(CVS\s4651)
|
||||||
D 2008-01-01T06:19:02
|
D 2008-01-01T19:02:09
|
||||||
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
||||||
F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9
|
F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@ -90,13 +90,13 @@ F src/build.c cbfd98ceb95c61c226cd60a845fa7967b66c8931
|
|||||||
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
|
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
|
||||||
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
|
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
|
||||||
F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6
|
F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6
|
||||||
F src/delete.c 1f957c4acb2270772c6fab8411459e7dd43d585f
|
F src/delete.c 6c090aeb5e97a224ee1f232a02359ee79e8ab411
|
||||||
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
|
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
|
||||||
F src/expr.c 43807e139e14957330095d9ac183f7ad449ce907
|
F src/expr.c d0969aa79a8e12f8ba49ffe97ae671bee47e37dc
|
||||||
F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d
|
F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d
|
||||||
F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c
|
F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c
|
||||||
F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53
|
F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53
|
||||||
F src/insert.c 2b145fca8e538b7f2c2de429e931c1501e55e5ac
|
F src/insert.c 3c82c974150506bed75f58dec3744503bf112dd4
|
||||||
F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2
|
F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2
|
||||||
F src/legacy.c 4ac53191fad2e3c4d59bde1228879b2dc5a96d66
|
F src/legacy.c 4ac53191fad2e3c4d59bde1228879b2dc5a96d66
|
||||||
F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35
|
F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35
|
||||||
@ -131,12 +131,12 @@ F src/pragma.c dd5b1983168eacba1a5084571775b904ea95404f
|
|||||||
F src/prepare.c 7aeba7851773fbe3950a26b35d3389bef0eb1c62
|
F src/prepare.c 7aeba7851773fbe3950a26b35d3389bef0eb1c62
|
||||||
F src/printf.c eb27822ba2eec669161409ca31279a24c26ac910
|
F src/printf.c eb27822ba2eec669161409ca31279a24c26ac910
|
||||||
F src/random.c 4a22746501bf36b0a088c66e38dde5daba6a35da
|
F src/random.c 4a22746501bf36b0a088c66e38dde5daba6a35da
|
||||||
F src/select.c 5a137027415a74e950603baddbbcbe9d3f8bc5a5
|
F src/select.c 247d668f5be042b914ed8e46edf9cdb57a1eca29
|
||||||
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
|
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
|
||||||
F src/shell.c 77895a54c2082157e169c857a2e244525ec25af7
|
F src/shell.c 77895a54c2082157e169c857a2e244525ec25af7
|
||||||
F src/sqlite.h.in 2a7e3776534bbe6ff2cdc058f3abebe91e7e429f
|
F src/sqlite.h.in 2a7e3776534bbe6ff2cdc058f3abebe91e7e429f
|
||||||
F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb
|
F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb
|
||||||
F src/sqliteInt.h 445530263725d19d6315f137f234aea08ad59303
|
F src/sqliteInt.h cf993fe510f6a4cdc18e60b80eee3725c2f1001e
|
||||||
F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e
|
F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e
|
||||||
F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4
|
F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4
|
||||||
F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf
|
F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf
|
||||||
@ -163,8 +163,8 @@ F src/test_server.c a6ece6c835e7eae835054124e09e947e422b1ac5
|
|||||||
F src/test_tclvar.c b2d1115e4d489179d3f029e765211b2ad527ba59
|
F src/test_tclvar.c b2d1115e4d489179d3f029e765211b2ad527ba59
|
||||||
F src/test_thread.c e297dd41db0b249646e69f97d36ec13e56e8b730
|
F src/test_thread.c e297dd41db0b249646e69f97d36ec13e56e8b730
|
||||||
F src/tokenize.c a4e04438c11fed2c67ec47fe3edbef9cca2d1b48
|
F src/tokenize.c a4e04438c11fed2c67ec47fe3edbef9cca2d1b48
|
||||||
F src/trigger.c 66695e1375b969ea41a38dec9f40ea28bb0ac767
|
F src/trigger.c 24bdfee77ce9472db91267597225506c31fc3d9b
|
||||||
F src/update.c 57c07b63410cdd3d14888e33439aa1955a3514c1
|
F src/update.c 59124a9d5d52bb411f6fba6475b93f2f443fc971
|
||||||
F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736
|
F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736
|
||||||
F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624
|
F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624
|
||||||
F src/vacuum.c 25ffbd766f25bca099ead1c1e11f5528c86102b8
|
F src/vacuum.c 25ffbd766f25bca099ead1c1e11f5528c86102b8
|
||||||
@ -193,7 +193,7 @@ F test/attach.test 72529edb04115675894a7399609983ea46b73ba6
|
|||||||
F test/attach2.test a295d2d7061adcee5884ef4a93c7c96a82765437
|
F test/attach2.test a295d2d7061adcee5884ef4a93c7c96a82765437
|
||||||
F test/attach3.test 7b92dc8e40c1ebca9732ca6f2d3fefbd46f196df
|
F test/attach3.test 7b92dc8e40c1ebca9732ca6f2d3fefbd46f196df
|
||||||
F test/attachmalloc.test 56c5e55563dba6d64641ef2f70ce06900df16912
|
F test/attachmalloc.test 56c5e55563dba6d64641ef2f70ce06900df16912
|
||||||
F test/auth.test 74b49b669cb6ca022124838ff957e1e11b1a8002
|
F test/auth.test be181f70ced0c84ecb5e2515d9b620f89f6a7b87
|
||||||
F test/auth2.test 65ac294b8d52cbdd463f61e77ad0165268373126
|
F test/auth2.test 65ac294b8d52cbdd463f61e77ad0165268373126
|
||||||
F test/autoinc.test 0e67964f4855081e3a325e484adfebaab41f23a1
|
F test/autoinc.test 0e67964f4855081e3a325e484adfebaab41f23a1
|
||||||
F test/autovacuum.test 4339e66003b9cf813dd667a83aed2dee27c4c36d
|
F test/autovacuum.test 4339e66003b9cf813dd667a83aed2dee27c4c36d
|
||||||
@ -493,6 +493,7 @@ F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83
|
|||||||
F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9
|
F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9
|
||||||
F test/trigger7.test 0afa870be2ce1b132cdb85b17a4a4ef45aa8cece
|
F test/trigger7.test 0afa870be2ce1b132cdb85b17a4a4ef45aa8cece
|
||||||
F test/trigger8.test 3a09275aa2214fdff56f731b1e775d8dfee4408a
|
F test/trigger8.test 3a09275aa2214fdff56f731b1e775d8dfee4408a
|
||||||
|
F test/trigger9.test 49c7cb761e9d3617ed868717b90b545e9bae8e73
|
||||||
F test/types.test 98e7a631bddf0806204358b452b02d0e319318a6
|
F test/types.test 98e7a631bddf0806204358b452b02d0e319318a6
|
||||||
F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
|
F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
|
||||||
F test/types3.test b730a7db03ef69f0fdb85b2addc20d1a0a04039b
|
F test/types3.test b730a7db03ef69f0fdb85b2addc20d1a0a04039b
|
||||||
@ -602,7 +603,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
|
|||||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||||
P 6dea8c16384443ed4ab59d1e2694534992ec3118
|
P b51782ccac28598eec7adc9302fe7d1986bfdaf8
|
||||||
R 782ae7c60f2ef919b3a8af5b140614e6
|
R 904ead844e1f41e01a54c3518029f00d
|
||||||
U danielk1977
|
U danielk1977
|
||||||
Z 52c90bef75d1e50f96fdd91d4d73d155
|
Z 755babd79b5a2ad03f400826316421af
|
||||||
|
@ -1 +1 @@
|
|||||||
b51782ccac28598eec7adc9302fe7d1986bfdaf8
|
e08a33ed7255c22ce2805363f44a1d7770acb2dd
|
47
src/delete.c
47
src/delete.c
@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** in order to generate code for DELETE FROM statements.
|
** in order to generate code for DELETE FROM statements.
|
||||||
**
|
**
|
||||||
** $Id: delete.c,v 1.134 2007/12/12 17:42:53 danielk1977 Exp $
|
** $Id: delete.c,v 1.135 2008/01/01 19:02:09 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -113,6 +113,11 @@ void sqlite3DeleteFrom(
|
|||||||
int isView; /* True if attempting to delete from a view */
|
int isView; /* True if attempting to delete from a view */
|
||||||
int triggers_exist = 0; /* True if any triggers exist */
|
int triggers_exist = 0; /* True if any triggers exist */
|
||||||
#endif
|
#endif
|
||||||
|
int iBeginAfterTrigger; /* Address of after trigger program */
|
||||||
|
int iEndAfterTrigger; /* Exit of after trigger program */
|
||||||
|
int iBeginBeforeTrigger; /* Address of before trigger program */
|
||||||
|
int iEndBeforeTrigger; /* Exit of before trigger program */
|
||||||
|
u32 old_col_mask = 0; /* Mask of OLD.* columns in use */
|
||||||
|
|
||||||
sContext.pParse = 0;
|
sContext.pParse = 0;
|
||||||
db = pParse->db;
|
db = pParse->db;
|
||||||
@ -192,11 +197,28 @@ void sqlite3DeleteFrom(
|
|||||||
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
||||||
sqlite3BeginWriteOperation(pParse, triggers_exist, iDb);
|
sqlite3BeginWriteOperation(pParse, triggers_exist, iDb);
|
||||||
|
|
||||||
|
if( triggers_exist ){
|
||||||
|
int iGoto = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
|
||||||
|
addr = sqlite3VdbeMakeLabel(v);
|
||||||
|
iBeginBeforeTrigger = sqlite3VdbeCurrentAddr(v);
|
||||||
|
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_BEFORE, pTab,
|
||||||
|
-1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
|
||||||
|
addr, &old_col_mask, 0);
|
||||||
|
iEndBeforeTrigger = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
|
||||||
|
iBeginAfterTrigger = sqlite3VdbeCurrentAddr(v);
|
||||||
|
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1,
|
||||||
|
oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
|
||||||
|
addr, &old_col_mask, 0);
|
||||||
|
iEndAfterTrigger = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
|
||||||
|
sqlite3VdbeJumpHere(v, iGoto);
|
||||||
|
}
|
||||||
|
|
||||||
/* If we are trying to delete from a view, realize that view into
|
/* If we are trying to delete from a view, realize that view into
|
||||||
** a ephemeral table.
|
** a ephemeral table.
|
||||||
*/
|
*/
|
||||||
if( isView ){
|
if( isView ){
|
||||||
Select *pView = sqlite3SelectDup(db, pTab->pSelect);
|
Select *pView = sqlite3SelectDup(db, pTab->pSelect);
|
||||||
|
sqlite3SelectMask(pParse, pView, old_col_mask);
|
||||||
sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0);
|
sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0);
|
||||||
sqlite3SelectDelete(pView);
|
sqlite3SelectDelete(pView);
|
||||||
}
|
}
|
||||||
@ -276,6 +298,9 @@ void sqlite3DeleteFrom(
|
|||||||
*/
|
*/
|
||||||
if( triggers_exist ){
|
if( triggers_exist ){
|
||||||
int mem1 = pParse->nMem++;
|
int mem1 = pParse->nMem++;
|
||||||
|
int addr_rowdata;
|
||||||
|
u32 mask;
|
||||||
|
sqlite3VdbeResolveLabel(v, addr);
|
||||||
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
|
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
|
||||||
sqlite3VdbeAddOp(v, OP_StackDepth, -1, 0);
|
sqlite3VdbeAddOp(v, OP_StackDepth, -1, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_MemStore, mem1, 0);
|
sqlite3VdbeAddOp(v, OP_MemStore, mem1, 0);
|
||||||
@ -284,15 +309,20 @@ void sqlite3DeleteFrom(
|
|||||||
}
|
}
|
||||||
sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
|
sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
|
||||||
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
|
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
|
if( old_col_mask ){
|
||||||
|
sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
|
||||||
|
}else{
|
||||||
|
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
|
||||||
|
}
|
||||||
sqlite3VdbeAddOp(v, OP_Insert, oldIdx, 0);
|
sqlite3VdbeAddOp(v, OP_Insert, oldIdx, 0);
|
||||||
if( !isView ){
|
if( !isView ){
|
||||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_BEFORE, pTab,
|
/* Jump back and run the BEFORE triggers */
|
||||||
-1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
|
sqlite3VdbeAddOp(v, OP_Goto, 0, iBeginBeforeTrigger);
|
||||||
addr);
|
sqlite3VdbeJumpHere(v, iEndBeforeTrigger);
|
||||||
|
|
||||||
if( !isView ){
|
if( !isView ){
|
||||||
sqlite3VdbeAddOp(v, OP_MemLoad, mem1, 0);
|
sqlite3VdbeAddOp(v, OP_MemLoad, mem1, 0);
|
||||||
}
|
}
|
||||||
@ -336,9 +366,10 @@ void sqlite3DeleteFrom(
|
|||||||
}
|
}
|
||||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||||
}
|
}
|
||||||
(void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1,
|
|
||||||
oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
|
/* Jump back and run the AFTER triggers */
|
||||||
addr);
|
sqlite3VdbeAddOp(v, OP_Goto, 0, iBeginAfterTrigger);
|
||||||
|
sqlite3VdbeJumpHere(v, iEndAfterTrigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* End of the delete loop */
|
/* End of the delete loop */
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
** This file contains routines used for analyzing expressions and
|
** This file contains routines used for analyzing expressions and
|
||||||
** for generating VDBE code that evaluates expressions in SQLite.
|
** for generating VDBE code that evaluates expressions in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: expr.c,v 1.320 2007/12/14 15:12:21 drh Exp $
|
** $Id: expr.c,v 1.321 2008/01/01 19:02:09 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -1107,14 +1107,17 @@ static int lookupName(
|
|||||||
if( zDb==0 && zTab!=0 && cnt==0 && pParse->trigStack!=0 ){
|
if( zDb==0 && zTab!=0 && cnt==0 && pParse->trigStack!=0 ){
|
||||||
TriggerStack *pTriggerStack = pParse->trigStack;
|
TriggerStack *pTriggerStack = pParse->trigStack;
|
||||||
Table *pTab = 0;
|
Table *pTab = 0;
|
||||||
|
u32 *piColMask;
|
||||||
if( pTriggerStack->newIdx != -1 && sqlite3StrICmp("new", zTab) == 0 ){
|
if( pTriggerStack->newIdx != -1 && sqlite3StrICmp("new", zTab) == 0 ){
|
||||||
pExpr->iTable = pTriggerStack->newIdx;
|
pExpr->iTable = pTriggerStack->newIdx;
|
||||||
assert( pTriggerStack->pTab );
|
assert( pTriggerStack->pTab );
|
||||||
pTab = pTriggerStack->pTab;
|
pTab = pTriggerStack->pTab;
|
||||||
|
piColMask = &(pTriggerStack->newColMask);
|
||||||
}else if( pTriggerStack->oldIdx != -1 && sqlite3StrICmp("old", zTab)==0 ){
|
}else if( pTriggerStack->oldIdx != -1 && sqlite3StrICmp("old", zTab)==0 ){
|
||||||
pExpr->iTable = pTriggerStack->oldIdx;
|
pExpr->iTable = pTriggerStack->oldIdx;
|
||||||
assert( pTriggerStack->pTab );
|
assert( pTriggerStack->pTab );
|
||||||
pTab = pTriggerStack->pTab;
|
pTab = pTriggerStack->pTab;
|
||||||
|
piColMask = &(pTriggerStack->oldColMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( pTab ){
|
if( pTab ){
|
||||||
@ -1133,6 +1136,9 @@ static int lookupName(
|
|||||||
pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
|
pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
|
||||||
}
|
}
|
||||||
pExpr->pTab = pTab;
|
pExpr->pTab = pTab;
|
||||||
|
if( iCol>=0 ){
|
||||||
|
*piColMask |= ((u32)1<<iCol) | (iCol>=32?0xffffffff:0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle INSERT statements in SQLite.
|
** to handle INSERT statements in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: insert.c,v 1.197 2007/12/14 16:11:09 drh Exp $
|
** $Id: insert.c,v 1.198 2008/01/01 19:02:09 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -708,7 +708,7 @@ void sqlite3Insert(
|
|||||||
|
|
||||||
/* Fire BEFORE or INSTEAD OF triggers */
|
/* Fire BEFORE or INSTEAD OF triggers */
|
||||||
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_BEFORE, pTab,
|
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_BEFORE, pTab,
|
||||||
newIdx, -1, onError, endOfLoop) ){
|
newIdx, -1, onError, endOfLoop, 0, 0) ){
|
||||||
goto insert_cleanup;
|
goto insert_cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -837,7 +837,7 @@ void sqlite3Insert(
|
|||||||
|
|
||||||
/* Code AFTER triggers */
|
/* Code AFTER triggers */
|
||||||
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_AFTER, pTab,
|
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_AFTER, pTab,
|
||||||
newIdx, -1, onError, endOfLoop) ){
|
newIdx, -1, onError, endOfLoop, 0, 0) ){
|
||||||
goto insert_cleanup;
|
goto insert_cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
31
src/select.c
31
src/select.c
@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle SELECT statements in SQLite.
|
** to handle SELECT statements in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: select.c,v 1.372 2007/12/14 17:24:40 drh Exp $
|
** $Id: select.c,v 1.373 2008/01/01 19:02:09 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -2961,6 +2961,35 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
|||||||
pAggInfo->directMode = 0;
|
pAggInfo->directMode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_TRIGGER
|
||||||
|
/*
|
||||||
|
** This function is used when a SELECT statement is used to create a
|
||||||
|
** temporary table for iterating through when running an INSTEAD OF
|
||||||
|
** UPDATE or INSTEAD OF DELETE trigger.
|
||||||
|
**
|
||||||
|
** If possible, the SELECT statement is modified so that NULL values
|
||||||
|
** are stored in the temporary table for all columns for which the
|
||||||
|
** corresponding bit in argument mask is not set. If mask takes the
|
||||||
|
** special value 0xffffffff, then all columns are populated.
|
||||||
|
*/
|
||||||
|
int sqlite3SelectMask(Parse *pParse, Select *p, u32 mask){
|
||||||
|
if( !p->pPrior && !p->isDistinct && mask!=0xffffffff ){
|
||||||
|
ExprList *pEList;
|
||||||
|
int i;
|
||||||
|
if( sqlite3SelectResolve(pParse, p, 0) ){
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
pEList = p->pEList;
|
||||||
|
for(i=0; i<pEList->nExpr && i<32; i++){
|
||||||
|
if( !(mask&((u32)1<<i)) ){
|
||||||
|
sqlite3ExprDelete(pEList->a[i].pExpr);
|
||||||
|
pEList->a[i].pExpr = sqlite3Expr(pParse->db, TK_NULL, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Generate code for the given SELECT statement.
|
** Generate code for the given SELECT statement.
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.626 2007/12/13 03:45:08 drh Exp $
|
** @(#) $Id: sqliteInt.h,v 1.627 2008/01/01 19:02:09 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITEINT_H_
|
#ifndef _SQLITEINT_H_
|
||||||
#define _SQLITEINT_H_
|
#define _SQLITEINT_H_
|
||||||
@ -1558,6 +1558,8 @@ struct TriggerStack {
|
|||||||
Table *pTab; /* Table that triggers are currently being coded on */
|
Table *pTab; /* Table that triggers are currently being coded on */
|
||||||
int newIdx; /* Index of vdbe cursor to "new" temp table */
|
int newIdx; /* Index of vdbe cursor to "new" temp table */
|
||||||
int oldIdx; /* Index of vdbe cursor to "old" temp table */
|
int oldIdx; /* Index of vdbe cursor to "old" temp table */
|
||||||
|
u32 newColMask;
|
||||||
|
u32 oldColMask;
|
||||||
int orconf; /* Current orconf policy */
|
int orconf; /* Current orconf policy */
|
||||||
int ignoreJump; /* where to jump to for a RAISE(IGNORE) */
|
int ignoreJump; /* where to jump to for a RAISE(IGNORE) */
|
||||||
Trigger *pTrigger; /* The trigger currently being coded */
|
Trigger *pTrigger; /* The trigger currently being coded */
|
||||||
@ -1716,6 +1718,7 @@ int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*, char *aff);
|
|||||||
Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
|
Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
|
||||||
Expr*,ExprList*,int,Expr*,Expr*);
|
Expr*,ExprList*,int,Expr*,Expr*);
|
||||||
void sqlite3SelectDelete(Select*);
|
void sqlite3SelectDelete(Select*);
|
||||||
|
int sqlite3SelectMask(Parse *, Select *, u32);
|
||||||
Table *sqlite3SrcListLookup(Parse*, SrcList*);
|
Table *sqlite3SrcListLookup(Parse*, SrcList*);
|
||||||
int sqlite3IsReadOnly(Parse*, Table*, int);
|
int sqlite3IsReadOnly(Parse*, Table*, int);
|
||||||
void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
|
void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
|
||||||
@ -1783,7 +1786,7 @@ void sqlite3ChangeCookie(sqlite3*, Vdbe*, int);
|
|||||||
void sqlite3DropTriggerPtr(Parse*, Trigger*);
|
void sqlite3DropTriggerPtr(Parse*, Trigger*);
|
||||||
int sqlite3TriggersExist(Parse*, Table*, int, ExprList*);
|
int sqlite3TriggersExist(Parse*, Table*, int, ExprList*);
|
||||||
int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int,
|
int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int,
|
||||||
int, int);
|
int, int, u32*, u32*);
|
||||||
void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
|
void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
|
||||||
void sqlite3DeleteTriggerStep(TriggerStep*);
|
void sqlite3DeleteTriggerStep(TriggerStep*);
|
||||||
TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*);
|
TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*);
|
||||||
@ -1798,7 +1801,7 @@ void sqlite3ChangeCookie(sqlite3*, Vdbe*, int);
|
|||||||
# define sqlite3DeleteTrigger(A)
|
# define sqlite3DeleteTrigger(A)
|
||||||
# define sqlite3DropTriggerPtr(A,B)
|
# define sqlite3DropTriggerPtr(A,B)
|
||||||
# define sqlite3UnlinkAndDeleteTrigger(A,B,C)
|
# define sqlite3UnlinkAndDeleteTrigger(A,B,C)
|
||||||
# define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I) 0
|
# define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I,J,K) 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int sqlite3JoinType(Parse*, Token*, Token*, Token*);
|
int sqlite3JoinType(Parse*, Token*, Token*, Token*);
|
||||||
|
@ -751,6 +751,13 @@ static int codeTriggerProgram(
|
|||||||
** a row containing values to be substituted for old.* expressions in the
|
** a row containing values to be substituted for old.* expressions in the
|
||||||
** trigger program(s).
|
** trigger program(s).
|
||||||
**
|
**
|
||||||
|
** If they are not NULL, the piOldColMask and piNewColMask output variables
|
||||||
|
** are set to values that describe the columns used by the trigger program
|
||||||
|
** in the OLD.* and NEW.* tables respectively. If column N of the
|
||||||
|
** pseudo-table is read at least once, the corresponding bit of the output
|
||||||
|
** mask is set. If a column with an index greater than 32 is read, the
|
||||||
|
** output mask is set to the special value 0xffffffff.
|
||||||
|
**
|
||||||
*/
|
*/
|
||||||
int sqlite3CodeRowTrigger(
|
int sqlite3CodeRowTrigger(
|
||||||
Parse *pParse, /* Parse context */
|
Parse *pParse, /* Parse context */
|
||||||
@ -761,11 +768,16 @@ int sqlite3CodeRowTrigger(
|
|||||||
int newIdx, /* The indice of the "new" row to access */
|
int newIdx, /* The indice of the "new" row to access */
|
||||||
int oldIdx, /* The indice of the "old" row to access */
|
int oldIdx, /* The indice of the "old" row to access */
|
||||||
int orconf, /* ON CONFLICT policy */
|
int orconf, /* ON CONFLICT policy */
|
||||||
int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */
|
int ignoreJump, /* Instruction to jump to for RAISE(IGNORE) */
|
||||||
|
u32 *piOldColMask, /* OUT: Mask of columns used from the OLD.* table */
|
||||||
|
u32 *piNewColMask /* OUT: Mask of columns used from the NEW.* table */
|
||||||
){
|
){
|
||||||
Trigger *p;
|
Trigger *p;
|
||||||
TriggerStack trigStackEntry;
|
TriggerStack trigStackEntry;
|
||||||
|
|
||||||
|
trigStackEntry.oldColMask = 0;
|
||||||
|
trigStackEntry.newColMask = 0;
|
||||||
|
|
||||||
assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
|
assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
|
||||||
assert(tr_tm == TRIGGER_BEFORE || tr_tm == TRIGGER_AFTER );
|
assert(tr_tm == TRIGGER_BEFORE || tr_tm == TRIGGER_AFTER );
|
||||||
|
|
||||||
@ -835,6 +847,8 @@ int sqlite3CodeRowTrigger(
|
|||||||
sqlite3VdbeResolveLabel(pParse->pVdbe, endTrigger);
|
sqlite3VdbeResolveLabel(pParse->pVdbe, endTrigger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if( piOldColMask ) *piOldColMask |= trigStackEntry.oldColMask;
|
||||||
|
if( piNewColMask ) *piNewColMask |= trigStackEntry.newColMask;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* !defined(SQLITE_OMIT_TRIGGER) */
|
#endif /* !defined(SQLITE_OMIT_TRIGGER) */
|
||||||
|
65
src/update.c
65
src/update.c
@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle UPDATE statements.
|
** to handle UPDATE statements.
|
||||||
**
|
**
|
||||||
** $Id: update.c,v 1.144 2007/12/12 16:06:23 danielk1977 Exp $
|
** $Id: update.c,v 1.145 2008/01/01 19:02:09 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -111,6 +111,12 @@ void sqlite3Update(
|
|||||||
int isView; /* Trying to update a view */
|
int isView; /* Trying to update a view */
|
||||||
int triggers_exist = 0; /* True if any row triggers exist */
|
int triggers_exist = 0; /* True if any row triggers exist */
|
||||||
#endif
|
#endif
|
||||||
|
int iBeginAfterTrigger; /* Address of after trigger program */
|
||||||
|
int iEndAfterTrigger; /* Exit of after trigger program */
|
||||||
|
int iBeginBeforeTrigger; /* Address of before trigger program */
|
||||||
|
int iEndBeforeTrigger; /* Exit of before trigger program */
|
||||||
|
u32 old_col_mask = 0; /* Mask of OLD.* columns in use */
|
||||||
|
u32 new_col_mask = 0; /* Mask of NEW.* columns in use */
|
||||||
|
|
||||||
int newIdx = -1; /* index of trigger "new" temp table */
|
int newIdx = -1; /* index of trigger "new" temp table */
|
||||||
int oldIdx = -1; /* index of trigger "old" temp table */
|
int oldIdx = -1; /* index of trigger "old" temp table */
|
||||||
@ -288,12 +294,33 @@ void sqlite3Update(
|
|||||||
sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
|
sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Generate the code for triggers.
|
||||||
|
*/
|
||||||
|
if( triggers_exist ){
|
||||||
|
int iGoto = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
|
||||||
|
addr = sqlite3VdbeMakeLabel(v);
|
||||||
|
iBeginBeforeTrigger = sqlite3VdbeCurrentAddr(v);
|
||||||
|
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab,
|
||||||
|
newIdx, oldIdx, onError, addr, &old_col_mask, &new_col_mask) ){
|
||||||
|
goto update_cleanup;
|
||||||
|
}
|
||||||
|
iEndBeforeTrigger = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
|
||||||
|
iBeginAfterTrigger = sqlite3VdbeCurrentAddr(v);
|
||||||
|
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_AFTER, pTab,
|
||||||
|
newIdx, oldIdx, onError, addr, &old_col_mask, &new_col_mask) ){
|
||||||
|
goto update_cleanup;
|
||||||
|
}
|
||||||
|
iEndAfterTrigger = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
|
||||||
|
sqlite3VdbeJumpHere(v, iGoto);
|
||||||
|
}
|
||||||
|
|
||||||
/* If we are trying to update a view, realize that view into
|
/* If we are trying to update a view, realize that view into
|
||||||
** a ephemeral table.
|
** a ephemeral table.
|
||||||
*/
|
*/
|
||||||
if( isView ){
|
if( isView ){
|
||||||
Select *pView;
|
Select *pView;
|
||||||
pView = sqlite3SelectDup(db, pTab->pSelect);
|
pView = sqlite3SelectDup(db, pTab->pSelect);
|
||||||
|
sqlite3SelectMask(pParse, pView, old_col_mask|new_col_mask);
|
||||||
sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0);
|
sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0);
|
||||||
sqlite3SelectDelete(pView);
|
sqlite3SelectDelete(pView);
|
||||||
}
|
}
|
||||||
@ -320,7 +347,6 @@ void sqlite3Update(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( triggers_exist ){
|
if( triggers_exist ){
|
||||||
|
|
||||||
/* Create pseudo-tables for NEW and OLD
|
/* Create pseudo-tables for NEW and OLD
|
||||||
*/
|
*/
|
||||||
sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
|
sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
|
||||||
@ -330,6 +356,7 @@ void sqlite3Update(
|
|||||||
|
|
||||||
/* The top of the update loop for when there are triggers.
|
/* The top of the update loop for when there are triggers.
|
||||||
*/
|
*/
|
||||||
|
sqlite3VdbeResolveLabel(v, addr);
|
||||||
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
|
addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_StackDepth, -1, 0);
|
sqlite3VdbeAddOp(v, OP_StackDepth, -1, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_MemStore, mem1, 0);
|
sqlite3VdbeAddOp(v, OP_MemStore, mem1, 0);
|
||||||
@ -345,7 +372,11 @@ void sqlite3Update(
|
|||||||
/* Generate the OLD table
|
/* Generate the OLD table
|
||||||
*/
|
*/
|
||||||
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
|
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
|
if( !old_col_mask ){
|
||||||
|
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
|
||||||
|
}else{
|
||||||
|
sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
|
||||||
|
}
|
||||||
sqlite3VdbeAddOp(v, OP_Insert, oldIdx, 0);
|
sqlite3VdbeAddOp(v, OP_Insert, oldIdx, 0);
|
||||||
|
|
||||||
/* Generate the NEW table
|
/* Generate the NEW table
|
||||||
@ -361,11 +392,15 @@ void sqlite3Update(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
j = aXRef[i];
|
j = aXRef[i];
|
||||||
if( j<0 ){
|
if( new_col_mask&((u32)1<<i) || new_col_mask==0xffffffff ){
|
||||||
sqlite3VdbeAddOp(v, OP_Column, iCur, i);
|
if( j<0 ){
|
||||||
sqlite3ColumnDefault(v, pTab, i);
|
sqlite3VdbeAddOp(v, OP_Column, iCur, i);
|
||||||
|
sqlite3ColumnDefault(v, pTab, i);
|
||||||
|
}else{
|
||||||
|
sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr);
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr);
|
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
|
sqlite3VdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
|
||||||
@ -378,13 +413,9 @@ void sqlite3Update(
|
|||||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fire the BEFORE and INSTEAD OF triggers
|
sqlite3VdbeAddOp(v, OP_Goto, 0, iBeginBeforeTrigger);
|
||||||
*/
|
sqlite3VdbeJumpHere(v, iEndBeforeTrigger);
|
||||||
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab,
|
|
||||||
newIdx, oldIdx, onError, addr) ){
|
|
||||||
goto update_cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !isView ){
|
if( !isView ){
|
||||||
sqlite3VdbeAddOp(v, OP_MemLoad, mem1, 0);
|
sqlite3VdbeAddOp(v, OP_MemLoad, mem1, 0);
|
||||||
}
|
}
|
||||||
@ -495,10 +526,8 @@ void sqlite3Update(
|
|||||||
}
|
}
|
||||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||||
}
|
}
|
||||||
if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_AFTER, pTab,
|
sqlite3VdbeAddOp(v, OP_Goto, 0, iBeginAfterTrigger);
|
||||||
newIdx, oldIdx, onError, addr) ){
|
sqlite3VdbeJumpHere(v, iEndAfterTrigger);
|
||||||
goto update_cleanup;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Repeat the above with the next record to be updated, until
|
/* Repeat the above with the next record to be updated, until
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
# focus of this script is testing the sqlite3_set_authorizer() API
|
# focus of this script is testing the sqlite3_set_authorizer() API
|
||||||
# and related functionality.
|
# and related functionality.
|
||||||
#
|
#
|
||||||
# $Id: auth.test,v 1.39 2007/11/13 10:30:26 danielk1977 Exp $
|
# $Id: auth.test,v 1.40 2008/01/01 19:02:09 danielk1977 Exp $
|
||||||
#
|
#
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
@ -2246,12 +2246,12 @@ do_test auth-4.3 {
|
|||||||
} [list \
|
} [list \
|
||||||
SQLITE_UPDATE v1 x main {} \
|
SQLITE_UPDATE v1 x main {} \
|
||||||
SQLITE_READ v1 x main {} \
|
SQLITE_READ v1 x main {} \
|
||||||
SQLITE_SELECT {} {} {} v1 \
|
|
||||||
SQLITE_READ t2 a main v1 \
|
|
||||||
SQLITE_READ t2 b main v1 \
|
|
||||||
SQLITE_INSERT v1chng {} main r2 \
|
SQLITE_INSERT v1chng {} main r2 \
|
||||||
SQLITE_READ v1 x main r2 \
|
SQLITE_READ v1 x main r2 \
|
||||||
SQLITE_READ v1 x main r2]
|
SQLITE_READ v1 x main r2 \
|
||||||
|
SQLITE_READ t2 a main v1 \
|
||||||
|
SQLITE_READ t2 b main v1 \
|
||||||
|
SQLITE_SELECT {} {} {} v1]
|
||||||
do_test auth-4.4 {
|
do_test auth-4.4 {
|
||||||
execsql {
|
execsql {
|
||||||
CREATE TRIGGER r3 INSTEAD OF DELETE ON v1 BEGIN
|
CREATE TRIGGER r3 INSTEAD OF DELETE ON v1 BEGIN
|
||||||
@ -2269,11 +2269,11 @@ do_test auth-4.5 {
|
|||||||
} [list \
|
} [list \
|
||||||
SQLITE_DELETE v1 {} main {} \
|
SQLITE_DELETE v1 {} main {} \
|
||||||
SQLITE_READ v1 x main {} \
|
SQLITE_READ v1 x main {} \
|
||||||
SQLITE_SELECT {} {} {} v1 \
|
SQLITE_INSERT v1chng {} main r3 \
|
||||||
|
SQLITE_READ v1 x main r3 \
|
||||||
SQLITE_READ t2 a main v1 \
|
SQLITE_READ t2 a main v1 \
|
||||||
SQLITE_READ t2 b main v1 \
|
SQLITE_READ t2 b main v1 \
|
||||||
SQLITE_INSERT v1chng {} main r3 \
|
SQLITE_SELECT {} {} {} v1]
|
||||||
SQLITE_READ v1 x main r3]
|
|
||||||
|
|
||||||
} ;# ifcapable view && trigger
|
} ;# ifcapable view && trigger
|
||||||
|
|
||||||
|
147
test/trigger9.test
Normal file
147
test/trigger9.test
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
# 2008 January 1
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
#***********************************************************************
|
||||||
|
# This file implements regression tests for SQLite library. Specifically,
|
||||||
|
# it tests some compiler optimizations for SQL statements featuring
|
||||||
|
# triggers:
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
# trigger9-1.* - Test that if there are no references to OLD.* cols, or a
|
||||||
|
# reference to only OLD.rowid, the data is not loaded.
|
||||||
|
#
|
||||||
|
# trigger9-2.* - Test that for NEW.* records populated by UPDATE
|
||||||
|
# statements, unused fields are populated with NULL values.
|
||||||
|
#
|
||||||
|
# trigger9-3.* - Test that the temporary tables used for OLD.* references
|
||||||
|
# in "INSTEAD OF" triggers have NULL values in unused
|
||||||
|
# fields.
|
||||||
|
#
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
ifcapable {!trigger} {
|
||||||
|
finish_test
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
proc has_rowdata {sql} {
|
||||||
|
expr {[lsearch [execsql "explain $sql"] RowData]>=0}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_test trigger9-1.1 {
|
||||||
|
execsql {
|
||||||
|
PRAGMA page_size = 1024;
|
||||||
|
CREATE TABLE t1(x, y, z);
|
||||||
|
INSERT INTO t1 VALUES('1', randstr(10000,10000), '2');
|
||||||
|
INSERT INTO t1 VALUES('2', randstr(10000,10000), '4');
|
||||||
|
INSERT INTO t1 VALUES('3', randstr(10000,10000), '6');
|
||||||
|
CREATE TABLE t2(x);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
do_test trigger9-1.2.1 {
|
||||||
|
sqlite3 db test.db
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
CREATE TRIGGER trig1 BEFORE DELETE ON t1 BEGIN
|
||||||
|
INSERT INTO t2 VALUES(old.rowid);
|
||||||
|
END;
|
||||||
|
DELETE FROM t1;
|
||||||
|
SELECT * FROM t2;
|
||||||
|
}
|
||||||
|
} {1 2 3}
|
||||||
|
do_test trigger9-1.2.3 {
|
||||||
|
has_rowdata {DELETE FROM t1}
|
||||||
|
} 0
|
||||||
|
do_test trigger9-1.2.4 { execsql { ROLLBACK } } {}
|
||||||
|
|
||||||
|
do_test trigger9-1.3.1 {
|
||||||
|
sqlite3 db test.db
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
CREATE TRIGGER trig1 BEFORE DELETE ON t1 BEGIN
|
||||||
|
INSERT INTO t2 VALUES(old.x);
|
||||||
|
END;
|
||||||
|
DELETE FROM t1;
|
||||||
|
SELECT * FROM t2;
|
||||||
|
}
|
||||||
|
} {1 2 3}
|
||||||
|
do_test trigger9-1.3.2 {
|
||||||
|
has_rowdata {DELETE FROM t1}
|
||||||
|
} 1
|
||||||
|
do_test trigger9-1.3.3 { execsql { ROLLBACK } } {}
|
||||||
|
|
||||||
|
do_test trigger9-1.4.1 {
|
||||||
|
sqlite3 db test.db
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
CREATE TRIGGER trig1 BEFORE DELETE ON t1 WHEN old.x='1' BEGIN
|
||||||
|
INSERT INTO t2 VALUES(old.rowid);
|
||||||
|
END;
|
||||||
|
DELETE FROM t1;
|
||||||
|
SELECT * FROM t2;
|
||||||
|
}
|
||||||
|
} {1}
|
||||||
|
do_test trigger9-1.4.2 {
|
||||||
|
has_rowdata {DELETE FROM t1}
|
||||||
|
} 1
|
||||||
|
do_test trigger9-1.4.3 { execsql { ROLLBACK } } {}
|
||||||
|
|
||||||
|
do_test trigger9-1.5.1 {
|
||||||
|
sqlite3 db test.db
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
CREATE TRIGGER trig1 BEFORE UPDATE ON t1 BEGIN
|
||||||
|
INSERT INTO t2 VALUES(old.rowid);
|
||||||
|
END;
|
||||||
|
UPDATE t1 SET y = '';
|
||||||
|
SELECT * FROM t2;
|
||||||
|
}
|
||||||
|
} {1 2 3}
|
||||||
|
do_test trigger9-1.5.2 {
|
||||||
|
has_rowdata {UPDATE t1 SET y = ''}
|
||||||
|
} 0
|
||||||
|
do_test trigger9-1.5.3 { execsql { ROLLBACK } } {}
|
||||||
|
|
||||||
|
do_test trigger9-1.6.1 {
|
||||||
|
sqlite3 db test.db
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
CREATE TRIGGER trig1 BEFORE UPDATE ON t1 BEGIN
|
||||||
|
INSERT INTO t2 VALUES(old.x);
|
||||||
|
END;
|
||||||
|
UPDATE t1 SET y = '';
|
||||||
|
SELECT * FROM t2;
|
||||||
|
}
|
||||||
|
} {1 2 3}
|
||||||
|
do_test trigger9-1.6.2 {
|
||||||
|
has_rowdata {UPDATE t1 SET y = ''}
|
||||||
|
} 1
|
||||||
|
do_test trigger9-1.6.3 { execsql { ROLLBACK } } {}
|
||||||
|
|
||||||
|
do_test trigger9-1.7.1 {
|
||||||
|
sqlite3 db test.db
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
CREATE TRIGGER trig1 BEFORE UPDATE ON t1 WHEN old.x>='2' BEGIN
|
||||||
|
INSERT INTO t2 VALUES(old.x);
|
||||||
|
END;
|
||||||
|
UPDATE t1 SET y = '';
|
||||||
|
SELECT * FROM t2;
|
||||||
|
}
|
||||||
|
} {2 3}
|
||||||
|
do_test trigger9-1.7.2 {
|
||||||
|
has_rowdata {UPDATE t1 SET y = ''}
|
||||||
|
} 1
|
||||||
|
do_test trigger9-1.7.3 { execsql { ROLLBACK } } {}
|
||||||
|
|
||||||
|
finish_test
|
Loading…
Reference in New Issue
Block a user