aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordanielk1977 <danielk1977@noemail.net>2004-05-31 08:26:49 +0000
committerdanielk1977 <danielk1977@noemail.net>2004-05-31 08:26:49 +0000
commit1d850a72c265ad9368b322ca39125c9b0c3d8509 (patch)
tree3ae42a002f87796ecea58f7094dea2096fa4439a /src
parenta19b775db9b2f12263e54cf0f64162ced526fff5 (diff)
downloadsqlite-1d850a72c265ad9368b322ca39125c9b0c3d8509.tar.gz
sqlite-1d850a72c265ad9368b322ca39125c9b0c3d8509.zip
Replace OP_Begin, OP_Commit and OP_Rollback with OP_AutoCommit. (CVS 1500)
FossilOrigin-Name: b8ed812c92f2dbb4431d45aeb41646ceb53e0cbc
Diffstat (limited to 'src')
-rw-r--r--src/btree.c16
-rw-r--r--src/btree.h4
-rw-r--r--src/build.c94
-rw-r--r--src/main.c3
-rw-r--r--src/pager.c6
-rw-r--r--src/pragma.c4
-rw-r--r--src/sqliteInt.h5
-rw-r--r--src/test3.c86
-rw-r--r--src/trigger.c10
-rw-r--r--src/vacuum.c28
-rw-r--r--src/vdbe.c115
-rw-r--r--src/vdbeInt.h1
-rw-r--r--src/vdbeapi.c6
-rw-r--r--src/vdbeaux.c111
14 files changed, 297 insertions, 192 deletions
diff --git a/src/btree.c b/src/btree.c
index 8057be79b..86b98d671 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
-** $Id: btree.c,v 1.152 2004/05/30 20:46:09 drh Exp $
+** $Id: btree.c,v 1.153 2004/05/31 08:26:49 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@@ -4183,3 +4183,17 @@ int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
}
return rc;
}
+
+/*
+** Return non-zero if a transaction is active.
+*/
+int sqlite3BtreeIsInTrans(Btree *pBt){
+ return (pBt && pBt->inTrans);
+}
+
+/*
+** Return non-zero if a statement transaction is active.
+*/
+int sqlite3BtreeIsInStmt(Btree *pBt){
+ return (pBt && pBt->inStmt);
+}
diff --git a/src/btree.h b/src/btree.h
index 639e55bcd..c6c4f08bc 100644
--- a/src/btree.h
+++ b/src/btree.h
@@ -13,7 +13,7 @@
** subsystem. See comments in the source code for a detailed description
** of what each interface routine does.
**
-** @(#) $Id: btree.h,v 1.49 2004/05/30 20:46:09 drh Exp $
+** @(#) $Id: btree.h,v 1.50 2004/05/31 08:26:49 danielk1977 Exp $
*/
#ifndef _BTREE_H_
#define _BTREE_H_
@@ -48,6 +48,8 @@ int sqlite3BtreeBeginStmt(Btree*);
int sqlite3BtreeCommitStmt(Btree*);
int sqlite3BtreeRollbackStmt(Btree*);
int sqlite3BtreeCreateTable(Btree*, int*, int flags);
+int sqlite3BtreeIsInTrans(Btree*);
+int sqlite3BtreeIsInStmt(Btree*);
const char *sqlite3BtreeGetFilename(Btree *);
int sqlite3BtreeCopyFile(Btree *, Btree *);
diff --git a/src/build.c b/src/build.c
index 5699c5d3d..6aeb8cbd8 100644
--- a/src/build.c
+++ b/src/build.c
@@ -23,7 +23,7 @@
** ROLLBACK
** PRAGMA
**
-** $Id: build.c,v 1.200 2004/05/29 11:24:50 danielk1977 Exp $
+** $Id: build.c,v 1.201 2004/05/31 08:26:49 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -920,6 +920,15 @@ char sqlite3AffinityType(const char *zType, int nType){
** 1 chance in 2^32. So we're safe enough.
*/
void sqlite3ChangeCookie(sqlite *db, Vdbe *v, int iDb){
+ unsigned char r;
+ int *pSchemaCookie = &(db->aDb[iDb].schema_cookie);
+
+ sqlite3Randomness(1, &r);
+ *pSchemaCookie = *pSchemaCookie + r + 1;
+ db->flags |= SQLITE_InternChanges;
+ sqlite3VdbeAddOp(v, OP_Integer, *pSchemaCookie, 0);
+ sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 0);
+/*
if( db->next_cookie==db->aDb[0].schema_cookie ){
unsigned char r;
sqlite3Randomness(1, &r);
@@ -928,6 +937,7 @@ void sqlite3ChangeCookie(sqlite *db, Vdbe *v, int iDb){
sqlite3VdbeAddOp(v, OP_Integer, db->next_cookie, 0);
sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 0);
}
+*/
}
/*
@@ -1104,7 +1114,7 @@ void sqlite3EndTable(Parse *pParse, Token *pEnd, Select *pSelect){
}
sqlite3VdbeOp3(v, OP_MakeRecord, 5, 0, "tttit", P3_STATIC);
sqlite3VdbeAddOp(v, OP_PutIntKey, 0, 0);
- if( !p->iDb ){
+ if( p->iDb!=1 ){
sqlite3ChangeCookie(db, v, p->iDb);
}
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
@@ -1830,7 +1840,6 @@ void sqlite3CreateIndex(
int n;
Vdbe *v;
int lbl1, lbl2;
- int i;
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto exit_create_index;
@@ -2165,19 +2174,17 @@ void sqlite3SrcListDelete(SrcList *pList){
*/
void sqlite3BeginTransaction(Parse *pParse, int onError){
sqlite *db;
+ Vdbe *v;
if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
if( pParse->nErr || sqlite3_malloc_failed ) return;
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return;
- if( db->flags & SQLITE_InTrans ){
- sqlite3ErrorMsg(pParse, "cannot start a transaction within a transaction");
- return;
- }
- sqlite3BeginWriteOperation(pParse, 0, 0);
- if( !pParse->explain ){
- db->flags |= SQLITE_InTrans;
- db->onError = onError;
- }
+
+ v = sqlite3GetVdbe(pParse);
+ if( !v ) return;
+ sqlite3VdbeAddOp(v, OP_AutoCommit, 0, 0);
+
+ /* FIX ME: Need to deal with onError */
}
/*
@@ -2185,20 +2192,15 @@ void sqlite3BeginTransaction(Parse *pParse, int onError){
*/
void sqlite3CommitTransaction(Parse *pParse){
sqlite *db;
+ Vdbe *v;
if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
if( pParse->nErr || sqlite3_malloc_failed ) return;
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return;
- if( (db->flags & SQLITE_InTrans)==0 ){
- sqlite3ErrorMsg(pParse, "cannot commit - no transaction is active");
- return;
- }
- if( !pParse->explain ){
- db->flags &= ~SQLITE_InTrans;
- }
- sqlite3EndWriteOperation(pParse);
- if( !pParse->explain ){
- db->onError = OE_Default;
+
+ v = sqlite3GetVdbe(pParse);
+ if( v ){
+ sqlite3VdbeAddOp(v, OP_AutoCommit, 1, 0);
}
}
@@ -2212,17 +2214,10 @@ void sqlite3RollbackTransaction(Parse *pParse){
if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return;
if( pParse->nErr || sqlite3_malloc_failed ) return;
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return;
- if( (db->flags & SQLITE_InTrans)==0 ){
- sqlite3ErrorMsg(pParse, "cannot rollback - no transaction is active");
- return;
- }
+
v = sqlite3GetVdbe(pParse);
if( v ){
- sqlite3VdbeAddOp(v, OP_Rollback, 0, 0);
- }
- if( !pParse->explain ){
- db->flags &= ~SQLITE_InTrans;
- db->onError = OE_Default;
+ sqlite3VdbeAddOp(v, OP_AutoCommit, 1, 1);
}
}
@@ -2235,9 +2230,9 @@ void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
Vdbe *v = sqlite3GetVdbe(pParse);
assert( iDb>=0 && iDb<db->nDb );
assert( db->aDb[iDb].pBt!=0 );
- if( iDb!=1 && !DbHasProperty(db, iDb, DB_Cookie) ){
+ if( iDb!=1 && (iDb>63 || !(pParse->cookieMask & ((u64)1<<iDb))) ){
sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, db->aDb[iDb].schema_cookie);
- DbSetProperty(db, iDb, DB_Cookie);
+ pParse->cookieMask |= ((u64)1<<iDb);
}
}
@@ -2260,21 +2255,15 @@ void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
** specified auxiliary database and the temp database are made writable.
*/
void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
- Vdbe *v;
- sqlite *db = pParse->db;
- if( DbHasProperty(db, iDb, DB_Locked) ) return;
- v = sqlite3GetVdbe(pParse);
+ Vdbe *v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
- if( !db->aDb[iDb].inTrans ){
- sqlite3VdbeAddOp(v, OP_Transaction, iDb, 0);
- DbSetProperty(db, iDb, DB_Locked);
- sqlite3CodeVerifySchema(pParse, iDb);
- if( iDb!=1 ){
- sqlite3BeginWriteOperation(pParse, setStatement, 1);
- }
- }else if( setStatement ){
+ sqlite3VdbeAddOp(v, OP_Transaction, iDb, 0);
+ sqlite3CodeVerifySchema(pParse, iDb);
+ if( setStatement ){
sqlite3VdbeAddOp(v, OP_Statement, iDb, 0);
- DbSetProperty(db, iDb, DB_Locked);
+ }
+ if( iDb!=1 ){
+ sqlite3BeginWriteOperation(pParse, setStatement, 1);
}
}
@@ -2289,15 +2278,6 @@ void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
** call to sqlite3EndWriteOperation() at the conclusion of the statement.
*/
void sqlite3EndWriteOperation(Parse *pParse){
- Vdbe *v;
- sqlite *db = pParse->db;
- if( pParse->trigStack ) return; /* if this is in a trigger */
- v = sqlite3GetVdbe(pParse);
- if( v==0 ) return;
- if( db->flags & SQLITE_InTrans ){
- /* A BEGIN has executed. Do not commit until we see an explicit
- ** COMMIT statement. */
- }else{
- sqlite3VdbeAddOp(v, OP_Commit, 0, 0);
- }
+ /* Delete me! */
+ return;
}
diff --git a/src/main.c b/src/main.c
index b3fbebc70..af8e74b80 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.196 2004/05/29 10:23:19 danielk1977 Exp $
+** $Id: main.c,v 1.197 2004/05/31 08:26:49 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -1020,6 +1020,7 @@ static int openDatabase(
db->nDb = 2;
db->aDb = db->aDbStatic;
db->enc = def_enc;
+ db->autoCommit = 1;
/* db->flags |= SQLITE_ShortColNames; */
sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0);
diff --git a/src/pager.c b/src/pager.c
index b5315e8f5..d2b84b97b 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while
** another is writing.
**
-** @(#) $Id: pager.c,v 1.108 2004/05/14 01:58:13 drh Exp $
+** @(#) $Id: pager.c,v 1.109 2004/05/31 08:26:49 danielk1977 Exp $
*/
#include "os.h" /* Must be first to enable large file support */
#include "sqliteInt.h"
@@ -865,7 +865,7 @@ end_stmt_playback:
void sqlite3pager_set_cachesize(Pager *pPager, int mxPage){
if( mxPage>=0 ){
pPager->noSync = pPager->tempFile;
- if( pPager->noSync==0 ) pPager->needSync = 0;
+ if( pPager->noSync ) pPager->needSync = 0;
}else{
pPager->noSync = 1;
mxPage = -mxPage;
@@ -904,7 +904,7 @@ void sqlite3pager_set_cachesize(Pager *pPager, int mxPage){
void sqlite3pager_set_safety_level(Pager *pPager, int level){
pPager->noSync = level==1 || pPager->tempFile;
pPager->fullSync = level==3 && !pPager->tempFile;
- if( pPager->noSync==0 ) pPager->needSync = 0;
+ if( pPager->noSync ) pPager->needSync = 0;
}
/*
diff --git a/src/pragma.c b/src/pragma.c
index 1c50d37aa..d80005b41 100644
--- a/src/pragma.c
+++ b/src/pragma.c
@@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
-** $Id: pragma.c,v 1.34 2004/05/29 11:24:50 danielk1977 Exp $
+** $Id: pragma.c,v 1.35 2004/05/31 08:26:49 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -93,7 +93,7 @@ static int changeTempStorage(Parse *pParse, const char *zStorageType){
sqlite *db = pParse->db;
if( db->temp_store==ts ) return SQLITE_OK;
if( db->aDb[1].pBt!=0 ){
- if( db->flags & SQLITE_InTrans ){
+ if( !db->autoCommit ){
sqlite3ErrorMsg(pParse, "temporary storage cannot be changed "
"from within a transaction");
return SQLITE_ERROR;
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index f1d13b52f..9abf2d301 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.261 2004/05/29 02:37:19 danielk1977 Exp $
+** @(#) $Id: sqliteInt.h,v 1.262 2004/05/31 08:26:49 danielk1977 Exp $
*/
#include "config.h"
#include "sqlite.h"
@@ -389,6 +389,7 @@ struct sqlite {
u8 busy; /* TRUE if currently initializing */
} init;
struct Vdbe *pVdbe; /* List of active virtual machines */
+ int activeVdbeCnt; /* Number of vdbes currently executing */
void (*xTrace)(void*,const char*); /* Trace function */
void *pTraceArg; /* Argument to the trace function */
#ifndef SQLITE_OMIT_AUTHORIZATION
@@ -406,6 +407,7 @@ struct sqlite {
char *zErrMsg; /* Most recent error message (UTF-8 encoded) */
void *zErrMsg16; /* Most recent error message (UTF-16 encoded) */
u8 enc; /* Text encoding for this database. */
+ u8 autoCommit; /* The auto-commit flag. */
};
/*
@@ -989,6 +991,7 @@ struct Parse {
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
TriggerStack *trigStack; /* Trigger actions being coded */
+ u64 cookieMask; /* Bitmask of schema verified databases */
};
/*
diff --git a/src/test3.c b/src/test3.c
index a402b3146..5c03c7a07 100644
--- a/src/test3.c
+++ b/src/test3.c
@@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
-** $Id: test3.c,v 1.39 2004/05/30 20:46:09 drh Exp $
+** $Id: test3.c,v 1.40 2004/05/31 08:26:49 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "pager.h"
@@ -192,6 +192,87 @@ static int btree_commit(
}
/*
+** Usage: btree_begin_statement ID
+**
+** Start a new statement transaction
+*/
+static int btree_begin_statement(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ const char **argv /* Text of each argument */
+){
+ Btree *pBt;
+ int rc;
+ if( argc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ID\"", 0);
+ return TCL_ERROR;
+ }
+ if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
+ rc = sqlite3BtreeBeginStmt(pBt);
+ if( rc!=SQLITE_OK ){
+ Tcl_AppendResult(interp, errorName(rc), 0);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+/*
+** Usage: btree_rollback_statement ID
+**
+** Rollback changes
+*/
+static int btree_rollback_statement(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ const char **argv /* Text of each argument */
+){
+ Btree *pBt;
+ int rc;
+ if( argc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ID\"", 0);
+ return TCL_ERROR;
+ }
+ if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
+ rc = sqlite3BtreeRollbackStmt(pBt);
+ if( rc!=SQLITE_OK ){
+ Tcl_AppendResult(interp, errorName(rc), 0);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+/*
+** Usage: btree_commit_statement ID
+**
+** Commit all changes
+*/
+static int btree_commit_statement(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ const char **argv /* Text of each argument */
+){
+ Btree *pBt;
+ int rc;
+ if( argc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " ID\"", 0);
+ return TCL_ERROR;
+ }
+ if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
+ rc = sqlite3BtreeCommitStmt(pBt);
+ if( rc!=SQLITE_OK ){
+ Tcl_AppendResult(interp, errorName(rc), 0);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+/*
** Usage: btree_create_table ID FLAGS
**
** Create a new table in the database
@@ -1257,6 +1338,9 @@ int Sqlitetest3_Init(Tcl_Interp *interp){
{ "btree_integrity_check", (Tcl_CmdProc*)btree_integrity_check },
{ "btree_breakpoint", (Tcl_CmdProc*)btree_breakpoint },
{ "btree_varint_test", (Tcl_CmdProc*)btree_varint_test },
+ { "btree_begin_statement", (Tcl_CmdProc*)btree_begin_statement },
+ { "btree_commit_statement", (Tcl_CmdProc*)btree_commit_statement },
+ { "btree_rollback_statement", (Tcl_CmdProc*)btree_rollback_statement },
};
int i;
diff --git a/src/trigger.c b/src/trigger.c
index bb4499847..20f71b57d 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -231,8 +231,8 @@ void sqlite3FinishTrigger(
sqlite3VdbeChangeP3(v, addr+2, nt->name, 0);
sqlite3VdbeChangeP3(v, addr+3, nt->table, 0);
sqlite3VdbeChangeP3(v, addr+6, pAll->z, pAll->n);
- if( nt->iDb==0 ){
- sqlite3ChangeCookie(db, v, 0);
+ if( nt->iDb!=0 ){
+ sqlite3ChangeCookie(db, v, nt->iDb);
}
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
sqlite3EndWriteOperation(pParse);
@@ -488,8 +488,8 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
sqlite3OpenMasterTable(v, pTrigger->iDb);
base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0);
- if( pTrigger->iDb==0 ){
- sqlite3ChangeCookie(db, v, 0);
+ if( pTrigger->iDb!=1 ){
+ sqlite3ChangeCookie(db, v, pTrigger->iDb);
}
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
sqlite3EndWriteOperation(pParse);
@@ -711,6 +711,7 @@ int sqlite3CodeRowTrigger(
){
Trigger * pTrigger;
TriggerStack * pTriggerStack;
+ u64 cookieMask = pParse->cookieMask;
assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER );
@@ -782,6 +783,7 @@ int sqlite3CodeRowTrigger(
pTrigger = pTrigger->pNext;
}
+ pParse->cookieMask = cookieMask;
return 0;
}
diff --git a/src/vacuum.c b/src/vacuum.c
index be47ee938..ff0a5b4fb 100644
--- a/src/vacuum.c
+++ b/src/vacuum.c
@@ -14,7 +14,7 @@
** Most of the code in this file may be omitted by defining the
** SQLITE_OMIT_VACUUM macro.
**
-** $Id: vacuum.c,v 1.18 2004/05/29 10:43:07 danielk1977 Exp $
+** $Id: vacuum.c,v 1.19 2004/05/31 08:26:49 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -96,11 +96,12 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite *db){
int nFilename; /* number of characters in zFilename[] */
char *zTemp = 0; /* a temporary file in same directory as zFilename */
int i; /* Loop counter */
+ Btree *pTemp;
char *zSql = 0;
sqlite3_stmt *pStmt = 0;
- if( db->flags & SQLITE_InTrans ){
+ if( !db->autoCommit ){
sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction",
(char*)0);
rc = SQLITE_ERROR;
@@ -189,20 +190,15 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite *db){
** opened for writing. This way, the SQL transaction used to create the
** temporary database never needs to be committed.
*/
-
- /* FIX ME: The above will be the case shortly. But for now, a transaction
- ** will have been started on the main database file by the 'BEGIN'.
- */
-/*
- rc = sqlite3BtreeBeginTrans(db->aDb[0].pBt);
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
-*/
-
- if( db->aDb[db->nDb-1].inTrans ){
- Btree *pTemp = db->aDb[db->nDb-1].pBt;
+ pTemp = db->aDb[db->nDb-1].pBt;
+ if( sqlite3BtreeIsInTrans(pTemp) ){
Btree *pMain = db->aDb[0].pBt;
u32 meta;
+ assert( 0==sqlite3BtreeIsInTrans(pMain) );
+ rc = sqlite3BtreeBeginTrans(db->aDb[0].pBt);
+ if( rc!=SQLITE_OK ) goto end_of_vacuum;
+
/* Copy Btree meta values 3 and 4. These correspond to SQL layer meta
** values 2 and 3, the default values of a couple of pragmas.
*/
@@ -216,13 +212,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite *db){
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = sqlite3BtreeCopyFile(pMain, pTemp);
-
- /* FIX ME: Remove the main btree from the transaction so that it is not
- ** rolled back. This won't be required once the new 'auto-commit'
- ** model is in place.
- */
rc = sqlite3BtreeCommit(pMain);
- db->aDb[0].inTrans = 0;
}
end_of_vacuum:
diff --git a/src/vdbe.c b/src/vdbe.c
index 5c20d830b..787b0eeff 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.350 2004/05/30 21:14:59 drh Exp $
+** $Id: vdbe.c,v 1.351 2004/05/31 08:26:49 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -2196,9 +2196,40 @@ case OP_MakeRecord: {
*/
case OP_Statement: {
int i = pOp->p1;
- if( i>=0 && i<db->nDb && db->aDb[i].pBt && db->aDb[i].inTrans==1 ){
- rc = sqlite3BtreeBeginStmt(db->aDb[i].pBt);
- if( rc==SQLITE_OK ) db->aDb[i].inTrans = 2;
+ Btree *pBt;
+ if( i>=0 && i<db->nDb && (pBt = db->aDb[i].pBt) && !(db->autoCommit) ){
+ assert( sqlite3BtreeIsInTrans(pBt) );
+ if( !sqlite3BtreeIsInStmt(pBt) ){
+ rc = sqlite3BtreeBeginStmt(pBt);
+ }
+ }
+ break;
+}
+
+/* Opcode: AutoCommit P1 P2 *
+**
+** Set the database auto-commit flag to P1 (1 or 0). If P2 is true, roll
+** back any currently active btree transactions.
+*/
+case OP_AutoCommit: {
+ u8 i = pOp->p1;
+ u8 rollback = pOp->p2;
+
+ assert( i==1 || i==0 );
+ assert( i==1 || rollback==0 );
+
+ if( i!=db->autoCommit ){
+ db->autoCommit = i;
+ if( pOp->p2 ){
+ sqlite3RollbackAll(db);
+ }
+ }else{
+ sqlite3SetString(&p->zErrMsg,
+ (!i)?"cannot start a transaction within a transaction":(
+ (rollback)?"cannot rollback - no transaction is active":
+ "cannot commit - no transaction is active"), 0);
+
+ rc = SQLITE_ERROR;
}
break;
}
@@ -2222,15 +2253,18 @@ case OP_Statement: {
case OP_Transaction: {
int busy = 1;
int i = pOp->p1;
+ Btree *pBt;
+
assert( i>=0 && i<db->nDb );
- if( db->aDb[i].inTrans ) break;
- while( db->aDb[i].pBt!=0 && busy ){
+ pBt = db->aDb[i].pBt;
+
+ if( sqlite3BtreeIsInTrans(pBt) ) break;
+ while( pBt && busy /* && !sqlite3BtreeIsInTrans(pBt) */ ){
rc = sqlite3BtreeBeginTrans(db->aDb[i].pBt);
switch( rc ){
case SQLITE_BUSY: {
if( db->xBusyCallback==0 ){
p->pc = pc;
- p->undoTransOnError = 1;
p->rc = SQLITE_BUSY;
p->pTos = pTos;
return SQLITE_BUSY;
@@ -2245,7 +2279,6 @@ case OP_Transaction: {
/* Fall thru into the next case */
}
case SQLITE_OK: {
- p->inTempTrans = 0;
busy = 0;
break;
}
@@ -2254,58 +2287,6 @@ case OP_Transaction: {
}
}
}
- db->aDb[i].inTrans = 1;
- p->undoTransOnError = 1;
- break;
-}
-
-/* Opcode: Commit * * *
-**
-** Cause all modifications to the database that have been made since the
-** last Transaction to actually take effect. No additional modifications
-** are allowed until another transaction is started. The Commit instruction
-** deletes the journal file and releases the write lock on the database.
-** A read lock continues to be held if there are still cursors open.
-*/
-case OP_Commit: {
- int i;
- if( db->xCommitCallback!=0 ){
- if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
- if( db->xCommitCallback(db->pCommitArg)!=0 ){
- rc = SQLITE_CONSTRAINT;
- }
- if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
- }
- for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
- if( db->aDb[i].inTrans ){
- rc = sqlite3BtreeCommit(db->aDb[i].pBt);
- db->aDb[i].inTrans = 0;
- }
- }
- if( rc==SQLITE_OK ){
- sqlite3CommitInternalChanges(db);
- }else{
- sqlite3RollbackAll(db);
- }
- break;
-}
-
-/* Opcode: Rollback P1 * *
-**
-** Cause all modifications to the database that have been made since the
-** last Transaction to be undone. The database is restored to its state
-** before the Transaction opcode was executed. No additional modifications
-** are allowed until another transaction is started.
-**
-** P1 is the index of the database file that is committed. An index of 0
-** is used for the main database and an index of 1 is used for the file used
-** to hold temporary tables.
-**
-** This instruction automatically closes all cursors and releases both
-** the read and write locks on the indicated database.
-*/
-case OP_Rollback: {
- sqlite3RollbackAll(db);
break;
}
@@ -3568,12 +3549,16 @@ case OP_IdxRecno: {
assert( pC->deferredMoveto==0 );
assert( pC->intKey==0 );
- rc = sqlite3VdbeIdxRowid(pCrsr, &rowid);
- if( rc!=SQLITE_OK ){
- goto abort_due_to_error;
+ if( pC->nullRow ){
+ pTos->flags = MEM_Null;
+ }else{
+ rc = sqlite3VdbeIdxRowid(pCrsr, &rowid);
+ if( rc!=SQLITE_OK ){
+ goto abort_due_to_error;
+ }
+ pTos->flags = MEM_Int;
+ pTos->i = rowid;
}
- pTos->flags = MEM_Int;
- pTos->i = rowid;
#if 0
/* Read the final 9 bytes of the key into buf[]. If the whole key is
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index d41dbdd3b..a7f0dbf75 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -307,7 +307,6 @@ struct Vdbe {
int rc; /* Value to return */
unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */
int errorAction; /* Recovery action to do in case of an error */
- int undoTransOnError; /* If error, either ROLLBACK or COMMIT */
int inTempTrans; /* True if temp database is transactioned */
int returnStack[100]; /* Return address stack for OP_Gosub & OP_Return */
int returnDepth; /* Next unused element in returnStack[] */
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index 682d9a63e..56388fd71 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -168,6 +168,10 @@ int sqlite3_step(sqlite3_stmt *pStmt){
p->rc = SQLITE_MISUSE;
return SQLITE_MISUSE;
}
+ if( p->pc<0 ){
+ db->activeVdbeCnt++;
+ p->pc = 0;
+ }
if( p->explain ){
rc = sqlite3VdbeList(p);
}else{
@@ -378,7 +382,7 @@ const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
*/
static int vdbeUnbind(Vdbe *p, int i){
Mem *pVar;
- if( p->magic!=VDBE_MAGIC_RUN || p->pc!=0 ){
+ if( p->magic!=VDBE_MAGIC_RUN || p->pc>=0 ){
sqlite3Error(p->db, SQLITE_MISUSE, 0);
return SQLITE_MISUSE;
}
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 55ced4b21..60e785361 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -659,12 +659,11 @@ void sqlite3VdbeMakeReady(
}
#endif
p->pTos = &p->aStack[-1];
- p->pc = 0;
+ p->pc = -1;
p->rc = SQLITE_OK;
p->uniqueCnt = 0;
p->returnDepth = 0;
p->errorAction = OE_Abort;
- p->undoTransOnError = 0;
p->popStack = 0;
p->explain |= isExplain;
p->magic = VDBE_MAGIC_RUN;
@@ -896,6 +895,32 @@ int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){
return rc;
}
+/*
+** This routine checks that the sqlite3.activeVdbeCnt count variable
+** matches the number of vdbe's in the list sqlite3.pVdbe that are
+** currently active. An assertion fails if the two counts do not match.
+**
+** This is a no-op if NDEBUG is defined.
+*/
+#ifndef NDEBUG
+static void checkActiveVdbeCnt(sqlite *db){
+ Vdbe *p;
+ int cnt = 0;
+
+ p = db->pVdbe;
+ while( p ){
+ if( (p->magic==VDBE_MAGIC_RUN && p->pc>=0) || p->magic==VDBE_MAGIC_HALT ){
+ cnt++;
+ }
+ p = p->pNext;
+ }
+
+ assert( cnt==db->activeVdbeCnt );
+}
+#else
+#define checkActiveVdbeCnt(x)
+#endif
+
/*
** Clean up a VDBE after execution but do not delete the VDBE just yet.
** Write any error messages into *pzErrMsg. Return the result code.
@@ -906,10 +931,13 @@ int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){
int sqlite3VdbeReset(Vdbe *p, char **pzErrMsg){
sqlite *db = p->db;
int i;
+ int (*xFunc)(Btree *pBt) = 0; /* Function to call on each btree backend */
+ int needXcommit = 0;
if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){
sqlite3SetString(pzErrMsg, sqlite3_error_string(SQLITE_MISUSE), (char*)0);
- sqlite3Error(p->db, SQLITE_MISUSE, sqlite3_error_string(SQLITE_MISUSE),0);
+ sqlite3Error(p->db, SQLITE_MISUSE, 0 ,0);
+ db->activeVdbeCnt--;
return SQLITE_MISUSE;
}
if( p->zErrMsg ){
@@ -922,48 +950,61 @@ int sqlite3VdbeReset(Vdbe *p, char **pzErrMsg){
p->zErrMsg = 0;
}else if( p->rc ){
sqlite3SetString(pzErrMsg, sqlite3_error_string(p->rc), (char*)0);
- sqlite3Error(p->db, p->rc, "%s", sqlite3_error_string(p->rc) , 0);
+ sqlite3Error(p->db, p->rc, 0);
}else{
sqlite3Error(p->db, SQLITE_OK, 0);
}
Cleanup(p);
- if( p->rc!=SQLITE_OK ){
- switch( p->errorAction ){
- case OE_Abort: {
- if( !p->undoTransOnError ){
- for(i=0; i<db->nDb; i++){
- if( db->aDb[i].pBt ){
- sqlite3BtreeRollbackStmt(db->aDb[i].pBt);
- }
- }
- break;
- }
- /* Fall through to ROLLBACK */
- }
- case OE_Rollback: {
- sqlite3RollbackAll(db);
- db->flags &= ~SQLITE_InTrans;
- db->onError = OE_Default;
- break;
- }
- default: {
- if( p->undoTransOnError ){
- sqlite3RollbackAll(db);
- db->flags &= ~SQLITE_InTrans;
- db->onError = OE_Default;
+
+ /* Figure out which function to call on the btree backends that
+ ** have active transactions.
+ */
+ checkActiveVdbeCnt(db);
+ if( db->autoCommit && db->activeVdbeCnt==1 ){
+ if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
+ xFunc = sqlite3BtreeCommit;
+ needXcommit = 1;
+ }else{
+ xFunc = sqlite3BtreeRollback;
+ }
+ }else{
+ if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
+ xFunc = sqlite3BtreeCommitStmt;
+ }else if( p->errorAction==OE_Abort ){
+ xFunc = sqlite3BtreeRollbackStmt;
+ }else{
+ xFunc = sqlite3BtreeRollback;
+ db->autoCommit = 1;
+ }
+ }
+
+ for(i=0; xFunc && i<db->nDb; i++){
+ Btree *pBt = db->aDb[i].pBt;
+ if( sqlite3BtreeIsInTrans(pBt) ){
+ int rc;
+ if( db->xCommitCallback && needXcommit ){
+ if( db->xCommitCallback(db->pCommitArg)!=0 ){
+ p->rc = SQLITE_CONSTRAINT;
+ sqlite3Error(db, SQLITE_CONSTRAINT, 0);
+ xFunc = sqlite3BtreeRollback;
}
- break;
+ needXcommit = 0;
}
+ rc = xFunc(pBt);
+ if( p->rc==SQLITE_OK ) p->rc = rc;
}
+ }
+
+
+ if( p->rc!=SQLITE_OK ){
sqlite3RollbackInternalChanges(db);
}
- for(i=0; i<db->nDb; i++){
- if( db->aDb[i].pBt && db->aDb[i].inTrans==2 ){
- sqlite3BtreeCommitStmt(db->aDb[i].pBt);
- db->aDb[i].inTrans = 1;
- }
+
+ if( (p->magic==VDBE_MAGIC_RUN && p->pc>=0) || p->magic==VDBE_MAGIC_HALT ){
+ db->activeVdbeCnt--;
}
- assert( p->pTos<&p->aStack[p->pc] || sqlite3_malloc_failed==1 );
+
+ assert( p->pTos<&p->aStack[p->pc<0?0:p->pc] || sqlite3_malloc_failed==1 );
#ifdef VDBE_PROFILE
{
FILE *out = fopen("vdbe_profile.out", "a");