diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/btree.c | 62 | ||||
-rw-r--r-- | src/btree.h | 3 | ||||
-rw-r--r-- | src/btreeInt.h | 6 | ||||
-rw-r--r-- | src/select.c | 4 | ||||
-rw-r--r-- | src/test_btree.c | 4 | ||||
-rw-r--r-- | src/test_func.c | 35 | ||||
-rw-r--r-- | src/vdbe.c | 24 | ||||
-rw-r--r-- | src/vdbeaux.c | 10 |
8 files changed, 103 insertions, 45 deletions
diff --git a/src/btree.c b/src/btree.c index 8ef51f595..cf531b908 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.480 2008/07/11 16:39:23 drh Exp $ +** $Id: btree.c,v 1.481 2008/07/11 21:02:54 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. @@ -361,14 +361,10 @@ static void clearCursorPosition(BtCursor *pCur){ ** Restore the cursor to the position it was in (or as close to as possible) ** when saveCursorPosition() was called. Note that this call deletes the ** saved position info stored by saveCursorPosition(), so there can be -** at most one effective restoreOrClearCursorPosition() call after each +** at most one effective restoreCursorPosition() call after each ** saveCursorPosition(). -** -** If the second argument argument - doSeek - is false, then instead of -** returning the cursor to its saved position, any saved position is deleted -** and the cursor state set to CURSOR_INVALID. */ -int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur){ +int sqlite3BtreeRestoreCursorPosition(BtCursor *pCur){ int rc; assert( cursorHoldsMutex(pCur) ); assert( pCur->eState>=CURSOR_REQUIRESEEK ); @@ -385,11 +381,35 @@ int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur){ return rc; } -#define restoreOrClearCursorPosition(p) \ +#define restoreCursorPosition(p) \ (p->eState>=CURSOR_REQUIRESEEK ? \ - sqlite3BtreeRestoreOrClearCursorPosition(p) : \ + sqlite3BtreeRestoreCursorPosition(p) : \ SQLITE_OK) +/* +** Determine whether or not a cursor has moved from the position it +** was last placed at. Cursor can move when the row they are pointing +** at is deleted out from under them. +** +** This routine returns an error code if something goes wrong. The +** integer *pHasMoved is set to one if the cursor has moved and 0 if not. +*/ +int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){ + int rc; + + rc = restoreCursorPosition(pCur); + if( rc ){ + *pHasMoved = 1; + return rc; + } + if( pCur->eState!=CURSOR_VALID || pCur->skip!=0 ){ + *pHasMoved = 1; + }else{ + *pHasMoved = 0; + } + return SQLITE_OK; +} + #ifndef SQLITE_OMIT_AUTOVACUUM /* ** Given a page number of a regular database page, return the page @@ -2768,9 +2788,7 @@ static int btreeCursor( return SQLITE_OK; create_cursor_exception: - if( pCur ){ - releasePage(pCur->pPage); - } + releasePage(pCur->pPage); unlockBtreeIfUnused(pBt); return rc; } @@ -2905,7 +2923,7 @@ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ int rc; assert( cursorHoldsMutex(pCur) ); - rc = restoreOrClearCursorPosition(pCur); + rc = restoreCursorPosition(pCur); if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID ); if( pCur->eState==CURSOR_INVALID ){ @@ -2929,7 +2947,7 @@ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ int rc; assert( cursorHoldsMutex(pCur) ); - rc = restoreOrClearCursorPosition(pCur); + rc = restoreCursorPosition(pCur); if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID ); if( pCur->eState==CURSOR_INVALID ){ @@ -3237,7 +3255,7 @@ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ int rc; assert( cursorHoldsMutex(pCur) ); - rc = restoreOrClearCursorPosition(pCur); + rc = restoreCursorPosition(pCur); if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_VALID ); assert( pCur->pPage!=0 ); @@ -3270,7 +3288,7 @@ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ #endif assert( cursorHoldsMutex(pCur) ); - rc = restoreOrClearCursorPosition(pCur); + rc = restoreCursorPosition(pCur); if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_VALID ); assert( pCur->pPage!=0 ); @@ -3821,7 +3839,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ MemPage *pPage; assert( cursorHoldsMutex(pCur) ); - rc = restoreOrClearCursorPosition(pCur); + rc = restoreCursorPosition(pCur); if( rc!=SQLITE_OK ){ return rc; } @@ -3890,7 +3908,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ MemPage *pPage; assert( cursorHoldsMutex(pCur) ); - rc = restoreOrClearCursorPosition(pCur); + rc = restoreCursorPosition(pCur); if( rc!=SQLITE_OK ){ return rc; } @@ -5834,7 +5852,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){ ** that the entry will be deleted from. */ if( - (rc = restoreOrClearCursorPosition(pCur))!=0 || + (rc = restoreCursorPosition(pCur))!=0 || (rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur))!=0 || (rc = sqlite3PagerWrite(pPage->pDbPage))!=0 ){ @@ -6362,10 +6380,10 @@ int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ */ int sqlite3BtreeFlags(BtCursor *pCur){ /* TODO: What about CURSOR_REQUIRESEEK state? Probably need to call - ** restoreOrClearCursorPosition() here. + ** restoreCursorPosition() here. */ MemPage *pPage; - restoreOrClearCursorPosition(pCur); + restoreCursorPosition(pCur); pPage = pCur->pPage; assert( cursorHoldsMutex(pCur) ); assert( pPage->pBt==pCur->pBt ); @@ -7176,7 +7194,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) ); assert(pCsr->isIncrblobHandle); - restoreOrClearCursorPosition(pCsr); + restoreCursorPosition(pCsr); assert( pCsr->eState!=CURSOR_REQUIRESEEK ); if( pCsr->eState!=CURSOR_VALID ){ return SQLITE_ABORT; diff --git a/src/btree.h b/src/btree.h index 780f1d3f1..3fe01cbd2 100644 --- a/src/btree.h +++ b/src/btree.h @@ -13,7 +13,7 @@ ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** -** @(#) $Id: btree.h,v 1.101 2008/07/11 16:15:18 drh Exp $ +** @(#) $Id: btree.h,v 1.102 2008/07/11 21:02:54 drh Exp $ */ #ifndef _BTREE_H_ #define _BTREE_H_ @@ -142,6 +142,7 @@ int sqlite3BtreeMoveto( int bias, int *pRes ); +int sqlite3BtreeCursorHasMoved(BtCursor*, int*); int sqlite3BtreeDelete(BtCursor*); int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey, const void *pData, int nData, diff --git a/src/btreeInt.h b/src/btreeInt.h index 0ec07aa9d..2fd42358e 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btreeInt.h,v 1.24 2008/07/10 00:32:42 drh Exp $ +** $Id: btreeInt.h,v 1.25 2008/07/11 21:02:54 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -466,7 +466,7 @@ struct BtCursor { ** The table that this cursor was opened on still exists, but has been ** modified since the cursor was last used. The cursor position is saved ** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in -** this state, restoreOrClearCursorPosition() can be called to attempt to +** this state, restoreCursorPosition() can be called to attempt to ** seek the cursor to the saved position. ** ** CURSOR_FAULT: @@ -631,7 +631,7 @@ int sqlite3BtreeGetPage(BtShared*, Pgno, MemPage**, int); int sqlite3BtreeInitPage(MemPage *pPage, MemPage *pParent); void sqlite3BtreeParseCellPtr(MemPage*, u8*, CellInfo*); void sqlite3BtreeParseCell(MemPage*, int, CellInfo*); -int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur); +int sqlite3BtreeRestoreCursorPosition(BtCursor *pCur); void sqlite3BtreeGetTempCursor(BtCursor *pCur, BtCursor *pTempCur); void sqlite3BtreeReleaseTempCursor(BtCursor *pCur); int sqlite3BtreeIsRootPage(MemPage *pPage); diff --git a/src/select.c b/src/select.c index e14e2920d..56ede613c 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.454 2008/07/10 17:59:12 danielk1977 Exp $ +** $Id: select.c,v 1.455 2008/07/11 21:02:54 drh Exp $ */ #include "sqliteInt.h" @@ -1165,7 +1165,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ assert( pTab->nCol>0 ); pTab->aCol = aCol = sqlite3DbMallocZero(db, sizeof(pTab->aCol[0])*pTab->nCol); for(i=0, pCol=aCol; i<pTab->nCol; i++, pCol++){ - Expr *p, *pR; + Expr *p; char *zType; char *zName; int nName; diff --git a/src/test_btree.c b/src/test_btree.c index 615c9601d..1b33ef9b0 100644 --- a/src/test_btree.c +++ b/src/test_btree.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test_btree.c,v 1.4 2008/07/10 00:32:42 drh Exp $ +** $Id: test_btree.c,v 1.5 2008/07/11 21:02:54 drh Exp $ */ #include "btreeInt.h" #include <tcl.h> @@ -87,7 +87,7 @@ int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){ int rc; if( pCur->eState==CURSOR_REQUIRESEEK ){ - rc = sqlite3BtreeRestoreOrClearCursorPosition(pCur); + rc = sqlite3BtreeRestoreCursorPosition(pCur); if( rc!=SQLITE_OK ){ return rc; } diff --git a/src/test_func.c b/src/test_func.c index 370455285..d43b7a9f2 100644 --- a/src/test_func.c +++ b/src/test_func.c @@ -12,7 +12,7 @@ ** Code for testing all sorts of SQLite interfaces. This code ** implements new SQL functions used by the test scripts. ** -** $Id: test_func.c,v 1.7 2008/07/08 14:17:35 danielk1977 Exp $ +** $Id: test_func.c,v 1.8 2008/07/11 21:02:54 drh Exp $ */ #include "sqlite3.h" #include "tcl.h" @@ -230,6 +230,38 @@ static void test_isolation( sqlite3_result_value(pCtx, argv[1]); } +/* +** Invoke an SQL statement recursively. The function result is the +** first column of the first row of the result set. +*/ +static void test_eval( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **argv +){ + sqlite3_stmt *pStmt; + int rc; + sqlite3 *db = sqlite3_context_db_handle(pCtx); + const char *zSql; + + zSql = (char*)sqlite3_value_text(argv[0]); + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3_step(pStmt); + if( rc==SQLITE_ROW ){ + sqlite3_result_value(pCtx, sqlite3_column_value(pStmt, 0)); + } + rc = sqlite3_finalize(pStmt); + } + if( rc ){ + char *zErr; + assert( pStmt==0 ); + zErr = sqlite3_mprintf("sqlite3_prepare_v2() error: %s",sqlite3_errmsg(db)); + sqlite3_result_text(pCtx, zErr, -1, sqlite3_free); + sqlite3_result_error_code(pCtx, rc); + } +} + static int registerTestFunctions(sqlite3 *db){ static const struct { @@ -245,6 +277,7 @@ static int registerTestFunctions(sqlite3 *db){ { "test_auxdata", -1, SQLITE_UTF8, test_auxdata}, { "test_error", 1, SQLITE_UTF8, test_error}, { "test_error", 2, SQLITE_UTF8, test_error}, + { "test_eval", 1, SQLITE_UTF8, test_eval}, { "test_isolation", 2, SQLITE_UTF8, test_isolation}, }; int i; diff --git a/src/vdbe.c b/src/vdbe.c index ac3e20868..d65995be0 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.760 2008/07/10 00:32:42 drh Exp $ +** $Id: vdbe.c,v 1.761 2008/07/11 21:02:54 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -1670,7 +1670,6 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ int flags; int res; char affinity; - Mem x1, x3; flags = pIn1->flags|pIn3->flags; @@ -3808,6 +3807,7 @@ case OP_Prev: /* jump */ case OP_Next: { /* jump */ Cursor *pC; BtCursor *pCrsr; + int res; CHECK_FOR_INTERRUPT; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); @@ -3817,19 +3817,17 @@ case OP_Next: { /* jump */ } pCrsr = pC->pCursor; assert( pCrsr ); - if( pC->nullRow==0 ){ - int res = 1; - assert( pC->deferredMoveto==0 ); - rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) : - sqlite3BtreePrevious(pCrsr, &res); - pC->nullRow = res; - pC->cacheStatus = CACHE_STALE; - if( res==0 ){ - pc = pOp->p2 - 1; + res = 1; + assert( pC->deferredMoveto==0 ); + rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) : + sqlite3BtreePrevious(pCrsr, &res); + pC->nullRow = res; + pC->cacheStatus = CACHE_STALE; + if( res==0 ){ + pc = pOp->p2 - 1; #ifdef SQLITE_TEST - sqlite3_search_count++; + sqlite3_search_count++; #endif - } } pC->rowidIsValid = 0; break; diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 6e61ce446..79fe89f00 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -14,7 +14,7 @@ ** to version 2.8.7, all this code was combined into the vdbe.c source file. ** But that file was getting too big so this subroutines were split out. ** -** $Id: vdbeaux.c,v 1.396 2008/07/11 16:15:18 drh Exp $ +** $Id: vdbeaux.c,v 1.397 2008/07/11 21:02:54 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -1864,6 +1864,14 @@ int sqlite3VdbeCursorMoveto(Cursor *p){ #endif p->deferredMoveto = 0; p->cacheStatus = CACHE_STALE; + }else if( p->pCursor ){ + int hasMoved; + int rc = sqlite3BtreeCursorHasMoved(p->pCursor, &hasMoved); + if( rc ) return rc; + if( hasMoved ){ + p->cacheStatus = CACHE_STALE; + p->nullRow = 1; + } } return SQLITE_OK; } |