Add code to invoke the virtual table transaction interface. Untested at this point. (CVS 3261)

FossilOrigin-Name: 6125140228e09cad2029a48e92aa0123d3daecfb
diff --git a/manifest b/manifest
index 14f9245..4a4feee 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\ssome\stests\s(and\sfixes)\sfor\svirtual\stables\sand\sthe\sauthorization\scallback.\sStill\smore\sto\scome.\s(CVS\s3260)
-D 2006-06-16T08:01:03
+C Add\scode\sto\sinvoke\sthe\svirtual\stable\stransaction\sinterface.\sUntested\sat\sthis\spoint.\s(CVS\s3261)
+D 2006-06-16T16:08:54
 F Makefile.in f839b470345d3cb4b0644068474623fe2464b5d3
 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -36,20 +36,20 @@
 F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f
 F src/btree.c ed343b3dbcbc7da9ac481ef2b98c4239fe6d9629
 F src/btree.h 40055cfc09defd1146bc5b922399c035f969e56d
-F src/build.c 28208a9049d7bf61f16fcb4bb850406857135953
+F src/build.c 3eb63f61249fd0fcd7075456b522a1ceb5f912bd
 F src/callback.c fd9bb39f7ff6b52bad8365617abc61c720640429
 F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675
 F src/date.c cd2bd5d1ebc6fa12d6312f69789ae5b0a2766f2e
-F src/delete.c f34599f681d291d5b5762ff162a4b10214809aef
+F src/delete.c e6a324650fb9f6afe5757ec5c7d8dad62d9496b8
 F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
 F src/expr.c 78b521337d628b1fd9d87b12dbbe771247aab585
 F src/func.c 01e559893b5e43bea85135ad3e481d86c447942a
 F src/hash.c 449f3d6620193aa557f5d86cbc5cc6b87702b185
 F src/hash.h 1b3f7e2609141fd571f62199fc38687d262e9564
-F src/insert.c 09440829e4fa2b0e11dbde5508b8a291025a745d
+F src/insert.c 5c1fddd7e4d05805e02e12bdced2a3841d2bd8dc
 F src/legacy.c fa15d505dd4e45044177ee4d1c6aeaf8c836d390
 F src/loadext.c 676257ae268457e7f03261d8ca0d1e72968a26c8
-F src/main.c 7875e8835539d4f16e8b62fad1dee9bda2091272
+F src/main.c 7101314a365120465bf5e308caaf518b7776430c
 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217
 F src/os.c 59f05de8c5777c34876607114a2fbe55ae578235
 F src/os.h ac2ccb4f48902c1611a7e1f171eb81d17e3b8eb2
@@ -74,7 +74,7 @@
 F src/shell.c ad73192b30a338a58fe81183d4a5d5a1d4e51d36
 F src/sqlite.h.in 77b42d1bb5deafa04ae156d24cd243c2d75800ac
 F src/sqlite3ext.h fc8647211af0caa9d8e49ab31624b357c1332380
-F src/sqliteInt.h 2eb48bd25f5fccce86d80e6872b045ed61b91687
+F src/sqliteInt.h 5f8de04c331fb6c80e70e309f550c8cc8efb6e1f
 F src/table.c f64ec4fbfe333f8df925bc6ba494f55e05b0e75e
 F src/tclsqlite.c c408a49ae44525fc69757b4ed39f6ca0f56549a5
 F src/test1.c 40f20775903bc76d3be3e7c026dddcbc221c1cb0
@@ -93,18 +93,18 @@
 F src/test_tclvar.c c52f67fbe06d32804af2ba9a2d7aadfc15f5910c
 F src/tokenize.c 6ebcafa6622839968dda4418a7b6945f277a128f
 F src/trigger.c 0fc40125820409a6274834a6e04ad804d96e2793
-F src/update.c 5e638a61102776c0f0333994e18361b40598b44f
+F src/update.c d3b991905ed8b26feb2055bdab40ce3c42e1b522
 F src/utf.c ab81ac59084ff1c07d421eb1a0a84ec809603b44
 F src/util.c ca6ee72772c0f5dc04d2e0ab1973fd3b6a9bf79d
 F src/vacuum.c 5b37d0f436f8e1ffacd17934e44720b38d2247f9
-F src/vdbe.c f17a90ab6c630438394807c4e21c0c1c7731ee4f
+F src/vdbe.c 704940e7c0c811d721a4eac0f4bb3da4f4f88dc9
 F src/vdbe.h 258b5d1c0aaa72192f09ff0568ce42b383f156fa
 F src/vdbeInt.h 6ccb7eaae76ebd761470f6a035501ff33aa92c20
 F src/vdbeapi.c 6af0e7160af260052a7a4500464221a03dada75f
