]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Test that virtual table methods xBestIndex, xOpen, xFilter, xNext, xColumn, xRowid...
authordanielk1977 <danielk1977@noemail.net>
Fri, 1 Aug 2008 17:37:40 +0000 (17:37 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Fri, 1 Aug 2008 17:37:40 +0000 (17:37 +0000)
FossilOrigin-Name: 007359b770f225877880b11f4c5d97bb548e38ca

manifest
manifest.uuid
src/sqliteInt.h
src/test8.c
src/vdbe.c
src/vdbeaux.c
src/vtab.c
src/where.c
test/vtab1.test

index ee67f1a2dfbc0c16abee3d7b82ea6be93cee7669..d7974593d330e79de4c51777f88bd3ece5cffd5e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Test\scases\sfor\ssqlite3_db_config()\sand\ssqlite3_db_status().\s(CVS\s5518)
-D 2008-08-01T16:31:14
+C Test\sthat\svirtual\stable\smethods\sxBestIndex,\sxOpen,\sxFilter,\sxNext,\sxColumn,\sxRowid,\sxUpdate,\sxSync\sand\sxBegin\scan\sall\sreturn\serror\smessages\susing\sthe\ssqlite3_vtab.zErrMsg\svariable.\s(CVS\s5519)
+D 2008-08-01T17:37:41
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in bbb62eecc851379aef5a48a1bf8787eb13e6ec06
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -146,7 +146,7 @@ F src/select.c ef18af5624fc3189014e6b617a36562394740f91
 F src/shell.c 4b835fe734304ac22a3385868cd3790c1e4f7aa1
 F src/sqlite.h.in 30af3a002a0b672aaae8f4a5deb0a2e9a4b699af
 F src/sqlite3ext.h 1e3887c9bd3ae66cb599e922824b04cd0d0f2c3e
-F src/sqliteInt.h 99a49b2d85b7648fbb2f7933b145dfb5b11d8941
+F src/sqliteInt.h 80fa4a46024dee8cb6c66a6f04a716c253d98165
 F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
 F src/status.c 8ad1f215934c5f5afb91df86e44dccff7ef3c1d0
 F src/table.c 22744786199c9195720c15a7a42cb97b2e2728d8
@@ -158,7 +158,7 @@ F src/test4.c 41056378671e7b00e6305fa9ac6fa27e6f96f406
 F src/test5.c 847eb5cfe89c197b6b494858ccf60be981235bdf
 F src/test6.c 0a0304a69cfa4962a429d084c6d451ff9e4fb572
 F src/test7.c 475b1fa7e3275408b40a3cbdc9508cbdc41ffa02
-F src/test8.c ae09a70c009097561d0d21e0291d383ad059d3f8
+F src/test8.c f869497d3f6e8a7566e9b7116dce7ada49ee1183
 F src/test9.c 904ebe0ed1472d6bad17a81e2ecbfc20017dc237
 F src/test_async.c da9f58f49faccd3a26ba89f58de125862351b6e2
 F src/test_autoext.c f53b0cdf7bf5f08100009572a5d65cdb540bd0ad
@@ -183,16 +183,16 @@ F src/update.c 79b77a3cc8ed5f8903a7f37055fcedd69388dcae
 F src/utf.c a7004436a6ef2aee012ace93de274dd0f3c7624e
 F src/util.c afe659ccc05d1f8af9e8631dabfec3ee3a7144af
 F src/vacuum.c ef342828002debc97514617af3424aea8ef8522c
-F src/vdbe.c caa169475973e56a87eb90477928d84f3daa14b8
+F src/vdbe.c 90296a45d28939fd631c05c235dab7e123f94f57
 F src/vdbe.h c46155c221418bea29ee3a749d5950fcf85a70e2
 F src/vdbeInt.h ab27f964458fd070c6660f80694ab85d56d5f4c5
 F src/vdbeapi.c 25dd01c8b12978c14ec30e9a50666b23da767b27
-F src/vdbeaux.c dbd2756c203d8c45281dd2f33a9f4741b5f81047
+F src/vdbeaux.c 78c9d6413b8720edfe5b2a40a14850d21b0079b7
 F src/vdbeblob.c f93110888ddc246215e9ba1f831d3d375bfd8355
 F src/vdbefifo.c 20fda2a7c4c0bcee1b90eb7e545fefcdbf2e1de7
 F src/vdbemem.c bdf92746583b0187655d736c4a20a2622eb9ab69
-F src/vtab.c 691813795f1bba5df57389c1cec62f9e73eebd9d
-F src/where.c ee4878e42ac97e2b3389b44cee34b35458321488
+F src/vtab.c 914db4c9435c61a522e3cdaf103dac163d38aa30
+F src/where.c a800184a2d023b15d6f2758b7a6c7ab011258fee
 F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/all.test 89e09ed0074083ac6f208dc3243429e8f89efb69
@@ -569,7 +569,7 @@ F test/vacuum3.test 75dee6ffd1baa60308dcad93f2c689126500dcff
 F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
 F test/veryquick.test e265401afefa994cdf2fe4b6f286b1e87c2f9b9d
 F test/view.test 5799906511d6c77cfe3516d3d1189224350ef732
-F test/vtab1.test 905a1aedad6e7307aea29f00d87b255b04994777
+F test/vtab1.test 2108cfb3ff72cb0f46363589d3c4746c04723368
 F test/vtab2.test 1da49b015582965a8fc386aa23d051a5a622b08e
 F test/vtab3.test baad99fd27217f5d6db10660522e0b7192446de1
 F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275
@@ -615,7 +615,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P 3f70e03ae83d374f5f69770bd7a4b279584f7090
-R 21a8914e4d9d6622f109fe97eb26a591
-U drh
-Z 0e954aa8108084642ae7fe8343f84356
+P 6a6b94302acdfe6404b04bff1cc8d16c1ef69df9
+R 5672f7054494561346fae0939e873dda
+U danielk1977
+Z bf74e8d5f26a63b2617162677c14612e
index 46966a19cce1b77856c5d686a900870855110297..c38e0fd1e8ac9130295f0bd9e38dbb35d89e79a2 100644 (file)
@@ -1 +1 @@
-6a6b94302acdfe6404b04bff1cc8d16c1ef69df9
\ No newline at end of file
+007359b770f225877880b11f4c5d97bb548e38ca
\ No newline at end of file
index 1551183f4c41b99cbab2eb51a53a92cc80e30454..caf04211cc30c0c0f70a9f30bd9880e50ba58bdd 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.748 2008/07/31 17:35:45 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.749 2008/08/01 17:37:41 danielk1977 Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -2267,7 +2267,7 @@ int sqlite3AutoLoadExtensions(sqlite3*);
 #  define sqlite3VtabTransferError(A,B,C)
 #else
    void sqlite3VtabClear(Table*);
-   int sqlite3VtabSync(sqlite3 *db, int rc);
+   int sqlite3VtabSync(sqlite3 *db, char **);
    int sqlite3VtabRollback(sqlite3 *db);
    int sqlite3VtabCommit(sqlite3 *db);
    void sqlite3VtabTransferError(sqlite3 *db, int, sqlite3_vtab*);
index effd768b8fd265e2b6f587f30de2291e9308b68f..c6e1aa481bdc6acc4d8936c72c59e4cfaac2b475 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.69 2008/07/28 19:34:54 drh Exp $
+** $Id: test8.c,v 1.70 2008/08/01 17:37:41 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "tcl.h"
@@ -44,6 +44,22 @@ typedef struct echo_cursor echo_cursor;
 ** use the named table as a backing store will fail.
 */
 
+/*
+** Errors can be provoked within the following echo virtual table methods:
+**
+**   xBestIndex   xOpen     xFilter   xNext   
+**   xColumn      xRowid    xUpdate   xSync   
+**   xBegin
+**
+** This is done by setting the global tcl variable:
+**
+**   echo_module_fail($method,$tbl)
+**
+** where $method is set to the name of the virtual table method to fail
+** (i.e. "xBestIndex") and $tbl is the name of the table being echoed (not
+** the name of the virtual table, the name of the underlying real table).
+*/
+
 /* 
 ** An echo virtual-table object.
 **
@@ -76,6 +92,18 @@ struct echo_cursor {
   sqlite3_stmt *pStmt;
 };
 
+static int simulateVtabError(echo_vtab *p, const char *zMethod){
+  const char *zErr;
+  char zVarname[128];
+  zVarname[127] = '\0';
+  snprintf(zVarname, 127, "echo_module_fail(%s,%s)", zMethod, p->zTableName);
+  zErr = Tcl_GetVar(p->interp, zVarname, TCL_GLOBAL_ONLY);
+  if( zErr ){
+    p->base.zErrMsg = sqlite3_mprintf("echo-vtab-error: %s", zErr);
+  }
+  return (zErr!=0);
+}
+
 /*
 ** Convert an SQL-style quoted string into a normal string by removing
 ** the quote characters.  The conversion is done in-place.  If the
@@ -524,6 +552,9 @@ static int echoDestroy(sqlite3_vtab *pVtab){
 */
 static int echoOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
   echo_cursor *pCur;
+  if( simulateVtabError((echo_vtab *)pVTab, "xOpen") ){
+    return SQLITE_ERROR;
+  }
   pCur = sqlite3MallocZero(sizeof(echo_cursor));
   *ppCursor = (sqlite3_vtab_cursor *)pCur;
   return (pCur ? SQLITE_OK : SQLITE_NOMEM);
@@ -557,6 +588,10 @@ static int echoNext(sqlite3_vtab_cursor *cur){
   int rc = SQLITE_OK;
   echo_cursor *pCur = (echo_cursor *)cur;
 
+  if( simulateVtabError((echo_vtab *)(cur->pVtab), "xNext") ){
+    return SQLITE_ERROR;
+  }
+
   if( pCur->pStmt ){
     rc = sqlite3_step(pCur->pStmt);
     if( rc==SQLITE_ROW ){
@@ -576,6 +611,11 @@ static int echoNext(sqlite3_vtab_cursor *cur){
 static int echoColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
   int iCol = i + 1;
   sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt;
+
+  if( simulateVtabError((echo_vtab *)(cur->pVtab), "xColumn") ){
+    return SQLITE_ERROR;
+  }
+
   if( !pStmt ){
     sqlite3_result_null(ctx);
   }else{
@@ -590,6 +630,11 @@ static int echoColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
 */
 static int echoRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
   sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt;
+
+  if( simulateVtabError((echo_vtab *)(cur->pVtab), "xRowid") ){
+    return SQLITE_ERROR;
+  }
+
   *pRowid = sqlite3_column_int64(pStmt, 0);
   return SQLITE_OK;
 }
@@ -627,6 +672,10 @@ static int echoFilter(
   echo_vtab *pVtab = (echo_vtab *)pVtabCursor->pVtab;
   sqlite3 *db = pVtab->db;
 
+  if( simulateVtabError(pVtab, "xFilter") ){
+    return SQLITE_ERROR;
+  }
+
   /* Check that idxNum matches idxStr */
   assert( idxNum==hashString(idxStr) );
 
@@ -734,12 +783,15 @@ static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
   int rc = SQLITE_OK;
   int useCost = 0;
   double cost;
-
   int isIgnoreUsable = 0;
   if( Tcl_GetVar(interp, "echo_module_ignore_usable", TCL_GLOBAL_ONLY) ){
     isIgnoreUsable = 1;
   }
 
+  if( simulateVtabError(pVtab, "xBestIndex") ){
+    return SQLITE_ERROR;
+  }
+
   /* Determine the number of rows in the table and store this value in local
   ** variable nRow. The 'estimated-cost' of the scan will be the number of
   ** rows in the table for a linear scan, or the log (base 2) of the 
@@ -892,6 +944,10 @@ int echoUpdate(
   ** making any changes to a virtual table */
   assert( pVtab->inTransaction );
 
+  if( simulateVtabError(pVtab, "xUpdate") ){
+    return SQLITE_ERROR;
+  }
+
   /* If apData[0] is an integer and nData>1 then do an UPDATE */
   if( nData>1 && sqlite3_value_type(apData[0])==SQLITE_INTEGER ){
     char *zSep = " SET";
@@ -1019,6 +1075,10 @@ static int echoBegin(sqlite3_vtab *tab){
   ** a transaction */
   assert( !pVtab->inTransaction );
 
+  if( simulateVtabError(pVtab, "xBegin") ){
+    return SQLITE_ERROR;
+  }
+
   rc = echoTransactionCall(tab, "xBegin");
 
   if( rc==SQLITE_OK ){
@@ -1046,6 +1106,10 @@ static int echoSync(sqlite3_vtab *tab){
   ** transaction */
   assert( pVtab->inTransaction );
 
+  if( simulateVtabError(pVtab, "xSync") ){
+    return SQLITE_ERROR;
+  }
+
   rc = echoTransactionCall(tab, "xSync");
 
   if( rc==SQLITE_OK ){
@@ -1068,6 +1132,10 @@ static int echoCommit(sqlite3_vtab *tab){
   ** a transaction */
   assert( pVtab->inTransaction );
 
+  if( simulateVtabError(pVtab, "xCommit") ){
+    return SQLITE_ERROR;
+  }
+
   sqlite3BeginBenignMalloc();
   rc = echoTransactionCall(tab, "xCommit");
   sqlite3EndBenignMalloc();
index 744bc755912b526ec54d622fbfd3ae4e09a5b315..878d34ce72bd0e7f04b8a562fad5d59cf9871017 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.769 2008/07/30 13:27:11 drh Exp $
+** $Id: vdbe.c,v 1.770 2008/08/01 17:37:41 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -4570,11 +4570,21 @@ case OP_TableLock: {
 #ifndef SQLITE_OMIT_VIRTUALTABLE
 /* Opcode: VBegin * * * P4 *
 **
-** P4 a pointer to an sqlite3_vtab structure. Call the xBegin method 
-** for that table.
+** P4 may be a pointer to an sqlite3_vtab structure. If so, call the 
+** xBegin method for that table.
+**
+** Also, whether or not P4 is set, check that this is not being called from
+** within a callback to a virtual table xSync() method. If it is, set the
+** error code to SQLITE_LOCKED.
 */
 case OP_VBegin: {
-  rc = sqlite3VtabBegin(db, pOp->p4.pVtab);
+  sqlite3_vtab *pVtab = pOp->p4.pVtab;
+  rc = sqlite3VtabBegin(db, pVtab);
+  if( pVtab ){
+    sqlite3DbFree(db, p->zErrMsg);
+    p->zErrMsg = pVtab->zErrMsg;
+    pVtab->zErrMsg = 0;
+  }
   break;
 }
 #endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -4699,6 +4709,9 @@ case OP_VFilter: {   /* jump */
     p->inVtabMethod = 1;
     rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
     p->inVtabMethod = 0;
+    sqlite3DbFree(db, p->zErrMsg);
+    p->zErrMsg = pVtab->zErrMsg;
+    pVtab->zErrMsg = 0;
     if( rc==SQLITE_OK ){
       res = pModule->xEof(pVtabCursor);
     }
@@ -4721,6 +4734,7 @@ case OP_VFilter: {   /* jump */
 ** the virtual-table that the P1 cursor is pointing to.
 */
 case OP_VRowid: {             /* out2-prerelease */
+  sqlite3_vtab *pVtab;
   const sqlite3_module *pModule;
   sqlite_int64 iRow;
   Cursor *pCur = p->apCsr[pOp->p1];
@@ -4729,10 +4743,14 @@ case OP_VRowid: {             /* out2-prerelease */
   if( pCur->nullRow ){
     break;
   }
-  pModule = pCur->pVtabCursor->pVtab->pModule;
+  pVtab = pCur->pVtabCursor->pVtab;
+  pModule = pVtab->pModule;
   assert( pModule->xRowid );
   if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
   rc = pModule->xRowid(pCur->pVtabCursor, &iRow);
+  sqlite3DbFree(db, p->zErrMsg);
+  p->zErrMsg = pVtab->zErrMsg;
+  pVtab->zErrMsg = 0;
   if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
   MemSetTypeFlag(pOut, MEM_Int);
   pOut->u.i = iRow;
@@ -4748,6 +4766,7 @@ case OP_VRowid: {             /* out2-prerelease */
 ** P1 cursor is pointing to into register P3.
 */
 case OP_VColumn: {
+  sqlite3_vtab *pVtab;
   const sqlite3_module *pModule;
   Mem *pDest;
   sqlite3_context sContext;
@@ -4760,7 +4779,8 @@ case OP_VColumn: {
     sqlite3VdbeMemSetNull(pDest);
     break;
   }
-  pModule = pCur->pVtabCursor->pVtab->pModule;
+  pVtab = pCur->pVtabCursor->pVtab;
+  pModule = pVtab->pModule;
   assert( pModule->xColumn );
   memset(&sContext, 0, sizeof(sContext));
 
@@ -4774,6 +4794,9 @@ case OP_VColumn: {
 
   if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
   rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2);
+  sqlite3DbFree(db, p->zErrMsg);
+  p->zErrMsg = pVtab->zErrMsg;
+  pVtab->zErrMsg = 0;
 
   /* Copy the result of the function to the P3 register. We
   ** do this regardless of whether or not an error occured to ensure any
@@ -4802,6 +4825,7 @@ case OP_VColumn: {
 ** the end of its result set, then fall through to the next instruction.
 */
 case OP_VNext: {   /* jump */
+  sqlite3_vtab *pVtab;
   const sqlite3_module *pModule;
   int res = 0;
 
@@ -4810,7 +4834,8 @@ case OP_VNext: {   /* jump */
   if( pCur->nullRow ){
     break;
   }
-  pModule = pCur->pVtabCursor->pVtab->pModule;
+  pVtab = pCur->pVtabCursor->pVtab;
+  pModule = pVtab->pModule;
   assert( pModule->xNext );
 
   /* Invoke the xNext() method of the module. There is no way for the
@@ -4823,6 +4848,9 @@ case OP_VNext: {   /* jump */
   p->inVtabMethod = 1;
   rc = pModule->xNext(pCur->pVtabCursor);
   p->inVtabMethod = 0;
+  sqlite3DbFree(db, p->zErrMsg);
+  p->zErrMsg = pVtab->zErrMsg;
+  pVtab->zErrMsg = 0;
   if( rc==SQLITE_OK ){
     res = pModule->xEof(pCur->pVtabCursor);
   }
index 8dc9c58efd6d935052d1868f801bad36fc7aa9d7..22ff34a9e89e3ef90e951f3000243b8df3a53da9 100644 (file)
@@ -14,7 +14,7 @@
 ** to version 2.8.7, all this code was combined into the vdbe.c source file.
 ** But that file was getting too big so this subroutines were split out.
 **
-** $Id: vdbeaux.c,v 1.402 2008/07/31 01:43:14 shane Exp $
+** $Id: vdbeaux.c,v 1.403 2008/08/01 17:37:41 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -1216,7 +1216,7 @@ int sqlite3VdbeSetColName(Vdbe *p, int idx, int var, const char *zName, int N){
 ** write-transaction spanning more than one database file, this routine
 ** takes care of the master journal trickery.
 */
-static int vdbeCommit(sqlite3 *db){
+static int vdbeCommit(sqlite3 *db, Vdbe *p){
   int i;
   int nTrans = 0;  /* Number of databases with an active write-transaction */
   int rc = SQLITE_OK;
@@ -1228,7 +1228,7 @@ static int vdbeCommit(sqlite3 *db){
   ** required, as an xSync() callback may add an attached database
   ** to the transaction.
   */
-  rc = sqlite3VtabSync(db, rc);
+  rc = sqlite3VtabSync(db, &p->zErrMsg);
   if( rc!=SQLITE_OK ){
     return rc;
   }
@@ -1592,7 +1592,7 @@ int sqlite3VdbeHalt(Vdbe *p){
         ** successful or hit an 'OR FAIL' constraint. This means a commit 
         ** is required.
         */
-        int rc = vdbeCommit(db);
+        int rc = vdbeCommit(db, p);
         if( rc==SQLITE_BUSY ){
           sqlite3BtreeMutexArrayLeave(&p->aMutex);
           return SQLITE_BUSY;
index c9ff4e0bdd8b342fff3d72361f4d4836bb6e682e..62636104aa83750501ce5db4a32cd2af277f4208 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** This file contains code used to help implement virtual tables.
 **
-** $Id: vtab.c,v 1.72 2008/07/28 19:34:54 drh Exp $
+** $Id: vtab.c,v 1.73 2008/08/01 17:37:41 danielk1977 Exp $
 */
 #ifndef SQLITE_OMIT_VIRTUALTABLE
 #include "sqliteInt.h"
@@ -640,17 +640,18 @@ static void callFinaliser(sqlite3 *db, int offset){
 }
 
 /*
-** If argument rc2 is not SQLITE_OK, then return it and do nothing. 
-** Otherwise, invoke the xSync method of all virtual tables in the 
-** sqlite3.aVTrans array. Return the error code for the first error 
-** that occurs, or SQLITE_OK if all xSync operations are successful.
+** Invoke the xSync method of all virtual tables in the sqlite3.aVTrans
+** array. Return the error code for the first error that occurs, or
+** SQLITE_OK if all xSync operations are successful.
+**
+** Set *pzErrmsg to point to a buffer that should be released using 
+** sqlite3DbFree() containing an error message, if one is available.
 */
-int sqlite3VtabSync(sqlite3 *db, int rc2){
+int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){
   int i;
   int rc = SQLITE_OK;
   int rcsafety;
   sqlite3_vtab **aVTrans = db->aVTrans;
-  if( rc2!=SQLITE_OK ) return rc2;
 
   rc = sqlite3SafetyOff(db);
   db->aVTrans = 0;
@@ -660,6 +661,9 @@ int sqlite3VtabSync(sqlite3 *db, int rc2){
     x = pVtab->pModule->xSync;
     if( x ){
       rc = x(pVtab);
+      sqlite3DbFree(db, *pzErrmsg);
+      *pzErrmsg = pVtab->zErrMsg;
+      pVtab->zErrMsg = 0;
     }
   }
   db->aVTrans = aVTrans;
@@ -727,12 +731,9 @@ int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
 
     /* Invoke the xBegin method */
     rc = pModule->xBegin(pVtab);
-    sqlite3VtabTransferError(db, rc, pVtab);
-    if( rc!=SQLITE_OK ){
-      return rc;
+    if( rc==SQLITE_OK ){
+      rc = addToVTrans(db, pVtab);
     }
-
-    rc = addToVTrans(db, pVtab);
   }
   return rc;
 }
index dac5161b83dfee8499439c420d0e9b4caef4063b..9c70c31abdc429831167aab07adc5c79d3698aed 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.318 2008/07/28 19:34:54 drh Exp $
+** $Id: where.c,v 1.319 2008/08/01 17:37:41 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -1259,6 +1259,7 @@ static double bestVirtualIndex(
   sqlite3_index_info **ppIdxInfo /* Index information passed to xBestIndex */
 ){
   Table *pTab = pSrc->pTab;
+  sqlite3_vtab *pVtab = pTab->pVtab;
   sqlite3_index_info *pIdxInfo;
   struct sqlite3_index_constraint *pIdxCons;
   struct sqlite3_index_orderby *pIdxOrderBy;
@@ -1370,7 +1371,7 @@ static double bestVirtualIndex(
   ** sqlite3ViewGetColumnNames() would have picked up the error. 
   */
   assert( pTab->azModuleArg && pTab->azModuleArg[0] );
-  assert( pTab->pVtab );
+  assert( pVtab );
 #if 0
   if( pTab->pVtab==0 ){
     sqlite3ErrorMsg(pParse, "undefined module %s for table %s",
@@ -1423,10 +1424,22 @@ static double bestVirtualIndex(
   (void)sqlite3SafetyOff(pParse->db);
   WHERETRACE(("xBestIndex for %s\n", pTab->zName));
   TRACE_IDX_INPUTS(pIdxInfo);
-  rc = pTab->pVtab->pModule->xBestIndex(pTab->pVtab, pIdxInfo);
+  rc = pVtab->pModule->xBestIndex(pVtab, pIdxInfo);
   TRACE_IDX_OUTPUTS(pIdxInfo);
   (void)sqlite3SafetyOn(pParse->db);
 
+  if( rc!=SQLITE_OK ){
+    if( rc==SQLITE_NOMEM ){
+      pParse->db->mallocFailed = 1;
+    }else if( !pVtab->zErrMsg ){
+      sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc));
+    }else{
+      sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg);
+    }
+  }
+  sqlite3DbFree(pParse->db, pVtab->zErrMsg);
+  pVtab->zErrMsg = 0;
+
   for(i=0; i<pIdxInfo->nConstraint; i++){
     if( !pIdxInfo->aConstraint[i].usable && pUsage[i].argvIndex>0 ){
       sqlite3ErrorMsg(pParse, 
@@ -1435,15 +1448,7 @@ static double bestVirtualIndex(
     }
   }
 
-  if( rc!=SQLITE_OK ){
-    if( rc==SQLITE_NOMEM ){
-      pParse->db->mallocFailed = 1;
-    }else {
-      sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc));
-    }
-  }
   *(int*)&pIdxInfo->nOrderBy = nOrderBy;
-
   return pIdxInfo->estimatedCost;
 }
 #endif /* SQLITE_OMIT_VIRTUALTABLE */
index 3a568bd986da7dc36a63392e6414739601a6e083..c46b9ada5ac5db2af1b3900362eb9093749c6b9b 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is creating and dropping virtual tables.
 #
-# $Id: vtab1.test,v 1.55 2008/07/23 21:07:25 drh Exp $
+# $Id: vtab1.test,v 1.56 2008/08/01 17:37:41 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -52,6 +52,9 @@ ifcapable !vtab||!schema_pragmas {
 # We cannot create a virtual table if the module has not been registered.
 #
 do_test vtab1-1.1 {
+  explain {
+    CREATE VIRTUAL TABLE t1 USING echo;
+  }
   catchsql {
     CREATE VIRTUAL TABLE t1 USING echo;
   }
@@ -1108,6 +1111,48 @@ do_test vtab1-15.4 {
   }
 } {1 {datatype mismatch}}
 
+# The following tests - vtab1-16.* - are designed to test that setting 
+# sqlite3_vtab.zErrMsg variable can be used by the vtab interface to 
+# return an error message to the user.
+# 
+do_test vtab1-16.1 {
+  execsql {
+    CREATE TABLE t2(a PRIMARY KEY, b, c);
+    INSERT INTO t2 VALUES(1, 2, 3);
+    INSERT INTO t2 VALUES(4, 5, 6);
+    CREATE VIRTUAL TABLE echo_t2 USING echo(t2);
+  }
+} {}
+
+set tn 2
+foreach method [list \
+    xBestIndex       \
+    xOpen            \
+    xFilter          \
+    xNext            \
+    xColumn          \
+    xRowid           \
+] {
+  do_test vtab1-16.$tn {
+    set echo_module_fail($method,t2) "the $method method has failed"
+    catchsql { SELECT rowid, * FROM echo_t2 WHERE a >= 1 }
+  } "1 {echo-vtab-error: the $method method has failed}"
+  unset echo_module_fail($method,t2)
+  incr tn
+}
+
+foreach method [list \
+  xUpdate            \
+  xBegin             \
+  xSync              \
+] {
+  do_test vtab1-16.$tn {
+    set echo_module_fail($method,t2) "the $method method has failed"
+    catchsql { INSERT INTO echo_t2 VALUES(7, 8, 9) }
+  } "1 {echo-vtab-error: the $method method has failed}"
+  unset echo_module_fail($method,t2)
+  incr tn
+}
 
 unset -nocomplain echo_module_begin_fail
 finish_test