diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/btree.c | 51 | ||||
-rw-r--r-- | src/build.c | 90 | ||||
-rw-r--r-- | src/delete.c | 13 | ||||
-rw-r--r-- | src/main.c | 4 | ||||
-rw-r--r-- | src/random.c | 4 | ||||
-rw-r--r-- | src/select.c | 3 | ||||
-rw-r--r-- | src/test3.c | 14 | ||||
-rw-r--r-- | src/vdbe.c | 112 | ||||
-rw-r--r-- | src/vdbe.h | 187 |
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 |