/ Check-in [d8bacc16]
Login

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

Overview
Comment:Allocates VDBE cursors one by one in separate memory so that pointers to cursors can persist through a realloc(). (CVS 1383)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:d8bacc16801606176fe8639b2f55b4584ad549df
User & Date: drh 2004-05-14 21:59:40
Context
2004-05-15
00:29
More speed improvements to btree. (CVS 1384) check-in: aab4b794 user: drh tags: trunk
2004-05-14
21:59
Allocates VDBE cursors one by one in separate memory so that pointers to cursors can persist through a realloc(). (CVS 1383) check-in: d8bacc16 user: drh tags: trunk
21:12
Cache record headers in the OP_Column opcode. (CVS 1382) check-in: 8d9eab17 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace 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.292 2004/05/14 21:12:23 drh Exp $
           46  +** $Id: vdbe.c,v 1.293 2004/05/14 21:59:40 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   /*
................................................................................
   409    409   ** allocate more.
   410    410   **
   411    411   ** If a memory allocation error occurs, return 1.  Return 0 if
   412    412   ** everything works.
   413    413   */
   414    414   static int expandCursorArraySize(Vdbe *p, int mxCursor){
   415    415     if( mxCursor>=p->nCursor ){
   416         -    Cursor *aCsr = sqliteRealloc( p->aCsr, (mxCursor+1)*sizeof(Cursor) );
   417         -    if( aCsr==0 ) return 1;
   418         -    p->aCsr = aCsr;
   419         -    memset(&p->aCsr[p->nCursor], 0, sizeof(Cursor)*(mxCursor+1-p->nCursor));
   420         -    p->nCursor = mxCursor+1;
          416  +    p->apCsr = sqliteRealloc( p->apCsr, (mxCursor+1)*sizeof(Cursor*) );
          417  +    if( p->apCsr==0 ) return 1;
          418  +    while( p->nCursor<=mxCursor ){
          419  +      Cursor *pC;
          420  +      p->apCsr[p->nCursor++] = pC = sqliteMalloc( sizeof(Cursor) );
          421  +      if( pC==0 ) return 1;
          422  +    }
   421    423     }
   422    424     return 0;
   423    425   }
   424    426   
   425    427   /*
   426    428   ** Apply any conversion required by the supplied column affinity to
   427    429   ** memory cell pRec. affinity may be one of:
................................................................................
   558    560     unsigned long long start;  /* CPU clock count at start of opcode */
   559    561     int origPc;                /* Program counter at start of opcode */
   560    562   #endif
   561    563   #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
   562    564     int nProgressOps = 0;      /* Opcodes executed since progress callback. */
   563    565   #endif
   564    566   
   565         -  /* FIX ME. */
   566         -  expandCursorArraySize(p, 100);
   567         -
   568    567     if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
   569    568     assert( db->magic==SQLITE_MAGIC_BUSY );
   570    569     assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY );
   571    570     p->rc = SQLITE_OK;
   572    571     assert( p->explain==0 );
   573    572     if( sqlite3_malloc_failed ) goto no_mem;
   574    573     pTos = p->pTos;
