aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/btree.c51
-rw-r--r--src/build.c90
-rw-r--r--src/delete.c13
-rw-r--r--src/main.c4
-rw-r--r--src/random.c4
-rw-r--r--src/select.c3
-rw-r--r--src/test3.c14
-rw-r--r--src/vdbe.c112
-rw-r--r--src/vdbe.h187
9 files changed, 283 insertions, 195 deletions
diff --git a/src/btree.c b/src/btree.c
index a67af7d4a..0508d9971 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -21,7 +21,7 @@
** http://www.hwaci.com/drh/
**
*************************************************************************
-** $Id: btree.c,v 1.23 2001/09/13 14:46:10 drh Exp $
+** $Id: btree.c,v 1.24 2001/09/13 21:53:09 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@@ -1685,6 +1685,7 @@ static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){
int nxDiv; /* Next divider slot in pParent->apCell[] */
int rc; /* The return code */
int iCur; /* apCell[iCur] is the cell of the cursor */
+ MemPage *pOldCurPage; /* The cursor originally points to this page */
int totalSize; /* Total bytes for all cells */
int subtotal; /* Subtotal of bytes in cells on one page */
int cntNew[4]; /* Index in apCell[] of cell after i-th page */
@@ -1730,6 +1731,11 @@ static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){
rc = initPage(pPage, sqlitepager_pagenumber(pPage), 0);
assert( rc==SQLITE_OK );
reparentChildPages(pBt->pPager, pPage);
+ if( pCur && pCur->pPage==pChild ){
+ sqlitepager_unref(pChild);
+ pCur->pPage = pPage;
+ sqlitepager_ref(pPage);
+ }
freePage(pBt, pChild, pgnoChild);
sqlitepager_unref(pChild);
}else{
@@ -1760,8 +1766,8 @@ static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){
pChild->pParent = pPage;
sqlitepager_ref(pPage);
pChild->isOverfull = 1;
- if( pCur ){
- sqlitepager_unref(pCur->pPage);
+ if( pCur && pCur->pPage==pPage ){
+ sqlitepager_unref(pPage);
pCur->pPage = pChild;
}else{
extraUnref = pChild;
@@ -1796,7 +1802,7 @@ static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){
/*
** Initialize variables so that it will be safe to jump
- ** directory to balance_cleanup at any moment.
+ ** directly to balance_cleanup at any moment.
*/
nOld = nNew = 0;
sqlitepager_ref(pParent);
@@ -1836,15 +1842,25 @@ static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){
/*
** Set iCur to be the index in apCell[] of the cell that the cursor
** is pointing to. We will need this later on in order to keep the
- ** cursor pointing at the same cell.
+ ** cursor pointing at the same cell. If pCur points to a page that
+ ** has no involvement with this rebalancing, then set iCur to a large
+ ** number so that the iCur==j tests always fail in the main cell
+ ** distribution loop below.
*/
if( pCur ){
- iCur = pCur->idx;
- for(i=0; i<nDiv && idxDiv[i]<idx; i++){
- iCur += apOld[i]->nCell + 1;
+ iCur = 0;
+ for(i=0; i<nOld; i++){
+ if( pCur->pPage==apOld[i] ){
+ iCur += pCur->idx;
+ break;
+ }
+ iCur += apOld[i]->nCell;
+ if( i<nOld-1 && pCur->pPage==pParent && pCur->idx==idxDiv[i] ){
+ break;
+ }
+ iCur++;
}
- sqlitepager_unref(pCur->pPage);
- pCur->pPage = 0;
+ pOldCurPage = pCur->pPage;
}
/*
@@ -1965,8 +1981,9 @@ static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){
pParent->apCell[nxDiv]->h.leftChild = pgnoNew[nNew-1];
}
if( pCur ){
- assert( pCur->pPage!=0 );
+ assert( pOldCurPage!=0 );
sqlitepager_ref(pCur->pPage);
+ sqlitepager_unref(pOldCurPage);
}
/*
@@ -1980,7 +1997,7 @@ static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){
/*
** balance the parent page.
*/
- rc = balance(pBt, pParent, 0);
+ rc = balance(pBt, pParent, pCur);
/*
** Cleanup before returning.
@@ -2022,7 +2039,7 @@ int sqliteBtreeInsert(
MemPage *pPage;
Btree *pBt = pCur->pBt;
- if( !pCur->pBt->inTrans ){
+ if( !pCur->pBt->inTrans || nKey+nData==0 ){
return SQLITE_ERROR; /* Must start a transaction first */
}
rc = sqliteBtreeMoveto(pCur, pKey, nKey, &loc);
@@ -2107,8 +2124,10 @@ int sqliteBtreeDelete(BtCursor *pCur){
releaseTempCursor(&leafCur);
}else{
dropCell(pPage, pCur->idx, cellSize(pCell));
- if( pCur->idx>=pPage->nCell && pCur->idx>0 ){
- pCur->idx--;
+ if( pCur->idx>=pPage->nCell ){
+ pCur->idx = pPage->nCell-1;
+ if( pCur->idx<0 ){ pCur->idx = 0; }
+ pCur->bSkipNext = 0;
}else{
pCur->bSkipNext = 1;
}
@@ -2252,7 +2271,7 @@ int sqliteBtreeUpdateMeta(Btree *pBt, int *aMeta){
** All of the following code is omitted unless the library is compiled with
** the -DSQLITE_TEST=1 compiler option.
******************************************************************************/
-#ifdef SQLITE_TEST
+#if 1
/*
** Print a disassembly of the given page on standard output. This routine
diff --git a/src/build.c b/src/build.c
index 14d8793fa..436e0d262 100644
--- a/src/build.c
+++ b/src/build.c
@@ -33,7 +33,7 @@
** COPY
** VACUUM
**
-** $Id: build.c,v 1.31 2001/09/13 16:18:54 drh Exp $
+** $Id: build.c,v 1.32 2001/09/13 21:53:10 drh Exp $
*/
#include "sqliteInt.h"
@@ -241,6 +241,26 @@ void sqliteDeleteTable(sqlite *db, Table *pTable){
}
/*
+** Unlink the given table from the hash tables and the delete the
+** table structure and all its indices.
+*/
+static void sqliteUnlinkAndDeleteTable(sqlite *db, Table *pTable){
+ if( pTable->zName && db ){
+ int h = sqliteHashNoCase(pTable->zName, 0) % N_HASH;
+ if( db->apTblHash[h]==pTable ){
+ db->apTblHash[h] = pTable->pHash;
+ }else{
+ Table *p;
+ for(p=db->apTblHash[h]; p && p->pHash!=pTable; p=p->pHash){}
+ if( p && p->pHash==pTable ){
+ p->pHash = pTable->pHash;
+ }
+ }
+ }
+ sqliteDeleteTable(db, pTable);
+}
+
+/*
** Check all Tables and Indexes in the internal hash table and commit
** any additions or deletions to those hash tables.
**
@@ -262,7 +282,7 @@ void sqliteCommitInternalChanges(sqlite *db){
for(pTable = db->apTblHash[i]; pTable; pTable=pNext){
pNext = pTable->pHash;
if( pTable->isDelete ){
- sqliteDeleteTable(db, pTable);
+ sqliteUnlinkAndDeleteTable(db, pTable);
}else if( pTable->isCommit==0 ){
pTable->isCommit = 1;
}
@@ -298,7 +318,7 @@ void sqliteRollbackInternalChanges(sqlite *db){
for(pTable = db->apTblHash[i]; pTable; pTable=pNext){
pNext = pTable->pHash;
if( !pTable->isCommit ){
- sqliteDeleteTable(db, pTable);
+ sqliteUnlinkAndDeleteTable(db, pTable);
}else if( pTable->isDelete ){
pTable->isDelete = 0;
}
@@ -473,7 +493,7 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
*/
if( !pParse->initFlag ){
static VdbeOp addTable[] = {
- { OP_Open, 0, 2, 0},
+ { OP_Open, 0, 2, MASTER_NAME},
{ OP_NewRecno, 0, 0, 0},
{ OP_String, 0, 0, "table" },
{ OP_String, 0, 0, 0}, /* 3 */
@@ -495,6 +515,15 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
sqliteVdbeChangeP3(v, base+5, p->zName, 0);
sqliteVdbeChangeP3(v, base+6, pParse->sFirstToken.z, n);
sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
+ if( p->pIndex ){
+ /* If the table has a primary key, create an index in the database
+ ** for that key. */
+ Index *pIndex = p->pIndex;
+ assert( pIndex->pNext==0 );
+ assert( pIndex->tnum==0 );
+ sqliteVdbeAddOp(v, OP_CreateIndex, 0, 0, 0, 0),
+ sqliteVdbeIndexRootAddr(v, &pIndex->tnum);
+ }
if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
}
@@ -528,6 +557,7 @@ void sqliteDropTable(Parse *pParse, Token *pName){
Table *pTable;
Vdbe *v;
int base;
+ sqlite *db = pParse->db;
if( pParse->nErr || sqlite_malloc_failed ) return;
pTable = sqliteTableFromToken(pParse, pName);
@@ -545,29 +575,29 @@ void sqliteDropTable(Parse *pParse, Token *pName){
v = sqliteGetVdbe(pParse);
if( v ){
static VdbeOp dropTable[] = {
- { OP_Open, 0, 2, 0},
+ { OP_Open, 0, 2, MASTER_NAME},
{ OP_Rewind, 0, 0, 0},
{ OP_String, 0, 0, 0}, /* 2 */
- { OP_Next, 0, ADDR(10), 0}, /* 3 */
+ { OP_Next, 0, ADDR(9), 0}, /* 3 */
{ OP_Dup, 0, 0, 0},
{ OP_Column, 0, 3, 0},
{ OP_Ne, 0, ADDR(3), 0},
- { OP_Recno, 0, 0, 0},
{ OP_Delete, 0, 0, 0},
{ OP_Goto, 0, ADDR(3), 0},
- { OP_Destroy, 0, 0, 0}, /* 10 */
+ { OP_Destroy, 0, 0, 0}, /* 9 */
{ OP_Close, 0, 0, 0},
};
Index *pIdx;
- if( (pParse->db->flags & SQLITE_InTrans)==0 ){
+ if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
}
base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
- sqliteVdbeChangeP1(v, base+10, pTable->tnum);
+ sqliteVdbeChangeP3(v, base+2, pTable->zName, 0);
+ sqliteVdbeChangeP1(v, base+9, pTable->tnum);
for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, 0, 0, 0);
}
- if( (pParse->db->flags & SQLITE_InTrans)==0 ){
+ if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
}
}
@@ -580,7 +610,7 @@ void sqliteDropTable(Parse *pParse, Token *pName){
*/
if( !pParse->explain ){
pTable->isDelete = 1;
- pParse->db->flags |= SQLITE_InternChanges;
+ db->flags |= SQLITE_InternChanges;
}
}
@@ -720,16 +750,25 @@ void sqliteCreateIndex(
** CREATE INDEX statements are read out of the master table. In
** the latter case the index already exists on disk, which is why
** we don't want to recreate it.
+ **
+ ** If pTable==0 it means this index is generated as a primary key
+ ** and those does not have a CREATE INDEX statement to add to the
+ ** master table. Also, since primary keys are created at the same
+ ** time as tables, the table will be empty so there is no need to
+ ** initialize the index. Hence, skip all the code generation if
+ ** pTable==0.
*/
- if( pParse->initFlag==0 ){
+ else if( pParse->initFlag==0 && pTable!=0 ){
static VdbeOp addTable[] = {
- { OP_Open, 2, 2, 0},
+ { OP_Open, 2, 2, MASTER_NAME},
{ OP_NewRecno, 2, 0, 0},
{ OP_String, 0, 0, "index"},
{ OP_String, 0, 0, 0}, /* 3 */
- { OP_CreateIndex, 0, 0, 0},
- { OP_String, 0, 0, 0}, /* 5 */
- { OP_String, 0, 0, 0}, /* 6 */
+ { OP_CreateIndex, 1, 0, 0},
+ { OP_Dup, 0, 0, 0},
+ { OP_Open, 1, 0, 0}, /* 6 */
+ { OP_String, 0, 0, 0}, /* 7 */
+ { OP_String, 0, 0, 0}, /* 8 */
{ OP_MakeRecord, 5, 0, 0},
{ OP_Put, 2, 0, 0},
{ OP_Close, 2, 0, 0},
@@ -744,17 +783,17 @@ void sqliteCreateIndex(
if( pTable!=0 && (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
}
- sqliteVdbeAddOp(v, OP_Open, 0, pTab->tnum, pTab->zName, 0);
- sqliteVdbeAddOp(v, OP_Open, 1, pIndex->tnum, pIndex->zName, 0);
if( pStart && pEnd ){
int base;
n = (int)pEnd->z - (int)pStart->z + 1;
base = sqliteVdbeAddOpList(v, ArraySize(addTable), addTable);
sqliteVdbeChangeP3(v, base+3, pIndex->zName, 0);
sqliteVdbeIndexRootAddr(v, &pIndex->tnum);
- sqliteVdbeChangeP3(v, base+5, pTab->zName, 0);
- sqliteVdbeChangeP3(v, base+6, pStart->z, n);
+ sqliteVdbeChangeP3(v, base+6, pIndex->zName, 0);
+ sqliteVdbeChangeP3(v, base+7, pTab->zName, 0);
+ sqliteVdbeChangeP3(v, base+8, pStart->z, n);
}
+ sqliteVdbeAddOp(v, OP_Open, 0, pTab->tnum, pTab->zName, 0);
lbl1 = sqliteVdbeMakeLabel(v);
lbl2 = sqliteVdbeMakeLabel(v);
sqliteVdbeAddOp(v, OP_Rewind, 0, 0, 0, 0);
@@ -812,16 +851,15 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
v = sqliteGetVdbe(pParse);
if( v ){
static VdbeOp dropIndex[] = {
- { OP_Open, 0, 2, 0},
+ { OP_Open, 0, 2, MASTER_NAME},
{ OP_Rewind, 0, 0, 0},
{ OP_String, 0, 0, 0}, /* 2 */
- { OP_Next, 0, ADDR(9), 0}, /* 3 */
+ { OP_Next, 0, ADDR(8), 0}, /* 3 */
{ OP_Dup, 0, 0, 0},
{ OP_Column, 0, 1, 0},
{ OP_Ne, 0, ADDR(3), 0},
- { OP_Recno, 0, 0, 0},
{ OP_Delete, 0, 0, 0},
- { OP_Destroy, 0, 0, 0}, /* 9 */
+ { OP_Destroy, 0, 0, 0}, /* 8 */
{ OP_Close, 0, 0, 0},
};
int base;
@@ -830,7 +868,7 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
}
base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
- sqliteVdbeChangeP1(v, base+9, pIndex->tnum);
+ sqliteVdbeChangeP1(v, base+8, pIndex->tnum);
if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
}
diff --git a/src/delete.c b/src/delete.c
index ab5e7f2da..523bc2ec0 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
-** $Id: delete.c,v 1.11 2001/09/13 14:46:10 drh Exp $
+** $Id: delete.c,v 1.12 2001/09/13 21:53:10 drh Exp $
*/
#include "sqliteInt.h"
@@ -96,12 +96,12 @@ void sqliteDeleteFrom(
/* Special case: A DELETE without a WHERE clause deletes everything.
- ** It is easier just to deleted the database files directly.
+ ** It is easier just to clear all information the database tables directly.
*/
if( pWhere==0 ){
- sqliteVdbeAddOp(v, OP_Destroy, pTab->tnum, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, 0, 0, 0);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_Clear, pIdx->tnum, 0, 0, 0);
}
}
@@ -135,12 +135,11 @@ void sqliteDeleteFrom(
}
end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
+ sqliteVdbeAddOp(v, OP_MoveTo, base, 0, 0, 0);
if( pTab->pIndex ){
- sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
- sqliteVdbeAddOp(v, OP_MoveTo, base, 0, 0, 0);
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
int j;
- sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_Recno, base, 0, 0, 0);
for(j=0; j<pIdx->nColumn; j++){
sqliteVdbeAddOp(v, OP_Column, base, pIdx->aiColumn[j], 0, 0);
}
diff --git a/src/main.c b/src/main.c
index 8704149c9..7583542de 100644
--- a/src/main.c
+++ b/src/main.c
@@ -26,7 +26,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
-** $Id: main.c,v 1.33 2001/09/13 16:18:54 drh Exp $
+** $Id: main.c,v 1.34 2001/09/13 21:53:10 drh Exp $
*/
#include "sqliteInt.h"
#if defined(HAVE_USLEEP) && HAVE_USLEEP
@@ -253,6 +253,7 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
}
}
sqliteFree(db);
+ sqliteStrRealloc(pzErrMsg);
return 0;
}
@@ -265,6 +266,7 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
goto no_mem_on_open;
}else if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
sqlite_close(db);
+ sqliteStrRealloc(pzErrMsg);
return 0;
}else /* if( pzErrMsg ) */{
sqliteFree(*pzErrMsg);
diff --git a/src/random.c b/src/random.c
index 413b5d9c4..86cb91d20 100644
--- a/src/random.c
+++ b/src/random.c
@@ -27,7 +27,7 @@
** Random numbers are used by some of the database backends in order
** to generate random integer keys for tables or random filenames.
**
-** $Id: random.c,v 1.2 2001/01/31 13:28:09 drh Exp $
+** $Id: random.c,v 1.3 2001/09/13 21:53:10 drh Exp $
*/
#include "sqliteInt.h"
#include <time.h>
@@ -87,7 +87,7 @@ int sqliteRandomByte(void){
prng_state.s[prng_state.i] = prng_state.s[prng_state.j];
prng_state.s[prng_state.j] = t;
t = prng_state.s[prng_state.i] + prng_state.s[prng_state.j];
- return t & 0xff;
+ return prng_state.s[t & 0xff];
}
/*
diff --git a/src/select.c b/src/select.c
index e0e38a1e3..a937d93cd 100644
--- a/src/select.c
+++ b/src/select.c
@@ -24,7 +24,7 @@
** This file contains C code routines that are called by the parser
** to handle SELECT statements.
**
-** $Id: select.c,v 1.34 2001/09/13 16:18:54 drh Exp $
+** $Id: select.c,v 1.35 2001/09/13 21:53:10 drh Exp $
*/
#include "sqliteInt.h"
@@ -182,6 +182,7 @@ static int selectInnerLoop(
*/
if( eDest==SRT_Except ){
sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_MoveTo, iParm, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Delete, iParm, 0, 0, 0);
}else
diff --git a/src/test3.c b/src/test3.c
index 289c45e52..42f44b357 100644
--- a/src/test3.c
+++ b/src/test3.c
@@ -25,7 +25,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
-** $Id: test3.c,v 1.9 2001/08/20 00:33:58 drh Exp $
+** $Id: test3.c,v 1.10 2001/09/13 21:53:10 drh Exp $
*/
#include "sqliteInt.h"
#include "pager.h"
@@ -715,9 +715,11 @@ static int btree_key(
sqliteBtreeKeySize(pCur, &n);
zBuf = malloc( n+1 );
rc = sqliteBtreeKey(pCur, 0, n, zBuf);
- if( rc ){
+ if( rc!=n ){
+ char zMsg[100];
free(zBuf);
- Tcl_AppendResult(interp, errorName(rc), 0);
+ sprintf(zMsg, "truncated key: got %d of %d bytes", rc, n);
+ Tcl_AppendResult(interp, zMsg, 0);
return TCL_ERROR;
}
zBuf[n] = 0;
@@ -751,9 +753,11 @@ static int btree_data(
sqliteBtreeDataSize(pCur, &n);
zBuf = malloc( n+1 );
rc = sqliteBtreeData(pCur, 0, n, zBuf);
- if( rc ){
+ if( rc!=n ){
+ char zMsg[100];
free(zBuf);
- Tcl_AppendResult(interp, errorName(rc), 0);
+ sprintf(zMsg, "truncated data: got %d of %d bytes", rc, n);
+ Tcl_AppendResult(interp, zMsg, 0);
return TCL_ERROR;
}
zBuf[n] = 0;
diff --git a/src/vdbe.c b/src/vdbe.c
index 1133c1886..8962fd2b3 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -41,10 +41,11 @@
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
-** $Id: vdbe.c,v 1.63 2001/09/13 16:18:54 drh Exp $
+** $Id: vdbe.c,v 1.64 2001/09/13 21:53:10 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
+#include <unistd.h>
/*
** SQL is translated into a sequence of instructions to be
@@ -875,26 +876,26 @@ static char *zOpName[] = { 0,
"NewRecno", "Put", "Distinct", "Found",
"NotFound", "Delete", "Column", "KeyAsData",
"Recno", "FullKey", "Rewind", "Next",
- "Destroy", "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",
+ "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",
};
/*
@@ -1979,6 +1980,8 @@ case OP_Rollback: {
** 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.
**
+** If P2==0 then take the root page number from the top of the stack.
+**
** The P3 value is the name of the table or index being opened.
** The P3 value is not actually used by this opcode and may be
** omitted. But the code generator usually inserts the index or
@@ -1987,6 +1990,19 @@ case OP_Rollback: {
case OP_Open: {
int busy = 0;
int i = pOp->p1;
+ int tos = p->tos;
+ int p2 = pOp->p2;
+ if( p2<=0 ){
+ if( tos<0 ) goto not_enough_stack;
+ Integerify(p, tos);
+ p2 = p->aStack[tos].i;
+ POPSTACK;
+ if( p2<2 ){
+ sqliteSetString(pzErrMsg, "root page number less than 2", 0);
+ rc = SQLITE_INTERNAL;
+ goto cleanup;
+ }
+ }
VERIFY( if( i<0 ) goto bad_instruction; )
if( i>=p->nCursor ){
int j;
@@ -1999,7 +2015,7 @@ case OP_Open: {
}
memset(&p->aCsr[i], 0, sizeof(Cursor));
do{
- rc = sqliteBtreeCursor(pBt, pOp->p2, &p->aCsr[i].pCursor);
+ rc = sqliteBtreeCursor(pBt, p2, &p->aCsr[i].pCursor);
switch( rc ){
case SQLITE_BUSY: {
if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){
@@ -2240,29 +2256,18 @@ case OP_Put: {
/* Opcode: Delete P1 * *
**
-** The top of the stack is a key. Remove this key and its data
-** from database file P1. Then pop the stack to discard the key.
+** Delete the record at which the P1 cursor is currently pointing.
+**
+** The cursor will be left pointing at either the next or the previous
+** record in the table. If it is left pointing at the next record, then
+** the next OP_Next will be a no-op. Hence it is OK to delete a record
+** from within an OP_Next loop.
*/
case OP_Delete: {
- int tos = p->tos;
int i = pOp->p1;
- int res;
- VERIFY( if( tos<0 ) goto not_enough_stack; )
if( VERIFY( i>=0 && i<p->nCursor && ) p->aCsr[i].pCursor!=0 ){
- char *zKey;
- int nKey;
- if( aStack[tos].flags & STK_Int ){
- nKey = sizeof(int);
- zKey = (char*)&aStack[tos].i;
- }else{
- if( Stringify(p, tos) ) goto no_mem;
- nKey = aStack[tos].n;
- zKey = zStack[tos];
- }
- rc = sqliteBtreeMoveto(p->aCsr[i].pCursor, zKey, nKey, &res);
rc = sqliteBtreeDelete(p->aCsr[i].pCursor);
}
- POPSTACK;
break;
}
@@ -2303,11 +2308,11 @@ case OP_Column: {
static const int mxHdr = sizeof(aHdr)/sizeof(aHdr[0]);
int i = pOp->p1;
int p2 = pOp->p2;
- int tos = ++p->tos;
+ int tos = p->tos+1;
BtCursor *pCrsr;
char *z;
- VERIFY( if( NeedStack(p, tos) ) goto no_mem; )
+ VERIFY( if( NeedStack(p, tos+1) ) goto no_mem; )
if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
int (*xSize)(BtCursor*, int*);
int (*xRead)(BtCursor*, int, int, char*);
@@ -2371,6 +2376,7 @@ case OP_Column: {
zStack[tos] = z;
aStack[tos].n = amt;
}
+ p->tos = tos;
}
break;
}
@@ -2530,8 +2536,13 @@ case OP_NextIdx: {
zStack[tos] = 0;
if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = &p->aCsr[i])->pCursor!=0 ){
pCur = pCrsr->pCursor;
- rx = sqliteBtreeNext(pCur, &res);
- if( rx!=SQLITE_OK ) goto abort_due_to_error;
+ if( pCrsr->atFirst ){
+ pCrsr->atFirst = 0;
+ res = 0;
+ }else{
+ rx = sqliteBtreeNext(pCur, &res);
+ if( rx!=SQLITE_OK ) goto abort_due_to_error;
+ }
sqliteBtreeKeySize(pCur, &size);
if( res>0 || size!=pCrsr->nKey+sizeof(int) ||
sqliteBtreeKey(pCur, 0, pCrsr->nKey, pCrsr->zBuf)!=pCrsr->nKey ||
@@ -2599,6 +2610,17 @@ case OP_Destroy: {
break;
}
+/* Opcode: Clear P1 * *
+**
+** Delete all contents of the database table or index whose root page
+** in the database file is given by P1. But, unlike OP_Destroy, do not
+** remove the table or index from the database file.
+*/
+case OP_Clear: {
+ sqliteBtreeClearTable(pBt, pOp->p1);
+ break;
+}
+
/* Opcode: CreateTable * * *
**
** Allocate a new table in the main database file. Push the page number
@@ -2634,6 +2656,8 @@ case OP_CreateTable: {
** Allocate a new Index in the main database file. Push the page number
** for the root page of the new table onto the stack.
**
+** If P1>=0 then open a cursor named P1 on the newly created index.
+**
** The root page number is also written to a memory location which has
** be set up by the parser. The difference between CreateTable and
** CreateIndex is that each writes its root page number into a different
@@ -3684,7 +3708,7 @@ default: {
cleanup:
Cleanup(p);
- if( p->pTableRoot || p->pIndexRoot ){
+ if( (p->pTableRoot || p->pIndexRoot) && rc==SQLITE_OK ){
rc = SQLITE_INTERNAL;
sqliteSetString(pzErrMsg, "table or index root page not set", 0);
}
diff --git a/src/vdbe.h b/src/vdbe.h
index 59f834022..cbf7e08c9 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -27,7 +27,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.20 2001/09/13 14:46:11 drh Exp $
+** $Id: vdbe.h,v 1.21 2001/09/13 21:53:10 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
@@ -94,98 +94,99 @@ typedef struct VdbeOp VdbeOp;
#define OP_Next 20
#define OP_Destroy 21
-#define OP_CreateIndex 22
-#define OP_CreateTable 23
-#define OP_Reorganize 24
-
-#define OP_BeginIdx 25
-#define OP_NextIdx 26
-#define OP_PutIdx 27
-#define OP_DeleteIdx 28
-
-#define OP_MemLoad 29
-#define OP_MemStore 30
-
-#define OP_ListOpen 31
-#define OP_ListWrite 32
-#define OP_ListRewind 33
-#define OP_ListRead 34
-#define OP_ListClose 35
-
-#define OP_SortOpen 36
-#define OP_SortPut 37
-#define OP_SortMakeRec 38
-#define OP_SortMakeKey 39
-#define OP_Sort 40
-#define OP_SortNext 41
-#define OP_SortKey 42
-#define OP_SortCallback 43
-#define OP_SortClose 44
-
-#define OP_FileOpen 45
-#define OP_FileRead 46
-#define OP_FileColumn 47
-#define OP_FileClose 48
-
-#define OP_AggReset 49
-#define OP_AggFocus 50
-#define OP_AggIncr 51
-#define OP_AggNext 52
-#define OP_AggSet 53
-#define OP_AggGet 54
-
-#define OP_SetInsert 55
-#define OP_SetFound 56
-#define OP_SetNotFound 57
-#define OP_SetClear 58
-
-#define OP_MakeRecord 59
-#define OP_MakeKey 60
-#define OP_MakeIdxKey 61
-
-#define OP_Goto 62
-#define OP_If 63
-#define OP_Halt 64
-
-#define OP_ColumnCount 65
-#define OP_ColumnName 66
-#define OP_Callback 67
-
-#define OP_Integer 68
-#define OP_String 69
-#define OP_Null 70
-#define OP_Pop 71
-#define OP_Dup 72
-#define OP_Pull 73
-
-#define OP_Add 74
-#define OP_AddImm 75
-#define OP_Subtract 76
-#define OP_Multiply 77
-#define OP_Divide 78
-#define OP_Min 79
-#define OP_Max 80
-#define OP_Like 81
-#define OP_Glob 82
-#define OP_Eq 83
-#define OP_Ne 84
-#define OP_Lt 85
-#define OP_Le 86
-#define OP_Gt 87
-#define OP_Ge 88
-#define OP_IsNull 89
-#define OP_NotNull 90
-#define OP_Negative 91
-#define OP_And 92
-#define OP_Or 93
-#define OP_Not 94
-#define OP_Concat 95
-#define OP_Noop 96
-
-#define OP_Strlen 97
-#define OP_Substr 98
-
-#define OP_MAX 98
+#define OP_Clear 22
+#define OP_CreateIndex 23
+#define OP_CreateTable 24
+#define OP_Reorganize 25
+
+#define OP_BeginIdx 26
+#define OP_NextIdx 27
+#define OP_PutIdx 28
+#define OP_DeleteIdx 29
+
+#define OP_MemLoad 30
+#define OP_MemStore 31
+
+#define OP_ListOpen 32
+#define OP_ListWrite 33
+#define OP_ListRewind 34
+#define OP_ListRead 35
+#define OP_ListClose 36
+
+#define OP_SortOpen 37
+#define OP_SortPut 38
+#define OP_SortMakeRec 39
+#define OP_SortMakeKey 40
+#define OP_Sort 41
+#define OP_SortNext 42
+#define OP_SortKey 43
+#define OP_SortCallback 44
+#define OP_SortClose 45
+
+#define OP_FileOpen 46
+#define OP_FileRead 47
+#define OP_FileColumn 48
+#define OP_FileClose 49
+
+#define OP_AggReset 50
+#define OP_AggFocus 51
+#define OP_AggIncr 52
+#define OP_AggNext 53
+#define OP_AggSet 54
+#define OP_AggGet 55
+
+#define OP_SetInsert 56
+#define OP_SetFound 57
+#define OP_SetNotFound 58
+#define OP_SetClear 59
+
+#define OP_MakeRecord 60
+#define OP_MakeKey 61
+#define OP_MakeIdxKey 62
+
+#define OP_Goto 63
+#define OP_If 64
+#define OP_Halt 65
+
+#define OP_ColumnCount 66
+#define OP_ColumnName 67
+#define OP_Callback 68
+
+#define OP_Integer 69
+#define OP_String 70
+#define OP_Null 71
+#define OP_Pop 72
+#define OP_Dup 73
+#define OP_Pull 74
+
+#define OP_Add 75
+#define OP_AddImm 76
+#define OP_Subtract 77
+#define OP_Multiply 78
+#define OP_Divide 79
+#define OP_Min 80
+#define OP_Max 81
+#define OP_Like 82
+#define OP_Glob 83
+#define OP_Eq 84
+#define OP_Ne 85
+#define OP_Lt 86
+#define OP_Le 87
+#define OP_Gt 88
+#define OP_Ge 89
+#define OP_IsNull 90
+#define OP_NotNull 91
+#define OP_Negative 92
+#define OP_And 93
+#define OP_Or 94
+#define OP_Not 95
+#define OP_Concat 96
+#define OP_Noop 97
+
+#define OP_Strlen 98
+#define OP_Substr 99
+
+#define OP_MAX 99
/*
** Prototypes for the VDBE interface. See comments on the implementation