-F src/vdbeaux.c 85f2184f536219d3c20c66f1403ef77321d1e715
+F src/vdbeaux.c dc5cfd11a0529fcfd217a1807f7c9df513f1c276
 F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5
 F src/vdbemem.c 5f0afe3b92bb2c037f8d5d697f7c151fa50783a3
-F src/vtab.c cb5a2b23a241e657a8ee7c2b03574f6afa27214a
+F src/vtab.c 5d69a87980eaac026f74c8712961ed2b306ffba2
 F src/where.c d7c3cc011834882b2d58ebb3a6a1a569ead7ebd7
 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@@ -368,7 +368,7 @@
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P afa39a46320e9996a5478ea6e19eb4c2014327ac
-R e864f985538904b7098e2d0d1765152d
+P 9497c66e5533ec143d0efda4a419e4bdf922ae8c
+R d4bc1ee77da86ad3a4a5c0b77f2ab8e7
 U danielk1977
-Z b35d7828e5c540d613e21e95c6dfce99
+Z d74361b9f31a7257bb399e37ec5aacb7
diff --git a/manifest.uuid b/manifest.uuid
index 0b1a8c6..94fa1ca 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-9497c66e5533ec143d0efda4a419e4bdf922ae8c
\ No newline at end of file
+6125140228e09cad2029a48e92aa0123d3daecfb
\ No newline at end of file
diff --git a/src/build.c b/src/build.c
index 9f9eea1..517c27d 100644
--- a/src/build.c
+++ b/src/build.c
@@ -22,7 +22,7 @@
 **     COMMIT
 **     ROLLBACK
 **
-** $Id: build.c,v 1.402 2006/06/16 08:01:03 danielk1977 Exp $
+** $Id: build.c,v 1.403 2006/06/16 16:08:54 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -164,6 +164,12 @@
         sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
         sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
       }
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+      if( pParse->pVirtualLock ){
+        char *vtab = (char *)pParse->pVirtualLock->pVtab;
+        sqlite3VdbeOp3(v, OP_VBegin, 0, 0, vtab, P3_VTAB);
+      }
+#endif
 
       /* Once all the cookies have been verified and transactions opened, 
       ** obtain the required table-locks. This is a no-op unless the 
diff --git a/src/delete.c b/src/delete.c
index f1cdcdb..196d7fc 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** in order to generate code for DELETE FROM statements.
 **
-** $Id: delete.c,v 1.125 2006/06/15 04:28:13 danielk1977 Exp $
+** $Id: delete.c,v 1.126 2006/06/16 16:08:55 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -236,8 +236,7 @@
         sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, iDb);
       }
     }
-  }
-
+  } 
   /* The usual case: There is a WHERE clause so we have to scan through
   ** the table and pick which records to delete.
   */
@@ -312,6 +311,7 @@
       /* Delete the row */
 #ifndef SQLITE_OMIT_VIRTUALTABLE
       if( IsVirtual(pTab) ){
+        pParse->pVirtualLock = pTab;
         sqlite3VdbeOp3(v, OP_VUpdate, 0, 1, (const char*)pTab->pVtab, P3_VTAB);
       }else
 #endif
diff --git a/src/insert.c b/src/insert.c
index efefb2a..60737ed 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements in SQLite.
 **
-** $Id: insert.c,v 1.168 2006/06/16 06:17:47 danielk1977 Exp $
+** $Id: insert.c,v 1.169 2006/06/16 16:08:55 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -632,6 +632,7 @@
     */
 #ifndef SQLITE_OMIT_VIRTUALTABLE
     if( IsVirtual(pTab) ){
+      pParse->pVirtualLock = pTab;
       sqlite3VdbeOp3(v, OP_VUpdate, 1, pTab->nCol+2,
                      (const char*)pTab->pVtab, P3_VTAB);
     }else
diff --git a/src/main.c b/src/main.c
index 463ba99..44569e0 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,7 +14,7 @@
 ** other files are for internal use by SQLite and should not be
 ** accessed by users of the library.
 **
-** $Id: main.c,v 1.344 2006/06/15 04:28:13 danielk1977 Exp $
+** $Id: main.c,v 1.345 2006/06/16 16:08:55 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -206,6 +206,7 @@
   if( db->flags&SQLITE_InternChanges ){
     sqlite3ResetInternalSchema(db, 0);
   }