................................................................................
  1917   1916     */
  1918   1917     if( i<0 ){
  1919   1918       assert( &pTos[i]>=p->aStack );
  1920   1919       assert( pTos[i].flags & MEM_Str );
  1921   1920       zRec = pTos[i].z;
  1922   1921       payloadSize = pTos[i].n;
  1923   1922       pC->cacheValid = 0;
  1924         -  }else if( (pC = &p->aCsr[i])->pCursor!=0 ){
         1923  +  }else if( (pC = p->apCsr[i])->pCursor!=0 ){
  1925   1924       sqlite3VdbeCursorMoveto(pC);
  1926   1925       zRec = 0;
  1927   1926       pCrsr = pC->pCursor;
  1928   1927       if( pC->nullRow ){
  1929   1928         payloadSize = 0;
  1930   1929       }else if( pC->cacheValid ){
  1931   1930         payloadSize = pC->payloadSize;
................................................................................
  2619   2618         sqlite3SetString(&p->zErrMsg, "root page number less than 2", (char*)0);
  2620   2619         rc = SQLITE_INTERNAL;
  2621   2620         break;
  2622   2621       }
  2623   2622     }
  2624   2623     assert( i>=0 );
  2625   2624     if( expandCursorArraySize(p, i) ) goto no_mem;
  2626         -  pCur = &p->aCsr[i];
         2625  +  pCur = p->apCsr[i];
  2627   2626     sqlite3VdbeCleanupCursor(pCur);
  2628         -  memset(pCur, 0, sizeof(Cursor));
  2629   2627     pCur->nullRow = 1;
  2630   2628     if( pX==0 ) break;
  2631   2629     do{
  2632   2630       /* When opening cursors, always supply the comparison function
  2633   2631       ** sqlite3VdbeKeyCompare(). If the table being opened is of type
  2634   2632       ** INTKEY, the btree layer won't call the comparison function anyway.
  2635   2633       */
................................................................................
  2687   2685   ** of the connection to the database.  Same word; different meanings.
  2688   2686   */
  2689   2687   case OP_OpenTemp: {
  2690   2688     int i = pOp->p1;
  2691   2689     Cursor *pCx;
  2692   2690     assert( i>=0 );
  2693   2691     if( expandCursorArraySize(p, i) ) goto no_mem;
  2694         -  pCx = &p->aCsr[i];
         2692  +  pCx = p->apCsr[i];
  2695   2693     sqlite3VdbeCleanupCursor(pCx);
  2696   2694     memset(pCx, 0, sizeof(*pCx));
  2697   2695     pCx->nullRow = 1;
  2698   2696     rc = sqlite3BtreeFactory(db, 0, 1, TEMP_PAGES, &pCx->pBt);
  2699   2697   
  2700   2698     if( rc==SQLITE_OK ){
  2701   2699       rc = sqlite3BtreeBeginTrans(pCx->pBt);
................................................................................
  2732   2730   ** NEW or OLD tables in a trigger.
  2733   2731   */
  2734   2732   case OP_OpenPseudo: {
  2735   2733     int i = pOp->p1;
  2736   2734     Cursor *pCx;
  2737   2735     assert( i>=0 );
  2738   2736     if( expandCursorArraySize(p, i) ) goto no_mem;
  2739         -  pCx = &p->aCsr[i];
         2737  +  pCx = p->apCsr[i];
  2740   2738     sqlite3VdbeCleanupCursor(pCx);
  2741   2739     memset(pCx, 0, sizeof(*pCx));
  2742   2740     pCx->nullRow = 1;
  2743   2741     pCx->pseudoTable = 1;
  2744   2742     break;
  2745   2743   }
  2746   2744   
................................................................................
  2748   2746   **
  2749   2747   ** Close a cursor previously opened as P1.  If P1 is not
  2750   2748   ** currently open, this instruction is a no-op.
  2751   2749   */
  2752   2750   case OP_Close: {
  2753   2751     int i = pOp->p1;
  2754   2752     if( i>=0 && i<p->nCursor ){
  2755         -    sqlite3VdbeCleanupCursor(&p->aCsr[i]);
         2753  +    sqlite3VdbeCleanupCursor(p->apCsr[i]);
  2756   2754     }
  2757   2755     break;
  2758   2756   }
  2759   2757   
  2760   2758   /* Opcode: MoveTo P1 P2 *
  2761   2759   **
  2762   2760   ** Pop the top of the stack and use its value as a key.  Reposition
................................................................................
  2791   2789   case OP_MoveLt:
  2792   2790   case OP_MoveTo: {
  2793   2791     int i = pOp->p1;
  2794   2792     Cursor *pC;
  2795   2793   
  2796   2794     assert( pTos>=p->aStack );
  2797   2795     assert( i>=0 && i<p->nCursor );
  2798         -  pC = &p->aCsr[i];
         2796  +  pC = p->apCsr[i];
  2799   2797     if( pC->pCursor!=0 ){
  2800   2798       int res, oc;
  2801   2799       pC->nullRow = 0;
  2802   2800       if( pC->intKey ){
  2803   2801         i64 iKey;
  2804   2802         assert( !pOp->p3 );
  2805   2803         Integerify(pTos);
................................................................................
  2891   2889   case OP_NotFound:
  2892   2890   case OP_Found: {
  2893   2891     int i = pOp->p1;
  2894   2892     int alreadyExists = 0;
  2895   2893     Cursor *pC;
  2896   2894     assert( pTos>=p->aStack );
  2897   2895     assert( i>=0 && i<p->nCursor );
  2898         -  if( (pC = &p->aCsr[i])->pCursor!=0 ){
         2896  +  if( (pC = p->apCsr[i])->pCursor!=0 ){
  2899   2897       int res, rx;
  2900   2898       assert( pC->intKey==0 );
  2901   2899       Stringify(pTos);
  2902   2900       rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
  2903   2901       alreadyExists = rx==SQLITE_OK && res==0;
  2904   2902       pC->deferredMoveto = 0;
  2905   2903       pC->cacheValid = 0;
................................................................................
  2946   2944     /* Pop the value R off the top of the stack
  2947   2945     */
  2948   2946     assert( pNos>=p->aStack );
  2949   2947     Integerify(pTos);
  2950   2948     R = pTos->i;
  2951   2949     pTos--;
  2952   2950     assert( i>=0 && i<=p->nCursor );
  2953         -  pCx = &p->aCsr[i];
         2951  +  pCx = p->apCsr[i];
  2954   2952     pCrsr = pCx->pCursor;
  2955   2953     if( pCrsr!=0 ){
  2956   2954       int res, rc;
  2957   2955       i64 v;         /* The record number on the P1 entry that matches K */
  2958   2956       char *zKey;    /* The value of K */
  2959   2957       int nKey;      /* Number of bytes in K */
  2960   2958       int len;       /* Number of bytes in K without the rowid at the end */
................................................................................
  3030   3028   */
  3031   3029   case OP_NotExists: {
  3032   3030     int i = pOp->p1;
  3033   3031     Cursor *pC;
  3034   3032     BtCursor *pCrsr;
  3035   3033     assert( pTos>=p->aStack );
  3036   3034     assert( i>=0 && i<p->nCursor );
  3037         -  if( (pCrsr = (pC = &p->aCsr[i])->pCursor)!=0 ){
         3035  +  if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
  3038   3036       int res, rx;
  3039   3037       u64 iKey;
  3040   3038       assert( pTos->flags & MEM_Int );
  3041         -    assert( p->aCsr[i].intKey );
         3039  +    assert( p->apCsr[i]->intKey );
  3042   3040       iKey = intToKey(pTos->i);
  3043   3041       rx = sqlite3BtreeMoveto(pCrsr, 0, iKey, &res);
  3044   3042       pC->lastRecno = pTos->i;
  3045   3043       pC->recnoIsValid = res==0;
  3046   3044       pC->nullRow = 0;
  3047   3045       pC->cacheValid = 0;
  3048   3046       if( rx!=SQLITE_OK || res!=0 ){
................................................................................
  3063   3061   ** onto the stack.
  3064   3062   */
  3065   3063   case OP_NewRecno: {
  3066   3064     int i = pOp->p1;
  3067   3065     i64 v = 0;
  3068   3066     Cursor *pC;
  3069   3067     assert( i>=0 && i<p->nCursor );
  3070         -  if( (pC = &p->aCsr[i])->pCursor==0 ){
         3068  +  if( (pC = p->apCsr[i])->pCursor==0 ){
  3071   3069       /* The zero initialization above is all that is needed */
  3072   3070     }else{
  3073   3071       /* The next rowid or record number (different terms for the same
  3074   3072       ** thing) is obtained in a two-step algorithm.
  3075   3073       **
  3076   3074       ** First we attempt to find the largest existing rowid and add one
  3077   3075       ** to that.  But if the largest existing rowid is already the maximum
................................................................................
  3191   3189   case OP_PutIntKey:
  3192   3190   case OP_PutStrKey: {
  3193   3191     Mem *pNos = &pTos[-1];
  3194   3192     int i = pOp->p1;
  3195   3193     Cursor *pC;
  3196   3194     assert( pNos>=p->aStack );
  3197   3195     assert( i>=0 && i<p->nCursor );
  3198         -  if( ((pC = &p->aCsr[i])->pCursor!=0 || pC->pseudoTable) ){
         3196  +  if( ((pC = p->apCsr[i])->pCursor!=0 || pC->pseudoTable) ){
  3199   3197       char *zKey;
  3200   3198       i64 nKey; 
  3201   3199       i64 iKey;
  3202   3200       if( pOp->opcode==OP_PutStrKey ){
  3203   3201         Stringify(pNos);
  3204   3202         nKey = pNos->n;
  3205   3203         zKey = pNos->z;
................................................................................
  3278   3276   **
  3279   3277   ** If P1 is a pseudo-table, then this instruction is a no-op.
  3280   3278   */
  3281   3279   case OP_Delete: {
  3282   3280     int i = pOp->p1;
  3283   3281     Cursor *pC;
  3284   3282     assert( i>=0 && i<p->nCursor );
  3285         -  pC = &p->aCsr[i];
         3283  +  pC = p->apCsr[i];
  3286   3284     if( pC->pCursor!=0 ){
  3287   3285       sqlite3VdbeCursorMoveto(pC);
  3288   3286       rc = sqlite3BtreeDelete(pC->pCursor);
  3289   3287       pC->nextRowidValid = 0;
  3290   3288       pC->cacheValid = 0;
  3291   3289     }
  3292   3290     if( pOp->p2 & OPFLAG_NCHANGE ) db->nChange++;
................................................................................
  3311   3309   ** off (if P2==0).  In key-as-data mode, the OP_Column opcode pulls
  3312   3310   ** data off of the key rather than the data.  This is used for
  3313   3311   ** processing compound selects.
  3314   3312   */
  3315   3313   case OP_KeyAsData: {
  3316   3314     int i = pOp->p1;
  3317   3315     assert( i>=0 && i<p->nCursor );
  3318         -  p->aCsr[i].keyAsData = pOp->p2;
         3316  +  p->apCsr[i]->keyAsData = pOp->p2;
  3319   3317     break;
  3320   3318   }
  3321   3319   
  3322   3320   /* Opcode: RowData P1 * *
  3323   3321   **
  3324   3322   ** Push onto the stack the complete row data for cursor P1.
  3325   3323   ** There is no interpretation of the data.  It is just copied
................................................................................
  3341   3339   case OP_RowData: {
  3342   3340     int i = pOp->p1;
  3343   3341     Cursor *pC;
  3344   3342     int n;
  3345   3343   
  3346   3344     pTos++;
  3347   3345     assert( i>=0 && i<p->nCursor );
  3348         -  pC = &p->aCsr[i];
         3346  +  pC = p->apCsr[i];
  3349   3347     if( pC->nullRow ){
  3350   3348       pTos->flags = MEM_Null;
  3351   3349     }else if( pC->pCursor!=0 ){
  3352   3350       BtCursor *pCrsr = pC->pCursor;
  3353   3351       sqlite3VdbeCursorMoveto(pC);
  3354   3352       if( pC->nullRow ){
  3355   3353         pTos->flags = MEM_Null;
................................................................................
  3396   3394   */
  3397   3395   case OP_Recno: {
  3398   3396     int i = pOp->p1;
  3399   3397     Cursor *pC;
  3400   3398     i64 v;
  3401   3399   
  3402   3400     assert( i>=0 && i<p->nCursor );
  3403         -  pC = &p->aCsr[i];
         3401  +  pC = p->apCsr[i];
  3404   3402     sqlite3VdbeCursorMoveto(pC);
  3405   3403     pTos++;
  3406   3404     if( pC->recnoIsValid ){
  3407   3405       v = pC->lastRecno;
  3408   3406     }else if( pC->pseudoTable ){
  3409   3407       v = keyToInt(pC->iKey);
  3410   3408     }else if( pC->nullRow || pC->pCursor==0 ){
................................................................................
  3430   3428   ** integer.  This instruction pushes the entire key as a string.
  3431   3429   **
  3432   3430   ** This opcode may not be used on a pseudo-table.
  3433   3431   */
  3434   3432   case OP_FullKey: {
  3435   3433     int i = pOp->p1;
  3436   3434     BtCursor *pCrsr;
         3435  +  Cursor *pC;
  3437   3436   
  3438         -  assert( p->aCsr[i].keyAsData );
  3439         -  assert( !p->aCsr[i].pseudoTable );
         3437  +  assert( p->apCsr[i]->keyAsData );
         3438  +  assert( !p->apCsr[i]->pseudoTable );
  3440   3439     assert( i>=0 && i<p->nCursor );
  3441   3440     pTos++;
  3442         -  if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
         3441  +  if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
  3443   3442       u64 amt;
  3444   3443       char *z;
  3445   3444   
  3446         -    sqlite3VdbeCursorMoveto(&p->aCsr[i]);
  3447         -    assert( p->aCsr[i].intKey==0 );
         3445  +    sqlite3VdbeCursorMoveto(pC);
         3446  +    assert( pC->intKey==0 );
  3448   3447       sqlite3BtreeKeySize(pCrsr, &amt);
  3449   3448       if( amt<=0 ){
  3450   3449         rc = SQLITE_CORRUPT;
  3451   3450         goto abort_due_to_error;
  3452   3451       }
  3453   3452       if( amt>NBFS ){
  3454   3453         z = sqliteMallocRaw( amt );
................................................................................
  3469   3468   **
  3470   3469   ** Move the cursor P1 to a null row.  Any OP_Column operations
  3471   3470   ** that occur while the cursor is on the null row will always push 
  3472   3471   ** a NULL onto the stack.
  3473   3472   */
  3474   3473   case OP_NullRow: {
  3475   3474     int i = pOp->p1;
         3475  +  Cursor *pC;
  3476   3476   
  3477   3477     assert( i>=0 && i<p->nCursor );
  3478         -  p->aCsr[i].nullRow = 1;
  3479         -  p->aCsr[i].recnoIsValid = 0;
         3478  +  pC = p->apCsr[i];
         3479  +  pC->nullRow = 1;
         3480  +  pC->recnoIsValid = 0;
  3480   3481     break;
  3481   3482   }
  3482   3483   
  3483   3484   /* Opcode: Last P1 P2 *
  3484   3485   **
  3485   3486   ** The next use of the Recno or Column or Next instruction for P1 
  3486   3487   ** will refer to the last entry in the database table or index.
................................................................................
  3490   3491   */
  3491   3492   case OP_Last: {
  3492   3493     int i = pOp->p1;
  3493   3494     Cursor *pC;
  3494   3495     BtCursor *pCrsr;
  3495   3496   
  3496   3497     assert( i>=0 && i<p->nCursor );
  3497         -  pC = &p->aCsr[i];
         3498  +  pC = p->apCsr[i];
  3498   3499     if( (pCrsr = pC->pCursor)!=0 ){
  3499   3500       int res;
  3500   3501       rc = sqlite3BtreeLast(pCrsr, &res);
  3501   3502       pC->nullRow = res;
  3502   3503       pC->deferredMoveto = 0;
  3503   3504       pC->cacheValid = 0;
  3504   3505       if( res && pOp->p2>0 ){
................................................................................
  3521   3522   case OP_Rewind: {
  3522   3523     int i = pOp->p1;
  3523   3524     Cursor *pC;
  3524   3525     BtCursor *pCrsr;
  3525   3526     int res;
  3526   3527   
  3527   3528     assert( i>=0 && i<p->nCursor );
  3528         -  pC = &p->aCsr[i];
         3529  +  pC = p->apCsr[i];
  3529   3530     if( (pCrsr = pC->pCursor)!=0 ){
  3530   3531       rc = sqlite3BtreeFirst(pCrsr, &res);
  3531   3532       pC->atFirst = res==0;
  3532   3533       pC->deferredMoveto = 0;
  3533   3534       pC->cacheValid = 0;
  3534   3535     }else{
  3535   3536       res = 1;
................................................................................
  3560   3561   case OP_Prev:
  3561   3562   case OP_Next: {
  3562   3563     Cursor *pC;
  3563   3564     BtCursor *pCrsr;
  3564   3565   
  3565   3566     CHECK_FOR_INTERRUPT;
  3566   3567     assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  3567         -  pC = &p->aCsr[pOp->p1];
         3568  +  pC = p->apCsr[pOp->p1];
  3568   3569     if( (pCrsr = pC->pCursor)!=0 ){
  3569   3570       int res;
  3570   3571       if( pC->nullRow ){
  3571   3572         res = 1;
  3572   3573       }else{
  3573   3574         assert( pC->deferredMoveto==0 );
  3574   3575         rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) :
................................................................................
  3601   3602   case OP_IdxPut: {
  3602   3603     int i = pOp->p1;
  3603   3604     Cursor *pC;
  3604   3605     BtCursor *pCrsr;
  3605   3606     assert( pTos>=p->aStack );
  3606   3607     assert( i>=0 && i<p->nCursor );
  3607   3608     assert( pTos->flags & MEM_Str );
  3608         -  if( (pCrsr = (pC = &p->aCsr[i])->pCursor)!=0 ){
         3609  +  if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
  3609   3610       int nKey = pTos->n;
  3610   3611       const char *zKey = pTos->z;
  3611   3612       if( pOp->p2 ){
  3612   3613         int res;
  3613   3614         int len;
  3614   3615         u64 n;
  3615   3616      
................................................................................
  3658   3659   case OP_IdxDelete: {
  3659   3660     int i = pOp->p1;
  3660   3661     Cursor *pC;
  3661   3662     BtCursor *pCrsr;
  3662   3663     assert( pTos>=p->aStack );
  3663   3664     assert( pTos->flags & MEM_Str );
  3664   3665     assert( i>=0 && i<p->nCursor );
  3665         -  if( (pCrsr = (pC = &p->aCsr[i])->pCursor)!=0 ){
         3666  +  if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
  3666   3667       int rx, res;
  3667   3668       rx = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res);
  3668   3669       if( rx==SQLITE_OK && res==0 ){
  3669   3670         rc = sqlite3BtreeDelete(pCrsr);
  3670   3671       }
  3671   3672       assert( pC->deferredMoveto==0 );
  3672   3673       pC->cacheValid = 0;
................................................................................
  3683   3684   ** the record number of the table entry to which this index entry points.
  3684   3685   **
  3685   3686   ** See also: Recno, MakeIdxKey.
  3686   3687   */
  3687   3688   case OP_IdxRecno: {
  3688   3689     int i = pOp->p1;
  3689   3690     BtCursor *pCrsr;
         3691  +  Cursor *pC;
  3690   3692   
  3691   3693     assert( i>=0 && i<p->nCursor );
  3692   3694     pTos++;
  3693         -  if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
         3695  +  if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
  3694   3696       i64 rowid;
  3695   3697   
  3696         -    assert( p->aCsr[i].deferredMoveto==0 );
  3697         -    assert( p->aCsr[i].intKey==0 );
         3698  +    assert( pC->deferredMoveto==0 );
         3699  +    assert( pC->intKey==0 );
  3698   3700       rc = sqlite3VdbeIdxRowid(pCrsr, &rowid);
  3699   3701       if( rc!=SQLITE_OK ){
  3700   3702         goto abort_due_to_error;
  3701   3703       }
  3702   3704       pTos->flags = MEM_Int;
  3703   3705       pTos->i = rowid;
  3704   3706   
................................................................................
  3765   3767   ** In either case, the stack is popped once.
  3766   3768   */
  3767   3769   case OP_IdxLT:
  3768   3770   case OP_IdxGT:
  3769   3771   case OP_IdxGE: {
  3770   3772     int i= pOp->p1;
  3771   3773     BtCursor *pCrsr;
         3774  +  Cursor *pC;
  3772   3775   
  3773   3776     assert( i>=0 && i<p->nCursor );
  3774   3777     assert( pTos>=p->aStack );
  3775         -  if( (pCrsr = p->aCsr[i].pCursor)!=0 ){
         3778  +  if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
  3776   3779       int res, rc;
  3777         -    Cursor *pC = &p->aCsr[i];
  3778   3780    
  3779   3781       Stringify(pTos);
  3780         -    assert( p->aCsr[i].deferredMoveto==0 );
         3782  +    assert( pC->deferredMoveto==0 );
  3781   3783       if( pOp->p3 ){
  3782   3784         pC->incrKey = 1;
  3783   3785       }
  3784   3786       rc = sqlite3VdbeIdxKeyCompare(pC, pTos->n, pTos->z, 0, &res);
  3785   3787       pC->incrKey = 0;
  3786   3788       if( rc!=SQLITE_OK ){
  3787   3789         break;

Changes to src/vdbeInt.h.

   261    261     int nLabel;         /* Number of labels used */
   262    262     int nLabelAlloc;    /* Number of slots allocated in aLabel[] */
   263    263     int *aLabel;        /* Space to hold the labels */
   264    264     Mem *aStack;        /* The operand stack, except string values */
   265    265     Mem *pTos;          /* Top entry in the operand stack */
   266    266     char **zArgv;       /* Text values used by the callback */
   267    267     char **azColName;   /* Becomes the 4th parameter to callbacks */
   268         -  int nCursor;        /* Number of slots in aCsr[] */
   269         -  Cursor *aCsr;       /* One element of this array for each open cursor */
          268  +  int nCursor;        /* Number of slots in apCsr[] */
          269  +  Cursor **apCsr;     /* One element of this array for each open cursor */
   270    270     Sorter *pSort;      /* A linked list of objects to be sorted */
   271    271     FILE *pFile;        /* At most one open file handler */
   272    272     int nField;         /* Number of file fields */
   273    273     char **azField;     /* Data for each file field */
   274    274     int nVar;           /* Number of entries in azVariable[] */
   275    275     char **azVar;       /* Values for the OP_Variable opcode */
   276    276     int *anVar;         /* Length of each value in azVariable[] */

Changes to src/vdbeaux.c.

   732    732       sqlite3BtreeCloseCursor(pCx->pCursor);
   733    733     }
   734    734     if( pCx->pBt ){
   735    735       sqlite3BtreeClose(pCx->pBt);
   736    736     }
   737    737     sqliteFree(pCx->pData);
   738    738     sqliteFree(pCx->aType);
   739         -  memset(pCx, 0, sizeof(Cursor));
          739  +  memset(pCx, 0, sizeof(*pCx));
   740    740   }
   741    741   
   742    742   /*
   743    743   ** Close all cursors
   744    744   */
   745    745   static void closeAllCursors(Vdbe *p){
   746    746     int i;
   747    747     for(i=0; i<p->nCursor; i++){
   748         -    sqlite3VdbeCleanupCursor(&p->aCsr[i]);
          748  +    Cursor *pC = p->apCsr[i];
          749  +    sqlite3VdbeCleanupCursor(pC);
          750  +    sqliteFree(pC);
   749    751     }
   750         -  sqliteFree(p->aCsr);
   751         -  p->aCsr = 0;
          752  +  sqliteFree(p->apCsr);
          753  +  p->apCsr = 0;
   752    754     p->nCursor = 0;
   753    755   }
   754    756   
   755    757   /*
   756    758   ** Clean up the VM after execution.
   757    759   **
   758    760   ** This routine will automatically close any cursors, lists, and/or