/ Check-in [e42316f5]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Speed up in the handling of VDBE cursors. (CVS 1578)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:e42316f5708de6f639b7b54e08d4be73b45367e9
User & Date: drh 2004-06-12 20:12:51
Context
2004-06-12
20:42
The VDBE aggregate functions use an in-memory btree instead of a disk-based btree for improved performance. (CVS 1579) check-in: 8029f1e4 user: drh tags: trunk
20:12
Speed up in the handling of VDBE cursors. (CVS 1578) check-in: e42316f5 user: drh tags: trunk
18:12
Improve the speed of OP_Column through better caching. (CVS 1577) check-in: f687977a user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Show Whitespace Changes Patch

Changes to src/vdbe.c.

    39     39   **
    40     40   ** Various scripts scan this source file in order to generate HTML
    41     41   ** documentation, headers files, or other derived files.  The formatting
    42     42   ** of the code in this file is, therefore, important.  See other comments
    43     43   ** in this file for details.  If in doubt, do not deviate from existing
    44     44   ** commenting and indentation practices when changing or adding code.
    45     45   **
    46         -** $Id: vdbe.c,v 1.369 2004/06/12 18:12:16 drh Exp $
           46  +** $Id: vdbe.c,v 1.370 2004/06/12 20:12:51 drh Exp $
    47     47   */
    48     48   #include "sqliteInt.h"
    49     49   #include "os.h"
    50     50   #include <ctype.h>
    51     51   #include "vdbeInt.h"
    52     52   
    53     53   /*
................................................................................
   267    267     }else if( pRight ){
   268    268       pTail->pNext = pRight;
   269    269     }
   270    270     return sHead.pNext;
   271    271   }
   272    272   
   273    273   /*
   274         -** Make sure there is space in the Vdbe structure to hold at least
   275         -** mxCursor cursors.  If there is not currently enough space, then
   276         -** allocate more.
   277         -**
   278         -** If a memory allocation error occurs, return 1.  Return 0 if
   279         -** everything works.
          274  +** Allocate cursor number iCur.  Return a pointer to it.  Return NULL
          275  +** if we run out of memory.
   280    276   */
   281         -static int expandCursorArraySize(Vdbe *p, int mxCursor){
   282         -  if( mxCursor>=p->nCursor ){
   283         -    p->apCsr = sqliteRealloc( p->apCsr, (mxCursor+1)*sizeof(Cursor*) );
   284         -    if( p->apCsr==0 ) return 1;
   285         -    while( p->nCursor<=mxCursor ){
   286         -      Cursor *pC;
   287         -      p->apCsr[p->nCursor++] = pC = sqliteMalloc( sizeof(Cursor) );
   288         -      if( pC==0 ) return 1;
   289         -    }
   290         -  }
          277  +static Cursor *allocateCursor(Vdbe *p, int iCur){
          278  +  Cursor *pCx;
          279  +  if( iCur>=p->nCursor ){
          280  +    int i;
          281  +    p->apCsr = sqliteRealloc( p->apCsr, (iCur+1)*sizeof(Cursor*) );
          282  +    if( p->apCsr==0 ){
          283  +      p->nCursor = 0;
   291    284     return 0;
          285  +    }
          286  +    for(i=p->nCursor; i<iCur; i++){
          287  +      p->apCsr[i] = 0;
          288  +    }
          289  +    p->nCursor = iCur+1;
          290  +  }else if( p->apCsr[iCur] ){
          291  +    sqlite3VdbeFreeCursor(p->apCsr[iCur]);
          292  +  }
          293  +  p->apCsr[iCur] = pCx = sqliteMalloc( sizeof(Cursor) );
          294  +  return pCx;
   292    295   }
   293    296   
   294    297   /*
   295    298   ** Apply any conversion required by the supplied column affinity to
   296    299   ** memory cell pRec. affinity may be one of:
   297    300   **
   298    301   ** SQLITE_AFF_NUMERIC
................................................................................
  1863   1866   ** Before the OP_Column opcode can be executed on a cursor, this
  1864   1867   ** opcode must be called to set the number of fields in the table.
  1865   1868   **
  1866   1869   ** This opcode sets the number of columns for cursor P1 to P2.
  1867   1870   */
  1868   1871   case OP_SetNumColumns: {
  1869   1872     assert( (pOp->p1)<p->nCursor );
         1873  +  assert( p->apCsr[pOp->p1]!=0 );
  1870   1874     p->apCsr[pOp->p1]->nField = pOp->p2;
  1871   1875     break;
  1872   1876   }
  1873   1877   
  1874   1878   /* Opcode: IdxColumn P1 * *
  1875   1879   **
  1876   1880   ** P1 is a cursor opened on an index. Push the first field from the
................................................................................
  1927   1931     ** zRec is set to NULL.
  1928   1932     **
  1929   1933     ** We also compute the number of columns in the record.  For cursors,
  1930   1934     ** the number of columns is stored in the Cursor.nField element.  For
  1931   1935     ** records on the stack, the next entry down on the stack is an integer
  1932   1936     ** which is the number of records.
  1933   1937     */
         1938  +  assert( p1<0 || p->apCsr[p1]!=0 );
  1934   1939     if( p1<0 ){
  1935   1940       /* Take the record off of the stack */
  1936   1941       Mem *pRec = &pTos[p1];
  1937   1942       Mem *pCnt = &pRec[-1];
  1938   1943       assert( pRec>=p->aStack );
  1939   1944       assert( pRec->flags & MEM_Blob );
  1940   1945       payloadSize = pRec->n;
................................................................................
  2568   2573       if( p2<2 ){
  2569   2574         sqlite3SetString(&p->zErrMsg, "root page number less than 2", (char*)0);
  2570   2575         rc = SQLITE_INTERNAL;
  2571   2576         break;
  2572   2577       }
  2573   2578     }
  2574   2579     assert( i>=0 );
  2575         -  if( expandCursorArraySize(p, i) ) goto no_mem;
  2576         -  pCur = p->apCsr[i];
  2577         -  sqlite3VdbeCleanupCursor(pCur);
         2580  +  pCur = allocateCursor(p, i);
         2581  +  if( pCur==0 ) goto no_mem;
  2578   2582     pCur->nullRow = 1;
  2579   2583     if( pX==0 ) break;
  2580   2584     /* We always provide a key comparison function.  If the table being
  2581   2585     ** opened is of type INTKEY, the comparision function will be ignored. */
  2582   2586     rc = sqlite3BtreeCursor(pX, p2, wrFlag,
  2583   2587              sqlite3VdbeRecordCompare, pOp->p3,
  2584   2588              &pCur->pCursor);
................................................................................
  2631   2635   ** whereas "Temporary" in the context of CREATE TABLE means for the duration
  2632   2636   ** of the connection to the database.  Same word; different meanings.
  2633   2637   */
  2634   2638   case OP_OpenTemp: {
  2635   2639     int i = pOp->p1;
  2636   2640     Cursor *pCx;
  2637   2641     assert( i>=0 );
  2638         -  if( expandCursorArraySize(p, i) ) goto no_mem;
  2639         -  pCx = p->apCsr[i];
  2640         -  sqlite3VdbeCleanupCursor(pCx);
  2641         -  memset(pCx, 0, sizeof(*pCx));
         2642  +  pCx = allocateCursor(p, i);
         2643  +  if( pCx==0 ) goto no_mem;
  2642   2644     pCx->nullRow = 1;
  2643   2645     rc = sqlite3BtreeFactory(db, 0, 1, TEMP_PAGES, &pCx->pBt);
  2644   2646   
  2645   2647     if( rc==SQLITE_OK ){
  2646   2648       rc = sqlite3BtreeBeginTrans(pCx->pBt, 1, 0);
  2647   2649     }
  2648   2650     if( rc==SQLITE_OK ){
................................................................................
  2682   2684   ** A pseudo-table created by this opcode is useful for holding the
  2683   2685   ** NEW or OLD tables in a trigger.
  2684   2686   */
  2685   2687   case OP_OpenPseudo: {
  2686   2688     int i = pOp->p1;
  2687   2689     Cursor *pCx;
  2688   2690     assert( i>=0 );
  2689         -  if( expandCursorArraySize(p, i) ) goto no_mem;
  2690         -  pCx = p->apCsr[i];
  2691         -  sqlite3VdbeCleanupCursor(pCx);
  2692         -  memset(pCx, 0, sizeof(*pCx));
         2691  +  pCx = allocateCursor(p, i);
         2692  +  if( pCx==0 ) goto no_mem;
  2693   2693     pCx->nullRow = 1;
  2694   2694     pCx->pseudoTable = 1;
  2695   2695     pCx->pIncrKey = &pCx->bogusIncrKey;
  2696   2696     break;
  2697   2697   }
  2698   2698   
  2699   2699   /* Opcode: Close P1 * *
................................................................................
  2700   2700   **
  2701   2701   ** Close a cursor previously opened as P1.  If P1 is not
  2702   2702   ** currently open, this instruction is a no-op.
  2703   2703   */
  2704   2704   case OP_Close: {
  2705   2705     int i = pOp->p1;
  2706   2706     if( i>=0 && i<p->nCursor ){
  2707         -    sqlite3VdbeCleanupCursor(p->apCsr[i]);
         2707  +    sqlite3VdbeFreeCursor(p->apCsr[i]);
         2708  +    p->apCsr[i] = 0;
  2708   2709     }
  2709   2710     break;
  2710   2711   }
  2711   2712   
  2712   2713   /* Opcode: MoveGe P1 P2 *
  2713   2714   **
  2714   2715   ** Pop the top of the stack and use its value as a key.  Reposition
................................................................................
  2755   2756   case OP_MoveGt: {
  2756   2757     int i = pOp->p1;
  2757   2758     Cursor *pC;
  2758   2759   
  2759   2760     assert( pTos>=p->aStack );
  2760   2761     assert( i>=0 && i<p->nCursor );
  2761   2762     pC = p->apCsr[i];
         2763  +  assert( pC!=0 );
  2762   2764     if( pC->pCursor!=0 ){
  2763   2765       int res, oc;
  2764   2766       oc = pOp->opcode;
  2765   2767       pC->nullRow = 0;
  2766   2768       *pC->pIncrKey = oc==OP_MoveGt || oc==OP_MoveLe;
  2767   2769       if( pC->intKey ){
  2768   2770         i64 iKey;
................................................................................
  2854   2856   case OP_NotFound:
  2855   2857   case OP_Found: {
  2856   2858     int i = pOp->p1;
  2857   2859     int alreadyExists = 0;
  2858   2860     Cursor *pC;
  2859   2861     assert( pTos>=p->aStack );
  2860   2862     assert( i>=0 && i<p->nCursor );
         2863  +  assert( p->apCsr[i]!=0 );
  2861   2864     if( (pC = p->apCsr[i])->pCursor!=0 ){
  2862   2865       int res, rx;
  2863   2866       assert( pC->intKey==0 );
  2864   2867       Stringify(pTos, db->enc);
  2865   2868       rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
  2866   2869       alreadyExists = rx==SQLITE_OK && res==0;
  2867   2870       pC->deferredMoveto = 0;
................................................................................
  2911   2914     */
  2912   2915     assert( pNos>=p->aStack );
  2913   2916     Integerify(pTos, db->enc);
  2914   2917     R = pTos->i;
  2915   2918     pTos--;
  2916   2919     assert( i>=0 && i<=p->nCursor );
  2917   2920     pCx = p->apCsr[i];
         2921  +  assert( pCx!=0 );
  2918   2922     pCrsr = pCx->pCursor;
  2919   2923     if( pCrsr!=0 ){
  2920   2924       int res, rc;
  2921   2925       i64 v;         /* The record number on the P1 entry that matches K */
  2922   2926       char *zKey;    /* The value of K */
  2923   2927       int nKey;      /* Number of bytes in K */
  2924   2928       int len;       /* Number of bytes in K without the rowid at the end */
................................................................................
  2994   2998   */
  2995   2999   case OP_NotExists: {
  2996   3000     int i = pOp->p1;
  2997   3001     Cursor *pC;
  2998   3002     BtCursor *pCrsr;
  2999   3003     assert( pTos>=p->aStack );
  3000   3004     assert( i>=0 && i<p->nCursor );
         3005  +  assert( p->apCsr[i]!=0 );
  3001   3006     if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
  3002   3007       int res, rx;
  3003   3008       u64 iKey;
  3004   3009       assert( pTos->flags & MEM_Int );
  3005   3010       assert( p->apCsr[i]->intKey );
  3006   3011       iKey = intToKey(pTos->i);
  3007   3012       rx = sqlite3BtreeMoveto(pCrsr, 0, iKey, &res);
................................................................................
  3027   3032   ** onto the stack.
  3028   3033   */
  3029   3034   case OP_NewRecno: {
  3030   3035     int i = pOp->p1;
  3031   3036     i64 v = 0;
  3032   3037     Cursor *pC;
  3033   3038     assert( i>=0 && i<p->nCursor );
         3039  +  assert( p->apCsr[i]!=0 );
  3034   3040     if( (pC = p->apCsr[i])->pCursor==0 ){
  3035   3041       /* The zero initialization above is all that is needed */
  3036   3042     }else{
  3037   3043       /* The next rowid or record number (different terms for the same
  3038   3044       ** thing) is obtained in a two-step algorithm.
  3039   3045       **
  3040   3046       ** First we attempt to find the largest existing rowid and add one
................................................................................
  3155   3161   case OP_PutIntKey:
  3156   3162   case OP_PutStrKey: {
  3157   3163     Mem *pNos = &pTos[-1];
  3158   3164     int i = pOp->p1;
  3159   3165     Cursor *pC;
  3160   3166     assert( pNos>=p->aStack );
  3161   3167     assert( i>=0 && i<p->nCursor );
         3168  +  assert( p->apCsr[i]!=0 );
  3162   3169     if( ((pC = p->apCsr[i])->pCursor!=0 || pC->pseudoTable) ){
  3163   3170       char *zKey;
  3164   3171       i64 nKey; 
  3165   3172       i64 iKey;
  3166   3173       if( pOp->opcode==OP_PutStrKey ){
  3167   3174         Stringify(pNos, db->enc);
  3168   3175         nKey = pNos->n;
................................................................................
  3245   3252   ** If P1 is a pseudo-table, then this instruction is a no-op.
  3246   3253   */
  3247   3254   case OP_Delete: {
  3248   3255     int i = pOp->p1;
  3249   3256     Cursor *pC;
  3250   3257     assert( i>=0 && i<p->nCursor );
  3251   3258     pC = p->apCsr[i];
         3259  +  assert( pC!=0 );
  3252   3260     if( pC->pCursor!=0 ){
  3253   3261       sqlite3VdbeCursorMoveto(pC);
  3254   3262       rc = sqlite3BtreeDelete(pC->pCursor);
  3255   3263       pC->nextRowidValid = 0;
  3256   3264       pC->cacheValid = 0;
  3257   3265     }
  3258   3266     if( pOp->p2 & OPFLAG_NCHANGE ) db->nChange++;
................................................................................
  3279   3287   ** processing compound selects.
  3280   3288   */
  3281   3289   case OP_KeyAsData: {
  3282   3290     int i = pOp->p1;
  3283   3291     Cursor *pC;
  3284   3292     assert( i>=0 && i<p->nCursor );
  3285   3293     pC = p->apCsr[i];
         3294  +  assert( pC!=0 );
  3286   3295     pC->keyAsData = pOp->p2;
  3287   3296     break;
  3288   3297   }
  3289   3298   
  3290   3299   /* Opcode: RowData P1 * *
  3291   3300   **
  3292   3301   ** Push onto the stack the complete row data for cursor P1.
................................................................................
  3310   3319     int i = pOp->p1;
  3311   3320     Cursor *pC;
  3312   3321     int n;
  3313   3322   
  3314   3323     pTos++;
  3315   3324     assert( i>=0 && i<p->nCursor );
  3316   3325     pC = p->apCsr[i];
         3326  +  assert( pC!=0 );
  3317   3327     if( pC->nullRow ){
  3318   3328       pTos->flags = MEM_Null;
  3319   3329     }else if( pC->pCursor!=0 ){
  3320   3330       BtCursor *pCrsr = pC->pCursor;
  3321   3331       sqlite3VdbeCursorMoveto(pC);
  3322   3332       if( pC->nullRow ){
  3323   3333         pTos->flags = MEM_Null;
................................................................................
  3366   3376   case OP_Recno: {
  3367   3377     int i = pOp->p1;
  3368   3378     Cursor *pC;
  3369   3379     i64 v;
  3370   3380   
  3371   3381     assert( i>=0 && i<p->nCursor );
  3372   3382     pC = p->apCsr[i];
         3383  +  assert( pC!=0 );
  3373   3384     sqlite3VdbeCursorMoveto(pC);
  3374   3385     pTos++;
  3375   3386     if( pC->recnoIsValid ){
  3376   3387       v = pC->lastRecno;
  3377   3388     }else if( pC->pseudoTable ){
  3378   3389       v = keyToInt(pC->iKey);
  3379   3390     }else if( pC->nullRow || pC->pCursor==0 ){
................................................................................
  3401   3412   ** This opcode may not be used on a pseudo-table.
  3402   3413   */
  3403   3414   case OP_FullKey: {
  3404   3415     int i = pOp->p1;
  3405   3416     BtCursor *pCrsr;
  3406   3417     Cursor *pC;
  3407   3418   
         3419  +  assert( i>=0 && i<p->nCursor );
         3420  +  assert( p->apCsr[i]!=0 );
  3408   3421     assert( p->apCsr[i]->keyAsData );
  3409   3422     assert( !p->apCsr[i]->pseudoTable );
  3410         -  assert( i>=0 && i<p->nCursor );
  3411   3423     pTos++;
  3412   3424     if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
  3413   3425       u64 amt;
  3414   3426       char *z;
  3415   3427   
  3416   3428       sqlite3VdbeCursorMoveto(pC);
  3417   3429       assert( pC->intKey==0 );
................................................................................
  3444   3456   */
  3445   3457   case OP_NullRow: {
  3446   3458     int i = pOp->p1;
  3447   3459     Cursor *pC;
  3448   3460   
  3449   3461     assert( i>=0 && i<p->nCursor );
  3450   3462     pC = p->apCsr[i];
         3463  +  assert( pC!=0 );
  3451   3464     pC->nullRow = 1;
  3452   3465     pC->recnoIsValid = 0;
  3453   3466     break;
  3454   3467   }
  3455   3468   
  3456   3469   /* Opcode: Last P1 P2 *
  3457   3470   **
................................................................................
  3464   3477   case OP_Last: {
  3465   3478     int i = pOp->p1;
  3466   3479     Cursor *pC;
  3467   3480     BtCursor *pCrsr;
  3468   3481   
  3469   3482     assert( i>=0 && i<p->nCursor );
  3470   3483     pC = p->apCsr[i];
         3484  +  assert( pC!=0 );
  3471   3485     if( (pCrsr = pC->pCursor)!=0 ){
  3472   3486       int res;
  3473   3487       rc = sqlite3BtreeLast(pCrsr, &res);
  3474   3488       pC->nullRow = res;
  3475   3489       pC->deferredMoveto = 0;
  3476   3490       pC->cacheValid = 0;
  3477   3491       if( res && pOp->p2>0 ){
................................................................................
  3495   3509     int i = pOp->p1;
  3496   3510     Cursor *pC;
  3497   3511     BtCursor *pCrsr;
  3498   3512     int res;
  3499   3513   
  3500   3514     assert( i>=0 && i<p->nCursor );
  3501   3515     pC = p->apCsr[i];
         3516  +  assert( pC!=0 );
  3502   3517     if( (pCrsr = pC->pCursor)!=0 ){
  3503   3518       rc = sqlite3BtreeFirst(pCrsr, &res);
  3504   3519       pC->atFirst = res==0;
  3505   3520       pC->deferredMoveto = 0;
  3506   3521       pC->cacheValid = 0;
  3507   3522     }else{
  3508   3523       res = 1;
................................................................................
  3534   3549   case OP_Next: {
  3535   3550     Cursor *pC;
  3536   3551     BtCursor *pCrsr;
  3537   3552   
  3538   3553     CHECK_FOR_INTERRUPT;
  3539   3554     assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  3540   3555     pC = p->apCsr[pOp->p1];
         3556  +  assert( pC!=0 );
  3541   3557     if( (pCrsr = pC->pCursor)!=0 ){
  3542   3558       int res;
  3543   3559       if( pC->nullRow ){
  3544   3560         res = 1;
  3545   3561       }else{
  3546   3562         assert( pC->deferredMoveto==0 );
  3547   3563         rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) :
................................................................................
  3573   3589   */
  3574   3590   case OP_IdxPut: {
  3575   3591     int i = pOp->p1;
  3576   3592     Cursor *pC;
  3577   3593     BtCursor *pCrsr;
  3578   3594     assert( pTos>=p->aStack );
  3579   3595     assert( i>=0 && i<p->nCursor );
         3596  +  assert( p->apCsr[i]!=0 );
  3580   3597     assert( pTos->flags & MEM_Blob );
  3581   3598     if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
  3582   3599       int nKey = pTos->n;
  3583   3600       const char *zKey = pTos->z;
  3584   3601       if( pOp->p2 ){
  3585   3602         int res;
  3586   3603         int len;
................................................................................
  3625   3642   case OP_IdxDelete: {
  3626   3643     int i = pOp->p1;
  3627   3644     Cursor *pC;
  3628   3645     BtCursor *pCrsr;
  3629   3646     assert( pTos>=p->aStack );
  3630   3647     assert( pTos->flags & MEM_Blob );
  3631   3648     assert( i>=0 && i<p->nCursor );
         3649  +  assert( p->apCsr[i]!=0 );
  3632   3650     if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
  3633   3651       int rx, res;
  3634   3652       rx = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res);
  3635   3653       if( rx==SQLITE_OK && res==0 ){
  3636   3654         rc = sqlite3BtreeDelete(pCrsr);
  3637   3655       }
  3638   3656       assert( pC->deferredMoveto==0 );
................................................................................
  3653   3671   */
  3654   3672   case OP_IdxRecno: {
  3655   3673     int i = pOp->p1;
  3656   3674     BtCursor *pCrsr;
  3657   3675     Cursor *pC;
  3658   3676   
  3659   3677     assert( i>=0 && i<p->nCursor );
         3678  +  assert( p->apCsr[i]!=0 );
  3660   3679     pTos++;
  3661   3680     if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
  3662   3681       i64 rowid;
  3663   3682   
  3664   3683       assert( pC->deferredMoveto==0 );
  3665   3684       assert( pC->intKey==0 );
  3666   3685       if( pC->nullRow ){
................................................................................
  3759   3778   case OP_IdxGT:
  3760   3779   case OP_IdxGE: {
  3761   3780     int i= pOp->p1;
  3762   3781     BtCursor *pCrsr;
  3763   3782     Cursor *pC;
  3764   3783   
  3765   3784     assert( i>=0 && i<p->nCursor );
         3785  +  assert( p->apCsr[i]!=0 );
  3766   3786     assert( pTos>=p->aStack );
  3767   3787     if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
  3768   3788       int res, rc;
  3769   3789    
  3770   3790       assert( pTos->flags & MEM_Blob );  /* Created using OP_Make*Key */
  3771   3791       Stringify(pTos, db->enc);
  3772   3792       assert( pC->deferredMoveto==0 );

Changes to src/vdbeInt.h.

    58     58   ** a row trigger.  The data for the row is stored in Cursor.pData and
    59     59   ** the rowid is in Cursor.iKey.
    60     60   */
    61     61   struct Cursor {
    62     62     BtCursor *pCursor;    /* The cursor structure of the backend */
    63     63     i64 lastRecno;        /* Last recno from a Next or NextIdx operation */
    64     64     i64 nextRowid;        /* Next rowid returned by OP_NewRowid */
           65  +  Bool zeroed;          /* True if zeroed out and ready for reuse */
    65     66     Bool recnoIsValid;    /* True if lastRecno is valid */
    66     67     Bool keyAsData;       /* The OP_Column command works on key instead of data */
    67     68     Bool atFirst;         /* True if pointing to first entry */
    68     69     Bool useRandomRowid;  /* Generate new record numbers semi-randomly */
    69     70     Bool nullRow;         /* True if pointing to a row with no data */
    70     71     Bool nextRowidValid;  /* True if the nextRowid field is valid */
    71     72     Bool pseudoTable;     /* This is a NEW or OLD pseudo-tables of a trigger */
................................................................................
   348    349   #define VDBE_MAGIC_RUN      0xbdf20da3    /* VDBE is ready to execute */
   349    350   #define VDBE_MAGIC_HALT     0x519c2973    /* VDBE has completed execution */
   350    351   #define VDBE_MAGIC_DEAD     0xb606c3c8    /* The VDBE has been deallocated */
   351    352   
   352    353   /*
   353    354   ** Function prototypes
   354    355   */
   355         -void sqlite3VdbeCleanupCursor(Cursor*);
          356  +void sqlite3VdbeFreeCursor(Cursor*);
   356    357   void sqlite3VdbeSorterReset(Vdbe*);
   357    358   int sqlite3VdbeAggReset(sqlite *, Agg *, KeyInfo *);
   358    359   void sqlite3VdbeKeylistFree(Keylist*);
   359    360   void sqliteVdbePopStack(Vdbe*,int);
   360    361   int sqlite3VdbeCursorMoveto(Cursor*);
   361    362   #if !defined(NDEBUG) || defined(VDBE_PROFILE)
   362    363   void sqlite3VdbePrintOp(FILE*, int, Op*);

Changes to src/vdbeaux.c.

   822    822     }
   823    823   }
   824    824   
   825    825   /*
   826    826   ** Close a cursor and release all the resources that cursor happens
   827    827   ** to hold.
   828    828   */
   829         -void sqlite3VdbeCleanupCursor(Cursor *pCx){
          829  +void sqlite3VdbeFreeCursor(Cursor *pCx){
          830  +  if( pCx==0 ){
          831  +    return;
          832  +  }
   830    833     if( pCx->pCursor ){
   831    834       sqlite3BtreeCloseCursor(pCx->pCursor);
   832    835     }
   833    836     if( pCx->pBt ){
   834    837       sqlite3BtreeClose(pCx->pBt);
   835    838     }
   836    839     sqliteFree(pCx->pData);
   837    840     sqliteFree(pCx->aType);
   838         -  memset(pCx, 0, sizeof(*pCx));
          841  +  sqliteFree(pCx);
   839    842   }
   840    843   
   841    844   /*
   842    845   ** Close all cursors
   843    846   */
   844    847   static void closeAllCursors(Vdbe *p){
   845    848     int i;
   846    849     for(i=0; i<p->nCursor; i++){
   847         -    Cursor *pC = p->apCsr[i];
   848         -    sqlite3VdbeCleanupCursor(pC);
   849         -    sqliteFree(pC);
          850  +    sqlite3VdbeFreeCursor(p->apCsr[i]);
   850    851     }
   851    852     sqliteFree(p->apCsr);
   852    853     p->apCsr = 0;
   853    854     p->nCursor = 0;
   854    855   }
   855    856   
   856    857   /*