Avoid recursive calls to sqlite3VdbeMemRelease() when deleting VM frames used by trigger programs.

FossilOrigin-Name: 119ffe955eb1e8016cb8131a63bd17557f395f3f
This commit is contained in:
dan 2010-12-01 08:04:47 +00:00
parent 4a8198255d
commit 271065704c
6 changed files with 47 additions and 19 deletions

View File

@ -1,5 +1,5 @@
C Add\stest\sfile\se_dropview.test.
D 2010-11-30T12:12:25
C Avoid\srecursive\scalls\sto\ssqlite3VdbeMemRelease()\swhen\sdeleting\sVM\sframes\sused\sby\strigger\sprograms.
D 2010-12-01T08:04:48
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 4547616ad2286053af6ccccefa242dc925e49bf0
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -230,11 +230,11 @@ F src/util.c ab1c92426494f499f42b9e307537b03e923d75c1
F src/vacuum.c 924bd1bcee2dfb05376f79845bd3b4cec7b54b2f
F src/vdbe.c 21a9285fedf2e310ffc4bad27b828645dc2b20bb
F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2
F src/vdbeInt.h 7f4cf1b2b69bef3a432b1f23dfebef57275436b4
F src/vdbeInt.h 1f2137b905969f4de0648256aeb73abdf88f9213
F src/vdbeapi.c fb0036185b3c56e15916a5ee96309cd4acf6818f
F src/vdbeaux.c 762c2b146cf5fe7a7f743af1bbfed4a966aa937a
F src/vdbeaux.c b810a66902ee40c71cdb9c64f43760da516c91df
F src/vdbeblob.c e0ce3c54cc0c183af2ec67b63a289acf92251df4
F src/vdbemem.c 23723a12cd3ba7ab3099193094cbb2eb78956aa9
F src/vdbemem.c 411649a35686f54268ccabeda175322c4697f5a6
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
F src/vtab.c b297e8fa656ab5e66244ab15680d68db0adbec30
F src/wal.c f26b8d297bd11cb792e609917f9d4c6718ac8e0e
@ -796,7 +796,7 @@ F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4
F test/trigger9.test 5b0789f1c5c4600961f8e68511b825b87be53e31
F test/triggerA.test eaf11a29db2a11967d2d4b49d37f92bce598194e
F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe
F test/triggerC.test 2a23edcc00684d084902ba5ec93e721775c3a70a
F test/triggerC.test 8a691ff6dd47df2e57395bbec4b62101fac0f363
F test/triggerD.test c6add3817351451e419f6ff9e9a259b02b6e2de7
F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
@ -891,7 +891,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P ee8dc8c87ed15b76ba437df23e1d7b1b7fa30296
R 4a3bff37fc4c660278f60fbda77a6338
P 6197822cc8310fd7e1d7151683833e8b39fe631a
R 1616ff1293fc577a7a9463bdfe77090f
U dan
Z 27edb6190ff4f86a8a8a1f3444932c26
Z 6b55fe83d9e16cee919cd05f710b1461

View File

@ -1 +1 @@
6197822cc8310fd7e1d7151683833e8b39fe631a
119ffe955eb1e8016cb8131a63bd17557f395f3f

View File

@ -97,26 +97,34 @@ typedef struct VdbeCursor VdbeCursor;
** restoring the state of the VM to as it was before the sub-program
** began executing.
**
** Frames are stored in a linked list headed at Vdbe.pParent. Vdbe.pParent
** is the parent of the current frame, or zero if the current frame
** is the main Vdbe program.
** The memory for a VdbeFrame object is allocated and managed by a memory
** cell in the parent (calling) frame. When the memory cell is deleted or
** overwritten, the VdbeFrame object is not freed immediately. Instead, it
** is linked into the Vdbe.pDelFrame list. The contents of the Vdbe.pDelFrame
** list is deleted when the VM is reset in VdbeHalt(). The reason for doing
** this instead of deleting the VdbeFrame immediately is to avoid recursive
** calls to sqlite3VdbeMemRelease() when the memory cells belonging to the
** child frame are released.
**
** The currently executing frame is stored in Vdbe.pFrame. Vdbe.pFrame is
** set to NULL if the currently executing frame is the main program.
*/
typedef struct VdbeFrame VdbeFrame;
struct VdbeFrame {
Vdbe *v; /* VM this frame belongs to */
int pc; /* Program Counter */
Op *aOp; /* Program instructions */
int pc; /* Program Counter in parent (calling) frame */
Op *aOp; /* Program instructions for parent frame */
int nOp; /* Size of aOp array */
Mem *aMem; /* Array of memory cells */
Mem *aMem; /* Array of memory cells for parent frame */
int nMem; /* Number of entries in aMem */
VdbeCursor **apCsr; /* Element of Vdbe cursors */
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
u16 nCursor; /* Number of entries in apCsr */
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) */
VdbeFrame *pParent; /* Parent of this frame */
VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */
};
#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
@ -333,6 +341,7 @@ struct Vdbe {
FILE *trace; /* Write an execution trace here, if not NULL */
#endif
VdbeFrame *pFrame; /* Parent frame */
VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */
int nFrame; /* Number of frames in pFrame list */
u32 expmask; /* Binding to these vars invalidates VM */
SubProgram *pProgram; /* Linked list of all sub-programs used by VM */

View File

@ -1537,6 +1537,11 @@ static void closeAllCursors(Vdbe *p){
if( p->aMem ){
releaseMemArray(&p->aMem[1], p->nMem);
}
while( p->pDelFrame ){
VdbeFrame *pDel = p->pDelFrame;
p->pDelFrame = pDel->pParent;
sqlite3VdbeFrameDelete(pDel);
}
}
/*

View File

@ -487,7 +487,9 @@ int sqlite3VdbeMemNumerify(Mem *pMem){
*/
void sqlite3VdbeMemSetNull(Mem *pMem){
if( pMem->flags & MEM_Frame ){
sqlite3VdbeFrameDelete(pMem->u.pFrame);
VdbeFrame *pFrame = pMem->u.pFrame;
pFrame->pParent = pFrame->v->pDelFrame;
pFrame->v->pDelFrame = pFrame;
}
if( pMem->flags & MEM_RowSet ){
sqlite3RowSetClear(pMem->u.pRowSet);

View File

@ -937,6 +937,18 @@ do_test triggerC-12.2 {
execsql { SELECT count(*) FROM sqlite_master }
} {1}
do_execsql_test triggerC-13.1 {
PRAGMA recursive_triggers = ON;
CREATE TABLE t12(a, b);
INSERT INTO t12 VALUES(1, 2);
CREATE TRIGGER tr12 AFTER UPDATE ON t12 BEGIN
UPDATE t12 SET a=new.a+1, b=new.b+1;
END;
} {}
do_catchsql_test triggerC-13.2 {
UPDATE t12 SET a=a+1, b=b+1;
} {1 {too many levels of trigger recursion}}
finish_test