+  sqlite3VtabRollback(db);
 
   /* If one has been configured, invoke the rollback-hook callback */
   if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index bec2be0..95d2966 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.507 2006/06/16 08:01:04 danielk1977 Exp $
+** @(#) $Id: sqliteInt.h,v 1.508 2006/06/16 16:08:55 danielk1977 Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -494,6 +494,8 @@
 #ifndef SQLITE_OMIT_VIRTUALTABLE
   Hash aModule;                 /* populated by sqlite3_create_module() */
   Table *pVTab;                 /* vtab with active Connect/Create method */
+  sqlite3_vtab **aVTrans;       /* Virtual tables with open transactions */
+  int nVTrans;                  /* Allocated size of aVTrans */
 #endif
   Hash aFunc;                   /* All functions that can be in SQL exprs */
   Hash aCollSeq;                /* All collating sequences */
@@ -722,6 +724,7 @@
   u8 isVirtual;             /* True if this is a virtual table */
   int nModuleArg;           /* Number of arguments to the module */
   char **azModuleArg;       /* Text of all module args. [0] is module name */
+  u8 isCommit;              /* True once the CREATE TABLE has been committed */
 #endif
   Schema *pSchema;
 };
@@ -1304,10 +1307,11 @@
   TriggerStack *trigStack;  /* Trigger actions being coded */
   const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
 #ifndef SQLITE_OMIT_VIRTUALTABLE
-  int nArgAlloc;            /* Number of bytes allocated for zArg[] */
-  int nArgUsed;             /* Number of bytes of zArg[] used so far */
-  char *zArg;               /* Complete text of a module argument */
-  u8 declareVtab;           /* True if inside sqlite3_declare_vtab() */
+  int nArgAlloc;             /* Number of bytes allocated for zArg[] */
+  int nArgUsed;              /* Number of bytes of zArg[] used so far */
+  char *zArg;                /* Complete text of a module argument */
+  u8 declareVtab;            /* True if inside sqlite3_declare_vtab() */
+  Table *pVirtualLock;       /* Require virtual table lock on this table */
 #endif
 };
 
@@ -1815,8 +1819,15 @@
 
 #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);
 #endif
 void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*);
 void sqlite3VtabFinishParse(Parse*, Token*);
@@ -1825,6 +1836,7 @@
 int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);
 int sqlite3VtabCallConnect(Parse*, Table*);
 int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
+int sqlite3VtabBegin(sqlite3 *, sqlite3_vtab *);
 
 #ifdef SQLITE_SSE
 #include "sseInt.h"
diff --git a/src/update.c b/src/update.c
index bc2a271..b40d3a2 100644
--- a/src/update.c
+++ b/src/update.c
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle UPDATE statements.
 **
-** $Id: update.c,v 1.125 2006/06/14 19:00:22 drh Exp $
+** $Id: update.c,v 1.126 2006/06/16 16:08:55 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -475,6 +475,7 @@
     }
 
     /* Make the update */
+    pParse->pVirtualLock = pTab;
     sqlite3VdbeOp3(v, OP_VUpdate, 0, pTab->nCol+2, 
                       (const char*)pTab->pVtab, P3_VTAB);
   }
diff --git a/src/vdbe.c b/src/vdbe.c
index 0441334..b75bfe2 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -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.562 2006/06/16 06:17:47 danielk1977 Exp $
+** $Id: vdbe.c,v 1.563 2006/06/16 16:08:55 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -4543,6 +4543,18 @@
 ** P3 is the name of a virtual table in database P1. Call the xCreate method
 ** for that table.
 */
+case OP_VBegin: {   /* no-push */
+  rc = sqlite3VtabBegin(db, (sqlite3_vtab *)pOp->p3);
+  break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VCreate P1 * P3
+**
+** P3 is the name of a virtual table in database P1. Call the xCreate method
+** for that table.
+*/
 case OP_VCreate: {   /* no-push */
   rc = sqlite3VtabCallCreate(db, pOp->p1, pOp->p3, &p->zErrMsg);
   break;
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 13d5cfd..f599fdd 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -1002,6 +1002,7 @@
         rc = sqlite3BtreeSync(pBt, 0);
       }
     }
+    rc = sqlite3VtabSync(db, rc);
 
     /* Do the commit only if all databases successfully synced */
     if( rc==SQLITE_OK ){
@@ -1011,6 +1012,7 @@
           sqlite3BtreeCommit(pBt);
         }
       }
+      sqlite3VtabCommit(db);
     }
   }
 
@@ -1103,6 +1105,8 @@
         }
       }
     }
