]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add tests and fixes for handling malloc() failures related to the virtual table featu...
authordanielk1977 <danielk1977@noemail.net>
Fri, 23 Jun 2006 08:05:19 +0000 (08:05 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Fri, 23 Jun 2006 08:05:19 +0000 (08:05 +0000)
FossilOrigin-Name: 5d1d907189ff3ca7afada83033280cf258984ac0

13 files changed:
manifest
manifest.uuid
src/sqlite.h.in
src/sqliteInt.h
src/test8.c
src/vdbe.c
src/vdbeInt.h
src/vdbeaux.c
src/vtab.c
src/where.c
test/quick.test
test/tester.tcl
test/vtab_err.test

index 3a25ed2353c464b4a8e2ec0c5a48fe6fd918ccb9..9963ee2a9d382c9c24f9ed0ec677b567b361560e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Test\sthe\shandling\sof\serrors\sin\svirtual\stable\smethods.\s(CVS\s3284)
-D 2006-06-22T09:53:49
+C Add\stests\sand\sfixes\sfor\shandling\smalloc()\sfailures\srelated\sto\sthe\svirtual\stable\sfeature.\s(CVS\s3285)
+D 2006-06-23T08:05:19
 F Makefile.in f839b470345d3cb4b0644068474623fe2464b5d3
 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -72,9 +72,9 @@ F src/random.c d40f8d356cecbd351ccfab6eaedd7ec1b54f5261
 F src/select.c 380fa06c99ae01050c0054c4b1db91e9f1d8322d
 F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
 F src/shell.c ad73192b30a338a58fe81183d4a5d5a1d4e51d36
-F src/sqlite.h.in b8c6139b3af13a2c361a8a5aeabb28aa3eef1ae1
+F src/sqlite.h.in 698928d10c9960e14c008a9dfcbb1d785fc1d039
 F src/sqlite3ext.h e334107f6cad0d00c0414e04189742a45ce916b1
-F src/sqliteInt.h d79b031593462dfcbc8c122a5f698a00e6b124fa
+F src/sqliteInt.h 83920044668752bc05fde6176e5dea30851cdce0
 F src/table.c f64ec4fbfe333f8df925bc6ba494f55e05b0e75e
 F src/tclsqlite.c 32d9e0147077f2e2c127c5f214fb3fe03ef97d18
 F src/test1.c 233d5c83d11f34aa1c02eb72011ba9a30b72e078
@@ -84,7 +84,7 @@ F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25
 F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f
 F src/test6.c 60a02961ceb7b3edc25f5dc5c1ac2556622a76de
 F src/test7.c 03fa8d787f6aebc6d1f72504d52f33013ad2c8e3
-F src/test8.c b8014836e18b9f42d0ac5c190efcc8318694c14e
+F src/test8.c e09bf2654269ff025350d1a40f4b1058a6a07dbb
 F src/test_async.c e3deaedd4d86a56391b81808fde9e44fbd92f1d3
 F src/test_loadext.c 22065d601a18878e5542191001f0eaa5d77c0ed8
 F src/test_md5.c 6c42bc0a3c0b54be34623ff77a0eec32b2fa96e3
@@ -97,15 +97,15 @@ F src/update.c 686b13db8b28a129a2407aaffc8b7588d1104e0b
 F src/utf.c ab81ac59084ff1c07d421eb1a0a84ec809603b44
 F src/util.c ca6ee72772c0f5dc04d2e0ab1973fd3b6a9bf79d
 F src/vacuum.c 5b37d0f436f8e1ffacd17934e44720b38d2247f9
-F src/vdbe.c 2c36e0badc0bcc14f099e95ec84470c479fbd399
+F src/vdbe.c b4232a43e8603ed2aced49865bb1de82aa8371e1
 F src/vdbe.h 258b5d1c0aaa72192f09ff0568ce42b383f156fa
-F src/vdbeInt.h 6ccb7eaae76ebd761470f6a035501ff33aa92c20
+F src/vdbeInt.h de89a3475a0a914c49f92e51c303f7dd6f2b21fe
 F src/vdbeapi.c 6af0e7160af260052a7a4500464221a03dada75f
-F src/vdbeaux.c 2e4cb97e6d1612c0e108d68e038a7cd612bceb72
+F src/vdbeaux.c d8cf95bc96fbcd933db14cf6cd196098146d2afd
 F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5
 F src/vdbemem.c 5f0afe3b92bb2c037f8d5d697f7c151fa50783a3
-F src/vtab.c 99ca599e9e4af1a63a3caf4389410a16adacf9f6
-F src/where.c 0a13357175678d51a218326bca389f20bb41e38b
+F src/vtab.c 7edad77e201cc83b7826e53393c21d617e472fe1
+F src/where.c 6175449f1ff97a5bfea4068a35c050456c632e89
 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/all.test 5df90d015ca63fcef2a4b62c24f7316b66c4bfd4
@@ -225,7 +225,7 @@ F test/pagesize.test 05c74ea49f790734ec1e9ab765d9bf1cce79b8f2
 F test/pragma.test e2d72d9e9a24744356cd5a4d25ea842c5020d345
 F test/printf.test cdd8e20dd901382a385afcbaa777b9377815c2ad
 F test/progress.test 8b22b4974b0a95272566385f8cb8c341c7130df8 x
-F test/quick.test fc44005d54bc6b43609e3942ddf22babd8230fcc
+F test/quick.test 4eabf0fd67dc6e116cbebe3f8d899608239eae50
 F test/quote.test 5891f2338980916cf7415484b4ce785294044adb
 F test/reindex.test 38b138abe36bf9a08c791ed44d9f76cd6b97b78b
 F test/rollback.test 673cd8c44c685ad54987fe7f0eeba84efa09685d
@@ -252,7 +252,7 @@ F test/table.test 1c1539af8db89c68e467df02ec2607ec61c67bac
 F test/tableapi.test 6a66d58b37d46dc0f2b3c7d4bd2617d209399bd1
 F test/tclsqlite.test 93c399414273d829f3fc5fc4a8349b484fe84d5b
 F test/temptable.test c36f3e5a94507abb64f7ba23deeb4e1a8a8c3821
-F test/tester.tcl 66a4bfa61a05e08ea523ef077e7ad0eab090c327
+F test/tester.tcl 0436eda9b45cd937662b9766262cc2527448413f
 F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35
 F test/thread2.test 6d7b30102d600f51b4055ee3a5a19228799049fb
 F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
@@ -297,7 +297,7 @@ F test/vtab3.test f38d6d7d19f08bffdadce4d5b8cba078f8118587
 F test/vtab4.test 4b4293341443839ef6dc02f8d9e614702a6c67ff
 F test/vtab5.test 9fb8f335651afe8f870011e2f68e5b00c5ad03cd
 F test/vtab6.test 0b4fe07e421b2b9a334bec8781e75cbd8e230bd3
-F test/vtab_err.test 7b435152e5555ca01645cbd15864430a80c44765
+F test/vtab_err.test 11b90203ad60d63746d0de547b1ca014704d8f0e
 F test/where.test ee7c9a6659b07e1ee61177f6e7ff71565ee2c9df
 F test/where2.test a16476a5913e75cf65b38f2daa6157a6b7791394
 F test/where3.test 3b5ad2c58069e12be2bd86bc5e211a82810521aa
@@ -373,7 +373,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P d50c37975de7639627422cbed40eb03a431874d5
-R deba37635ada8fb35f1bc556c53eccea
+P 51b729d9d9f8a60cdfb552809e4aa10012f4eb68
+R c21237f21b6a4ca0ffad3dda7ecba2f2
 U danielk1977
-Z fb72a1410426354cd3d1ca1870332bcd
+Z 9f0e1165f66a8128b5c09a2e388b1740
index c307b704a8e7764816f3a5ed5ace1f404143b87d..fdd28a29289573d589d894570dca3a7edb995b28 100644 (file)
@@ -1 +1 @@
-51b729d9d9f8a60cdfb552809e4aa10012f4eb68
\ No newline at end of file
+5d1d907189ff3ca7afada83033280cf258984ac0
\ No newline at end of file
index cb613b2fe8078b06e4cc010bb628898d92d9349a..03b908e42ddc73d268185506e4dbc24ad2172082 100644 (file)
@@ -12,7 +12,7 @@
 ** This header file defines the interface that the SQLite library
 ** presents to client programs.
 **
-** @(#) $Id: sqlite.h.in,v 1.181 2006/06/22 09:53:50 danielk1977 Exp $
+** @(#) $Id: sqlite.h.in,v 1.182 2006/06/23 08:05:19 danielk1977 Exp $
 */
 #ifndef _SQLITE3_H_
 #define _SQLITE3_H_
@@ -1662,6 +1662,7 @@ int sqlite3_create_module(
 */
 struct sqlite3_vtab {
   const sqlite3_module *pModule;  /* The module for this virtual table */
+  int nRef;                       /* Used internally */
   /* Virtual table implementations will typically add additional fields */
 };
 
index 5a23d09b2108d884dbd34894174114ce738564a9..46139da214fc0aaf9c9b678686751028626c8237 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.510 2006/06/17 10:44:42 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.511 2006/06/23 08:05:19 danielk1977 Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1820,13 +1820,11 @@ void sqlite3CloseExtensions(sqlite3*);
 
 #ifdef SQLITE_OMIT_VIRTUALTABLE
 #  define sqlite3VtabClear(X)
-#  define sqlite3VtabCodeLock(X,Y)
 #  define sqlite3VtabSync(X,Y) (Y)
 #  define sqlite3VtabRollback(X)
 #  define sqlite3VtabCommit(X)
 #else
    void sqlite3VtabClear(Table*);
-   void sqlite3VtabCodeLock(Parse *pParse, Table *pTab);
    int sqlite3VtabSync(sqlite3 *db, int rc);
    int sqlite3VtabRollback(sqlite3 *db);
    int sqlite3VtabCommit(sqlite3 *db);
index dae047d35a970278174cbafa1097c947fd1f3ab2..89ba964d08dd0b5f43f72210d05f88b30619f55f 100644 (file)
@@ -13,7 +13,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** testing of the SQLite library.
 **
-** $Id: test8.c,v 1.31 2006/06/22 09:53:50 danielk1977 Exp $
+** $Id: test8.c,v 1.32 2006/06/23 08:05:26 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "tcl.h"
@@ -72,7 +72,7 @@ static int getColumnNames(
   char zBuf[1024];
   sqlite3_stmt *pStmt = 0;
   int rc = SQLITE_OK;
-  int nCol;
+  int nCol = 0;
 
   sprintf(zBuf, "SELECT * FROM %s", zTab);
   rc = sqlite3_prepare(db, zBuf, -1, &pStmt, 0);
@@ -143,14 +143,18 @@ static int getIndexArray(sqlite3 *db, const char *zTab, int **paIndex){
       assert( cid>=0 && cid<nCol );
       aIndex[cid] = 1;
     }
-    rc = sqlite3_finalize(pStmt2);
+    if( pStmt2 ){
+      rc = sqlite3_finalize(pStmt2);
+    }
     if( rc!=SQLITE_OK ){
       sqlite3_finalize(pStmt);
       goto get_index_array_out;
     }
   }
 
-  rc = sqlite3_finalize(pStmt);
+  if( pStmt ){
+    rc = sqlite3_finalize(pStmt);
+  }
 
 get_index_array_out:
   if( rc!=SQLITE_OK ){
@@ -206,10 +210,14 @@ static int echoDeclareVtab(
 #ifndef SQLITE_OMIT_VIRTUALTABLE
       sqlite3_declare_vtab(db, zCreateTable);
 #endif
+      rc = sqlite3_finalize(pStmt);
     } else {
-      rc = SQLITE_ERROR;
+      rc = sqlite3_finalize(pStmt);
+      if( rc==SQLITE_OK ){ 
+        rc = SQLITE_ERROR;
+      }
     }
-    sqlite3_finalize(pStmt);
+
     if( rc==SQLITE_OK ){
       rc = getIndexArray(db, argv[3], &pVtab->aIndex);
     }
@@ -244,9 +252,16 @@ static int echoConstructor(
   echo_vtab *pVtab;
 
   pVtab = sqliteMalloc( sizeof(*pVtab) );
+  if( !pVtab ){
+    return SQLITE_NOMEM;
+  }
   pVtab->interp = (Tcl_Interp *)pAux;
   pVtab->db = db;
   pVtab->zTableName = sqlite3MPrintf("%s", argv[3]);
+  if( !pVtab->zTableName ){
+    return SQLITE_NOMEM;
+  }
+
   for(i=0; i<argc; i++){
     appendToEchoModule(pVtab->interp, argv[i]);
   }
@@ -318,14 +333,17 @@ static int echoOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
   echo_cursor *pCur;
   pCur = sqliteMalloc(sizeof(echo_cursor));
   *ppCursor = (sqlite3_vtab_cursor *)pCur;
-  return SQLITE_OK;
+  return (pCur ? SQLITE_OK : SQLITE_NOMEM);
 }
 
 static int echoClose(sqlite3_vtab_cursor *cur){
+  int rc;
   echo_cursor *pCur = (echo_cursor *)cur;
-  sqlite3_finalize(pCur->pStmt);
+  sqlite3_stmt *pStmt = pCur->pStmt;
+  pCur->pStmt = 0;
   sqliteFree(pCur);
-  return SQLITE_OK;
+  rc = sqlite3_finalize(pStmt);
+  return rc;
 }
 
 /*
@@ -339,7 +357,7 @@ static int echoEof(sqlite3_vtab_cursor *cur){
 static int echoNext(sqlite3_vtab_cursor *cur){
   int rc;
   echo_cursor *pCur = (echo_cursor *)cur;
-
+  sqlite3_stmt *pStmt = pCur->pStmt;
   rc = sqlite3_step(pCur->pStmt);
 
   if( rc==SQLITE_ROW ){
@@ -398,13 +416,18 @@ static int echoFilter(
   int argc, sqlite3_value **argv
 ){
   int rc;
-  int ret;
   int i;
 
   echo_cursor *pCur = (echo_cursor *)pVtabCursor;
   echo_vtab *pVtab = (echo_vtab *)pVtabCursor->pVtab;
   sqlite3 *db = pVtab->db;
 
+  appendToEchoModule(pVtab->interp, "xFilter");
+  appendToEchoModule(pVtab->interp, idxStr);
+  for(i=0; i<argc; i++){
+    appendToEchoModule(pVtab->interp, sqlite3_value_text(argv[i]));
+  }
+
   assert( idxNum==hashString(idxStr) );
   sqlite3_finalize(pCur->pStmt);
   pCur->pStmt = 0;
@@ -437,20 +460,12 @@ static int echoFilter(
     }
   }
   if( rc==SQLITE_OK ){
-    ret = echoNext(pVtabCursor);
+    rc = echoNext(pVtabCursor);
   }else{
     assert( !pCur->pStmt );
-    ret = 0;
-    pCur->errcode = rc;
   }
 
-  appendToEchoModule(pVtab->interp, "xFilter");
-  appendToEchoModule(pVtab->interp, idxStr);
-  for(i=0; i<argc; i++){
-    appendToEchoModule(pVtab->interp, sqlite3_value_text(argv[i]));
-  }
-
-  return ret;
+  return rc;
 }
 
 /*
index d59ce628f87d2687933e36ff30e2dc4f102d71d8..9fb569d2f7dbc25bde00d41c0fcfb860a257aa25 100644 (file)
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.565 2006/06/22 09:53:50 danielk1977 Exp $
+** $Id: vdbe.c,v 1.566 2006/06/23 08:05:26 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -180,7 +180,7 @@ static Cursor *allocateCursor(Vdbe *p, int iCur, int iDb){
   Cursor *pCx;
   assert( iCur<p->nCursor );
   if( p->apCsr[iCur] ){
-    sqlite3VdbeFreeCursor(p->apCsr[iCur]);
+    sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
   }
   p->apCsr[iCur] = pCx = sqliteMalloc( sizeof(Cursor) );
   if( pCx ){
@@ -2733,7 +2733,7 @@ case OP_OpenPseudo: {       /* no-push */
 case OP_Close: {       /* no-push */
   int i = pOp->p1;
   if( i>=0 && i<p->nCursor ){
-    sqlite3VdbeFreeCursor(p->apCsr[i]);
+    sqlite3VdbeFreeCursor(p, p->apCsr[i]);
     p->apCsr[i] = 0;
   }
   break;
@@ -4597,7 +4597,10 @@ case OP_VOpen: {   /* no-push */
 
     /* Initialise vdbe cursor object */
     pCur = allocateCursor(p, pOp->p1, -1);
-    pCur->pVtabCursor = pVtabCursor;
+    if( pCur ){
+      pCur->pVtabCursor = pVtabCursor;
+      pCur->pModule = pVtabCursor->pVtab->pModule;
+    }
   }
   break;
 }
@@ -4651,7 +4654,9 @@ case OP_VFilter: {   /* no-push */
     }
 
     if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+    p->inVtabMethod = 1;
     rc = pModule->xFilter(pCur->pVtabCursor, pTos->i, pOp->p3, nArg, apArg);
+    p->inVtabMethod = 0;
     if( rc==SQLITE_OK ){
       res = pModule->xEof(pCur->pVtabCursor);
     }
@@ -4762,7 +4767,9 @@ case OP_VNext: {   /* no-push */
     ** some other method is next invoked on the save virtual table cursor.
     */
     if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+    p->inVtabMethod = 1;
     rc = pModule->xNext(pCur->pVtabCursor);
+    p->inVtabMethod = 0;
     if( rc==SQLITE_OK ){
       res = pModule->xEof(pCur->pVtabCursor);
     }
index e4ab44cd89f8a72814911423adb3d5112b39fdb4..0c54c3d25418590ae68110d143e9e6e4de982e37 100644 (file)
@@ -85,6 +85,7 @@ struct Cursor {
   i64 seqCount;         /* Sequence counter */
 #ifndef SQLITE_OMIT_VIRTUALTABLE
   sqlite3_vtab_cursor *pVtabCursor;  /* The cursor for a virtual table */
+  sqlite3_module *pModule;           /* Module for cursor pVtabCursor */
 #endif
 
   /* Cached information about the header for the data record that the
@@ -324,6 +325,9 @@ struct Vdbe {
   int fetchId;          /* Statement number used by sqlite3_fetch_statement */
   int lru;              /* Counter used for LRU cache replacement */
 #endif
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+  int inVtabMethod;
+#endif
 };
 
 /*
@@ -337,7 +341,7 @@ struct Vdbe {
 /*
 ** Function prototypes
 */
-void sqlite3VdbeFreeCursor(Cursor*);
+void sqlite3VdbeFreeCursor(Vdbe *, Cursor*);
 void sqliteVdbePopStack(Vdbe*,int);
 int sqlite3VdbeCursorMoveto(Cursor*);
 #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
index 8074e58c7690e57f4e2811054a6ef710bb270d20..6d524f82e4132d1bda78b2f864302f2bd2f19ffb 100644 (file)
@@ -841,7 +841,7 @@ void sqlite3VdbeMakeReady(
 ** Close a cursor and release all the resources that cursor happens
 ** to hold.
 */
-void sqlite3VdbeFreeCursor(Cursor *pCx){
+void sqlite3VdbeFreeCursor(Vdbe *p, Cursor *pCx){
   if( pCx==0 ){
     return;
   }
@@ -855,8 +855,10 @@ void sqlite3VdbeFreeCursor(Cursor *pCx){
   if( pCx->pVtabCursor ){
     sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
     sqlite3_vtab *pVtab = pVtabCursor->pVtab;
-    const sqlite3_module *pModule = pVtab->pModule;
+    const sqlite3_module *pModule = pCx->pModule;
+    p->inVtabMethod = 1;
     pModule->xClose(pVtabCursor);
+    p->inVtabMethod = 0;
   }
 #endif
   sqliteFree(pCx->pData);
@@ -871,7 +873,9 @@ static void closeAllCursors(Vdbe *p){
   int i;
   if( p->apCsr==0 ) return;
   for(i=0; i<p->nCursor; i++){
-    sqlite3VdbeFreeCursor(p->apCsr[i]);
+    if( !p->inVtabMethod || (p->apCsr[i] && !p->apCsr[i]->pVtabCursor) ){
+      sqlite3VdbeFreeCursor(p, p->apCsr[i]);
+    }
     p->apCsr[i] = 0;
   }
 }
@@ -1149,23 +1153,6 @@ static int vdbeCommit(sqlite3 *db){
   return rc;
 }
 
-/*
-** Find every active VM other than pVdbe and change its status to
-** aborted.  This happens when one VM causes a rollback due to an
-** ON CONFLICT ROLLBACK clause (for example).  The other VMs must be
-** aborted so that they do not have data rolled out from underneath
-** them leading to a segfault.
-*/
-void sqlite3AbortOtherActiveVdbes(sqlite3 *db, Vdbe *pExcept){
-  Vdbe *pOther;
-  for(pOther=db->pVdbe; pOther; pOther=pOther->pNext){
-    if( pOther==pExcept ) continue;
-    if( pOther->magic!=VDBE_MAGIC_RUN || pOther->pc<0 ) continue;
-    closeAllCursors(pOther);
-    pOther->aborted = 1;
-  }
-}
-
 /* 
 ** This routine checks that the sqlite3.activeVdbeCnt count variable
 ** matches the number of vdbe's in the list sqlite3.pVdbe that are
@@ -1192,6 +1179,25 @@ static void checkActiveVdbeCnt(sqlite3 *db){
 #define checkActiveVdbeCnt(x)
 #endif
 
+/*
+** Find every active VM other than pVdbe and change its status to
+** aborted.  This happens when one VM causes a rollback due to an
+** ON CONFLICT ROLLBACK clause (for example).  The other VMs must be
+** aborted so that they do not have data rolled out from underneath
+** them leading to a segfault.
+*/
+void sqlite3AbortOtherActiveVdbes(sqlite3 *db, Vdbe *pExcept){
+  Vdbe *pOther;
+  for(pOther=db->pVdbe; pOther; pOther=pOther->pNext){
+    if( pOther==pExcept ) continue;
+    if( pOther->magic!=VDBE_MAGIC_RUN || pOther->pc<0 ) continue;
+    checkActiveVdbeCnt(db);
+    closeAllCursors(pOther);
+    checkActiveVdbeCnt(db);
+    pOther->aborted = 1;
+  }
+}
+
 /*
 ** This routine is called the when a VDBE tries to halt.  If the VDBE
 ** has made changes and is in autocommit mode, then commit those
@@ -1375,8 +1381,7 @@ int sqlite3VdbeHalt(Vdbe *p){
     }
   }
 
-  /* We have successfully halted and closed the VM.  Record this fact. */
-  if( p->pc>=0 ){
+  if( p->pc>=0  ){
     db->activeVdbeCnt--;
   }
   p->magic = VDBE_MAGIC_HALT;
index 576ffa1235849ec778e0315c7b5253937d06532f..74824fcda8976bfb41539b1422cde2e505da0f08 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** This file contains code used to help implement virtual tables.
 **
-** $Id: vtab.c,v 1.20 2006/06/21 16:02:43 danielk1977 Exp $
+** $Id: vtab.c,v 1.21 2006/06/23 08:05:30 danielk1977 Exp $
 */
 #ifndef SQLITE_OMIT_VIRTUALTABLE
 #include "sqliteInt.h"
@@ -46,9 +46,14 @@ int sqlite3_create_module(
 ** record.
 */
 void sqlite3VtabClear(Table *p){
-  if( p->pVtab ){
+  sqlite3_vtab *pVtab = p->pVtab;
+  if( pVtab ){
     assert( p->pMod && p->pMod->pModule );
-    p->pMod->pModule->xDisconnect(p->pVtab);
+    pVtab->nRef--;
+    if( pVtab->nRef==0 ){
+      pVtab->pModule->xDisconnect(pVtab);
+    }
+    p->pVtab = 0;
   }
   if( p->azModuleArg ){
     int i;
@@ -91,7 +96,6 @@ void sqlite3VtabBeginParse(
 ){
   int iDb;              /* The database the table is being created in */
   Table *pTable;        /* The new virtual table */
-  Token *pDummy;        /* Dummy arg for sqlite3TwoPartName() */
 
   sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0);
   pTable = pParse->pNewTable;
@@ -114,10 +118,9 @@ void sqlite3VtabBeginParse(
   ** sqlite_master table, has already been made by sqlite3StartTable().
   ** The second call, to obtain permission to create the table, is made now.
   */
-  if( sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName, 
-          pTable->azModuleArg[0], pParse->db->aDb[iDb].zName) 
-  ){
-    return;
+  if( pTable->azModuleArg ){
+    sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName, 
+            pTable->azModuleArg[0], pParse->db->aDb[iDb].zName);
   }
 #endif
 }
@@ -272,6 +275,7 @@ static int vtabCallConstructor(
   int rc2;
   char **azArg = pTab->azModuleArg;
   int nArg = pTab->nModuleArg;
+  char *zErr = sqlite3MPrintf("vtable constructor failed: %s", pTab->zName);
 
   assert( !db->pVTab );
   assert( xConstruct );
@@ -281,12 +285,14 @@ static int vtabCallConstructor(
   assert( rc==SQLITE_OK );
   rc = xConstruct(db, pMod->pAux, nArg, azArg, &pTab->pVtab);
   rc2 = sqlite3SafetyOn(db);
-  if( pTab->pVtab ){
+  if( rc==SQLITE_OK && pTab->pVtab ){
     pTab->pVtab->pModule = pMod->pModule;
+    pTab->pVtab->nRef = 1;
   }
 
   if( SQLITE_OK!=rc ){
-    *pzErr = sqlite3MPrintf("vtable constructor failed: %s", pTab->zName);
+    *pzErr = zErr;
+    zErr = 0;
   } else if( db->pVTab ){
     const char *zFormat = "vtable constructor did not declare schema: %s";
     *pzErr = sqlite3MPrintf(zFormat, pTab->zName);
@@ -296,6 +302,7 @@ static int vtabCallConstructor(
     rc = rc2;
   }
   db->pVTab = 0;
+  sqliteFree(zErr);
   return rc;
 }
 
@@ -337,7 +344,7 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
 /*
 ** Add the virtual table pVtab to the array sqlite3.aVTrans[].
 */
-int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
+static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
   const int ARRAY_INCR = 5;
 
   /* Grow the sqlite3.aVTrans array if required */
@@ -354,6 +361,7 @@ int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
 
   /* Add pVtab to the end of sqlite3.aVTrans */
   db->aVTrans[db->nVTrans++] = pVtab;
+  pVtab->nRef++;
   return SQLITE_OK;
 }
 
@@ -471,11 +479,6 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab)
   return rc;
 }
 
-void sqlite3VtabCodeLock(Parse *pParse, Table *pTab){
-  Vdbe *v = sqlite3GetVdbe(pParse);
-  sqlite3VdbeOp3(v, OP_VBegin, 0, 0, (const char*)pTab->pVtab, P3_VTAB);
-}
-
 /*
 ** This function invokes either the xRollback or xCommit method
 ** of each of the virtual tables in the sqlite3.aVTrans array. The method
@@ -491,6 +494,10 @@ static void callFinaliser(sqlite3 *db, int offset){
     int (*x)(sqlite3_vtab *);
     x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset);
     if( x ) x(pVtab);
+    pVtab->nRef--;
+    if( pVtab->nRef==0 ){
+      pVtab->pModule->xDisconnect(pVtab);
+    }
   }
   sqliteFree(db->aVTrans);
   db->nVTrans = 0;
index f11ee759cac9b550935ca589b9813045f39413dc..197f2f31dd0f4cbd1b4575ad4fbfb4389ae0db28 100644 (file)
@@ -16,7 +16,7 @@
 ** so is applicable.  Because this module is responsible for selecting
 ** indices, you might also think of this module as the "query optimizer".
 **
-** $Id: where.c,v 1.221 2006/06/20 13:07:28 danielk1977 Exp $
+** $Id: where.c,v 1.222 2006/06/23 08:05:31 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -1125,10 +1125,16 @@ static double bestVirtualIndex(
   }
 
   sqlite3SafetyOff(pParse->db);
-  pTab->pVtab->pModule->xBestIndex(pTab->pVtab, pIdxInfo);
-  rc = sqlite3SafetyOn(pParse->db);
+  rc = pTab->pVtab->pModule->xBestIndex(pTab->pVtab, pIdxInfo);
   if( rc!=SQLITE_OK ){
-    sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc));
+    if( rc==SQLITE_NOMEM ){
+      sqlite3FailedMalloc();
+    }else {
+      sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc));
+    }
+    sqlite3SafetyOn(pParse->db);
+  }else{
+    rc = sqlite3SafetyOn(pParse->db);
   }
 
   *(int*)&pIdxInfo->nOrderBy = nOrderBy;
index 13c29f0c7802584e01265b0d8d5f0e26059b4f82..3f58e0a955d10c9351143a8a9b534fdd16218357 100644 (file)
@@ -6,7 +6,7 @@
 #***********************************************************************
 # This file runs all tests.
 #
-# $Id: quick.test,v 1.44 2006/06/14 10:38:03 danielk1977 Exp $
+# $Id: quick.test,v 1.45 2006/06/23 08:05:38 danielk1977 Exp $
 
 proc lshift {lvar} {
   upvar $lvar l
@@ -55,6 +55,7 @@ set EXCLUDE {
   btree8.test
   utf16.test
   shared_err.test
+  vtab_err.test
 }
 
 if {[sqlite3 -has-codec]} {
index 2a9670441671635c82ac2c7970449c6f43c2043b..3e359be5b15af5315d518ef451da2b205c87fb7f 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements some common TCL routines used for regression
 # testing the SQLite library
 #
-# $Id: tester.tcl,v 1.64 2006/01/24 13:09:33 danielk1977 Exp $
+# $Id: tester.tcl,v 1.65 2006/06/23 08:05:38 danielk1977 Exp $
 
 # Make sure tclsqlite3 was compiled correctly.  Abort now with an
 # error message if not.
@@ -149,6 +149,7 @@ proc finalize_testing {} {
   catch {
     pp_check_for_leaks
   }
+breakpoint
   sqlite3 db {}
   # sqlite3_clear_tsd_memdebug
   db close
index cae67c2e6c42eab233b04e357bb1aaa39c04f58d..73f044a5fc8536fb9c4d2bc02c5b8d256f17fd5b 100644 (file)
@@ -9,7 +9,7 @@
 #
 #***********************************************************************
 #
-# $Id: vtab_err.test,v 1.1 2006/06/22 09:53:50 danielk1977 Exp $
+# $Id: vtab_err.test,v 1.2 2006/06/23 08:05:39 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -19,6 +19,107 @@ ifcapable !vtab {
   return
 }
 
+# Usage: do_malloc_test <test number> <options...>
+#
+# The first argument, <test number>, is an integer used to name the
+# tests executed by this proc. Options are as follows:
+#
+#     -tclprep          TCL script to run to prepare test.
+#     -sqlprep          SQL script to run to prepare test.
+#     -tclbody          TCL script to run with malloc failure simulation.
+#     -sqlbody          TCL script to run with malloc failure simulation.
+#     -cleanup          TCL script to run after the test.
+#
+# This command runs a series of tests to verify SQLite's ability
+# to handle an out-of-memory condition gracefully. It is assumed
+# that if this condition occurs a malloc() call will return a
+# NULL pointer. Linux, for example, doesn't do that by default. See
+# the "BUGS" section of malloc(3).
+#
+# Each iteration of a loop, the TCL commands in any argument passed
+# to the -tclbody switch, followed by the SQL commands in any argument
+# passed to the -sqlbody switch are executed. Each iteration the
+# Nth call to sqliteMalloc() is made to fail, where N is increased
+# each time the loop runs starting from 1. When all commands execute
+# successfully, the loop ends.
+#
+proc do_malloc_test {tn args} {
+  array unset ::mallocopts 
+  array set ::mallocopts $args
+
+  set ::go 1
+  for {set ::n 1} {$::go && $::n < 50000} {incr ::n} {
+    do_test $tn.$::n {
+
+      # Remove all traces of database files test.db and test2.db from the files
+      # system. Then open (empty database) "test.db" with the handle [db].
+      # 
+      sqlite_malloc_fail 0
+      catch {db close} 
+      catch {file delete -force test.db}
+      catch {file delete -force test.db-journal}
+      catch {file delete -force test2.db}
+      catch {file delete -force test2.db-journal}
+      catch {sqlite3 db test.db} 
+      set ::DB [sqlite3_connection_pointer db]
+
+      # Execute any -tclprep and -sqlprep scripts.
+      #
+      if {[info exists ::mallocopts(-tclprep)]} {
+        eval $::mallocopts(-tclprep)
+      }
+      if {[info exists ::mallocopts(-sqlprep)]} {
+        execsql $::mallocopts(-sqlprep)
+      }
+
+      # Now set the ${::n}th malloc() to fail and execute the -tclbody and
+      # -sqlbody scripts.
+      #
+      sqlite_malloc_fail $::n
+      set ::mallocbody {}
+      if {[info exists ::mallocopts(-tclbody)]} {
+        append ::mallocbody "$::mallocopts(-tclbody)\n"
+      }
+      if {[info exists ::mallocopts(-sqlbody)]} {
+        append ::mallocbody "db eval {$::mallocopts(-sqlbody)}"
+      }
+      set v [catch $::mallocbody msg]
+
+      # If the test fails (if $v!=0) and the database connection actually
+      # exists, make sure the failure code is SQLITE_NOMEM.
+      if {$v&&[info command db]=="db"&&[info exists ::mallocopts(-sqlbody)]} {
+        if {[db errorcode]!=7 && $msg!="vtable constructor failed: e"} {
+          set v 999
+        }
+      }
+
+      set leftover [lindex [sqlite_malloc_stat] 2]
+      if {$leftover>0} {
+        if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v  Message=$msg"}
+        set ::go 0
+        if {$v} {
+          puts "\nError message returned: $msg"
+        } else {
+          set v {1 1}
+        }
+      } else {
+        set v2 [expr {
+          $msg == "" || $msg == "out of memory" || 
+          $msg == "vtable constructor failed: e"
+        }]
+        if {!$v2} {puts "\nError message returned: $msg"}
+        lappend v $v2
+      }
+    } {1 1}
+
+    if {[info exists ::mallocopts(-cleanup)]} {
+      catch [list uplevel #0 $::mallocopts(-cleanup)] msg
+    }
+  }
+  unset ::mallocopts
+}
+
+
 do_ioerr_test vtab_err-1 -tclprep {
   register_echo_module [sqlite3_connection_pointer db]
 } -sqlbody {
@@ -38,5 +139,24 @@ do_ioerr_test vtab_err-1 -tclprep {
 }
 
 
+do_malloc_test vtab_err-2 -tclprep {
+  register_echo_module [sqlite3_connection_pointer db]
+} -sqlbody {
+  BEGIN;
+  CREATE TABLE r(a PRIMARY KEY, b, c);
+  CREATE VIRTUAL TABLE e USING echo(r);
+  INSERT INTO e VALUES(1, 2, 3);
+  INSERT INTO e VALUES('a', 'b', 'c');
+  UPDATE e SET c = 10;
+  DELETE FROM e WHERE a = 'a';
+  COMMIT;
+  BEGIN;
+    CREATE TABLE r2(a, b, c);
+    INSERT INTO r2 SELECT * FROM e;
+    INSERT INTO e SELECT a||'x', b, c FROM r2;
+  COMMIT;
+} 
+
+sqlite_malloc_fail 0
 finish_test