mirror of
https://github.com/sqlite/sqlite.git
synced 2025-12-24 14:17:58 +03:00
Get the ABORT conflict resolution algorithm working. (CVS 362)
FossilOrigin-Name: 9be4d4c6f12056782966396dca0b8e2d384d0cf2
This commit is contained in:
64
src/btree.c
64
src/btree.c
@@ -9,7 +9,7 @@
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: btree.c,v 1.46 2002/01/04 03:09:29 drh Exp $
|
||||
** $Id: btree.c,v 1.47 2002/02/02 18:49:20 drh Exp $
|
||||
**
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** For a detailed discussion of BTrees, refer to
|
||||
@@ -302,7 +302,8 @@ struct Btree {
|
||||
Pager *pPager; /* The page cache */
|
||||
BtCursor *pCursor; /* A list of all open cursors */
|
||||
PageOne *page1; /* First page of the database */
|
||||
int inTrans; /* True if a transaction is in progress */
|
||||
u8 inTrans; /* True if a transaction is in progress */
|
||||
u8 inCkpt; /* True if there is a checkpoint on the transaction */
|
||||
Hash locks; /* Key: root page number. Data: lock count */
|
||||
};
|
||||
typedef Btree Bt;
|
||||
@@ -691,6 +692,7 @@ static void unlockBtreeIfUnused(Btree *pBt){
|
||||
sqlitepager_unref(pBt->page1);
|
||||
pBt->page1 = 0;
|
||||
pBt->inTrans = 0;
|
||||
pBt->inCkpt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -753,6 +755,7 @@ int sqliteBtreeBeginTrans(Btree *pBt){
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pBt->inTrans = 1;
|
||||
pBt->inCkpt = 0;
|
||||
}else{
|
||||
unlockBtreeIfUnused(pBt);
|
||||
}
|
||||
@@ -770,6 +773,7 @@ int sqliteBtreeCommit(Btree *pBt){
|
||||
if( pBt->inTrans==0 ) return SQLITE_ERROR;
|
||||
rc = sqlitepager_commit(pBt->pPager);
|
||||
pBt->inTrans = 0;
|
||||
pBt->inCkpt = 0;
|
||||
unlockBtreeIfUnused(pBt);
|
||||
return rc;
|
||||
}
|
||||
@@ -788,6 +792,7 @@ int sqliteBtreeRollback(Btree *pBt){
|
||||
BtCursor *pCur;
|
||||
if( pBt->inTrans==0 ) return SQLITE_OK;
|
||||
pBt->inTrans = 0;
|
||||
pBt->inCkpt = 0;
|
||||
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
|
||||
if( pCur->pPage ){
|
||||
sqlitepager_unref(pCur->pPage);
|
||||
@@ -799,6 +804,61 @@ int sqliteBtreeRollback(Btree *pBt){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the checkpoint for the current transaction. The checkpoint serves
|
||||
** as a sub-transaction that can be rolled back independently of the
|
||||
** main transaction. You must start a transaction before starting a
|
||||
** checkpoint. The checkpoint is ended automatically if the transaction
|
||||
** commits or rolls back.
|
||||
**
|
||||
** Only one checkpoint may be active at a time. It is an error to try
|
||||
** to start a new checkpoint if another checkpoint is already active.
|
||||
*/
|
||||
int sqliteBtreeBeginCkpt(Btree *pBt){
|
||||
int rc;
|
||||
if( !pBt->inTrans || pBt->inCkpt ) return SQLITE_ERROR;
|
||||
rc = sqlitepager_ckpt_begin(pBt->pPager);
|
||||
pBt->inCkpt = 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Commit a checkpoint to transaction currently in progress. If no
|
||||
** checkpoint is active, this is a no-op.
|
||||
*/
|
||||
int sqliteBtreeCommitCkpt(Btree *pBt){
|
||||
int rc;
|
||||
if( pBt->inCkpt ){
|
||||
rc = sqlitepager_ckpt_commit(pBt->pPager);
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Rollback the checkpoint to the current transaction. If there
|
||||
** is no active checkpoint or transaction, this routine is a no-op.
|
||||
**
|
||||
** All cursors will be invalided by this operation. Any attempt
|
||||
** to use a cursor that was open at the beginning of this operation
|
||||
** will result in an error.
|
||||
*/
|
||||
int sqliteBtreeRollbackCkpt(Btree *pBt){
|
||||
int rc;
|
||||
BtCursor *pCur;
|
||||
if( pBt->inCkpt==0 ) return SQLITE_OK;
|
||||
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
|
||||
if( pCur->pPage ){
|
||||
sqlitepager_unref(pCur->pPage);
|
||||
pCur->pPage = 0;
|
||||
}
|
||||
}
|
||||
rc = sqlitepager_ckpt_rollback(pBt->pPager);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new cursor for the BTree whose root is on the page
|
||||
** iTable. The act of acquiring a cursor gets a read lock on
|
||||
|
||||
@@ -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.19 2002/01/04 03:09:30 drh Exp $
|
||||
** @(#) $Id: btree.h,v 1.20 2002/02/02 18:49:20 drh Exp $
|
||||
*/
|
||||
#ifndef _BTREE_H_
|
||||
#define _BTREE_H_
|
||||
@@ -28,6 +28,9 @@ int sqliteBtreeSetCacheSize(Btree*, int);
|
||||
int sqliteBtreeBeginTrans(Btree*);
|
||||
int sqliteBtreeCommit(Btree*);
|
||||
int sqliteBtreeRollback(Btree*);
|
||||
int sqliteBtreeBeginCkpt(Btree*);
|
||||
int sqliteBtreeCommitCkpt(Btree*);
|
||||
int sqliteBtreeRollbackCkpt(Btree*);
|
||||
|
||||
int sqliteBtreeCreateTable(Btree*, int*);
|
||||
int sqliteBtreeCreateIndex(Btree*, int*);
|
||||
|
||||
36
src/build.c
36
src/build.c
@@ -25,7 +25,7 @@
|
||||
** ROLLBACK
|
||||
** PRAGMA
|
||||
**
|
||||
** $Id: build.c,v 1.70 2002/01/31 15:54:22 drh Exp $
|
||||
** $Id: build.c,v 1.71 2002/02/02 18:49:20 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -1338,7 +1338,7 @@ void sqliteCopy(
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v ){
|
||||
int openOp;
|
||||
sqliteBeginWriteOperation(pParse);
|
||||
sqliteBeginMultiWriteOperation(pParse);
|
||||
addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0);
|
||||
sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
|
||||
sqliteVdbeDequoteP3(v, addr);
|
||||
@@ -1493,23 +1493,43 @@ void sqliteRollbackTransaction(Parse *pParse){
|
||||
|
||||
/*
|
||||
** Generate VDBE code that prepares for doing an operation that
|
||||
** might change the database. If we are in the middle of a transaction,
|
||||
** then this sets a checkpoint. If we are not in a transaction, then
|
||||
** start a transaction.
|
||||
** might change the database. The operation will be atomic in the
|
||||
** sense that it will either do its changes completely or not at
|
||||
** all. So there is not need to set a checkpoint is a transaction
|
||||
** is already in effect.
|
||||
*/
|
||||
void sqliteBeginWriteOperation(Parse *pParse){
|
||||
Vdbe *v;
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ) return;
|
||||
if( pParse->db->flags & SQLITE_InTrans ){
|
||||
/* sqliteVdbeAddOp(v, OP_CheckPoint, 0, 0); */
|
||||
}else{
|
||||
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate VDBE code that prepares for doing an operation that
|
||||
** might change the database. The operation might not be atomic in
|
||||
** the sense that an error may be discovered and the operation might
|
||||
** abort after some changes have been made. If we are in the middle
|
||||
** of a transaction, then this sets a checkpoint. If we are not in
|
||||
** a transaction, then start a transaction.
|
||||
*/
|
||||
void sqliteBeginMultiWriteOperation(Parse *pParse){
|
||||
Vdbe *v;
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ) return;
|
||||
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_Checkpoint, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that concludes an operation that may have changed
|
||||
** the database. This is a companion function to BeginWriteOperation().
|
||||
|
||||
@@ -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.39 2002/01/31 15:54:22 drh Exp $
|
||||
** $Id: insert.c,v 1.40 2002/02/02 18:49:20 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -79,7 +79,11 @@ void sqliteInsert(
|
||||
*/
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ) goto insert_cleanup;
|
||||
sqliteBeginWriteOperation(pParse);
|
||||
if( pSelect ){
|
||||
sqliteBeginMultiWriteOperation(pParse);
|
||||
}else{
|
||||
sqliteBeginWriteOperation(pParse);
|
||||
}
|
||||
|
||||
/* Figure out how many columns of data are supplied. If the data
|
||||
** is coming from a SELECT statement, then this step has to generate
|
||||
|
||||
65
src/pager.c
65
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.37 2002/02/02 15:01:16 drh Exp $
|
||||
** @(#) $Id: pager.c,v 1.38 2002/02/02 18:49:20 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "pager.h"
|
||||
@@ -45,10 +45,6 @@
|
||||
** threads can be reading or writing while one
|
||||
** process is writing.
|
||||
**
|
||||
** SQLITE_CHECKPOINT The page cache is writing to the database and
|
||||
** preserving its changes so that it can back them
|
||||
** out later if need be.
|
||||
**
|
||||
** The page cache comes up in SQLITE_UNLOCK. The first time a
|
||||
** sqlite_page_get() occurs, the state transitions to SQLITE_READLOCK.
|
||||
** After all pages have been released using sqlite_page_unref(),
|
||||
@@ -59,20 +55,10 @@
|
||||
** be in SQLITE_READLOCK before it transitions to SQLITE_WRITELOCK.)
|
||||
** The sqlite_page_rollback() and sqlite_page_commit() functions
|
||||
** transition the state from SQLITE_WRITELOCK back to SQLITE_READLOCK.
|
||||
**
|
||||
** The sqlite_ckpt_begin() function moves the state from SQLITE_WRITELOCK
|
||||
** to SQLITE_CHECKPOINT. The state transitions back to SQLITE_WRITELOCK
|
||||
** on calls to sqlite_ckpt_commit() or sqlite_ckpt_rollback(). While
|
||||
** in SQLITE_CHECKPOINT, calls to sqlite_commit() or sqlite_rollback()
|
||||
** transition directly back to SQLITE_READLOCK.
|
||||
**
|
||||
** The code does unequality comparisons on these constants so the order
|
||||
** must be preserved.
|
||||
*/
|
||||
#define SQLITE_UNLOCK 0
|
||||
#define SQLITE_READLOCK 1
|
||||
#define SQLITE_WRITELOCK 2
|
||||
#define SQLITE_CHECKPOINT 3
|
||||
|
||||
|
||||
/*
|
||||
@@ -254,12 +240,12 @@ static int pager_unwritelock(Pager *pPager){
|
||||
int rc;
|
||||
PgHdr *pPg;
|
||||
if( pPager->state<SQLITE_WRITELOCK ) return SQLITE_OK;
|
||||
sqlitepager_ckpt_commit(pPager);
|
||||
sqliteOsClose(&pPager->jfd);
|
||||
pPager->journalOpen = 0;
|
||||
sqliteOsDelete(pPager->zJournal);
|
||||
rc = sqliteOsReadLock(&pPager->fd);
|
||||
assert( rc==SQLITE_OK );
|
||||
sqliteFree( pPager->aInCkpt );
|
||||
sqliteFree( pPager->aInJournal );
|
||||
pPager->aInJournal = 0;
|
||||
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
|
||||
@@ -279,7 +265,7 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd){
|
||||
PgHdr *pPg; /* An existing page in the cache */
|
||||
PageRecord pgRec;
|
||||
|
||||
rc = sqliteOsRead(&pPager->jfd, &pgRec, sizeof(pgRec));
|
||||
rc = sqliteOsRead(jfd, &pgRec, sizeof(pgRec));
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
/* Sanity checking on the page */
|
||||
@@ -383,8 +369,9 @@ end_playback:
|
||||
** This is similar to playing back the transaction journal but with
|
||||
** a few extra twists.
|
||||
**
|
||||
** (1) The original size of the database file is stored in
|
||||
** pPager->ckptSize, not in the journal file itself.
|
||||
** (1) The number of pages in the database file at the start of
|
||||
** the checkpoint is stored in pPager->ckptSize, not in the
|
||||
** journal file itself.
|
||||
**
|
||||
** (2) In addition to playing back the checkpoint journal, also
|
||||
** playback all pages of the transaction journal beginning
|
||||
@@ -397,7 +384,7 @@ static int pager_ckpt_playback(Pager *pPager){
|
||||
|
||||
/* Truncate the database back to its original size.
|
||||
*/
|
||||
rc = sqliteOsTruncate(&pPager->fd, pPager->ckptSize);
|
||||
rc = sqliteOsTruncate(&pPager->fd, pPager->ckptSize*SQLITE_PAGE_SIZE);
|
||||
pPager->dbSize = pPager->ckptSize;
|
||||
|
||||
/* Figure out how many records are in the checkpoint journal.
|
||||
@@ -437,14 +424,9 @@ static int pager_ckpt_playback(Pager *pPager){
|
||||
|
||||
|
||||
end_ckpt_playback:
|
||||
sqliteOsClose(&pPager->cpfd);
|
||||
pPager->ckptOpen = 0;
|
||||
if( rc!=SQLITE_OK ){
|
||||
pager_unwritelock(pPager);
|
||||
pPager->errMask |= PAGER_ERR_CORRUPT;
|
||||
rc = SQLITE_CORRUPT;
|
||||
}else{
|
||||
rc = pager_unwritelock(pPager);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -595,7 +577,6 @@ int sqlitepager_pagecount(Pager *pPager){
|
||||
int sqlitepager_close(Pager *pPager){
|
||||
PgHdr *pPg, *pNext;
|
||||
switch( pPager->state ){
|
||||
case SQLITE_CHECKPOINT:
|
||||
case SQLITE_WRITELOCK: {
|
||||
sqlitepager_rollback(pPager);
|
||||
sqliteOsUnlock(&pPager->fd);
|
||||
@@ -883,7 +864,7 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
||||
}else{
|
||||
pPg->inJournal = 0;
|
||||
}
|
||||
if( pPager->aInCkpt && (int)pgno*SQLITE_PAGE_SIZE<=pPager->ckptSize ){
|
||||
if( pPager->aInCkpt && (int)pgno<=pPager->ckptSize ){
|
||||
pPg->inCkpt = (pPager->aInCkpt[pgno/8] & (1<<(pgno&7)))!=0;
|
||||
}else{
|
||||
pPg->inCkpt = 0;
|
||||
@@ -1111,8 +1092,7 @@ int sqlitepager_write(void *pData){
|
||||
/* If the checkpoint journal is open and the page is not in it,
|
||||
** then write the current page to the checkpoint journal.
|
||||
*/
|
||||
if( pPager->ckptOpen && !pPg->inCkpt
|
||||
&& (int)pPg->pgno*SQLITE_PAGE_SIZE < pPager->ckptSize ){
|
||||
if( pPager->ckptOpen && !pPg->inCkpt && (int)pPg->pgno<=pPager->ckptSize ){
|
||||
assert( pPg->inJournal );
|
||||
rc = sqliteOsWrite(&pPager->cpfd, &pPg->pgno, sizeof(Pgno));
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -1268,7 +1248,7 @@ int sqlitepager_ckpt_begin(Pager *pPager){
|
||||
}
|
||||
rc = sqliteOsFileSize(&pPager->jfd, &pPager->ckptJSize);
|
||||
if( rc ) goto ckpt_begin_failed;
|
||||
pPager->ckptSize = pPager->dbSize * SQLITE_PAGE_SIZE;
|
||||
pPager->ckptSize = pPager->dbSize;
|
||||
rc = sqlitepager_opentemp(zTemp, &pPager->cpfd);
|
||||
if( rc ) goto ckpt_begin_failed;
|
||||
pPager->ckptOpen = 1;
|
||||
@@ -1286,10 +1266,16 @@ ckpt_begin_failed:
|
||||
** Commit a checkpoint.
|
||||
*/
|
||||
int sqlitepager_ckpt_commit(Pager *pPager){
|
||||
assert( pPager->ckptOpen );
|
||||
sqliteOsClose(&pPager->cpfd);
|
||||
sqliteFree(pPager->aInCkpt);
|
||||
pPager->ckptOpen = 0;
|
||||
if( pPager->ckptOpen ){
|
||||
PgHdr *pPg;
|
||||
sqliteOsClose(&pPager->cpfd);
|
||||
pPager->ckptOpen = 0;
|
||||
sqliteFree( pPager->aInCkpt );
|
||||
pPager->aInCkpt = 0;
|
||||
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
|
||||
pPg->inCkpt = 0;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -1298,11 +1284,12 @@ int sqlitepager_ckpt_commit(Pager *pPager){
|
||||
*/
|
||||
int sqlitepager_ckpt_rollback(Pager *pPager){
|
||||
int rc;
|
||||
assert( pPager->ckptOpen );
|
||||
rc = pager_ckpt_playback(pPager);
|
||||
sqliteOsClose(&pPager->cpfd);
|
||||
sqliteFree(pPager->aInCkpt);
|
||||
pPager->ckptOpen = 0;
|
||||
if( pPager->ckptOpen ){
|
||||
rc = pager_ckpt_playback(pPager);
|
||||
sqlitepager_ckpt_commit(pPager);
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.83 2002/01/31 15:54:22 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.84 2002/02/02 18:49:21 drh Exp $
|
||||
*/
|
||||
#include "sqlite.h"
|
||||
#include "hash.h"
|
||||
@@ -565,4 +565,5 @@ void sqliteGenerateRowIndexDelete(Vdbe*, Table*, int, char*);
|
||||
void sqliteGenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);
|
||||
void sqliteCompleteInsertion(Parse*, Table*, int, char*, int, int);
|
||||
void sqliteBeginWriteOperation(Parse*);
|
||||
void sqliteBeginMultiWriteOperation(Parse*);
|
||||
void sqliteEndWriteOperation(Parse*);
|
||||
|
||||
@@ -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.32 2002/01/31 15:54:22 drh Exp $
|
||||
** $Id: update.c,v 1.33 2002/02/02 18:49:21 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -161,7 +161,7 @@ void sqliteUpdate(
|
||||
*/
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ) goto update_cleanup;
|
||||
sqliteBeginWriteOperation(pParse);
|
||||
sqliteBeginMultiWriteOperation(pParse);
|
||||
|
||||
/* Begin the database scan
|
||||
*/
|
||||
|
||||
133
src/vdbe.c
133
src/vdbe.c
@@ -30,7 +30,7 @@
|
||||
** But other routines are also provided to help in building up
|
||||
** a program instruction by instruction.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.113 2002/01/31 15:54:22 drh Exp $
|
||||
** $Id: vdbe.c,v 1.114 2002/02/02 18:49:21 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -860,35 +860,35 @@ void sqliteVdbeDelete(Vdbe *p){
|
||||
** this array, then copy and paste it into this file, if you want.
|
||||
*/
|
||||
static char *zOpName[] = { 0,
|
||||
"Transaction", "Commit", "Rollback", "ReadCookie",
|
||||
"SetCookie", "VerifyCookie", "Open", "OpenTemp",
|
||||
"OpenWrite", "OpenAux", "OpenWrAux", "Close",
|
||||
"MoveTo", "NewRecno", "PutIntKey", "PutStrKey",
|
||||
"Distinct", "Found", "NotFound", "IsUnique",
|
||||
"NotExists", "Delete", "Column", "KeyAsData",
|
||||
"Recno", "FullKey", "Rewind", "Next",
|
||||
"Destroy", "Clear", "CreateIndex", "CreateTable",
|
||||
"Reorganize", "IdxPut", "IdxDelete", "IdxRecno",
|
||||
"IdxGT", "IdxGE", "MemLoad", "MemStore",
|
||||
"ListWrite", "ListRewind", "ListRead", "ListReset",
|
||||
"SortPut", "SortMakeRec", "SortMakeKey", "Sort",
|
||||
"SortNext", "SortCallback", "SortReset", "FileOpen",
|
||||
"FileRead", "FileColumn", "AggReset", "AggFocus",
|
||||
"AggIncr", "AggNext", "AggSet", "AggGet",
|
||||
"SetInsert", "SetFound", "SetNotFound", "MakeRecord",
|
||||
"MakeKey", "MakeIdxKey", "IncrKey", "Goto",
|
||||
"If", "Halt", "ColumnCount", "ColumnName",
|
||||
"Callback", "NullCallback", "Integer", "String",
|
||||
"Pop", "Dup", "Pull", "Push",
|
||||
"MustBeInt", "Add", "AddImm", "Subtract",
|
||||
"Multiply", "Divide", "Remainder", "BitAnd",
|
||||
"BitOr", "BitNot", "ShiftLeft", "ShiftRight",
|
||||
"AbsValue", "Precision", "Min", "Max",
|
||||
"Like", "Glob", "Eq", "Ne",
|
||||
"Lt", "Le", "Gt", "Ge",
|
||||
"IsNull", "NotNull", "Negative", "And",
|
||||
"Or", "Not", "Concat", "Noop",
|
||||
"Strlen", "Substr", "Limit",
|
||||
"Transaction", "Checkpoint", "Commit", "Rollback",
|
||||
"ReadCookie", "SetCookie", "VerifyCookie", "Open",
|
||||
"OpenTemp", "OpenWrite", "OpenAux", "OpenWrAux",
|
||||
"Close", "MoveTo", "NewRecno", "PutIntKey",
|
||||
"PutStrKey", "Distinct", "Found", "NotFound",
|
||||
"IsUnique", "NotExists", "Delete", "Column",
|
||||
"KeyAsData", "Recno", "FullKey", "Rewind",
|
||||
"Next", "Destroy", "Clear", "CreateIndex",
|
||||
"CreateTable", "Reorganize", "IdxPut", "IdxDelete",
|
||||
"IdxRecno", "IdxGT", "IdxGE", "MemLoad",
|
||||
"MemStore", "ListWrite", "ListRewind", "ListRead",
|
||||
"ListReset", "SortPut", "SortMakeRec", "SortMakeKey",
|
||||
"Sort", "SortNext", "SortCallback", "SortReset",
|
||||
"FileOpen", "FileRead", "FileColumn", "AggReset",
|
||||
"AggFocus", "AggIncr", "AggNext", "AggSet",
|
||||
"AggGet", "SetInsert", "SetFound", "SetNotFound",
|
||||
"MakeRecord", "MakeKey", "MakeIdxKey", "IncrKey",
|
||||
"Goto", "If", "Halt", "ColumnCount",
|
||||
"ColumnName", "Callback", "NullCallback", "Integer",
|
||||
"String", "Pop", "Dup", "Pull",
|
||||
"Push", "MustBeInt", "Add", "AddImm",
|
||||
"Subtract", "Multiply", "Divide", "Remainder",
|
||||
"BitAnd", "BitOr", "BitNot", "ShiftLeft",
|
||||
"ShiftRight", "AbsValue", "Precision", "Min",
|
||||
"Max", "Like", "Glob", "Eq",
|
||||
"Ne", "Lt", "Le", "Gt",
|
||||
"Ge", "IsNull", "NotNull", "Negative",
|
||||
"And", "Or", "Not", "Concat",
|
||||
"Noop", "Strlen", "Substr", "Limit",
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1072,8 +1072,9 @@ int sqliteVdbeExec(
|
||||
sqlite *db = p->db; /* The database */
|
||||
char **zStack; /* Text stack */
|
||||
Stack *aStack; /* Additional stack information */
|
||||
int rollbackOnError = 1; /* Do a ROLLBACK if an error is encountered */
|
||||
char zBuf[100]; /* Space to sprintf() an integer */
|
||||
int errorAction = OE_Abort; /* Recovery action to do in case of an error */
|
||||
int undoTransOnError = 0; /* If error, either ROLLBACK or COMMIT */
|
||||
char zBuf[100]; /* Space to sprintf() an integer */
|
||||
|
||||
|
||||
/* No instruction ever pushes more than a single element onto the
|
||||
@@ -1172,7 +1173,7 @@ case OP_Goto: {
|
||||
case OP_Halt: {
|
||||
if( pOp->p1!=SQLITE_OK ){
|
||||
rc = pOp->p1;
|
||||
rollbackOnError = pOp->p2!=OE_Fail;
|
||||
errorAction = pOp->p2;
|
||||
goto abort_due_to_error;
|
||||
}else{
|
||||
pc = p->nOp-1;
|
||||
@@ -2319,18 +2320,32 @@ case OP_IncrKey: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Checkpoint * * *
|
||||
**
|
||||
** Begin a checkpoint. A checkpoint is the beginning of a operation that
|
||||
** is part of a larger transaction but which might need to be rolled back
|
||||
** itself without effecting the containing transaction. A checkpoint will
|
||||
** be automatically committed or rollback when the VDBE halts.
|
||||
*/
|
||||
case OP_Checkpoint: {
|
||||
rc = sqliteBtreeBeginCkpt(pBt);
|
||||
if( rc==SQLITE_OK && db->pBeTemp ){
|
||||
rc = sqliteBtreeBeginCkpt(pBt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Transaction * * *
|
||||
**
|
||||
** Begin a transaction. The transaction ends when a Commit or Rollback
|
||||
** opcode is encountered or whenever there is an execution error that causes
|
||||
** a script to abort. A transaction is not ended by a Halt.
|
||||
** opcode is encountered. Depending on the ON CONFLICT setting, the
|
||||
** transaction might also be rolled back if an error is encountered.
|
||||
**
|
||||
** A write lock is obtained on the database file when a transaction is
|
||||
** started. No other process can read or write the file while the
|
||||
** transaction is underway. Starting a transaction also creates a
|
||||
** rollback journal.
|
||||
** A transaction must be started before any changes can be made to the
|
||||
** database.
|
||||
** rollback journal. A transaction must be started before any changes
|
||||
** can be made to the database.
|
||||
*/
|
||||
case OP_Transaction: {
|
||||
int busy = 0;
|
||||
@@ -2359,6 +2374,7 @@ case OP_Transaction: {
|
||||
}
|
||||
}
|
||||
}while( busy );
|
||||
undoTransOnError = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4466,14 +4482,39 @@ default: {
|
||||
|
||||
cleanup:
|
||||
Cleanup(p);
|
||||
if( rc!=SQLITE_OK && rollbackOnError ){
|
||||
closeAllCursors(p);
|
||||
sqliteBtreeRollback(pBt);
|
||||
if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp);
|
||||
sqliteRollbackInternalChanges(db);
|
||||
db->flags &= ~SQLITE_InTrans;
|
||||
db->onError = OE_Default;
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
switch( errorAction ){
|
||||
case OE_Abort: {
|
||||
if( !undoTransOnError ){
|
||||
sqliteBtreeRollbackCkpt(pBt);
|
||||
if( db->pBeTemp ) sqliteBtreeRollbackCkpt(db->pBeTemp);
|
||||
break;
|
||||
}
|
||||
/* Fall through to ROLLBACK */
|
||||
}
|
||||
case OE_Rollback: {
|
||||
sqliteBtreeRollback(pBt);
|
||||
if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp);
|
||||
sqliteRollbackInternalChanges(db);
|
||||
db->flags &= ~SQLITE_InTrans;
|
||||
db->onError = OE_Default;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if( undoTransOnError ){
|
||||
sqliteBtreeCommit(pBt);
|
||||
if( db->pBeTemp ) sqliteBtreeCommit(db->pBeTemp);
|
||||
sqliteCommitInternalChanges(db);
|
||||
db->flags &= ~SQLITE_InTrans;
|
||||
db->onError = OE_Default;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
sqliteBtreeCommitCkpt(pBt);
|
||||
if( db->pBeTemp ) sqliteBtreeCommitCkpt(db->pBeTemp);
|
||||
}
|
||||
return rc;
|
||||
|
||||
/* Jump to here if a malloc() fails. It's hard to get a malloc()
|
||||
|
||||
233
src/vdbe.h
233
src/vdbe.h
@@ -15,7 +15,7 @@
|
||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||
** simple program to access and modify the underlying database.
|
||||
**
|
||||
** $Id: vdbe.h,v 1.39 2002/01/29 18:41:25 drh Exp $
|
||||
** $Id: vdbe.h,v 1.40 2002/02/02 18:49:21 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_VDBE_H_
|
||||
#define _SQLITE_VDBE_H_
|
||||
@@ -69,139 +69,140 @@ typedef struct VdbeOp VdbeOp;
|
||||
** can be used to renumber these opcodes when new opcodes are inserted.
|
||||
*/
|
||||
#define OP_Transaction 1
|
||||
#define OP_Commit 2
|
||||
#define OP_Rollback 3
|
||||
#define OP_Checkpoint 2
|
||||
#define OP_Commit 3
|
||||
#define OP_Rollback 4
|
||||
|
||||
#define OP_ReadCookie 4
|
||||
#define OP_SetCookie 5
|
||||
#define OP_VerifyCookie 6
|
||||
#define OP_ReadCookie 5
|
||||
#define OP_SetCookie 6
|
||||
#define OP_VerifyCookie 7
|
||||
|
||||
#define OP_Open 7
|
||||
#define OP_OpenTemp 8
|
||||
#define OP_OpenWrite 9
|
||||
#define OP_OpenAux 10
|
||||
#define OP_OpenWrAux 11
|
||||
#define OP_Close 12
|
||||
#define OP_MoveTo 13
|
||||
#define OP_NewRecno 14
|
||||
#define OP_PutIntKey 15
|
||||
#define OP_PutStrKey 16
|
||||
#define OP_Distinct 17
|
||||
#define OP_Found 18
|
||||
#define OP_NotFound 19
|
||||
#define OP_IsUnique 20
|
||||
#define OP_NotExists 21
|
||||
#define OP_Delete 22
|
||||
#define OP_Column 23
|
||||
#define OP_KeyAsData 24
|
||||
#define OP_Recno 25
|
||||
#define OP_FullKey 26
|
||||
#define OP_Rewind 27
|
||||
#define OP_Next 28
|
||||
#define OP_Open 8
|
||||
#define OP_OpenTemp 9
|
||||
#define OP_OpenWrite 10
|
||||
#define OP_OpenAux 11
|
||||
#define OP_OpenWrAux 12
|
||||
#define OP_Close 13
|
||||
#define OP_MoveTo 14
|
||||
#define OP_NewRecno 15
|
||||
#define OP_PutIntKey 16
|
||||
#define OP_PutStrKey 17
|
||||
#define OP_Distinct 18
|
||||
#define OP_Found 19
|
||||
#define OP_NotFound 20
|
||||
#define OP_IsUnique 21
|
||||
#define OP_NotExists 22
|
||||
#define OP_Delete 23
|
||||
#define OP_Column 24
|
||||
#define OP_KeyAsData 25
|
||||
#define OP_Recno 26
|
||||
#define OP_FullKey 27
|
||||
#define OP_Rewind 28
|
||||
#define OP_Next 29
|
||||
|
||||
#define OP_Destroy 29
|
||||
#define OP_Clear 30
|
||||
#define OP_CreateIndex 31
|
||||
#define OP_CreateTable 32
|
||||
#define OP_Reorganize 33
|
||||
#define OP_Destroy 30
|
||||
#define OP_Clear 31
|
||||
#define OP_CreateIndex 32
|
||||
#define OP_CreateTable 33
|
||||
#define OP_Reorganize 34
|
||||
|
||||
#define OP_IdxPut 34
|
||||
#define OP_IdxDelete 35
|
||||
#define OP_IdxRecno 36
|
||||
#define OP_IdxGT 37
|
||||
#define OP_IdxGE 38
|
||||
#define OP_IdxPut 35
|
||||
#define OP_IdxDelete 36
|
||||
#define OP_IdxRecno 37
|
||||
#define OP_IdxGT 38
|
||||
#define OP_IdxGE 39
|
||||
|
||||
#define OP_MemLoad 39
|
||||
#define OP_MemStore 40
|
||||
#define OP_MemLoad 40
|
||||
#define OP_MemStore 41
|
||||
|
||||
#define OP_ListWrite 41
|
||||
#define OP_ListRewind 42
|
||||
#define OP_ListRead 43
|
||||
#define OP_ListReset 44
|
||||
#define OP_ListWrite 42
|
||||
#define OP_ListRewind 43
|
||||
#define OP_ListRead 44
|
||||
#define OP_ListReset 45
|
||||
|
||||
#define OP_SortPut 45
|
||||
#define OP_SortMakeRec 46
|
||||
#define OP_SortMakeKey 47
|
||||
#define OP_Sort 48
|
||||
#define OP_SortNext 49
|
||||
#define OP_SortCallback 50
|
||||
#define OP_SortReset 51
|
||||
#define OP_SortPut 46
|
||||
#define OP_SortMakeRec 47
|
||||
#define OP_SortMakeKey 48
|
||||
#define OP_Sort 49
|
||||
#define OP_SortNext 50
|
||||
#define OP_SortCallback 51
|
||||
#define OP_SortReset 52
|
||||
|
||||
#define OP_FileOpen 52
|
||||
#define OP_FileRead 53
|
||||
#define OP_FileColumn 54
|
||||
#define OP_FileOpen 53
|
||||
#define OP_FileRead 54
|
||||
#define OP_FileColumn 55
|
||||
|
||||
#define OP_AggReset 55
|
||||
#define OP_AggFocus 56
|
||||
#define OP_AggIncr 57
|
||||
#define OP_AggNext 58
|
||||
#define OP_AggSet 59
|
||||
#define OP_AggGet 60
|
||||
#define OP_AggReset 56
|
||||
#define OP_AggFocus 57
|
||||
#define OP_AggIncr 58
|
||||
#define OP_AggNext 59
|
||||
#define OP_AggSet 60
|
||||
#define OP_AggGet 61
|
||||
|
||||
#define OP_SetInsert 61
|
||||
#define OP_SetFound 62
|
||||
#define OP_SetNotFound 63
|
||||
#define OP_SetInsert 62
|
||||
#define OP_SetFound 63
|
||||
#define OP_SetNotFound 64
|
||||
|
||||
#define OP_MakeRecord 64
|
||||
#define OP_MakeKey 65
|
||||
#define OP_MakeIdxKey 66
|
||||
#define OP_IncrKey 67
|
||||
#define OP_MakeRecord 65
|
||||
#define OP_MakeKey 66
|
||||
#define OP_MakeIdxKey 67
|
||||
#define OP_IncrKey 68
|
||||
|
||||
#define OP_Goto 68
|
||||
#define OP_If 69
|
||||
#define OP_Halt 70
|
||||
#define OP_Goto 69
|
||||
#define OP_If 70
|
||||
#define OP_Halt 71
|
||||
|
||||
#define OP_ColumnCount 71
|
||||
#define OP_ColumnName 72
|
||||
#define OP_Callback 73
|
||||
#define OP_NullCallback 74
|
||||
#define OP_ColumnCount 72
|
||||
#define OP_ColumnName 73
|
||||
#define OP_Callback 74
|
||||
#define OP_NullCallback 75
|
||||
|
||||
#define OP_Integer 75
|
||||
#define OP_String 76
|
||||
#define OP_Pop 77
|
||||
#define OP_Dup 78
|
||||
#define OP_Pull 79
|
||||
#define OP_Push 80
|
||||
#define OP_MustBeInt 81
|
||||
#define OP_Integer 76
|
||||
#define OP_String 77
|
||||
#define OP_Pop 78
|
||||
#define OP_Dup 79
|
||||
#define OP_Pull 80
|
||||
#define OP_Push 81
|
||||
#define OP_MustBeInt 82
|
||||
|
||||
#define OP_Add 82
|
||||
#define OP_AddImm 83
|
||||
#define OP_Subtract 84
|
||||
#define OP_Multiply 85
|
||||
#define OP_Divide 86
|
||||
#define OP_Remainder 87
|
||||
#define OP_BitAnd 88
|
||||
#define OP_BitOr 89
|
||||
#define OP_BitNot 90
|
||||
#define OP_ShiftLeft 91
|
||||
#define OP_ShiftRight 92
|
||||
#define OP_AbsValue 93
|
||||
#define OP_Precision 94
|
||||
#define OP_Min 95
|
||||
#define OP_Max 96
|
||||
#define OP_Like 97
|
||||
#define OP_Glob 98
|
||||
#define OP_Eq 99
|
||||
#define OP_Ne 100
|
||||
#define OP_Lt 101
|
||||
#define OP_Le 102
|
||||
#define OP_Gt 103
|
||||
#define OP_Ge 104
|
||||
#define OP_IsNull 105
|
||||
#define OP_NotNull 106
|
||||
#define OP_Negative 107
|
||||
#define OP_And 108
|
||||
#define OP_Or 109
|
||||
#define OP_Not 110
|
||||
#define OP_Concat 111
|
||||
#define OP_Noop 112
|
||||
#define OP_Add 83
|
||||
#define OP_AddImm 84
|
||||
#define OP_Subtract 85
|
||||
#define OP_Multiply 86
|
||||
#define OP_Divide 87
|
||||
#define OP_Remainder 88
|
||||
#define OP_BitAnd 89
|
||||
#define OP_BitOr 90
|
||||
#define OP_BitNot 91
|
||||
#define OP_ShiftLeft 92
|
||||
#define OP_ShiftRight 93
|
||||
#define OP_AbsValue 94
|
||||
#define OP_Precision 95
|
||||
#define OP_Min 96
|
||||
#define OP_Max 97
|
||||
#define OP_Like 98
|
||||
#define OP_Glob 99
|
||||
#define OP_Eq 100
|
||||
#define OP_Ne 101
|
||||
#define OP_Lt 102
|
||||
#define OP_Le 103
|
||||
#define OP_Gt 104
|
||||
#define OP_Ge 105
|
||||
#define OP_IsNull 106
|
||||
#define OP_NotNull 107
|
||||
#define OP_Negative 108
|
||||
#define OP_And 109
|
||||
#define OP_Or 110
|
||||
#define OP_Not 111
|
||||
#define OP_Concat 112
|
||||
#define OP_Noop 113
|
||||
|
||||
#define OP_Strlen 113
|
||||
#define OP_Substr 114
|
||||
#define OP_Strlen 114
|
||||
#define OP_Substr 115
|
||||
|
||||
#define OP_Limit 115
|
||||
#define OP_Limit 116
|
||||
|
||||
#define OP_MAX 115
|
||||
#define OP_MAX 116
|
||||
|
||||
/*
|
||||
** Prototypes for the VDBE interface. See comments on the implementation
|
||||
|
||||
Reference in New Issue
Block a user