Add code to invoke the virtual table transaction interface. Untested at this point. (CVS 3261)
FossilOrigin-Name: 6125140228e09cad2029a48e92aa0123d3daecfb
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 */