mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-24 22:22:08 +03:00
Fixes for new triggers scheme.
FossilOrigin-Name: 9eb91efda5241609ff18ff15ef5eaa0e86788eab
This commit is contained in:
46
manifest
46
manifest
@ -1,5 +1,5 @@
|
||||
C Changes\sto\ssupport\srecursive\striggers.
|
||||
D 2009-08-28T18:53:45
|
||||
C Fixes\sfor\snew\striggers\sscheme.
|
||||
D 2009-08-30T11:42:52
|
||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||
F Makefile.in 73ddeec9dd10b85876c5c2ce1fdce627e1dcc7f8
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
@ -112,20 +112,20 @@ F src/build.c 212476dc971756e7f7429e677059fafc678afbd5
|
||||
F src/callback.c 9bc0ae998f15207d3115224979331c0aafc9bcc3
|
||||
F src/complete.c 5ad5c6cd4548211867c204c41a126d73a9fbcea0
|
||||
F src/date.c ab5f7137656652a48434d64f96bdcdc823bb23b3
|
||||
F src/delete.c 0fa2c14bb3520590ef48bf214d4925cfb6e95e8c
|
||||
F src/expr.c 24a8f8088d2af202852bac0a364614d20d5e663c
|
||||
F src/delete.c 5b7c810b7e70e1c4abe1d2532f97003565b14b61
|
||||
F src/expr.c 09ef2a72664c51550dbe226c99782fab42cccf48
|
||||
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
|
||||
F src/func.c e536218d193b8d326aab91120bc4c6f28aa2b606
|
||||
F src/global.c 271952d199a8cc59d4ce840b3bbbfd2f30c8ba32
|
||||
F src/hash.c ebcaa921ffd9d86f7ea5ae16a0a29d1c871130a7
|
||||
F src/hash.h 35b216c13343d0b4f87d9f21969ac55ad72174e1
|
||||
F src/hwtime.h 4a1d45f4cae1f402ea19686acf24acf4f0cb53cb
|
||||
F src/insert.c 5bddd3d65fceb671f56b000c202d07d17bed2775
|
||||
F src/insert.c 5b548c8070b492269f7dab999a0e2b4ae21516e2
|
||||
F src/journal.c e00df0c0da8413ab6e1bb7d7cab5665d4a9000d0
|
||||
F src/legacy.c 303b4ffcf1ae652fcf5ef635846c563c254564f6
|
||||
F src/lempar.c 0c4d1ab0a5ef2b0381eb81a732c54f68f27a574d
|
||||
F src/loadext.c 0e88a335665db0b2fb4cece3e49dcb65d832635a
|
||||
F src/main.c c2fc25f25edf7bfb4b70622e21dc6c8476b6d66d
|
||||
F src/main.c 45b3779140336d21a54f289888ff40cb9d2316c7
|
||||
F src/malloc.c b1725183bcc4ce2e569f1b65da844dc3e4c7a643
|
||||
F src/mem0.c f2f84062d1f35814d6535c9f9e33de3bfb3b132c
|
||||
F src/mem1.c e6d5c23941288df8191b8a98c28e3f57771e2270
|
||||
@ -152,7 +152,7 @@ F src/parse.y 6c42631e72a3d14cde2bee85e79409066066d3df
|
||||
F src/pcache.c c92ffd4f3e1279b3766854c6d18b5bf4aac0d1fa
|
||||
F src/pcache.h 435ef324197f79391f9c92b71d7f92b548ad7a36
|
||||
F src/pcache1.c 211295a9ff6a5b30f1ca50516731a5cf3e9bf82c
|
||||
F src/pragma.c 9eb44ac1d3dc1ac3ea4f444abe1a10ae8acaa16c
|
||||
F src/pragma.c 6b1fa9f180d88b3f905cebd593ef6aef9334be43
|
||||
F src/prepare.c 49739b385c4cd0667cfa9941c41bf6d4f8edc157
|
||||
F src/printf.c 508a1c59433353552b6553cba175eaa7331f8fc1
|
||||
F src/random.c 676b9d7ac820fe81e6fb2394ac8c10cff7f38628
|
||||
@ -162,7 +162,7 @@ F src/select.c 56ecb073e6f6696173ad80493aa14355225b6e53
|
||||
F src/shell.c db2643650b9268df89a4bedca3f1c6d9e786f1bb
|
||||
F src/sqlite.h.in 3ccf717d82101f19548d0b1243f0a6f4854d51ee
|
||||
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
|
||||
F src/sqliteInt.h ff4ae0702b0d816395030f9170151954f26830a7
|
||||
F src/sqliteInt.h d87eb4976edacb68fb9b7557163ae0def733354b
|
||||
F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d
|
||||
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
|
||||
F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d
|
||||
@ -199,16 +199,16 @@ F src/test_tclvar.c 9e42fa59d3d2f064b7ab8628e7ab2dc8a9fe93d4
|
||||
F src/test_thread.c b8a1ab7ca1a632f18e8a361880d5d65eeea08eac
|
||||
F src/test_wsd.c 3ae5101de6cbfda2720152ab659ea84079719241
|
||||
F src/tokenize.c af8a56e6a50c5042fc305bfa796275e9bf26ff2b
|
||||
F src/trigger.c 135c1fc78ada9d5a5d8ffee412263547b1a93ca9
|
||||
F src/update.c cddbcabb2fccc146b8712f5b97e636c413c34906
|
||||
F src/trigger.c 26e493efad371e521178d60d43fcf7878dbdd344
|
||||
F src/update.c 574464e0049eb289ab863c583f84474b5b76cd39
|
||||
F src/utf.c 3ca2c9461b8e942c68da28bfccd448663f536a6f
|
||||
F src/util.c efb5f8e533d4beef545cf765cab5f7920b4c75f9
|
||||
F src/vacuum.c 3fe0eebea6d2311c1c2ab2962887d11f7a4dcfb0
|
||||
F src/vdbe.c e45309524c11866f2d158b3578aecfe6d9af0676
|
||||
F src/vdbe.c 5e9d870ec390fbc329f11424b121681e8da5d75c
|
||||
F src/vdbe.h 080fe6bc1264438becb8bf9b9f3c84074c336b78
|
||||
F src/vdbeInt.h 9b62f7053dc1255e9c5dec16f35b5fd079ba7ed4
|
||||
F src/vdbeInt.h 1291908344bcbaa8cf47de86d7108cb92c3a71a3
|
||||
F src/vdbeapi.c 8d5013ab6104be757c208a70ffb191cc27d2b688
|
||||
F src/vdbeaux.c cf440244489accee8ddeb85c24b239659c31de1b
|
||||
F src/vdbeaux.c ea92afd36df2e7f3a47cff5ea41aa5489ea4c971
|
||||
F src/vdbeblob.c f93cb60ac388633ed3bde8a94ef161ad2dbfb689
|
||||
F src/vdbemem.c dc551981833756ea34a3e0b238f759479e7cf526
|
||||
F src/vtab.c 10df5c77cea34a49f2ad4e5de763f820d6223eb4
|
||||
@ -236,7 +236,7 @@ F test/attachmalloc.test cf8cf17d183de357b1147a9baacbdfc85b940b61
|
||||
F test/auth.test 8e9a21d7321c9ad20d26f630acc02e15f2f2a3b6
|
||||
F test/auth2.test ee3ba272e2b975e913afc9b041ee75706e190005
|
||||
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
|
||||
F test/autoinc.test f1959df99bca67066db8ff816ae89b49f1f42e00
|
||||
F test/autoinc.test 8242b84e5af8af6e00db4b5c5d48afdf304a12cb
|
||||
F test/autovacuum.test 25f891bc343a8bf5d9229e2e9ddab9f31a9ab5ec
|
||||
F test/autovacuum_ioerr2.test 598b0663074d3673a9c1bc9a16e80971313bafe6
|
||||
F test/avtrans.test 1e901d8102706b63534dbd2bdd4d8f16c4082650
|
||||
@ -480,7 +480,7 @@ F test/minmax.test 722d80816f7e096bf2c04f4111f1a6c1ba65453d
|
||||
F test/minmax2.test 33504c01a03bd99226144e4b03f7631a274d66e0
|
||||
F test/minmax3.test 94742aa922153953ce3562702815e4f1f079bdb8
|
||||
F test/misc1.test 1b89c02c4a33b49dee4cd1d20d161aaaba719075
|
||||
F test/misc2.test 1ee89298de9c16b61454658b24999c403e86afe4
|
||||
F test/misc2.test 0bd5a44926124b9194b03499b37b8377f6d0b23b
|
||||
F test/misc3.test 72c5dc87a78e7865c5ec7a969fc572913dbe96b6
|
||||
F test/misc4.test 91e8ed25c092c2bb4e0bb01864631e2930f8d7de
|
||||
F test/misc5.test 6a5c1e3217a95b0db05ff9a0f1ecb5ce9043ffef
|
||||
@ -642,7 +642,7 @@ F test/tkt3581.test 1966b7193f1e3f14951cce8c66907ae69454e9a3
|
||||
F test/tkt35xx.test ed9721bd9eb1693b3b4d3cf2a093fa7f92af0c93
|
||||
F test/tkt3630.test 929f64852103054125200bc825c316d5f75d42f7
|
||||
F test/tkt3718.test 3b59dcb5c4e7754dacd91e7fd353a61492cc402a
|
||||
F test/tkt3731.test 8a6e3732f5a8a24eb875a6faf287ef77bb8c0579
|
||||
F test/tkt3731.test d3ae761d8e31ddb2919e55776000e645e6b5b9f1
|
||||
F test/tkt3757.test 8f2208930655bbd4f92c14e19e72303a43e098ef
|
||||
F test/tkt3761.test b95ea9c98f21cf91325f18a984887e62caceab33
|
||||
F test/tkt3762.test 2a9f3b03df44ec49ec0cfa8d5da6574c2a7853df
|
||||
@ -661,7 +661,7 @@ F test/tkt3918.test e6cdf6bfcfe9ba939d86a4238a9dc55d6eec5d42
|
||||
F test/tkt3922.test 022ace32c049e3964f68492c12eb803e8e4856d8
|
||||
F test/tkt3929.test 6a4c3baefb4e75127356b7d675b5df42c35c00d1
|
||||
F test/tkt3935.test e15261fedb9e30a4305a311da614a5d8e693c767
|
||||
F test/tkt3992.test c193b9643b1c25d020c503a986d5e4089e65c530
|
||||
F test/tkt3992.test 2ba939cc646eaa46761dfd55f975cad69bf4e254
|
||||
F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd
|
||||
F test/tkt4018.test f581cf52dc359171875cb649bdc38b525d7b9309
|
||||
F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
|
||||
@ -670,14 +670,14 @@ F test/trans.test d887cb07630dc39879a322d958ad8b006137485c
|
||||
F test/trans2.test d5337e61de45e66b1fcbf9db833fa8c82e624b22
|
||||
F test/trans3.test d728abaa318ca364dc370e06576aa7e5fbed7e97
|
||||
F test/trigger1.test 2e18561f85e448bb633c9c9de792e9bbf7b2dd3e
|
||||
F test/trigger2.test 53cf2209f68eb5bbb0ea0a07d694007fa702f1ed
|
||||
F test/trigger3.test 501b8489eb6b9cb5b005f60b071583c01a3c3041
|
||||
F test/trigger2.test 10b5fa93a8646b4a446ad10e9e36af896b83c408
|
||||
F test/trigger3.test 841602f2659b17bc4a2fcbbf7fcbea4577750aad
|
||||
F test/trigger4.test 8e90ee98cba940cd5f96493f82e55083806ab8a0
|
||||
F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83
|
||||
F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9
|
||||
F test/trigger7.test 72feaf8dbc52cea84de0c3e6ce7559ff19c479af
|
||||
F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4
|
||||
F test/trigger9.test e6e8dbab673666b3c0a63f0fefcff2329fe6bba8
|
||||
F test/trigger9.test 5b0789f1c5c4600961f8e68511b825b87be53e31
|
||||
F test/triggerA.test 0718ad2d9bfef27c7af00e636df79bee6b988da7
|
||||
F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe
|
||||
F test/types.test 9a825ec8eea4e965d7113b74c76a78bb5240f2ac
|
||||
@ -747,7 +747,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl 672f81d693a03f80f5ae60bfefacd8a349e76746
|
||||
P dee1b8eb402f47c6d5ee60aac28f8e3dcf98167f
|
||||
R ef22ff6ef84d7c63fbbf7ca259ee2aa2
|
||||
P 9b9c19211593d5ff7b39254a29c284560a8bcedb
|
||||
R 10a0aa3fda7c1b8d215a3d925d83afe3
|
||||
U dan
|
||||
Z 871f833b67d466cf35f851400879eb8b
|
||||
Z fc25ca89c2c8570dc6970eb3da5d927f
|
||||
|
@ -1 +1 @@
|
||||
9b9c19211593d5ff7b39254a29c284560a8bcedb
|
||||
9eb91efda5241609ff18ff15ef5eaa0e86788eab
|
@ -408,11 +408,14 @@ void sqlite3DeleteFrom(
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( mask==0xffffffff || mask&(1<<i) ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regOld+i);
|
||||
sqlite3ColumnDefault(v, pTab, i, regOld+i);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Affinity, regOld, pTab->nCol);
|
||||
sqlite3TableAffinityStr(v, pTab);
|
||||
|
||||
sqlite3CodeRowTrigger(pParse, pTrigger,
|
||||
TK_DELETE, 0, TRIGGER_BEFORE, pTab, -1, regOld, OE_Default, addr
|
||||
TK_DELETE, 0, TRIGGER_BEFORE, pTab, -1, iRowid, OE_Default, addr
|
||||
);
|
||||
}
|
||||
|
||||
@ -432,7 +435,7 @@ void sqlite3DeleteFrom(
|
||||
|
||||
/* Code the AFTER triggers. This is a no-op if there are no triggers. */
|
||||
sqlite3CodeRowTrigger(pParse,
|
||||
pTrigger, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1, regOld, OE_Default, addr
|
||||
pTrigger, TK_DELETE, 0, TRIGGER_AFTER, pTab, -1, iRowid, OE_Default, addr
|
||||
);
|
||||
|
||||
/* End of the delete loop */
|
||||
|
13
src/expr.c
13
src/expr.c
@ -90,7 +90,9 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
pColl = p->pColl;
|
||||
if( pColl ) break;
|
||||
op = p->op;
|
||||
if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER) && p->pTab!=0 ){
|
||||
if( p->pTab!=0 && (
|
||||
op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER || op==TK_TRIGGER
|
||||
)){
|
||||
/* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally
|
||||
** a TK_COLUMN but was previously evaluated and cached in a register */
|
||||
const char *zColl;
|
||||
@ -2557,11 +2559,12 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
}
|
||||
|
||||
case TK_TRIGGER: {
|
||||
sqlite3VdbeAddOp3(v, OP_TriggerVal, pExpr->iColumn, target,pExpr->iTable);
|
||||
assert( pExpr->pTab );
|
||||
VdbeComment((v, "%s.%s",
|
||||
int iVal = pExpr->iTable * (pExpr->pTab->nCol+1) + 1 + pExpr->iColumn;
|
||||
sqlite3VdbeAddOp2(v, OP_Param, iVal, target);
|
||||
VdbeComment((v, "%s.%s -> $%d",
|
||||
(pExpr->iTable ? "new" : "old"),
|
||||
(pExpr->iColumn<0 ? "rowid" : pExpr->pTab->aCol[pExpr->iColumn].zName)
|
||||
(pExpr->iColumn<0 ? "rowid" : pExpr->pTab->aCol[pExpr->iColumn].zName),
|
||||
target
|
||||
));
|
||||
break;
|
||||
}
|
||||
|
51
src/insert.c
51
src/insert.c
@ -197,20 +197,21 @@ static int autoIncBegin(
|
||||
){
|
||||
int memId = 0; /* Register holding maximum rowid */
|
||||
if( pTab->tabFlags & TF_Autoincrement ){
|
||||
Parse *pRoot = (pParse->pRoot ? pParse->pRoot : pParse);
|
||||
AutoincInfo *pInfo;
|
||||
|
||||
pInfo = pParse->pAinc;
|
||||
pInfo = pRoot->pAinc;
|
||||
while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
|
||||
if( pInfo==0 ){
|
||||
pInfo = sqlite3DbMallocRaw(pParse->db, sizeof(*pInfo));
|
||||
if( pInfo==0 ) return 0;
|
||||
pInfo->pNext = pParse->pAinc;
|
||||
pParse->pAinc = pInfo;
|
||||
pInfo->pNext = pRoot->pAinc;
|
||||
pRoot->pAinc = pInfo;
|
||||
pInfo->pTab = pTab;
|
||||
pInfo->iDb = iDb;
|
||||
pParse->nMem++; /* Register to hold name of table */
|
||||
pInfo->regCtr = ++pParse->nMem; /* Max rowid register */
|
||||
pParse->nMem++; /* Rowid in sqlite_sequence */
|
||||
pRoot->nMem++; /* Register to hold name of table */
|
||||
pInfo->regCtr = ++pRoot->nMem; /* Max rowid register */
|
||||
pRoot->nMem++; /* Rowid in sqlite_sequence */
|
||||
}
|
||||
memId = pInfo->regCtr;
|
||||
}
|
||||
@ -229,6 +230,9 @@ void sqlite3AutoincrementBegin(Parse *pParse){
|
||||
int addr; /* A VDBE address */
|
||||
Vdbe *v = pParse->pVdbe; /* VDBE under construction */
|
||||
|
||||
/* If currently generating a trigger program, this call is a no-op */
|
||||
if( pParse->pTriggerTab ) return;
|
||||
|
||||
assert( v ); /* We failed long ago if this is not so */
|
||||
for(p = pParse->pAinc; p; p = p->pNext){
|
||||
pDb = &db->aDb[p->iDb];
|
||||
@ -805,8 +809,7 @@ void sqlite3Insert(
|
||||
*/
|
||||
endOfLoop = sqlite3VdbeMakeLabel(v);
|
||||
if( tmask & TRIGGER_BEFORE ){
|
||||
int regTrigRowid;
|
||||
int regCols;
|
||||
int regCols = sqlite3GetTempRange(pParse, pTab->nCol+1);
|
||||
|
||||
/* build the NEW.* reference row. Note that if there is an INTEGER
|
||||
** PRIMARY KEY into which a NULL is being inserted, that NULL will be
|
||||
@ -814,21 +817,20 @@ void sqlite3Insert(
|
||||
** we do not know what the unique ID will be (because the insert has
|
||||
** not happened yet) so we substitute a rowid of -1
|
||||
*/
|
||||
regTrigRowid = sqlite3GetTempReg(pParse);
|
||||
if( keyColumn<0 ){
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, -1, regTrigRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols);
|
||||
}else{
|
||||
int j1;
|
||||
if( useTempTable ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regTrigRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regCols);
|
||||
}else{
|
||||
assert( pSelect==0 ); /* Otherwise useTempTable is true */
|
||||
sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regTrigRowid);
|
||||
sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regCols);
|
||||
}
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regTrigRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, -1, regTrigRowid);
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols);
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
sqlite3VdbeAddOp1(v, OP_MustBeInt, regTrigRowid);
|
||||
sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols);
|
||||
}
|
||||
|
||||
/* Cannot have triggers on a virtual table. If it were possible,
|
||||
@ -838,7 +840,6 @@ void sqlite3Insert(
|
||||
|
||||
/* Create the new column data
|
||||
*/
|
||||
regCols = sqlite3GetTempRange(pParse, pTab->nCol);
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( pColumn==0 ){
|
||||
j = i;
|
||||
@ -848,12 +849,12 @@ void sqlite3Insert(
|
||||
}
|
||||
}
|
||||
if( pColumn && j>=pColumn->nId ){
|
||||
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i);
|
||||
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1);
|
||||
}else if( useTempTable ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1);
|
||||
}else{
|
||||
assert( pSelect==0 ); /* Otherwise useTempTable is true */
|
||||
sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i);
|
||||
sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i+1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -863,16 +864,15 @@ void sqlite3Insert(
|
||||
** table column affinities.
|
||||
*/
|
||||
if( !isView ){
|
||||
sqlite3VdbeAddOp2(v, OP_Affinity, regCols, pTab->nCol);
|
||||
sqlite3VdbeAddOp2(v, OP_Affinity, regCols+1, pTab->nCol);
|
||||
sqlite3TableAffinityStr(v, pTab);
|
||||
}
|
||||
|
||||
/* Fire BEFORE or INSTEAD OF triggers */
|
||||
sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE,
|
||||
pTab, regCols, -1, onError, endOfLoop);
|
||||
pTab, -1, regCols-pTab->nCol-1, onError, endOfLoop);
|
||||
|
||||
sqlite3ReleaseTempReg(pParse, regTrigRowid);
|
||||
sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol);
|
||||
sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol+1);
|
||||
}
|
||||
|
||||
/* Push the record number for the new entry onto the stack. The
|
||||
@ -994,7 +994,7 @@ void sqlite3Insert(
|
||||
if( pTrigger ){
|
||||
/* Code AFTER triggers */
|
||||
sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER,
|
||||
pTab, regData, -1, onError, endOfLoop);
|
||||
pTab, -1, regData-2-pTab->nCol, onError, endOfLoop);
|
||||
}
|
||||
|
||||
/* The bottom of the main insertion loop, if the data source
|
||||
@ -1153,7 +1153,6 @@ void sqlite3GenerateConstraintChecks(
|
||||
nCol = pTab->nCol;
|
||||
regData = regRowid + 1;
|
||||
|
||||
|
||||
/* Test all NOT NULL constraints.
|
||||
*/
|
||||
for(i=0; i<nCol; i++){
|
||||
@ -1229,7 +1228,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
|
||||
if( onError!=OE_Replace || pTab->pIndex ){
|
||||
if( isUpdate ){
|
||||
j2 = sqlite3VdbeAddOp3(v, OP_Eq, regRowid, 0, regRowid-1);
|
||||
j2 = sqlite3VdbeAddOp3(v, OP_Eq, regRowid, 0, rowidChng);
|
||||
}
|
||||
j3 = sqlite3VdbeAddOp3(v, OP_NotExists, baseCur, 0, regRowid);
|
||||
switch( onError ){
|
||||
|
@ -1590,6 +1590,9 @@ static int openDatabase(
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_LOAD_EXTENSION
|
||||
| SQLITE_LoadExtension
|
||||
#endif
|
||||
#ifdef SQLITE_DISABLE_RECURSIVE_TRIGGERS
|
||||
| SQLITE_NoRecTriggers
|
||||
#endif
|
||||
;
|
||||
sqlite3HashInit(&db->aCollSeq);
|
||||
|
@ -190,6 +190,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
|
||||
/* TODO: Maybe it shouldn't be possible to change the ReadUncommitted
|
||||
** flag if there are any active statements. */
|
||||
{ "read_uncommitted", SQLITE_ReadUncommitted },
|
||||
{ "disable_recursive_triggers", SQLITE_NoRecTriggers },
|
||||
};
|
||||
int i;
|
||||
const struct sPragmaType *p;
|
||||
|
@ -911,6 +911,7 @@ struct sqlite3 {
|
||||
|
||||
#define SQLITE_RecoveryMode 0x00040000 /* Ignore schema errors */
|
||||
#define SQLITE_ReverseOrder 0x00100000 /* Reverse unordered SELECTs */
|
||||
#define SQLITE_NoRecTriggers 0x00200000 /* Disable recursive triggers */
|
||||
|
||||
/*
|
||||
** Possible values for the sqlite.magic field.
|
||||
|
@ -698,6 +698,10 @@ static int codeTriggerProgram(
|
||||
*/
|
||||
pParse->orconf = (orconfin==OE_Default)?pStep->orconf:orconfin;
|
||||
|
||||
if( pStep->op!=TK_SELECT ){
|
||||
sqlite3VdbeAddOp1(v, OP_ResetCount, 0);
|
||||
}
|
||||
|
||||
switch( pStep->op ){
|
||||
case TK_UPDATE: {
|
||||
sqlite3Update(pParse,
|
||||
@ -734,6 +738,9 @@ static int codeTriggerProgram(
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( pStep->op!=TK_SELECT ){
|
||||
sqlite3VdbeAddOp1(v, OP_ResetCount, 1);
|
||||
}
|
||||
pStep = pStep->pNext;
|
||||
}
|
||||
/* sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0); */
|
||||
@ -818,13 +825,19 @@ static CodedTrigger *codeRowTrigger(
|
||||
|
||||
v = sqlite3GetVdbe(pSubParse);
|
||||
if( v ){
|
||||
VdbeComment((v, "Trigger: %s (%s %s%s%s ON %s) (%s)", pTrigger->zName,
|
||||
VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)",
|
||||
pTrigger->zName, onErrorText(orconf),
|
||||
(pTrigger->tr_tm==TRIGGER_BEFORE ? "BEFORE" : "AFTER"),
|
||||
(op==TK_UPDATE ? "UPDATE" : ""),
|
||||
(op==TK_INSERT ? "INSERT" : ""),
|
||||
(op==TK_DELETE ? "DELETE" : ""),
|
||||
pTab->zName, onErrorText(orconf)
|
||||
pTab->zName
|
||||
));
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
sqlite3VdbeChangeP4(v, -1,
|
||||
sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC
|
||||
);
|
||||
#endif
|
||||
|
||||
if( pTrigger->pWhen ){
|
||||
/* Code the WHEN clause. If it evaluates to false (or NULL) the
|
||||
@ -838,11 +851,13 @@ static CodedTrigger *codeRowTrigger(
|
||||
}
|
||||
|
||||
/* Code the trigger program into the sub-vdbe. */
|
||||
codeTriggerProgram(pSubParse, pTrigger->step_list, OE_Default);
|
||||
codeTriggerProgram(pSubParse, pTrigger->step_list, orconf);
|
||||
if( iEndTrigger ){
|
||||
sqlite3VdbeResolveLabel(v, iEndTrigger);
|
||||
}
|
||||
sqlite3VdbeAddOp0(v, OP_Halt);
|
||||
VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf)));
|
||||
|
||||
transferParseError(pParse, pSubParse);
|
||||
pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pParse->nArg);
|
||||
pProgram->nMem = pSubParse->nMem;
|
||||
@ -961,10 +976,10 @@ void sqlite3CodeRowTrigger(
|
||||
/* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program
|
||||
** is a pointer to the sub-vdbe containing the trigger program. */
|
||||
if( pC ){
|
||||
sqlite3VdbeAddOp3(v, OP_Program, oldIdx, newIdx, ++pParse->nMem);
|
||||
sqlite3VdbeAddOp3(v, OP_Program, oldIdx, ignoreJump, ++pParse->nMem);
|
||||
pC->pProgram->nRef++;
|
||||
sqlite3VdbeChangeP4(v, -1, (const char *)pC->pProgram, P4_SUBPROGRAM);
|
||||
VdbeComment((v, "Call trigger: %s (%s)", p->zName,onErrorText(orconf)));
|
||||
VdbeComment((v, "Call: %s.%s", p->zName, onErrorText(orconf)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
40
src/update.c
40
src/update.c
@ -130,6 +130,7 @@ void sqlite3Update(
|
||||
int regNew;
|
||||
int regOld;
|
||||
int regRowSet = 0; /* Rowset of rows to be updated */
|
||||
int regRec; /* Register used for new table record to insert */
|
||||
|
||||
memset(&sContext, 0, sizeof(sContext));
|
||||
db = pParse->db;
|
||||
@ -145,7 +146,7 @@ void sqlite3Update(
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
|
||||
/* Figure out if we have any triggers and if the table being
|
||||
** updated is a view
|
||||
** updated is a view.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges, 0);
|
||||
@ -282,6 +283,7 @@ void sqlite3Update(
|
||||
}
|
||||
regNew = pParse->nMem + 1;
|
||||
pParse->nMem += pTab->nCol;
|
||||
regRec = ++pParse->nMem;
|
||||
|
||||
/* Start the view context. */
|
||||
if( isView ){
|
||||
@ -421,16 +423,29 @@ void sqlite3Update(
|
||||
}
|
||||
}
|
||||
|
||||
/* If this is not a view, create the record that will be inserted into
|
||||
** the table (assuming no constraint checks fail). A side effect of
|
||||
** creating the record is applying affinity transformations to the
|
||||
** array of registers populated by the block above. This needs to be
|
||||
** done before the BEFORE triggers are fired. */
|
||||
#if 0
|
||||
if( !isView ){
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regNew, pTab->nCol, regRec);
|
||||
sqlite3TableAffinityStr(v, pTab);
|
||||
sqlite3ExprCacheAffinityChange(pParse, regNew, pTab->nCol);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Fire any BEFORE UPDATE triggers. This happens before constraints are
|
||||
** verified. One could argue that this is wrong. */
|
||||
sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
|
||||
TRIGGER_BEFORE, pTab, regNew, regOld, onError, addr);
|
||||
TRIGGER_BEFORE, pTab, -1, regOldRowid, onError, addr);
|
||||
|
||||
if( !isView ){
|
||||
|
||||
/* Do constraint checks. */
|
||||
sqlite3GenerateConstraintChecks(pParse, pTab, iCur, regNewRowid,
|
||||
aRegIdx, chngRowid, 1, onError, addr, 0);
|
||||
aRegIdx, (chngRowid?regOldRowid:0), 1, onError, addr, 0);
|
||||
|
||||
/* Delete the index entries associated with the current record. */
|
||||
j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid);
|
||||
@ -442,8 +457,21 @@ void sqlite3Update(
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
|
||||
/* Create the new index entries and the new record. */
|
||||
sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid, aRegIdx,1,-1,0,0);
|
||||
/* Insert the new index entries and the new record. */
|
||||
sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid, aRegIdx, 1, -1, 0, 0);
|
||||
|
||||
#if 0
|
||||
for(i=0; i<nIdx; i++){
|
||||
if( aRegIdx[i] ){
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iCur+1+i, aRegIdx[i]);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iCur, regRec, regNewRowid);
|
||||
if( !pParse->nested ){
|
||||
sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_ISUPDATE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Increment the row counter
|
||||
@ -453,7 +481,7 @@ void sqlite3Update(
|
||||
}
|
||||
|
||||
sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
|
||||
TRIGGER_AFTER, pTab, regNew, regOld, onError, addr);
|
||||
TRIGGER_AFTER, pTab, -1, regOldRowid, onError, addr);
|
||||
|
||||
/* Repeat the above with the next record to be updated, until
|
||||
** all record selected by the WHERE clause have been updated.
|
||||
|
135
src/vdbe.c
135
src/vdbe.c
@ -852,6 +852,7 @@ case OP_Halt: {
|
||||
p->nFrame--;
|
||||
pc = sqlite3VdbeFrameRestore(pFrame);
|
||||
if( pOp->p2==OE_Ignore ){
|
||||
pc = p->aOp[pc].p2-1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -3546,11 +3547,11 @@ case OP_Sequence: { /* out2-prerelease */
|
||||
** table that cursor P1 points to. The new record number is written
|
||||
** written to register P2.
|
||||
**
|
||||
** If P3>0 then P3 is a register that holds the largest previously
|
||||
** generated record number. No new record numbers are allowed to be less
|
||||
** than this value. When this value reaches its maximum, a SQLITE_FULL
|
||||
** error is generated. The P3 register is updated with the generated
|
||||
** record number. This P3 mechanism is used to help implement the
|
||||
** If P3>0 then P3 is a register in the root frame of this VDBE that holds
|
||||
** the largest previously generated record number. No new record numbers are
|
||||
** allowed to be less than this value. When this value reaches its maximum,
|
||||
** a SQLITE_FULL error is generated. The P3 register is updated with the '
|
||||
** generated record number. This P3 mechanism is used to help implement the
|
||||
** AUTOINCREMENT feature.
|
||||
*/
|
||||
case OP_NewRowid: { /* out2-prerelease */
|
||||
@ -3559,6 +3560,7 @@ case OP_NewRowid: { /* out2-prerelease */
|
||||
int res; /* Result of an sqlite3BtreeLast() */
|
||||
int cnt; /* Counter to limit the number of searches */
|
||||
Mem *pMem; /* Register holding largest rowid for AUTOINCREMENT */
|
||||
VdbeFrame *pFrame; /* Root frame of VDBE */
|
||||
|
||||
v = 0;
|
||||
res = 0;
|
||||
@ -3617,9 +3619,16 @@ case OP_NewRowid: { /* out2-prerelease */
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
if( pOp->p3 ){
|
||||
assert( pOp->p3>0 && pOp->p3<=p->nMem ); /* P3 is a valid memory cell */
|
||||
pMem = &p->aMem[pOp->p3];
|
||||
REGISTER_TRACE(pOp->p3, pMem);
|
||||
if( p->pFrame ){
|
||||
for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
|
||||
pMem = &pFrame->aMem[pOp->p3];
|
||||
}else{
|
||||
pMem = &p->aMem[pOp->p3];
|
||||
}
|
||||
/* Assert that P3 is a valid memory cell. */
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->pFrame ? pFrame->nMem : p->nMem) );
|
||||
|
||||
REGISTER_TRACE(pOp->p3, pMem);
|
||||
sqlite3VdbeMemIntegerify(pMem);
|
||||
assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */
|
||||
if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){
|
||||
@ -4740,68 +4749,29 @@ case OP_RowSetTest: { /* jump, in1, in3 */
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
/* Opcode: ContextPush * * *
|
||||
**
|
||||
** Save the current Vdbe context such that it can be restored by a ContextPop
|
||||
** opcode. The context stores the last insert row id, the last statement change
|
||||
** count, and the current statement change count.
|
||||
*/
|
||||
case OP_ContextPush: {
|
||||
int i;
|
||||
Context *pContext;
|
||||
|
||||
i = p->contextStackTop++;
|
||||
assert( i>=0 );
|
||||
/* FIX ME: This should be allocated as part of the vdbe at compile-time */
|
||||
if( i>=p->contextStackDepth ){
|
||||
p->contextStackDepth = i+1;
|
||||
p->contextStack = sqlite3DbReallocOrFree(db, p->contextStack,
|
||||
sizeof(Context)*(i+1));
|
||||
if( p->contextStack==0 ) goto no_mem;
|
||||
}
|
||||
pContext = &p->contextStack[i];
|
||||
pContext->lastRowid = db->lastRowid;
|
||||
pContext->nChange = p->nChange;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: ContextPop * * *
|
||||
**
|
||||
** Restore the Vdbe context to the state it was in when contextPush was last
|
||||
** executed. The context stores the last insert row id, the last statement
|
||||
** change count, and the current statement change count.
|
||||
*/
|
||||
case OP_ContextPop: {
|
||||
Context *pContext;
|
||||
pContext = &p->contextStack[--p->contextStackTop];
|
||||
assert( p->contextStackTop>=0 );
|
||||
db->lastRowid = pContext->lastRowid;
|
||||
p->nChange = pContext->nChange;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Program P1 P2 P3 P4 *
|
||||
**
|
||||
** Execute a trigger program. P1 contains the address of the memory cell
|
||||
** that contains the left-most column of the old.* table (unless the trigger
|
||||
** program is firing as a result of an INSERT statement). P2 is the address
|
||||
** of the corresponding column in the new.* table (unless the trigger
|
||||
** program is being fired due to a DELETE).
|
||||
** Execute the trigger program passed as P4 (type P4_SUBPROGRAM).
|
||||
**
|
||||
** Register P3 contains the address of a memory cell in this (the parent)
|
||||
** VM that is used to allocate the memory required by the sub-vdbe at
|
||||
** runtime.
|
||||
** P1 contains the address of the memory cell that contains the first memory
|
||||
** cell in an array of values used as arguments to the sub-program. P2
|
||||
** contains the address to jump to if the sub-program throws an IGNORE
|
||||
** exception using the RAISE() function. Register P3 contains the address
|
||||
** of a memory cell in this (the parent) VM that is used to allocate the
|
||||
** memory required by the sub-vdbe at runtime.
|
||||
**
|
||||
** P4 is a pointer to the VM containing the trigger program.
|
||||
*/
|
||||
case OP_Program: {
|
||||
case OP_Program: { /* jump */
|
||||
VdbeFrame *pFrame;
|
||||
SubProgram *pProgram = pOp->p4.pProgram;
|
||||
Mem *pRt = &p->aMem[pOp->p3]; /* Register to allocate runtime space */
|
||||
assert( pProgram->nOp>0 );
|
||||
|
||||
/* If noRecTrigger is true, then recursive invocation of triggers is
|
||||
** disabled for backwards compatibility.
|
||||
/* If the SQLITE_NoRecTriggers flag it set, then recursive invocation of
|
||||
** triggers is disabled for backwards compatibility (flag set/cleared by
|
||||
** the "PRAGMA disable_recursive_triggers" command).
|
||||
**
|
||||
** It is recursive invocation of triggers, at the SQL level, that is
|
||||
** disabled. In some cases a single trigger may generate more than one
|
||||
@ -4810,7 +4780,7 @@ case OP_Program: {
|
||||
** single trigger all have the same value for the SubProgram.token
|
||||
** variable.
|
||||
*/
|
||||
if( 1 || p->noRecTrigger ){
|
||||
if( db->flags&SQLITE_NoRecTriggers ){
|
||||
void *t = pProgram->token;
|
||||
for(pFrame=p->pFrame; pFrame && pFrame->token!=t; pFrame=pFrame->pParent);
|
||||
if( pFrame ) break;
|
||||
@ -4874,6 +4844,8 @@ case OP_Program: {
|
||||
|
||||
p->nFrame++;
|
||||
pFrame->pParent = p->pFrame;
|
||||
pFrame->lastRowid = db->lastRowid;
|
||||
pFrame->nChange = p->nChange;
|
||||
p->pFrame = pFrame;
|
||||
p->aMem = &VdbeFrameMem(pFrame)[-1];
|
||||
p->nMem = pFrame->nChildMem;
|
||||
@ -4886,26 +4858,21 @@ case OP_Program: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: TriggerVal P1 P2 P3 * *
|
||||
/* Opcode: Param P1 P2 * * *
|
||||
**
|
||||
** Copy a value currently stored in a memory cell of the parent VM to
|
||||
** a cell in this VMs address space. This is used by trigger programs
|
||||
** to access the new.* and old.* values.
|
||||
** This opcode is only ever present in sub-programs called via the
|
||||
** OP_Program instruction. Copy a value currently stored in a memory
|
||||
** cell of the calling (parent) frame to cell P2 in the current frames
|
||||
** address space. This is used by trigger programs to access the new.*
|
||||
** and old.* values.
|
||||
**
|
||||
** If parameter P3 is non-zero, then the value read is from the new.*
|
||||
** table. If P3 is zero, then the value is read from the old.* table.
|
||||
** Parameter P1 is the index of the required new.* or old.* column (or
|
||||
** -1 for rowid).
|
||||
**
|
||||
** Parameter P2 is the index of the memory cell in this VM to copy the
|
||||
** value to.
|
||||
** The address of the cell in the parent frame is determined by adding
|
||||
** the value of the P1 argument to the value of the P1 argument to the
|
||||
** calling OP_Program instruction.
|
||||
*/
|
||||
case OP_TriggerVal: { /* out2-prerelease */
|
||||
VdbeFrame *pF = p->pFrame;
|
||||
Mem *pIn;
|
||||
int iFrom = pOp->p1; /* Memory cell in parent frame */
|
||||
iFrom += (pOp->p3 ? pF->aOp[pF->pc].p2 : pF->aOp[pF->pc].p1);
|
||||
pIn = &pF->aMem[iFrom];
|
||||
case OP_Param: { /* out2-prerelease */
|
||||
VdbeFrame *pFrame = p->pFrame;
|
||||
Mem *pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1];
|
||||
sqlite3VdbeMemShallowCopy(pOut, pIn, MEM_Ephem);
|
||||
break;
|
||||
}
|
||||
@ -4915,13 +4882,23 @@ case OP_TriggerVal: { /* out2-prerelease */
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
/* Opcode: MemMax P1 P2 * * *
|
||||
**
|
||||
** Set the value of register P1 to the maximum of its current value
|
||||
** and the value in register P2.
|
||||
** P1 is a register in the root frame of this VM (the root frame is
|
||||
** different from the current frame if this instruction is being executed
|
||||
** within a sub-program). Set the value of register P1 to the maximum of
|
||||
** its current value and the value in register P2.
|
||||
**
|
||||
** This instruction throws an error if the memory cell is not initially
|
||||
** an integer.
|
||||
*/
|
||||
case OP_MemMax: { /* in1, in2 */
|
||||
case OP_MemMax: { /* in2 */
|
||||
Mem *pIn1;
|
||||
VdbeFrame *pFrame;
|
||||
if( p->pFrame ){
|
||||
for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
|
||||
pIn1 = &pFrame->aMem[pOp->p1];
|
||||
}else{
|
||||
pIn1 = &p->aMem[pOp->p1];
|
||||
}
|
||||
sqlite3VdbeMemIntegerify(pIn1);
|
||||
sqlite3VdbeMemIntegerify(pIn2);
|
||||
if( pIn1->u.i<pIn2->u.i){
|
||||
|
@ -103,6 +103,8 @@ struct VdbeFrame {
|
||||
void *token; /* Copy of SubProgram.token */
|
||||
int nChildMem; /* Number of memory cells for child frame */
|
||||
int nChildCsr; /* Number of cursors for child frame */
|
||||
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
|
||||
int nChange; /* Statement changes (Vdbe.nChanges) */
|
||||
};
|
||||
|
||||
#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
|
||||
@ -243,21 +245,6 @@ struct Set {
|
||||
HashElem *prev; /* Previously accessed hash elemen */
|
||||
};
|
||||
|
||||
/*
|
||||
** A Context stores the last insert rowid, the last statement change count,
|
||||
** and the current statement change count (i.e. changes since last statement).
|
||||
** The current keylist is also stored in the context.
|
||||
** Elements of Context structure type make up the ContextStack, which is
|
||||
** updated by the ContextPush and ContextPop opcodes (used by triggers).
|
||||
** The context is pushed before executing a trigger a popped when the
|
||||
** trigger finishes.
|
||||
*/
|
||||
typedef struct Context Context;
|
||||
struct Context {
|
||||
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
|
||||
int nChange; /* Statement changes (Vdbe.nChanges) */
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of the virtual machine. This structure contains the complete
|
||||
** state of the virtual machine.
|
||||
@ -297,9 +284,6 @@ struct Vdbe {
|
||||
int nMem; /* Number of memory locations currently allocated */
|
||||
Mem *aMem; /* The memory locations */
|
||||
int cacheCtr; /* VdbeCursor row cache generation counter */
|
||||
int contextStackTop; /* Index of top element in the context stack */
|
||||
int contextStackDepth; /* The size of the "context" stack */
|
||||
Context *contextStack; /* Stack used by opcodes ContextPush & ContextPop*/
|
||||
int pc; /* The program counter */
|
||||
int rc; /* Value to return */
|
||||
char *zErrMsg; /* Error message written here */
|
||||
|
@ -295,7 +295,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
||||
}else if( opcode==OP_Transaction && pOp->p2!=0 ){
|
||||
p->readOnly = 0;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
}else if( opcode==OP_VUpdate || opcode==OP_VRename ){
|
||||
}else if( opcode==OP_VUpdate || opcode==OP_VRename || opcode==OP_Program ){
|
||||
doesStatementRollback = 1;
|
||||
}else if( opcode==OP_VFilter ){
|
||||
int n;
|
||||
@ -1336,6 +1336,8 @@ int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
|
||||
v->nMem = pFrame->nMem;
|
||||
v->apCsr = pFrame->apCsr;
|
||||
v->nCursor = pFrame->nCursor;
|
||||
v->db->lastRowid = pFrame->lastRowid;
|
||||
v->nChange = pFrame->nChange;
|
||||
return pFrame->pc;
|
||||
}
|
||||
|
||||
@ -1387,12 +1389,6 @@ static void Cleanup(Vdbe *p){
|
||||
for(i=1; i<=p->nMem; i++){ assert( p->aMem[i].flags==MEM_Null ); }
|
||||
#endif
|
||||
|
||||
if( p->contextStack ){
|
||||
sqlite3DbFree(db, p->contextStack);
|
||||
}
|
||||
p->contextStack = 0;
|
||||
p->contextStackDepth = 0;
|
||||
p->contextStackTop = 0;
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = 0;
|
||||
p->pResultSet = 0;
|
||||
|
@ -558,6 +558,8 @@ do_test autoinc-9.1 {
|
||||
}
|
||||
} {t3 0}
|
||||
|
||||
catchsql { pragma disable_recursive_triggers = 1 }
|
||||
|
||||
# Ticket #3928. Make sure that triggers to not make extra slots in
|
||||
# the SQLITE_SEQUENCE table.
|
||||
#
|
||||
|
@ -18,6 +18,11 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# The tests in this file were written before SQLite supported recursive
|
||||
# trigger invocation, and some tests depend on that to pass. So disable
|
||||
# recursive triggers for this file.
|
||||
catchsql { pragma disable_recursive_triggers = 1 }
|
||||
|
||||
ifcapable {trigger} {
|
||||
# Test for ticket #360
|
||||
#
|
||||
@ -358,6 +363,7 @@ ifcapable tclvar {
|
||||
db close
|
||||
file delete -force test.db
|
||||
sqlite3 db test.db
|
||||
catchsql { pragma disable_recursive_triggers = 1 }
|
||||
|
||||
# Ticket #453. If the SQL ended with "-", the tokenizer was calling that
|
||||
# an incomplete token, which caused problem. The solution was to just call
|
||||
|
@ -18,6 +18,11 @@ ifcapable {!trigger} {
|
||||
return
|
||||
}
|
||||
|
||||
# The tests in this file were written before SQLite supported recursive
|
||||
# trigger invocation, and some tests depend on that to pass. So disable
|
||||
# recursive triggers for this file.
|
||||
catchsql { pragma disable_recursive_triggers = 1 }
|
||||
|
||||
do_test tkt3731-1.1 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||
|
@ -29,6 +29,7 @@ do_test tkt3992-1.1 {
|
||||
INSERT INTO parameters2(mountcnt, version) VALUES(1, 1.0);
|
||||
}
|
||||
} {}
|
||||
puts [execsql { SELECT *,typeof(mountcnt),typeof(version) FROM parameters1 }]
|
||||
|
||||
do_test tkt3992-1.2 {
|
||||
execsql {
|
||||
@ -38,8 +39,12 @@ do_test tkt3992-1.2 {
|
||||
} {2 1.0}
|
||||
|
||||
do_test tkt3992-1.3 {
|
||||
explain { UPDATE parameters2 SET mountcnt = mountcnt + 1 }
|
||||
breakpoint
|
||||
execsql {
|
||||
pragma vdbe_trace = 1;
|
||||
UPDATE parameters2 SET mountcnt = mountcnt + 1;
|
||||
pragma vdbe_trace = 0;
|
||||
SELECT * FROM parameters2;
|
||||
}
|
||||
} {2 1.0}
|
||||
@ -72,9 +77,6 @@ do_test tkt3992-2.3 {
|
||||
}
|
||||
set res
|
||||
} {real}
|
||||
explain {
|
||||
UPDATE t2 SET a = 'I';
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
@ -54,6 +54,11 @@ ifcapable {!trigger} {
|
||||
return
|
||||
}
|
||||
|
||||
# The tests in this file were written before SQLite supported recursive
|
||||
# trigger invocation, and some tests depend on that to pass. So disable
|
||||
# recursive triggers for this file.
|
||||
catchsql { pragma disable_recursive_triggers = 1 }
|
||||
|
||||
# 1.
|
||||
ifcapable subquery {
|
||||
set ii 0
|
||||
|
@ -18,10 +18,14 @@ ifcapable {!trigger} {
|
||||
return
|
||||
}
|
||||
|
||||
# Test that we can cause ROLLBACK, FAIL and ABORT correctly
|
||||
# catchsql { DROP TABLE tbl; }
|
||||
catchsql { CREATE TABLE tbl (a, b, c) }
|
||||
# The tests in this file were written before SQLite supported recursive }
|
||||
# trigger invocation, and some tests depend on that to pass. So disable
|
||||
# recursive triggers for this file.
|
||||
catchsql { pragma disable_recursive_triggers = 1 }
|
||||
|
||||
# Test that we can cause ROLLBACK, FAIL and ABORT correctly
|
||||
#
|
||||
catchsql { CREATE TABLE tbl(a, b ,c) }
|
||||
execsql {
|
||||
CREATE TRIGGER before_tbl_insert BEFORE INSERT ON tbl BEGIN SELECT CASE
|
||||
WHEN (new.a = 4) THEN RAISE(IGNORE) END;
|
||||
@ -54,7 +58,7 @@ do_test trigger3-1.3 {
|
||||
# FAIL
|
||||
do_test trigger3-2.1 {
|
||||
catchsql {
|
||||
BEGIN;
|
||||
BEGIN;
|
||||
INSERT INTO tbl VALUES (5, 5, 6);
|
||||
INSERT INTO tbl VALUES (2, 5, 6);
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ do_test trigger9-1.3.1 {
|
||||
} {1 2 3}
|
||||
do_test trigger9-1.3.2 {
|
||||
has_rowdata {DELETE FROM t1}
|
||||
} 1
|
||||
} 0
|
||||
do_test trigger9-1.3.3 { execsql { ROLLBACK } } {}
|
||||
|
||||
do_test trigger9-1.4.1 {
|
||||
@ -90,7 +90,7 @@ do_test trigger9-1.4.1 {
|
||||
} {1}
|
||||
do_test trigger9-1.4.2 {
|
||||
has_rowdata {DELETE FROM t1}
|
||||
} 1
|
||||
} 0
|
||||
do_test trigger9-1.4.3 { execsql { ROLLBACK } } {}
|
||||
|
||||
do_test trigger9-1.5.1 {
|
||||
@ -120,7 +120,7 @@ do_test trigger9-1.6.1 {
|
||||
} {1 2 3}
|
||||
do_test trigger9-1.6.2 {
|
||||
has_rowdata {UPDATE t1 SET y = ''}
|
||||
} 1
|
||||
} 0
|
||||
do_test trigger9-1.6.3 { execsql { ROLLBACK } } {}
|
||||
|
||||
do_test trigger9-1.7.1 {
|
||||
@ -135,7 +135,7 @@ do_test trigger9-1.7.1 {
|
||||
} {2 3}
|
||||
do_test trigger9-1.7.2 {
|
||||
has_rowdata {UPDATE t1 SET y = ''}
|
||||
} 1
|
||||
} 0
|
||||
do_test trigger9-1.7.3 { execsql { ROLLBACK } } {}
|
||||
|
||||
do_test trigger9-3.1 {
|
||||
|
Reference in New Issue
Block a user