1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Fix a memory leak that occurs when an out-of-memory error occurs while

preparing a statement that has multiple virtual table updates within
triggers.  Other virtual table changes to support full-coverage testing. (CVS 6661)

FossilOrigin-Name: 02b77a582c65e0eb45eb1a9abbdeef11f52d7ce6
This commit is contained in:
drh
2009-05-20 20:10:47 +00:00
parent 9e27890ed9
commit 748ce21115
3 changed files with 39 additions and 29 deletions

View File

@@ -1,5 +1,5 @@
C Remove\sunused,\sundocumented,\sand\suntested\serror\sreporting\slogic\sfrom\sthe\nxFindFunction\sinterface\sin\svirtual\stables.\s(CVS\s6660) C Fix\sa\smemory\sleak\sthat\soccurs\swhen\san\sout-of-memory\serror\soccurs\swhile\npreparing\sa\sstatement\sthat\shas\smultiple\svirtual\stable\supdates\swithin\ntriggers.\s\sOther\svirtual\stable\schanges\sto\ssupport\sfull-coverage\stesting.\s(CVS\s6661)
D 2009-05-20T16:22:02 D 2009-05-20T20:10:47
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 583e87706abc3026960ed759aff6371faf84c211 F Makefile.in 583e87706abc3026960ed759aff6371faf84c211
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -210,7 +210,7 @@ F src/vdbeapi.c 86aa27a5f3493aaffb8ac051782aa3b22670d7ed
F src/vdbeaux.c 1a07329bdf51cc3687f88d9f5b2bd3f1d47cc5a8 F src/vdbeaux.c 1a07329bdf51cc3687f88d9f5b2bd3f1d47cc5a8
F src/vdbeblob.c 5c5abe9af28316772e7829359f6f9cda2c737ebd F src/vdbeblob.c 5c5abe9af28316772e7829359f6f9cda2c737ebd
F src/vdbemem.c d8b985eeb88214941380372466a30ca410043a93 F src/vdbemem.c d8b985eeb88214941380372466a30ca410043a93
F src/vtab.c f998f539acbf0f1c5f8ee6bd0cdf6a641c802242 F src/vtab.c b0216337ae7d27708dedd56d220e6f4fecda92f1
F src/walker.c 7cdf63223c953d4343c6833e940f110281a378ee F src/walker.c 7cdf63223c953d4343c6833e940f110281a378ee
F src/where.c c5fa4a7a58880aecc657ebce5f8df98c9b67eec0 F src/where.c c5fa4a7a58880aecc657ebce5f8df98c9b67eec0
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@@ -729,7 +729,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
P 929cfbc66f6e2ea6b44417305d0f4ae36567c9bf P 55d6ced262f5281076e4a68097ed21e150a9c225
R cfd08e5b3a0fcc71899f8a11df4112dc R 746ae05c43433a273890f71e50932349
U drh U drh
Z b7b7868ab892ecebd1d46c334eedc57e Z b6bf88ddaf7ac2f73c27614c2e34432b

View File

@@ -1 +1 @@
55d6ced262f5281076e4a68097ed21e150a9c225 02b77a582c65e0eb45eb1a9abbdeef11f52d7ce6

View File

