Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -41,11 +41,11 @@ ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** 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.369 2004/06/12 18:12:16 drh Exp $ +** $Id: vdbe.c,v 1.370 2004/06/12 20:12:51 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include #include "vdbeInt.h" @@ -269,28 +269,31 @@ } return sHead.pNext; } /* -** Make sure there is space in the Vdbe structure to hold at least -** mxCursor cursors. If there is not currently enough space, then -** allocate more. -** -** If a memory allocation error occurs, return 1. Return 0 if -** everything works. +** Allocate cursor number iCur. Return a pointer to it. Return NULL +** if we run out of memory. */ -static int expandCursorArraySize(Vdbe *p, int mxCursor){ - if( mxCursor>=p->nCursor ){ - p->apCsr = sqliteRealloc( p->apCsr, (mxCursor+1)*sizeof(Cursor*) ); - if( p->apCsr==0 ) return 1; - while( p->nCursor<=mxCursor ){ - Cursor *pC; - p->apCsr[p->nCursor++] = pC = sqliteMalloc( sizeof(Cursor) ); - if( pC==0 ) return 1; +static Cursor *allocateCursor(Vdbe *p, int iCur){ + Cursor *pCx; + if( iCur>=p->nCursor ){ + int i; + p->apCsr = sqliteRealloc( p->apCsr, (iCur+1)*sizeof(Cursor*) ); + if( p->apCsr==0 ){ + p->nCursor = 0; + return 0; } + for(i=p->nCursor; iapCsr[i] = 0; + } + p->nCursor = iCur+1; + }else if( p->apCsr[iCur] ){ + sqlite3VdbeFreeCursor(p->apCsr[iCur]); } - return 0; + p->apCsr[iCur] = pCx = sqliteMalloc( sizeof(Cursor) ); + return pCx; } /* ** Apply any conversion required by the supplied column affinity to ** memory cell pRec. affinity may be one of: @@ -1865,10 +1868,11 @@ ** ** This opcode sets the number of columns for cursor P1 to P2. */ case OP_SetNumColumns: { assert( (pOp->p1)nCursor ); + assert( p->apCsr[pOp->p1]!=0 ); p->apCsr[pOp->p1]->nField = pOp->p2; break; } /* Opcode: IdxColumn P1 * * @@ -1929,10 +1933,11 @@ ** We also compute the number of columns in the record. For cursors, ** the number of columns is stored in the Cursor.nField element. For ** records on the stack, the next entry down on the stack is an integer ** which is the number of records. */ + assert( p1<0 || p->apCsr[p1]!=0 ); if( p1<0 ){ /* Take the record off of the stack */ Mem *pRec = &pTos[p1]; Mem *pCnt = &pRec[-1]; assert( pRec>=p->aStack ); @@ -2570,13 +2575,12 @@ rc = SQLITE_INTERNAL; break; } } assert( i>=0 ); - if( expandCursorArraySize(p, i) ) goto no_mem; - pCur = p->apCsr[i]; - sqlite3VdbeCleanupCursor(pCur); + pCur = allocateCursor(p, i); + if( pCur==0 ) goto no_mem; pCur->nullRow = 1; if( pX==0 ) break; /* We always provide a key comparison function. If the table being ** opened is of type INTKEY, the comparision function will be ignored. */ rc = sqlite3BtreeCursor(pX, p2, wrFlag, @@ -2633,14 +2637,12 @@ */ case OP_OpenTemp: { int i = pOp->p1; Cursor *pCx; assert( i>=0 ); - if( expandCursorArraySize(p, i) ) goto no_mem; - pCx = p->apCsr[i]; - sqlite3VdbeCleanupCursor(pCx); - memset(pCx, 0, sizeof(*pCx)); + pCx = allocateCursor(p, i); + if( pCx==0 ) goto no_mem; pCx->nullRow = 1; rc = sqlite3BtreeFactory(db, 0, 1, TEMP_PAGES, &pCx->pBt); if( rc==SQLITE_OK ){ rc = sqlite3BtreeBeginTrans(pCx->pBt, 1, 0); @@ -2684,14 +2686,12 @@ */ case OP_OpenPseudo: { int i = pOp->p1; Cursor *pCx; assert( i>=0 ); - if( expandCursorArraySize(p, i) ) goto no_mem; - pCx = p->apCsr[i]; - sqlite3VdbeCleanupCursor(pCx); - memset(pCx, 0, sizeof(*pCx)); + pCx = allocateCursor(p, i); + if( pCx==0 ) goto no_mem; pCx->nullRow = 1; pCx->pseudoTable = 1; pCx->pIncrKey = &pCx->bogusIncrKey; break; } @@ -2702,11 +2702,12 @@ ** currently open, this instruction is a no-op. */ case OP_Close: { int i = pOp->p1; if( i>=0 && inCursor ){ - sqlite3VdbeCleanupCursor(p->apCsr[i]); + sqlite3VdbeFreeCursor(p->apCsr[i]); + p->apCsr[i] = 0; } break; } /* Opcode: MoveGe P1 P2 * @@ -2757,10 +2758,11 @@ Cursor *pC; assert( pTos>=p->aStack ); assert( i>=0 && inCursor ); pC = p->apCsr[i]; + assert( pC!=0 ); if( pC->pCursor!=0 ){ int res, oc; oc = pOp->opcode; pC->nullRow = 0; *pC->pIncrKey = oc==OP_MoveGt || oc==OP_MoveLe; @@ -2856,10 +2858,11 @@ int i = pOp->p1; int alreadyExists = 0; Cursor *pC; assert( pTos>=p->aStack ); assert( i>=0 && inCursor ); + assert( p->apCsr[i]!=0 ); if( (pC = p->apCsr[i])->pCursor!=0 ){ int res, rx; assert( pC->intKey==0 ); Stringify(pTos, db->enc); rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res); @@ -2913,10 +2916,11 @@ Integerify(pTos, db->enc); R = pTos->i; pTos--; assert( i>=0 && i<=p->nCursor ); pCx = p->apCsr[i]; + assert( pCx!=0 ); pCrsr = pCx->pCursor; if( pCrsr!=0 ){ int res, rc; i64 v; /* The record number on the P1 entry that matches K */ char *zKey; /* The value of K */ @@ -2996,10 +3000,11 @@ int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; assert( pTos>=p->aStack ); assert( i>=0 && inCursor ); + assert( p->apCsr[i]!=0 ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ int res, rx; u64 iKey; assert( pTos->flags & MEM_Int ); assert( p->apCsr[i]->intKey ); @@ -3029,10 +3034,11 @@ case OP_NewRecno: { int i = pOp->p1; i64 v = 0; Cursor *pC; assert( i>=0 && inCursor ); + assert( p->apCsr[i]!=0 ); if( (pC = p->apCsr[i])->pCursor==0 ){ /* The zero initialization above is all that is needed */ }else{ /* The next rowid or record number (different terms for the same ** thing) is obtained in a two-step algorithm. @@ -3157,10 +3163,11 @@ Mem *pNos = &pTos[-1]; int i = pOp->p1; Cursor *pC; assert( pNos>=p->aStack ); assert( i>=0 && inCursor ); + assert( p->apCsr[i]!=0 ); if( ((pC = p->apCsr[i])->pCursor!=0 || pC->pseudoTable) ){ char *zKey; i64 nKey; i64 iKey; if( pOp->opcode==OP_PutStrKey ){ @@ -3247,10 +3254,11 @@ case OP_Delete: { int i = pOp->p1; Cursor *pC; assert( i>=0 && inCursor ); pC = p->apCsr[i]; + assert( pC!=0 ); if( pC->pCursor!=0 ){ sqlite3VdbeCursorMoveto(pC); rc = sqlite3BtreeDelete(pC->pCursor); pC->nextRowidValid = 0; pC->cacheValid = 0; @@ -3281,10 +3289,11 @@ case OP_KeyAsData: { int i = pOp->p1; Cursor *pC; assert( i>=0 && inCursor ); pC = p->apCsr[i]; + assert( pC!=0 ); pC->keyAsData = pOp->p2; break; } /* Opcode: RowData P1 * * @@ -3312,10 +3321,11 @@ int n; pTos++; assert( i>=0 && inCursor ); pC = p->apCsr[i]; + assert( pC!=0 ); if( pC->nullRow ){ pTos->flags = MEM_Null; }else if( pC->pCursor!=0 ){ BtCursor *pCrsr = pC->pCursor; sqlite3VdbeCursorMoveto(pC); @@ -3368,10 +3378,11 @@ Cursor *pC; i64 v; assert( i>=0 && inCursor ); pC = p->apCsr[i]; + assert( pC!=0 ); sqlite3VdbeCursorMoveto(pC); pTos++; if( pC->recnoIsValid ){ v = pC->lastRecno; }else if( pC->pseudoTable ){ @@ -3403,13 +3414,14 @@ case OP_FullKey: { int i = pOp->p1; BtCursor *pCrsr; Cursor *pC; + assert( i>=0 && inCursor ); + assert( p->apCsr[i]!=0 ); assert( p->apCsr[i]->keyAsData ); assert( !p->apCsr[i]->pseudoTable ); - assert( i>=0 && inCursor ); pTos++; if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ u64 amt; char *z; @@ -3446,10 +3458,11 @@ int i = pOp->p1; Cursor *pC; assert( i>=0 && inCursor ); pC = p->apCsr[i]; + assert( pC!=0 ); pC->nullRow = 1; pC->recnoIsValid = 0; break; } @@ -3466,10 +3479,11 @@ Cursor *pC; BtCursor *pCrsr; assert( i>=0 && inCursor ); pC = p->apCsr[i]; + assert( pC!=0 ); if( (pCrsr = pC->pCursor)!=0 ){ int res; rc = sqlite3BtreeLast(pCrsr, &res); pC->nullRow = res; pC->deferredMoveto = 0; @@ -3497,10 +3511,11 @@ BtCursor *pCrsr; int res; assert( i>=0 && inCursor ); pC = p->apCsr[i]; + assert( pC!=0 ); if( (pCrsr = pC->pCursor)!=0 ){ rc = sqlite3BtreeFirst(pCrsr, &res); pC->atFirst = res==0; pC->deferredMoveto = 0; pC->cacheValid = 0; @@ -3536,10 +3551,11 @@ BtCursor *pCrsr; CHECK_FOR_INTERRUPT; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); if( (pCrsr = pC->pCursor)!=0 ){ int res; if( pC->nullRow ){ res = 1; }else{ @@ -3575,10 +3591,11 @@ int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; assert( pTos>=p->aStack ); assert( i>=0 && inCursor ); + assert( p->apCsr[i]!=0 ); assert( pTos->flags & MEM_Blob ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ int nKey = pTos->n; const char *zKey = pTos->z; if( pOp->p2 ){ @@ -3627,10 +3644,11 @@ Cursor *pC; BtCursor *pCrsr; assert( pTos>=p->aStack ); assert( pTos->flags & MEM_Blob ); assert( i>=0 && inCursor ); + assert( p->apCsr[i]!=0 ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ int rx, res; rx = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res); if( rx==SQLITE_OK && res==0 ){ rc = sqlite3BtreeDelete(pCrsr); @@ -3655,10 +3673,11 @@ int i = pOp->p1; BtCursor *pCrsr; Cursor *pC; assert( i>=0 && inCursor ); + assert( p->apCsr[i]!=0 ); pTos++; if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ i64 rowid; assert( pC->deferredMoveto==0 ); @@ -3761,10 +3780,11 @@ int i= pOp->p1; BtCursor *pCrsr; Cursor *pC; assert( i>=0 && inCursor ); + assert( p->apCsr[i]!=0 ); assert( pTos>=p->aStack ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ int res, rc; assert( pTos->flags & MEM_Blob ); /* Created using OP_Make*Key */ Index: src/vdbeInt.h ================================================================== --- src/vdbeInt.h +++ src/vdbeInt.h @@ -60,10 +60,11 @@ */ struct Cursor { BtCursor *pCursor; /* The cursor structure of the backend */ i64 lastRecno; /* Last recno from a Next or NextIdx operation */ i64 nextRowid; /* Next rowid returned by OP_NewRowid */ + Bool zeroed; /* True if zeroed out and ready for reuse */ Bool recnoIsValid; /* True if lastRecno is valid */ Bool keyAsData; /* The OP_Column command works on key instead of data */ Bool atFirst; /* True if pointing to first entry */ Bool useRandomRowid; /* Generate new record numbers semi-randomly */ Bool nullRow; /* True if pointing to a row with no data */ @@ -350,11 +351,11 @@ #define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */ /* ** Function prototypes */ -void sqlite3VdbeCleanupCursor(Cursor*); +void sqlite3VdbeFreeCursor(Cursor*); void sqlite3VdbeSorterReset(Vdbe*); int sqlite3VdbeAggReset(sqlite *, Agg *, KeyInfo *); void sqlite3VdbeKeylistFree(Keylist*); void sqliteVdbePopStack(Vdbe*,int); int sqlite3VdbeCursorMoveto(Cursor*); Index: src/vdbeaux.c ================================================================== --- src/vdbeaux.c +++ src/vdbeaux.c @@ -824,31 +824,32 @@ /* ** Close a cursor and release all the resources that cursor happens ** to hold. */ -void sqlite3VdbeCleanupCursor(Cursor *pCx){ +void sqlite3VdbeFreeCursor(Cursor *pCx){ + if( pCx==0 ){ + return; + } if( pCx->pCursor ){ sqlite3BtreeCloseCursor(pCx->pCursor); } if( pCx->pBt ){ sqlite3BtreeClose(pCx->pBt); } sqliteFree(pCx->pData); sqliteFree(pCx->aType); - memset(pCx, 0, sizeof(*pCx)); + sqliteFree(pCx); } /* ** Close all cursors */ static void closeAllCursors(Vdbe *p){ int i; for(i=0; inCursor; i++){ - Cursor *pC = p->apCsr[i]; - sqlite3VdbeCleanupCursor(pC); - sqliteFree(pC); + sqlite3VdbeFreeCursor(p->apCsr[i]); } sqliteFree(p->apCsr); p->apCsr = 0; p->nCursor = 0; }