mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Fixes to the locking and rollback behavior. (CVS 261)
FossilOrigin-Name: 337b3d3b2a903328d9744c111979909a284b8348
This commit is contained in:
82
src/btree.c
82
src/btree.c
@ -9,7 +9,7 @@
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: btree.c,v 1.29 2001/09/16 00:13:26 drh Exp $
|
||||
** $Id: btree.c,v 1.30 2001/09/23 02:35:53 drh Exp $
|
||||
**
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** For a detailed discussion of BTrees, refer to
|
||||
@ -312,6 +312,7 @@ struct Btree {
|
||||
BtCursor *pCursor; /* A list of all open cursors */
|
||||
PageOne *page1; /* First page of the database */
|
||||
int inTrans; /* True if a transaction is in progress */
|
||||
Hash locks; /* Key: root page number. Data: lock count */
|
||||
};
|
||||
typedef Btree Bt;
|
||||
|
||||
@ -326,6 +327,7 @@ struct BtCursor {
|
||||
Pgno pgnoRoot; /* The root page of this tree */
|
||||
MemPage *pPage; /* Page that contains the entry */
|
||||
int idx; /* Index of the entry in pPage->apCell[] */
|
||||
u8 wrFlag; /* True if writable */
|
||||
u8 bSkipNext; /* sqliteBtreeNext() is no-op if true */
|
||||
u8 iMatch; /* compare result from last sqliteBtreeMoveto() */
|
||||
};
|
||||
@ -619,6 +621,7 @@ int sqliteBtreeOpen(
|
||||
sqlitepager_set_destructor(pBt->pPager, pageDestructor);
|
||||
pBt->pCursor = 0;
|
||||
pBt->page1 = 0;
|
||||
sqliteHashInit(&pBt->locks, SQLITE_HASH_INT, 0);
|
||||
*ppBtree = pBt;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@ -631,6 +634,7 @@ int sqliteBtreeClose(Btree *pBt){
|
||||
sqliteBtreeCloseCursor(pBt->pCursor);
|
||||
}
|
||||
sqlitepager_close(pBt->pPager);
|
||||
sqliteHashClear(&pBt->locks);
|
||||
sqliteFree(pBt);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@ -771,17 +775,25 @@ int sqliteBtreeCommit(Btree *pBt){
|
||||
}
|
||||
|
||||
/*
|
||||
** Rollback the transaction in progress. All cursors must be
|
||||
** closed before this routine is called.
|
||||
** Rollback the transaction in progress. 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.
|
||||
**
|
||||
** This will release the write lock on the database file. If there
|
||||
** are no active cursors, it also releases the read lock.
|
||||
*/
|
||||
int sqliteBtreeRollback(Btree *pBt){
|
||||
int rc;
|
||||
if( pBt->pCursor!=0 ) return SQLITE_ERROR;
|
||||
BtCursor *pCur;
|
||||
if( pBt->inTrans==0 ) return SQLITE_OK;
|
||||
pBt->inTrans = 0;
|
||||
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
|
||||
if( pCur->pPage ){
|
||||
sqlitepager_unref(pCur->pPage);
|
||||
pCur->pPage = 0;
|
||||
}
|
||||
}
|
||||
rc = sqlitepager_rollback(pBt->pPager);
|
||||
unlockBtreeIfUnused(pBt);
|
||||
return rc;
|
||||
@ -792,9 +804,11 @@ int sqliteBtreeRollback(Btree *pBt){
|
||||
** iTable. The act of acquiring a cursor gets a read lock on
|
||||
** the database file.
|
||||
*/
|
||||
int sqliteBtreeCursor(Btree *pBt, int iTable, BtCursor **ppCur){
|
||||
int sqliteBtreeCursor(Btree *pBt, int iTable, int wrFlag, BtCursor **ppCur){
|
||||
int rc;
|
||||
BtCursor *pCur;
|
||||
int nLock;
|
||||
|
||||
if( pBt->page1==0 ){
|
||||
rc = lockBtree(pBt);
|
||||
if( rc!=SQLITE_OK ){
|
||||
@ -816,7 +830,15 @@ int sqliteBtreeCursor(Btree *pBt, int iTable, BtCursor **ppCur){
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto create_cursor_exception;
|
||||
}
|
||||
nLock = (int)sqliteHashFind(&pBt->locks, 0, iTable);
|
||||
if( nLock<0 || (nLock>0 && wrFlag) ){
|
||||
rc = SQLITE_LOCKED;
|
||||
goto create_cursor_exception;
|
||||
}
|
||||
nLock = wrFlag ? -1 : nLock+1;
|
||||
sqliteHashInsert(&pBt->locks, 0, iTable, (void*)nLock);
|
||||
pCur->pBt = pBt;
|
||||
pCur->wrFlag = wrFlag;
|
||||
pCur->idx = 0;
|
||||
pCur->pNext = pBt->pCursor;
|
||||
if( pCur->pNext ){
|
||||
@ -842,6 +864,7 @@ create_cursor_exception:
|
||||
** when the last cursor is closed.
|
||||
*/
|
||||
int sqliteBtreeCloseCursor(BtCursor *pCur){
|
||||
int nLock;
|
||||
Btree *pBt = pCur->pBt;
|
||||
if( pCur->pPrev ){
|
||||
pCur->pPrev->pNext = pCur->pNext;
|
||||
@ -851,8 +874,14 @@ int sqliteBtreeCloseCursor(BtCursor *pCur){
|
||||
if( pCur->pNext ){
|
||||
pCur->pNext->pPrev = pCur->pPrev;
|
||||
}
|
||||
sqlitepager_unref(pCur->pPage);
|
||||
if( pCur->pPage ){
|
||||
sqlitepager_unref(pCur->pPage);
|
||||
}
|
||||
unlockBtreeIfUnused(pBt);
|
||||
nLock = (int)sqliteHashFind(&pBt->locks, 0, pCur->pgnoRoot);
|
||||
assert( nLock!=0 );
|
||||
nLock = nLock<0 ? 0 : nLock-1;
|
||||
sqliteHashInsert(&pBt->locks, 0, pCur->pgnoRoot, (void*)nLock);
|
||||
sqliteFree(pCur);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@ -865,7 +894,9 @@ static void getTempCursor(BtCursor *pCur, BtCursor *pTempCur){
|
||||
memcpy(pTempCur, pCur, sizeof(*pCur));
|
||||
pTempCur->pNext = 0;
|
||||
pTempCur->pPrev = 0;
|
||||
sqlitepager_ref(pTempCur->pPage);
|
||||
if( pTempCur->pPage ){
|
||||
sqlitepager_ref(pTempCur->pPage);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -873,7 +904,9 @@ static void getTempCursor(BtCursor *pCur, BtCursor *pTempCur){
|
||||
** function above.
|
||||
*/
|
||||
static void releaseTempCursor(BtCursor *pCur){
|
||||
sqlitepager_unref(pCur->pPage);
|
||||
if( pCur->pPage ){
|
||||
sqlitepager_unref(pCur->pPage);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -888,8 +921,7 @@ int sqliteBtreeKeySize(BtCursor *pCur, int *pSize){
|
||||
MemPage *pPage;
|
||||
|
||||
pPage = pCur->pPage;
|
||||
assert( pPage!=0 );
|
||||
if( pCur->idx >= pPage->nCell ){
|
||||
if( pPage==0 || pCur->idx >= pPage->nCell ){
|
||||
*pSize = 0;
|
||||
}else{
|
||||
pCell = pPage->apCell[pCur->idx];
|
||||
@ -971,7 +1003,7 @@ int sqliteBtreeKey(BtCursor *pCur, int offset, int amt, char *zBuf){
|
||||
if( offset<0 ) return 0;
|
||||
if( amt==0 ) return 0;
|
||||
pPage = pCur->pPage;
|
||||
assert( pPage!=0 );
|
||||
if( pPage==0 ) return 0;
|
||||
if( pCur->idx >= pPage->nCell ){
|
||||
return 0;
|
||||
}
|
||||
@ -998,8 +1030,7 @@ int sqliteBtreeDataSize(BtCursor *pCur, int *pSize){
|
||||
MemPage *pPage;
|
||||
|
||||
pPage = pCur->pPage;
|
||||
assert( pPage!=0 );
|
||||
if( pCur->idx >= pPage->nCell ){
|
||||
if( pPage==0 || pCur->idx >= pPage->nCell ){
|
||||
*pSize = 0;
|
||||
}else{
|
||||
pCell = pPage->apCell[pCur->idx];
|
||||
@ -1024,8 +1055,7 @@ int sqliteBtreeData(BtCursor *pCur, int offset, int amt, char *zBuf){
|
||||
if( offset<0 ) return 0;
|
||||
if( amt==0 ) return 0;
|
||||
pPage = pCur->pPage;
|
||||
assert( pPage!=0 );
|
||||
if( pCur->idx >= pPage->nCell ){
|
||||
if( pPage==0 || pCur->idx >= pPage->nCell ){
|
||||
return 0;
|
||||
}
|
||||
pCell = pPage->apCell[pCur->idx];
|
||||
@ -1190,6 +1220,7 @@ static int moveToLeftmost(BtCursor *pCur){
|
||||
*/
|
||||
int sqliteBtreeFirst(BtCursor *pCur, int *pRes){
|
||||
int rc;
|
||||
if( pCur->pPage==0 ) return SQLITE_ABORT;
|
||||
rc = moveToRoot(pCur);
|
||||
if( rc ) return rc;
|
||||
if( pCur->pPage->nCell==0 ){
|
||||
@ -1225,6 +1256,7 @@ int sqliteBtreeFirst(BtCursor *pCur, int *pRes){
|
||||
*/
|
||||
int sqliteBtreeMoveto(BtCursor *pCur, const void *pKey, int nKey, int *pRes){
|
||||
int rc;
|
||||
if( pCur->pPage==0 ) return SQLITE_ABORT;
|
||||
pCur->bSkipNext = 0;
|
||||
rc = moveToRoot(pCur);
|
||||
if( rc ) return rc;
|
||||
@ -1275,6 +1307,9 @@ int sqliteBtreeMoveto(BtCursor *pCur, const void *pKey, int nKey, int *pRes){
|
||||
*/
|
||||
int sqliteBtreeNext(BtCursor *pCur, int *pRes){
|
||||
int rc;
|
||||
if( pCur->pPage==0 ){
|
||||
return SQLITE_ABORT;
|
||||
}
|
||||
if( pCur->bSkipNext ){
|
||||
pCur->bSkipNext = 0;
|
||||
if( pRes ) *pRes = 0;
|
||||
@ -2045,9 +2080,15 @@ int sqliteBtreeInsert(
|
||||
MemPage *pPage;
|
||||
Btree *pBt = pCur->pBt;
|
||||
|
||||
if( pCur->pPage==0 ){
|
||||
return SQLITE_ABORT; /* A rollback destroyed this cursor */
|
||||
}
|
||||
if( !pCur->pBt->inTrans || nKey+nData==0 ){
|
||||
return SQLITE_ERROR; /* Must start a transaction first */
|
||||
}
|
||||
if( !pCur->wrFlag ){
|
||||
return SQLITE_PERM; /* Cursor not open for writing */
|
||||
}
|
||||
rc = sqliteBtreeMoveto(pCur, pKey, nKey, &loc);
|
||||
if( rc ) return rc;
|
||||
pPage = pCur->pPage;
|
||||
@ -2090,12 +2131,18 @@ int sqliteBtreeDelete(BtCursor *pCur){
|
||||
int rc;
|
||||
Pgno pgnoChild;
|
||||
|
||||
if( pCur->pPage==0 ){
|
||||
return SQLITE_ABORT; /* A rollback destroyed this cursor */
|
||||
}
|
||||
if( !pCur->pBt->inTrans ){
|
||||
return SQLITE_ERROR; /* Must start a transaction first */
|
||||
}
|
||||
if( pCur->idx >= pPage->nCell ){
|
||||
return SQLITE_ERROR; /* The cursor is not pointing to anything */
|
||||
}
|
||||
if( !pCur->wrFlag ){
|
||||
return SQLITE_PERM; /* Did not open this cursor for writing */
|
||||
}
|
||||
rc = sqlitepager_write(pPage);
|
||||
if( rc ) return rc;
|
||||
pCell = pPage->apCell[pCur->idx];
|
||||
@ -2207,9 +2254,14 @@ static int clearDatabasePage(Btree *pBt, Pgno pgno, int freePageFlag){
|
||||
*/
|
||||
int sqliteBtreeClearTable(Btree *pBt, int iTable){
|
||||
int rc;
|
||||
int nLock;
|
||||
if( !pBt->inTrans ){
|
||||
return SQLITE_ERROR; /* Must start a transaction first */
|
||||
}
|
||||
nLock = (int)sqliteHashFind(&pBt->locks, 0, iTable);
|
||||
if( nLock ){
|
||||
return SQLITE_LOCKED;
|
||||
}
|
||||
rc = clearDatabasePage(pBt, (Pgno)iTable, 0);
|
||||
if( rc ){
|
||||
sqliteBtreeRollback(pBt);
|
||||
|
@ -12,7 +12,7 @@
|
||||
** This header file defines the interface that the sqlite B-Tree file
|
||||
** subsystem.
|
||||
**
|
||||
** @(#) $Id: btree.h,v 1.14 2001/09/16 00:13:26 drh Exp $
|
||||
** @(#) $Id: btree.h,v 1.15 2001/09/23 02:35:53 drh Exp $
|
||||
*/
|
||||
#ifndef _BTREE_H_
|
||||
#define _BTREE_H_
|
||||
@ -32,7 +32,7 @@ int sqliteBtreeCreateTable(Btree*, int*);
|
||||
int sqliteBtreeDropTable(Btree*, int);
|
||||
int sqliteBtreeClearTable(Btree*, int);
|
||||
|
||||
int sqliteBtreeCursor(Btree*, int iTable, BtCursor **ppCur);
|
||||
int sqliteBtreeCursor(Btree*, int iTable, int wrFlag, BtCursor **ppCur);
|
||||
int sqliteBtreeMoveto(BtCursor*, const void *pKey, int nKey, int *pRes);
|
||||
int sqliteBtreeDelete(BtCursor*);
|
||||
int sqliteBtreeInsert(BtCursor*, const void *pKey, int nKey,
|
||||
|
24
src/build.c
24
src/build.c
@ -25,7 +25,7 @@
|
||||
** ROLLBACK
|
||||
** PRAGMA
|
||||
**
|
||||
** $Id: build.c,v 1.38 2001/09/22 18:12:10 drh Exp $
|
||||
** $Id: build.c,v 1.39 2001/09/23 02:35:53 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -54,6 +54,7 @@ void sqliteExec(Parse *pParse){
|
||||
rc = sqliteVdbeExec(pParse->pVdbe, pParse->xCallback, pParse->pArg,
|
||||
&pParse->zErrMsg, db->pBusyArg,
|
||||
db->xBusyCallback);
|
||||
if( rc ) pParse->nErr++;
|
||||
}
|
||||
sqliteVdbeDelete(pParse->pVdbe);
|
||||
pParse->pVdbe = 0;
|
||||
@ -372,6 +373,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
|
||||
if( v ){
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -502,7 +504,7 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ) return;
|
||||
n = (int)pEnd->z - (int)pParse->sFirstToken.z + 1;
|
||||
sqliteVdbeAddOp(v, OP_Open, 0, 2, MASTER_NAME, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2, MASTER_NAME, 0);
|
||||
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0, "table", 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0, p->zName, 0);
|
||||
@ -583,7 +585,7 @@ void sqliteDropTable(Parse *pParse, Token *pName){
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v ){
|
||||
static VdbeOp dropTable[] = {
|
||||
{ OP_Open, 0, 2, MASTER_NAME},
|
||||
{ OP_OpenWrite, 0, 2, MASTER_NAME},
|
||||
{ OP_Rewind, 0, 0, 0},
|
||||
{ OP_String, 0, 0, 0}, /* 2 */
|
||||
{ OP_Next, 0, ADDR(9), 0}, /* 3 */
|
||||
@ -600,6 +602,7 @@ void sqliteDropTable(Parse *pParse, Token *pName){
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
|
||||
sqliteVdbeChangeP3(v, base+2, pTable->zName, 0);
|
||||
@ -779,14 +782,14 @@ void sqliteCreateIndex(
|
||||
*/
|
||||
else if( pParse->initFlag==0 && pTable!=0 ){
|
||||
static VdbeOp addTable[] = {
|
||||
{ OP_Open, 2, 2, MASTER_NAME},
|
||||
{ OP_OpenWrite, 2, 2, MASTER_NAME},
|
||||
{ OP_NewRecno, 2, 0, 0},
|
||||
{ OP_String, 0, 0, "index"},
|
||||
{ OP_String, 0, 0, 0}, /* 3 */
|
||||
{ OP_String, 0, 0, 0}, /* 4 */
|
||||
{ OP_CreateIndex, 1, 0, 0},
|
||||
{ OP_Dup, 0, 0, 0},
|
||||
{ OP_Open, 1, 0, 0}, /* 7 */
|
||||
{ OP_OpenWrite, 1, 0, 0}, /* 7 */
|
||||
{ OP_Null, 0, 0, 0},
|
||||
{ OP_String, 0, 0, 0}, /* 9 */
|
||||
{ OP_MakeRecord, 6, 0, 0},
|
||||
@ -804,6 +807,7 @@ void sqliteCreateIndex(
|
||||
if( pTable!=0 && (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
if( pStart && pEnd ){
|
||||
int base;
|
||||
@ -875,7 +879,7 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v ){
|
||||
static VdbeOp dropIndex[] = {
|
||||
{ OP_Open, 0, 2, MASTER_NAME},
|
||||
{ OP_OpenWrite, 0, 2, MASTER_NAME},
|
||||
{ OP_Rewind, 0, 0, 0},
|
||||
{ OP_String, 0, 0, 0}, /* 2 */
|
||||
{ OP_Next, 0, ADDR(8), 0}, /* 3 */
|
||||
@ -892,6 +896,7 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
|
||||
sqliteVdbeChangeP3(v, base+2, pIndex->zName, 0);
|
||||
@ -1065,13 +1070,14 @@ void sqliteCopy(
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0, 0, 0);
|
||||
sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
|
||||
sqliteVdbeDequoteP3(v, addr);
|
||||
sqliteVdbeAddOp(v, OP_Open, 0, pTab->tnum, pTab->zName, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, 0, pTab->tnum, pTab->zName, 0);
|
||||
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
sqliteVdbeAddOp(v, OP_Open, i, pIdx->tnum, pIdx->zName, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, i, pIdx->tnum, pIdx->zName, 0);
|
||||
}
|
||||
end = sqliteVdbeMakeLabel(v);
|
||||
addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end, 0, 0);
|
||||
@ -1138,6 +1144,7 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
if( zName ){
|
||||
sqliteVdbeAddOp(v, OP_Reorganize, 0, 0, zName, 0);
|
||||
@ -1176,6 +1183,7 @@ void sqliteBeginTransaction(Parse *pParse){
|
||||
if( v ){
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 1, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
db->flags |= SQLITE_InTrans;
|
||||
}
|
||||
|
19
src/delete.c
19
src/delete.c
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle DELETE FROM statements.
|
||||
**
|
||||
** $Id: delete.c,v 1.14 2001/09/16 00:13:27 drh Exp $
|
||||
** $Id: delete.c,v 1.15 2001/09/23 02:35:53 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -32,11 +32,13 @@ void sqliteDeleteFrom(
|
||||
WhereInfo *pWInfo; /* Information about the WHERE clause */
|
||||
Index *pIdx; /* For looping over indices of the table */
|
||||
int base; /* Index of the first available table cursor */
|
||||
sqlite *db; /* Main database structure */
|
||||
|
||||
if( pParse->nErr || sqlite_malloc_failed ){
|
||||
pTabList = 0;
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
db = pParse->db;
|
||||
|
||||
/* Locate the table which we want to delete. This table has to be
|
||||
** put in an IdList structure because some of the subroutines we
|
||||
@ -46,7 +48,7 @@ void sqliteDeleteFrom(
|
||||
pTabList = sqliteIdListAppend(0, pTableName);
|
||||
if( pTabList==0 ) goto delete_from_cleanup;
|
||||
for(i=0; i<pTabList->nId; i++){
|
||||
pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
|
||||
pTabList->a[i].pTab = sqliteFindTable(db, pTabList->a[i].zName);
|
||||
if( pTabList->a[i].pTab==0 ){
|
||||
sqliteSetString(&pParse->zErrMsg, "no such table: ",
|
||||
pTabList->a[i].zName, 0);
|
||||
@ -78,14 +80,15 @@ void sqliteDeleteFrom(
|
||||
*/
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ) goto delete_from_cleanup;
|
||||
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
|
||||
|
||||
/* Special case: A DELETE without a WHERE clause deletes everything.
|
||||
** It is easier just to clear all information the database tables directly.
|
||||
** It is easier just to erase the whole table.
|
||||
*/
|
||||
if( pWhere==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, 0, 0, 0);
|
||||
@ -118,9 +121,9 @@ void sqliteDeleteFrom(
|
||||
*/
|
||||
base = pParse->nTab;
|
||||
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Open, base, pTab->tnum, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum, 0, 0);
|
||||
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
||||
sqliteVdbeAddOp(v, OP_Open, base+i, pIdx->tnum, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, base+i, pIdx->tnum, 0, 0);
|
||||
}
|
||||
end = sqliteVdbeMakeLabel(v);
|
||||
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
|
||||
@ -140,7 +143,7 @@ void sqliteDeleteFrom(
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
|
||||
}
|
||||
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
17
src/insert.c
17
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.18 2001/09/16 00:13:27 drh Exp $
|
||||
** $Id: insert.c,v 1.19 2001/09/23 02:35:53 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -47,14 +47,16 @@ void sqliteInsert(
|
||||
int nColumn; /* Number of columns in the data */
|
||||
int base; /* First available cursor */
|
||||
int iCont, iBreak; /* Beginning and end of the loop over srcTab */
|
||||
sqlite *db; /* The main database structure */
|
||||
|
||||
if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;
|
||||
db = pParse->db;
|
||||
|
||||
/* Locate the table into which we will be inserting new information.
|
||||
*/
|
||||
zTab = sqliteTableNameFromToken(pTableName);
|
||||
if( zTab==0 ) goto insert_cleanup;
|
||||
pTab = sqliteFindTable(pParse->db, zTab);
|
||||
pTab = sqliteFindTable(db, zTab);
|
||||
sqliteFree(zTab);
|
||||
if( pTab==0 ){
|
||||
sqliteSetNString(&pParse->zErrMsg, "no such table: ", 0,
|
||||
@ -73,9 +75,10 @@ void sqliteInsert(
|
||||
*/
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ) goto insert_cleanup;
|
||||
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
|
||||
/* Figure out how many columns of data are supplied. If the data
|
||||
@ -152,9 +155,9 @@ void sqliteInsert(
|
||||
** all indices of that table.
|
||||
*/
|
||||
base = pParse->nTab;
|
||||
sqliteVdbeAddOp(v, OP_Open, base, pTab->tnum, pTab->zName, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum, pTab->zName, 0);
|
||||
for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
|
||||
sqliteVdbeAddOp(v, OP_Open, idx+base, pIdx->tnum, pIdx->zName, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, idx+base, pIdx->tnum, pIdx->zName, 0);
|
||||
}
|
||||
|
||||
/* If the data source is a SELECT statement, then we have to create
|
||||
@ -237,7 +240,7 @@ void sqliteInsert(
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, iCont, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, iBreak);
|
||||
}
|
||||
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
** This header file defines the interface that the SQLite library
|
||||
** presents to client programs.
|
||||
**
|
||||
** @(#) $Id: sqlite.h.in,v 1.18 2001/09/20 01:44:43 drh Exp $
|
||||
** @(#) $Id: sqlite.h.in,v 1.19 2001/09/23 02:35:53 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_H_
|
||||
#define _SQLITE_H_
|
||||
@ -138,19 +138,20 @@ int sqlite_exec(
|
||||
#define SQLITE_INTERNAL 2 /* An internal logic error in SQLite */
|
||||
#define SQLITE_PERM 3 /* Access permission denied */
|
||||
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
|
||||
#define SQLITE_BUSY 5 /* One or more database files are locked */
|
||||
#define SQLITE_NOMEM 6 /* A malloc() failed */
|
||||
#define SQLITE_READONLY 7 /* Attempt to write a readonly database */
|
||||
#define SQLITE_INTERRUPT 8 /* Operation terminated by sqlite_interrupt() */
|
||||
#define SQLITE_IOERR 9 /* Some kind of disk I/O error occurred */
|
||||
#define SQLITE_CORRUPT 10 /* The database disk image is malformed */
|
||||
#define SQLITE_NOTFOUND 11 /* (Internal Only) Table or record not found */
|
||||
#define SQLITE_FULL 12 /* Insertion failed because database is full */
|
||||
#define SQLITE_CANTOPEN 13 /* Unable to open the database file */
|
||||
#define SQLITE_PROTOCOL 14 /* Database lock protocol error */
|
||||
#define SQLITE_EMPTY 15 /* (Internal Only) Database table is empty */
|
||||
#define SQLITE_SCHEMA 16 /* The database schema changed */
|
||||
#define SQLITE_TOOBIG 17 /* Too much data for one row of a table */
|
||||
#define SQLITE_BUSY 5 /* The database file is locked */
|
||||
#define SQLITE_LOCKED 6 /* A table in the database is locked */
|
||||
#define SQLITE_NOMEM 7 /* A malloc() failed */
|
||||
#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
|
||||
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite_interrupt() */
|
||||
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
|
||||
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
|
||||
#define SQLITE_NOTFOUND 12 /* (Internal Only) Table or record not found */
|
||||
#define SQLITE_FULL 13 /* Insertion failed because database is full */
|
||||
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
|
||||
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
|
||||
#define SQLITE_EMPTY 16 /* (Internal Only) Database table is empty */
|
||||
#define SQLITE_SCHEMA 17 /* The database schema changed */
|
||||
#define SQLITE_TOOBIG 18 /* Too much data for one row of a table */
|
||||
|
||||
/* This function causes any pending database operation to abort and
|
||||
** return at its earliest opportunity. This routine is typically
|
||||
|
12
src/test3.c
12
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.11 2001/09/16 00:13:27 drh Exp $
|
||||
** $Id: test3.c,v 1.12 2001/09/23 02:35:53 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "pager.h"
|
||||
@ -499,7 +499,7 @@ static int btree_sanity_check(
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: btree_cursor ID TABLENUM
|
||||
** Usage: btree_cursor ID TABLENUM WRITEABLE
|
||||
**
|
||||
** Create a new cursor. Return the ID for the cursor.
|
||||
*/
|
||||
@ -513,16 +513,18 @@ static int btree_cursor(
|
||||
int iTable;
|
||||
BtCursor *pCur;
|
||||
int rc;
|
||||
int wrFlag;
|
||||
char zBuf[30];
|
||||
|
||||
if( argc!=3 ){
|
||||
if( argc!=4 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" ID TABLENUM\"", 0);
|
||||
" ID TABLENUM WRITEABLE\"", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
|
||||
if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
|
||||
rc = sqliteBtreeCursor(pBt, iTable, &pCur);
|
||||
if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
|
||||
rc = sqliteBtreeCursor(pBt, iTable, wrFlag, &pCur);
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
|
@ -15,7 +15,7 @@
|
||||
** individual tokens and sends those tokens one-by-one over to the
|
||||
** parser for analysis.
|
||||
**
|
||||
** $Id: tokenize.c,v 1.22 2001/09/16 00:13:27 drh Exp $
|
||||
** $Id: tokenize.c,v 1.23 2001/09/23 02:35:53 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -353,6 +353,9 @@ int sqliteRunParser(Parse *pParse, char *zSql, char **pzErrMsg){
|
||||
nErr++;
|
||||
sqliteFree(pParse->zErrMsg);
|
||||
pParse->zErrMsg = 0;
|
||||
}else if( pParse->rc!=SQLITE_OK ){
|
||||
sqliteSetString(pzErrMsg, sqliteErrStr(pParse->rc), 0);
|
||||
nErr++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
17
src/update.c
17
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.14 2001/09/16 00:13:27 drh Exp $
|
||||
** $Id: update.c,v 1.15 2001/09/23 02:35:53 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -34,12 +34,14 @@ void sqliteUpdate(
|
||||
Index *pIdx; /* For looping over indices */
|
||||
int nIdx; /* Number of indices that need updating */
|
||||
int base; /* Index of first available table cursor */
|
||||
sqlite *db; /* The database structure */
|
||||
Index **apIdx = 0; /* An array of indices that need updating too */
|
||||
int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
|
||||
** an expression for the i-th column of the table.
|
||||
** aXRef[i]==-1 if the i-th column is not changed. */
|
||||
|
||||
if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup;
|
||||
db = pParse->db;
|
||||
|
||||
/* Locate the table which we want to update. This table has to be
|
||||
** put in an IdList structure because some of the subroutines we
|
||||
@ -49,7 +51,7 @@ void sqliteUpdate(
|
||||
pTabList = sqliteIdListAppend(0, pTableName);
|
||||
if( pTabList==0 ) goto update_cleanup;
|
||||
for(i=0; i<pTabList->nId; i++){
|
||||
pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
|
||||
pTabList->a[i].pTab = sqliteFindTable(db, pTabList->a[i].zName);
|
||||
if( pTabList->a[i].pTab==0 ){
|
||||
sqliteSetString(&pParse->zErrMsg, "no such table: ",
|
||||
pTabList->a[i].zName, 0);
|
||||
@ -132,9 +134,10 @@ void sqliteUpdate(
|
||||
*/
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ) goto update_cleanup;
|
||||
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
|
||||
/* Begin the database scan
|
||||
@ -156,9 +159,9 @@ void sqliteUpdate(
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
|
||||
base = pParse->nTab;
|
||||
sqliteVdbeAddOp(v, OP_Open, base, pTab->tnum, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum, 0, 0);
|
||||
for(i=0; i<nIdx; i++){
|
||||
sqliteVdbeAddOp(v, OP_Open, base+i+1, apIdx[i]->tnum, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, base+i+1, apIdx[i]->tnum, 0, 0);
|
||||
}
|
||||
|
||||
/* Loop over every record that needs updating. We have to load
|
||||
@ -216,7 +219,7 @@ void sqliteUpdate(
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
|
||||
if( (pParse->db->flags & SQLITE_InTrans)==0 ){
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
** This file contains functions for allocating memory, comparing
|
||||
** strings, and stuff like that.
|
||||
**
|
||||
** $Id: util.c,v 1.27 2001/09/19 13:22:40 drh Exp $
|
||||
** $Id: util.c,v 1.28 2001/09/23 02:35:53 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <stdarg.h>
|
||||
@ -973,7 +973,8 @@ const char *sqliteErrStr(int rc){
|
||||
case SQLITE_INTERNAL: z = "internal SQLite implementation flaw"; break;
|
||||
case SQLITE_PERM: z = "access permission denied"; break;
|
||||
case SQLITE_ABORT: z = "callback requested query abort"; break;
|
||||
case SQLITE_BUSY: z = "database in use by another process"; break;
|
||||
case SQLITE_BUSY: z = "database is locked"; break;
|
||||
case SQLITE_LOCKED: z = "database table is locked"; break;
|
||||
case SQLITE_NOMEM: z = "out of memory"; break;
|
||||
case SQLITE_READONLY: z = "attempt to write a readonly database"; break;
|
||||
case SQLITE_INTERRUPT: z = "interrupted"; break;
|
||||
|
94
src/vdbe.c
94
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.73 2001/09/22 18:12:10 drh Exp $
|
||||
** $Id: vdbe.c,v 1.74 2001/09/23 02:35:53 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -675,6 +675,19 @@ static void cleanupCursor(Cursor *pCx){
|
||||
memset(pCx, 0, sizeof(Cursor));
|
||||
}
|
||||
|
||||
/*
|
||||
** Close all cursors
|
||||
*/
|
||||
static void closeAllCursors(Vdbe *p){
|
||||
int i;
|
||||
for(i=0; i<p->nCursor; i++){
|
||||
cleanupCursor(&p->aCsr[i]);
|
||||
}
|
||||
sqliteFree(p->aCsr);
|
||||
p->aCsr = 0;
|
||||
p->nCursor = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Clean up the VM after execution.
|
||||
**
|
||||
@ -686,12 +699,7 @@ static void Cleanup(Vdbe *p){
|
||||
PopStack(p, p->tos+1);
|
||||
sqliteFree(p->azColName);
|
||||
p->azColName = 0;
|
||||
for(i=0; i<p->nCursor; i++){
|
||||
cleanupCursor(&p->aCsr[i]);
|
||||
}
|
||||
sqliteFree(p->aCsr);
|
||||
p->aCsr = 0;
|
||||
p->nCursor = 0;
|
||||
closeAllCursors(p);
|
||||
for(i=0; i<p->nMem; i++){
|
||||
if( p->aMem[i].s.flags & STK_Dyn ){
|
||||
sqliteFree(p->aMem[i].z);
|
||||
@ -777,30 +785,30 @@ void sqliteVdbeDelete(Vdbe *p){
|
||||
static char *zOpName[] = { 0,
|
||||
"Transaction", "Commit", "Rollback", "ReadCookie",
|
||||
"SetCookie", "VerifyCookie", "Open", "OpenTemp",
|
||||
"Close", "MoveTo", "Fcnt", "NewRecno",
|
||||
"Put", "Distinct", "Found", "NotFound",
|
||||
"Delete", "Column", "KeyAsData", "Recno",
|
||||
"FullKey", "Rewind", "Next", "Destroy",
|
||||
"Clear", "CreateIndex", "CreateTable", "Reorganize",
|
||||
"BeginIdx", "NextIdx", "PutIdx", "DeleteIdx",
|
||||
"MemLoad", "MemStore", "ListOpen", "ListWrite",
|
||||
"ListRewind", "ListRead", "ListClose", "SortOpen",
|
||||
"SortPut", "SortMakeRec", "SortMakeKey", "Sort",
|
||||
"SortNext", "SortKey", "SortCallback", "SortClose",
|
||||
"FileOpen", "FileRead", "FileColumn", "FileClose",
|
||||
"AggReset", "AggFocus", "AggIncr", "AggNext",
|
||||
"AggSet", "AggGet", "SetInsert", "SetFound",
|
||||
"SetNotFound", "SetClear", "MakeRecord", "MakeKey",
|
||||
"MakeIdxKey", "Goto", "If", "Halt",
|
||||
"ColumnCount", "ColumnName", "Callback", "Integer",
|
||||
"String", "Null", "Pop", "Dup",
|
||||
"Pull", "Add", "AddImm", "Subtract",
|
||||
"Multiply", "Divide", "Min", "Max",
|
||||
"Like", "Glob", "Eq", "Ne",
|
||||
"Lt", "Le", "Gt", "Ge",
|
||||
"IsNull", "NotNull", "Negative", "And",
|
||||
"Or", "Not", "Concat", "Noop",
|
||||
"Strlen", "Substr",
|
||||
"OpenWrite", "Close", "MoveTo", "Fcnt",
|
||||
"NewRecno", "Put", "Distinct", "Found",
|
||||
"NotFound", "Delete", "Column", "KeyAsData",
|
||||
"Recno", "FullKey", "Rewind", "Next",
|
||||
"Destroy", "Clear", "CreateIndex", "CreateTable",
|
||||
"Reorganize", "BeginIdx", "NextIdx", "PutIdx",
|
||||
"DeleteIdx", "MemLoad", "MemStore", "ListOpen",
|
||||
"ListWrite", "ListRewind", "ListRead", "ListClose",
|
||||
"SortOpen", "SortPut", "SortMakeRec", "SortMakeKey",
|
||||
"Sort", "SortNext", "SortKey", "SortCallback",
|
||||
"SortClose", "FileOpen", "FileRead", "FileColumn",
|
||||
"FileClose", "AggReset", "AggFocus", "AggIncr",
|
||||
"AggNext", "AggSet", "AggGet", "SetInsert",
|
||||
"SetFound", "SetNotFound", "SetClear", "MakeRecord",
|
||||
"MakeKey", "MakeIdxKey", "Goto", "If",
|
||||
"Halt", "ColumnCount", "ColumnName", "Callback",
|
||||
"Integer", "String", "Null", "Pop",
|
||||
"Dup", "Pull", "Add", "AddImm",
|
||||
"Subtract", "Multiply", "Divide", "Min",
|
||||
"Max", "Like", "Glob", "Eq",
|
||||
"Ne", "Lt", "Le", "Gt",
|
||||
"Ge", "IsNull", "NotNull", "Negative",
|
||||
"And", "Or", "Not", "Concat",
|
||||
"Noop", "Strlen", "Substr",
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1985,7 +1993,7 @@ case OP_VerifyCookie: {
|
||||
|
||||
/* Opcode: Open P1 P2 P3
|
||||
**
|
||||
** Open a new cursor for the database table whose root page is
|
||||
** Open a read-only cursor for the database table whose root page is
|
||||
** P2 in the main database file. Give the new cursor an identifier
|
||||
** of P1. The P1 values need not be contiguous but all P1 values
|
||||
** should be small integers. It is an error for P1 to be negative.
|
||||
@ -2006,6 +2014,16 @@ case OP_VerifyCookie: {
|
||||
** omitted. But the code generator usually inserts the index or
|
||||
** table name into P3 to make the code easier to read.
|
||||
*/
|
||||
/* Opcode: OpenWrite P1 P2 P3
|
||||
**
|
||||
** Open a read/write cursor named P1 on the table or index whose root
|
||||
** page is P2. If P2==0 then take the root page number from the stack.
|
||||
**
|
||||
** This instruction works just like Open except that it opens the cursor
|
||||
** in read/write mode. For a given table, there can be one or more read-only
|
||||
** cursors or a single read/write cursor but not both.
|
||||
*/
|
||||
case OP_OpenWrite:
|
||||
case OP_Open: {
|
||||
int busy = 0;
|
||||
int i = pOp->p1;
|
||||
@ -2035,7 +2053,8 @@ case OP_Open: {
|
||||
cleanupCursor(&p->aCsr[i]);
|
||||
memset(&p->aCsr[i], 0, sizeof(Cursor));
|
||||
do{
|
||||
rc = sqliteBtreeCursor(pBt, p2, &p->aCsr[i].pCursor);
|
||||
int wrFlag = pOp->opcode==OP_OpenWrite;
|
||||
rc = sqliteBtreeCursor(pBt, p2, wrFlag, &p->aCsr[i].pCursor);
|
||||
switch( rc ){
|
||||
case SQLITE_BUSY: {
|
||||
if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){
|
||||
@ -2081,7 +2100,7 @@ case OP_OpenTemp: {
|
||||
memset(pCx, 0, sizeof(*pCx));
|
||||
rc = sqliteBtreeOpen(0, 0, TEMP_PAGES, &pCx->pBt);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqliteBtreeCursor(pCx->pBt, 2, &pCx->pCursor);
|
||||
rc = sqliteBtreeCursor(pCx->pBt, 2, 1, &pCx->pCursor);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqliteBtreeBeginTrans(pCx->pBt);
|
||||
@ -2637,7 +2656,7 @@ case OP_PutIdx: {
|
||||
BtCursor *pCrsr;
|
||||
VERIFY( if( tos<0 ) goto not_enough_stack; )
|
||||
if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
|
||||
sqliteBtreeInsert(pCrsr, zStack[tos], aStack[tos].n, "", 0);
|
||||
rc = sqliteBtreeInsert(pCrsr, zStack[tos], aStack[tos].n, "", 0);
|
||||
}
|
||||
POPSTACK;
|
||||
break;
|
||||
@ -2657,7 +2676,7 @@ case OP_DeleteIdx: {
|
||||
int rx, res;
|
||||
rx = sqliteBtreeMoveto(pCrsr, zStack[tos], aStack[tos].n, &res);
|
||||
if( rx==SQLITE_OK && res==0 ){
|
||||
sqliteBtreeDelete(pCrsr);
|
||||
rc = sqliteBtreeDelete(pCrsr);
|
||||
}
|
||||
}
|
||||
POPSTACK;
|
||||
@ -3784,7 +3803,8 @@ cleanup:
|
||||
rc = SQLITE_INTERNAL;
|
||||
sqliteSetString(pzErrMsg, "table or index root page not set", 0);
|
||||
}
|
||||
if( rc!=SQLITE_OK && (db->flags & SQLITE_InTrans)!=0 ){
|
||||
if( rc!=SQLITE_OK ){
|
||||
closeAllCursors(p);
|
||||
sqliteBtreeRollback(pBt);
|
||||
sqliteRollbackInternalChanges(db);
|
||||
db->flags &= ~SQLITE_InTrans;
|
||||
|
193
src/vdbe.h
193
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.23 2001/09/16 00:13:27 drh Exp $
|
||||
** $Id: vdbe.h,v 1.24 2001/09/23 02:35:53 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_VDBE_H_
|
||||
#define _SQLITE_VDBE_H_
|
||||
@ -69,116 +69,117 @@ typedef struct VdbeOp VdbeOp;
|
||||
|
||||
#define OP_Open 7
|
||||
#define OP_OpenTemp 8
|
||||
#define OP_Close 9
|
||||
#define OP_MoveTo 10
|
||||
#define OP_Fcnt 11
|
||||
#define OP_NewRecno 12
|
||||
#define OP_Put 13
|
||||
#define OP_Distinct 14
|
||||
#define OP_Found 15
|
||||
#define OP_NotFound 16
|
||||
#define OP_Delete 17
|
||||
#define OP_Column 18
|
||||
#define OP_KeyAsData 19
|
||||
#define OP_Recno 20
|
||||
#define OP_FullKey 21
|
||||
#define OP_Rewind 22
|
||||
#define OP_Next 23
|
||||
#define OP_OpenWrite 9
|
||||
#define OP_Close 10
|
||||
#define OP_MoveTo 11
|
||||
#define OP_Fcnt 12
|
||||
#define OP_NewRecno 13
|
||||
#define OP_Put 14
|
||||
#define OP_Distinct 15
|
||||
#define OP_Found 16
|
||||
#define OP_NotFound 17
|
||||
#define OP_Delete 18
|
||||
#define OP_Column 19
|
||||
#define OP_KeyAsData 20
|
||||
#define OP_Recno 21
|
||||
#define OP_FullKey 22
|
||||
#define OP_Rewind 23
|
||||
#define OP_Next 24
|
||||
|
||||
#define OP_Destroy 24
|
||||
#define OP_Clear 25
|
||||
#define OP_CreateIndex 26
|
||||
#define OP_CreateTable 27
|
||||
#define OP_Reorganize 28
|
||||
#define OP_Destroy 25
|
||||
#define OP_Clear 26
|
||||
#define OP_CreateIndex 27
|
||||
#define OP_CreateTable 28
|
||||
#define OP_Reorganize 29
|
||||
|
||||
#define OP_BeginIdx 29
|
||||
#define OP_NextIdx 30
|
||||
#define OP_PutIdx 31
|
||||
#define OP_DeleteIdx 32
|
||||
#define OP_BeginIdx 30
|
||||
#define OP_NextIdx 31
|
||||
#define OP_PutIdx 32
|
||||
#define OP_DeleteIdx 33
|
||||
|
||||
#define OP_MemLoad 33
|
||||
#define OP_MemStore 34
|
||||
#define OP_MemLoad 34
|
||||
#define OP_MemStore 35
|
||||
|
||||
#define OP_ListOpen 35
|
||||
#define OP_ListWrite 36
|
||||
#define OP_ListRewind 37
|
||||
#define OP_ListRead 38
|
||||
#define OP_ListClose 39
|
||||
#define OP_ListOpen 36
|
||||
#define OP_ListWrite 37
|
||||
#define OP_ListRewind 38
|
||||
#define OP_ListRead 39
|
||||
#define OP_ListClose 40
|
||||
|
||||
#define OP_SortOpen 40
|
||||
#define OP_SortPut 41
|
||||
#define OP_SortMakeRec 42
|
||||
#define OP_SortMakeKey 43
|
||||
#define OP_Sort 44
|
||||
#define OP_SortNext 45
|
||||
#define OP_SortKey 46
|
||||
#define OP_SortCallback 47
|
||||
#define OP_SortClose 48
|
||||
#define OP_SortOpen 41
|
||||
#define OP_SortPut 42
|
||||
#define OP_SortMakeRec 43
|
||||
#define OP_SortMakeKey 44
|
||||
#define OP_Sort 45
|
||||
#define OP_SortNext 46
|
||||
#define OP_SortKey 47
|
||||
#define OP_SortCallback 48
|
||||
#define OP_SortClose 49
|
||||
|
||||
#define OP_FileOpen 49
|
||||
#define OP_FileRead 50
|
||||
#define OP_FileColumn 51
|
||||
#define OP_FileClose 52
|
||||
#define OP_FileOpen 50
|
||||
#define OP_FileRead 51
|
||||
#define OP_FileColumn 52
|
||||
#define OP_FileClose 53
|
||||
|
||||
#define OP_AggReset 53
|
||||
#define OP_AggFocus 54
|
||||
#define OP_AggIncr 55
|
||||
#define OP_AggNext 56
|
||||
#define OP_AggSet 57
|
||||
#define OP_AggGet 58
|
||||
#define OP_AggReset 54
|
||||
#define OP_AggFocus 55
|
||||
#define OP_AggIncr 56
|
||||
#define OP_AggNext 57
|
||||
#define OP_AggSet 58
|
||||
#define OP_AggGet 59
|
||||
|
||||
#define OP_SetInsert 59
|
||||
#define OP_SetFound 60
|
||||
#define OP_SetNotFound 61
|
||||
#define OP_SetClear 62
|
||||
#define OP_SetInsert 60
|
||||
#define OP_SetFound 61
|
||||
#define OP_SetNotFound 62
|
||||
#define OP_SetClear 63
|
||||
|
||||
#define OP_MakeRecord 63
|
||||
#define OP_MakeKey 64
|
||||
#define OP_MakeIdxKey 65
|
||||
#define OP_MakeRecord 64
|
||||
#define OP_MakeKey 65
|
||||
#define OP_MakeIdxKey 66
|
||||
|
||||
#define OP_Goto 66
|
||||
#define OP_If 67
|
||||
#define OP_Halt 68
|
||||
#define OP_Goto 67
|
||||
#define OP_If 68
|
||||
#define OP_Halt 69
|
||||
|
||||
#define OP_ColumnCount 69
|
||||
#define OP_ColumnName 70
|
||||
#define OP_Callback 71
|
||||
#define OP_ColumnCount 70
|
||||
#define OP_ColumnName 71
|
||||
#define OP_Callback 72
|
||||
|
||||
#define OP_Integer 72
|
||||
#define OP_String 73
|
||||
#define OP_Null 74
|
||||
#define OP_Pop 75
|
||||
#define OP_Dup 76
|
||||
#define OP_Pull 77
|
||||
#define OP_Integer 73
|
||||
#define OP_String 74
|
||||
#define OP_Null 75
|
||||
#define OP_Pop 76
|
||||
#define OP_Dup 77
|
||||
#define OP_Pull 78
|
||||
|
||||
#define OP_Add 78
|
||||
#define OP_AddImm 79
|
||||
#define OP_Subtract 80
|
||||
#define OP_Multiply 81
|
||||
#define OP_Divide 82
|
||||
#define OP_Min 83
|
||||
#define OP_Max 84
|
||||
#define OP_Like 85
|
||||
#define OP_Glob 86
|
||||
#define OP_Eq 87
|
||||
#define OP_Ne 88
|
||||
#define OP_Lt 89
|
||||
#define OP_Le 90
|
||||
#define OP_Gt 91
|
||||
#define OP_Ge 92
|
||||
#define OP_IsNull 93
|
||||
#define OP_NotNull 94
|
||||
#define OP_Negative 95
|
||||
#define OP_And 96
|
||||
#define OP_Or 97
|
||||
#define OP_Not 98
|
||||
#define OP_Concat 99
|
||||
#define OP_Noop 100
|
||||
#define OP_Add 79
|
||||
#define OP_AddImm 80
|
||||
#define OP_Subtract 81
|
||||
#define OP_Multiply 82
|
||||
#define OP_Divide 83
|
||||
#define OP_Min 84
|
||||
#define OP_Max 85
|
||||
#define OP_Like 86
|
||||
#define OP_Glob 87
|
||||
#define OP_Eq 88
|
||||
#define OP_Ne 89
|
||||
#define OP_Lt 90
|
||||
#define OP_Le 91
|
||||
#define OP_Gt 92
|
||||
#define OP_Ge 93
|
||||
#define OP_IsNull 94
|
||||
#define OP_NotNull 95
|
||||
#define OP_Negative 96
|
||||
#define OP_And 97
|
||||
#define OP_Or 98
|
||||
#define OP_Not 99
|
||||
#define OP_Concat 100
|
||||
#define OP_Noop 101
|
||||
|
||||
#define OP_Strlen 101
|
||||
#define OP_Substr 102
|
||||
#define OP_Strlen 102
|
||||
#define OP_Substr 103
|
||||
|
||||
#define OP_MAX 102
|
||||
#define OP_MAX 103
|
||||
|
||||
/*
|
||||
** Prototypes for the VDBE interface. See comments on the implementation
|
||||
|
Reference in New Issue
Block a user