+    rc = sqlite3VtabSync(db, SQLITE_OK);
+    if( rc!=SQLITE_OK ) return rc;
     sqlite3OsClose(&master);
 
     /* Delete the master journal file. This commits the transaction. After
@@ -1138,6 +1142,7 @@
         sqlite3BtreeCommit(pBt);
       }
     }
+    sqlite3VtabCommit(db);
   }
 #endif
 
diff --git a/src/vtab.c b/src/vtab.c
index 2b647b1..fb1f4d9 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -11,7 +11,7 @@
 *************************************************************************
 ** This file contains code used to help implement virtual tables.
 **
-** $Id: vtab.c,v 1.14 2006/06/16 08:01:04 danielk1977 Exp $
+** $Id: vtab.c,v 1.15 2006/06/16 16:08:55 danielk1977 Exp $
 */
 #ifndef SQLITE_OMIT_VIRTUALTABLE
 #include "sqliteInt.h"
@@ -441,4 +441,101 @@
   return rc;
 }
 
+static int callFinaliser(sqlite3 *db, int offset, int doDelete){
+  int rc = SQLITE_OK;
+  int i;
+  for(i=0; rc==SQLITE_OK && i<db->nVTrans && db->aVTrans[i]; i++){
+    sqlite3_vtab *pVtab = db->aVTrans[i];
+    int (*x)(sqlite3_vtab *);
+    x = (int (*)(sqlite3_vtab *))((char *)pVtab->pModule + offset);
+    if( x ){
+      rc = x(pVtab);
+    }
+  }
+  if( doDelete ){
+    sqliteFree(db->aVTrans);
+    db->nVTrans = 0;
+    db->aVTrans = 0;
+  }
+  return rc;
+}
+
+void sqlite3VtabCodeLock(Parse *pParse, Table *pTab){
+  Vdbe *v = sqlite3GetVdbe(pParse);
+  sqlite3VdbeOp3(v, OP_VBegin, 0, 0, (const char*)pTab->pVtab, P3_VTAB);
+}
+
+/*
+** If argument rc 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.
+*/
+int sqlite3VtabSync(sqlite3 *db, int rc){
+  if( rc!=SQLITE_OK ) return rc;
+  return callFinaliser(db, (int)(&((sqlite3_module *)0)->xSync), 0);
+}
+
+/*
+** Invoke the xRollback method of all virtual tables in the 
+** sqlite3.aVTrans array. Then clear the array itself.
+*/
+int sqlite3VtabRollback(sqlite3 *db){
+  return callFinaliser(db, (int)(&((sqlite3_module *)0)->xRollback), 1);
+}
+
+/*
+** Invoke the xCommit method of all virtual tables in the 
+** sqlite3.aVTrans array. Then clear the array itself.
+*/
+int sqlite3VtabCommit(sqlite3 *db){
+  return callFinaliser(db, (int)(&((sqlite3_module *)0)->xCommit), 1);
+}
+
+/*
+** If the virtual table pVtab supports the transaction interface
+** (xBegin/xRollback/xCommit and optionally xSync) and a transaction is
+** not currently open, invoke the xBegin method now.
+**
+** If the xBegin call is successful, place the sqlite3_vtab pointer
+** in the sqlite3.aVTrans array.
+*/
+int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
+  int rc = SQLITE_OK;
+  const int ARRAY_INCR = 5;
+  const sqlite3_module *pModule = pVtab->pModule;
+  if( pModule->xBegin ){
+    int i;
+
+    /* If pVtab is already in the aVTrans array, return early */
+    for(i=0; (i<db->nVTrans) && 0!=db->aVTrans[i]; i++){
+      if( db->aVTrans[i]==pVtab ){
+        return SQLITE_OK;
+      }
+    }
+
+    /* Invoke the xBegin method */
+    rc = pModule->xBegin(pVtab);
+    if( rc!=SQLITE_OK ){
+      return rc;
+    }
+
+    /* Grow the sqlite3.aVTrans array if required */
+    if( (db->nVTrans%ARRAY_INCR)==0 ){
+      sqlite3_vtab *aVTrans;
+      int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR);
+      aVTrans = sqliteRealloc((void *)db->aVTrans, nBytes);
+      if( !aVTrans ){
+        return SQLITE_NOMEM;
+      }
+      memset(&aVTrans[db->nVTrans], 0, sizeof(sqlite3_vtab *)*ARRAY_INCR);
+      db->aVTrans = aVTrans;
+    }
+
+    /* Add pVtab to the end of sqlite3.aVTrans */
+    db->aVTrans[db->nVTrans++] = pVtab;
+  }
+  return rc;
+}
+
 #endif /* SQLITE_OMIT_VIRTUALTABLE */