@@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** This file contains code used to help implement virtual tables. ** This file contains code used to help implement virtual tables.
** **
** $Id: vtab.c,v 1.88 2009/05/20 16:22:02 drh Exp $ ** $Id: vtab.c,v 1.89 2009/05/20 20:10:47 drh Exp $
*/ */
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h" #include "sqliteInt.h"
@@ -107,11 +107,14 @@ void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){
assert(db); assert(db);
assert( sqlite3SafetyCheckOk(db) ); assert( sqlite3SafetyCheckOk(db) );
if( pVtab->nRef==0 ){ if( pVtab->nRef==0 ){
#ifdef SQLITE_DEBUG
if( db->magic==SQLITE_MAGIC_BUSY ){ if( db->magic==SQLITE_MAGIC_BUSY ){
(void)sqlite3SafetyOff(db); (void)sqlite3SafetyOff(db);
pVtab->pModule->xDisconnect(pVtab); pVtab->pModule->xDisconnect(pVtab);
(void)sqlite3SafetyOn(db); (void)sqlite3SafetyOn(db);
} else { } else
#endif
{
pVtab->pModule->xDisconnect(pVtab); pVtab->pModule->xDisconnect(pVtab);
} }
} }
@@ -188,7 +191,7 @@ void sqlite3VtabBeginParse(
sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0); sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0);
pTable = pParse->pNewTable; pTable = pParse->pNewTable;
if( pTable==0 || pParse->nErr ) return; if( pTable==0 ) return;
assert( 0==pTable->pIndex ); assert( 0==pTable->pIndex );
db = pParse->db; db = pParse->db;
@@ -221,7 +224,7 @@ void sqlite3VtabBeginParse(
** virtual table currently under construction in pParse->pTable. ** virtual table currently under construction in pParse->pTable.
*/ */
static void addArgumentToVtab(Parse *pParse){ static void addArgumentToVtab(Parse *pParse){
if( pParse->sArg.z && pParse->pNewTable ){ if( pParse->sArg.z && ALWAYS(pParse->pNewTable) ){
const char *z = (const char*)pParse->sArg.z; const char *z = (const char*)pParse->sArg.z;
int n = pParse->sArg.n; int n = pParse->sArg.n;
sqlite3 *db = pParse->db; sqlite3 *db = pParse->db;
@@ -378,7 +381,9 @@ static int vtabCallConstructor(
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVtab, &zErr); rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVtab, &zErr);
rc2 = sqlite3SafetyOn(db); rc2 = sqlite3SafetyOn(db);
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
if( rc==SQLITE_OK && pVtab ){ /* Justification of ALWAYS(): A correct vtab constructor must allocate
** the sqlite3_vtab object if successful. */
if( rc==SQLITE_OK && ALWAYS(pVtab) ){
pVtab->pModule = pMod->pModule; pVtab->pModule = pMod->pModule;
pVtab->nRef = 1; pVtab->nRef = 1;
pTab->pVtab = pVtab; pTab->pVtab = pVtab;
@@ -453,7 +458,8 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
Module *pMod; Module *pMod;
int rc = SQLITE_OK; int rc = SQLITE_OK;
if( !pTab || (pTab->tabFlags & TF_Virtual)==0 || pTab->pVtab ){ assert( pTab );
if( (pTab->tabFlags & TF_Virtual)==0 || pTab->pVtab ){
return SQLITE_OK; return SQLITE_OK;
} }
@@ -529,7 +535,9 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr); rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr);
} }
if( rc==SQLITE_OK && pTab->pVtab ){ /* Justification of ALWAYS(): The xConstructor method is required to
** create a valid sqlite3_vtab if it returns SQLITE_OK. */
if( rc==SQLITE_OK && ALWAYS(pTab->pVtab) ){
rc = addToVTrans(db, pTab->pVtab); rc = addToVTrans(db, pTab->pVtab);
} }
@@ -598,20 +606,16 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
** **
** This call is a no-op if zTab is not a virtual table. ** This call is a no-op if zTab is not a virtual table.
*/ */
int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab) int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){
{
int rc = SQLITE_OK; int rc = SQLITE_OK;
Table *pTab; Table *pTab;
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
assert(pTab); if( ALWAYS(pTab!=0 && pTab->pVtab!=0) ){
if( pTab->pVtab ){
int (*xDestroy)(sqlite3_vtab *pVTab) = pTab->pMod->pModule->xDestroy; int (*xDestroy)(sqlite3_vtab *pVTab) = pTab->pMod->pModule->xDestroy;
rc = sqlite3SafetyOff(db); rc = sqlite3SafetyOff(db);
assert( rc==SQLITE_OK ); assert( rc==SQLITE_OK );
if( xDestroy ){
rc = xDestroy(pTab->pVtab); rc = xDestroy(pTab->pVtab);
}
(void)sqlite3SafetyOn(db); (void)sqlite3SafetyOn(db);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
int i; int i;
@@ -639,9 +643,11 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab)
static void callFinaliser(sqlite3 *db, int offset){ static void callFinaliser(sqlite3 *db, int offset){
int i; int i;
if( db->aVTrans ){ if( db->aVTrans ){
for(i=0; i<db->nVTrans && db->aVTrans[i]; i++){ for(i=0; i<db->nVTrans; i++){
sqlite3_vtab *pVtab = db->aVTrans[i]; sqlite3_vtab *pVtab = db->aVTrans[i];
int (*x)(sqlite3_vtab *); int (*x)(sqlite3_vtab *);
assert( pVtab!=0 );
x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset); x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset);
if( x ) x(pVtab); if( x ) x(pVtab);
sqlite3VtabUnlock(db, pVtab); sqlite3VtabUnlock(db, pVtab);
@@ -668,9 +674,10 @@ int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){
rc = sqlite3SafetyOff(db); rc = sqlite3SafetyOff(db);
db->aVTrans = 0; db->aVTrans = 0;
for(i=0; rc==SQLITE_OK && i<db->nVTrans && aVTrans[i]; i++){ for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){
sqlite3_vtab *pVtab = aVTrans[i]; sqlite3_vtab *pVtab = aVTrans[i];
int (*x)(sqlite3_vtab *); int (*x)(sqlite3_vtab *);
assert( pVtab!=0 );
x = pVtab->pModule->xSync; x = pVtab->pModule->xSync;
if( x ){ if( x ){
rc = x(pVtab); rc = x(pVtab);
@@ -721,7 +728,7 @@ int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
/* Special case: If db->aVTrans is NULL and db->nVTrans is greater /* Special case: If db->aVTrans is NULL and db->nVTrans is greater
** than zero, then this function is being called from within a ** than zero, then this function is being called from within a
** virtual module xSync() callback. It is illegal to write to ** virtual module xSync() callback. It is illegal to write to
** virtual module tables in this case, so return SQLITE_MISUSE. ** virtual module tables in this case, so return SQLITE_LOCKED.
*/ */
if( sqlite3VtabInSync(db) ){ if( sqlite3VtabInSync(db) ){
return SQLITE_LOCKED; return SQLITE_LOCKED;
@@ -736,7 +743,7 @@ int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
/* If pVtab is already in the aVTrans array, return early */ /* If pVtab is already in the aVTrans array, return early */
for(i=0; (i<db->nVTrans) && 0!=db->aVTrans[i]; i++){ for(i=0; i<db->nVTrans; i++){
if( db->aVTrans[i]==pVtab ){ if( db->aVTrans[i]==pVtab ){
return SQLITE_OK; return SQLITE_OK;
} }
@@ -782,10 +789,10 @@ FuncDef *sqlite3VtabOverloadFunction(
/* Check to see the left operand is a column in a virtual table */ /* Check to see the left operand is a column in a virtual table */
if( pExpr==0 ) return pDef; if( NEVER(pExpr==0) ) return pDef;
if( pExpr->op!=TK_COLUMN ) return pDef; if( pExpr->op!=TK_COLUMN ) return pDef;
pTab = pExpr->pTab; pTab = pExpr->pTab;
if( pTab==0 ) return pDef; if( NEVER(pTab==0) ) return pDef;
if( (pTab->tabFlags & TF_Virtual)==0 ) return pDef; if( (pTab->tabFlags & TF_Virtual)==0 ) return pDef;
pVtab = pTab->pVtab; pVtab = pTab->pVtab;
assert( pVtab!=0 ); assert( pVtab!=0 );
@@ -832,13 +839,16 @@ FuncDef *sqlite3VtabOverloadFunction(
*/ */
void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){ void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
int i, n; int i, n;
Table **apVtabLock;
assert( IsVirtual(pTab) ); assert( IsVirtual(pTab) );
for(i=0; i<pParse->nVtabLock; i++){ for(i=0; i<pParse->nVtabLock; i++){
if( pTab==pParse->apVtabLock[i] ) return; if( pTab==pParse->apVtabLock[i] ) return;
} }
n = (pParse->nVtabLock+1)*sizeof(pParse->apVtabLock[0]); n = (pParse->nVtabLock+1)*sizeof(pParse->apVtabLock[0]);
pParse->apVtabLock = sqlite3_realloc(pParse->apVtabLock, n); apVtabLock = sqlite3_realloc(pParse->apVtabLock, n);
if( pParse->apVtabLock ){ if( apVtabLock ){
pParse->apVtabLock = apVtabLock;
pParse->apVtabLock[pParse->nVtabLock++] = pTab; pParse->apVtabLock[pParse->nVtabLock++] = pTab;
}else{ }else{
pParse->db->mallocFailed = 1; pParse->db->mallocFailed = 1;