/ Check-in [5f9d5068]
Login

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

Overview
Comment:Reduce the size of the VdbeCursor object from 144 to 120 bytes.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | OP_Column-refactor
Files: files | file ages | folders
SHA1:5f9d50688508affd0bc8e4d52e21dacfacdbb5ce
User & Date: drh 2013-11-20 21:51:33
Context
2013-11-21
00:10
Unpack some fields, adding some space back to the VdbeCursor object, in order to help the code to run a little faster. check-in: f8d5efcd user: drh tags: OP_Column-refactor
2013-11-20
21:51
Reduce the size of the VdbeCursor object from 144 to 120 bytes. check-in: 5f9d5068 user: drh tags: OP_Column-refactor
20:58
Improved comments on the OP_Column changes. Optimize out loading of overflow pages for content with zero length. Add test cases for the latter. check-in: 0e05679d user: drh tags: OP_Column-refactor
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/vdbe.c.

   224    224     if( SQLITE_OK==sqlite3VdbeMemGrow(pMem, nByte, 0) ){
   225    225       p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z;
   226    226       memset(pCx, 0, sizeof(VdbeCursor));
   227    227       pCx->iDb = iDb;
   228    228       pCx->nField = nField;
   229    229       if( nField ){
   230    230         pCx->aType = (u32 *)&pMem->z[ROUND8(sizeof(VdbeCursor))];
   231         -      pCx->aOffset = pCx->aType + nField;
   232    231       }
   233    232       if( isBtreeCursor ){
   234    233         pCx->pCursor = (BtCursor*)
   235    234             &pMem->z[ROUND8(sizeof(VdbeCursor))+(2*nField+2)*sizeof(u32)];
   236    235         sqlite3BtreeCursorZero(pCx->pCursor);
   237    236       }
   238    237     }
................................................................................
  2278   2277     pDest = &aMem[pOp->p3];
  2279   2278     memAboutToChange(p, pDest);
  2280   2279     assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  2281   2280     pC = p->apCsr[pOp->p1];
  2282   2281     assert( pC!=0 );
  2283   2282     assert( p2<pC->nField );
  2284   2283     aType = pC->aType;
  2285         -  aOffset = pC->aOffset;
         2284  +  aOffset = aType + pC->nField;
  2286   2285   #ifndef SQLITE_OMIT_VIRTUALTABLE
  2287   2286     assert( pC->pVtabCursor==0 ); /* OP_Column never called on virtual table */
  2288   2287   #endif
  2289   2288     pCrsr = pC->pCursor;
  2290   2289     assert( pCrsr!=0 || pC->pseudoTableReg>0 ); /* pCrsr NULL on PseudoTables */
  2291   2290     assert( pCrsr!=0 || pC->nullRow );          /* pC->nullRow on PseudoTables */
  2292   2291   
................................................................................
  2309   2308           pC->aRow = (u8*)pReg->z;
  2310   2309         }else{
  2311   2310           MemSetTypeFlag(pDest, MEM_Null);
  2312   2311           goto op_column_out;
  2313   2312         }
  2314   2313       }else{
  2315   2314         assert( pCrsr );
  2316         -      if( pC->isIndex ){
         2315  +      if( pC->isTable==0 ){
  2317   2316           assert( sqlite3BtreeCursorIsValid(pCrsr) );
  2318   2317           VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64);
  2319   2318           assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
  2320   2319           /* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the
  2321   2320           ** payload size, so it is impossible for payloadSize64 to be
  2322   2321           ** larger than 32 bits. */
  2323   2322           assert( (payloadSize64 & SQLITE_MAX_U32)==(u64)payloadSize64 );
................................................................................
  2374   2373       /* If there is more header available for parsing in the record, try
  2375   2374       ** to extract additional fields up through the p2+1-th field 
  2376   2375       */
  2377   2376       if( pC->iHdrOffset<aOffset[0] ){
  2378   2377         /* Make sure zData points to enough of the record to cover the header. */
  2379   2378         if( pC->aRow==0 ){
  2380   2379           memset(&sMem, 0, sizeof(sMem));
  2381         -        rc = sqlite3VdbeMemFromBtree(pCrsr, 0, pC->aOffset[0], pC->isIndex,
  2382         -                                     &sMem);
         2380  +        rc = sqlite3VdbeMemFromBtree(pCrsr, 0, aOffset[0], 
         2381  +                                     !pC->isTable, &sMem);
  2383   2382           if( rc!=SQLITE_OK ){
  2384   2383             goto op_column_error;
  2385   2384           }
  2386   2385           zData = (u8*)sMem.z;
  2387   2386         }else{
  2388   2387           zData = pC->aRow;
  2389   2388         }
................................................................................
  2472   2471         ** will work for everything else.  Content is also irrelevant if
  2473   2472         ** the content length is 0. */
  2474   2473         zData = t<=13 ? (u8*)&payloadSize64 : 0;
  2475   2474         sMem.zMalloc = 0;
  2476   2475       }else{
  2477   2476         memset(&sMem, 0, sizeof(sMem));
  2478   2477         sqlite3VdbeMemMove(&sMem, pDest);
  2479         -      rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len,  pC->isIndex,
         2478  +      rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable,
  2480   2479                                      &sMem);
  2481   2480         if( rc!=SQLITE_OK ){
  2482   2481           goto op_column_error;
  2483   2482         }
  2484   2483         zData = (u8*)sMem.z;
  2485   2484       }
  2486   2485       sqlite3VdbeSerialGet(zData, t, pDest);
................................................................................
  3269   3268     assert( OPFLAG_BULKCSR==BTREE_BULKLOAD );
  3270   3269     sqlite3BtreeCursorHints(pCur->pCursor, (pOp->p5 & OPFLAG_BULKCSR));
  3271   3270   
  3272   3271     /* Since it performs no memory allocation or IO, the only value that
  3273   3272     ** sqlite3BtreeCursor() may return is SQLITE_OK. */
  3274   3273     assert( rc==SQLITE_OK );
  3275   3274   
  3276         -  /* Set the VdbeCursor.isTable and isIndex variables. Previous versions of
         3275  +  /* Set the VdbeCursor.isTable variable. Previous versions of
  3277   3276     ** SQLite used to check if the root-page flags were sane at this point
  3278   3277     ** and report database corruption if they were not, but this check has
  3279   3278     ** since moved into the btree layer.  */  
  3280   3279     pCur->isTable = pOp->p4type!=P4_KEYINFO;
  3281         -  pCur->isIndex = !pCur->isTable;
  3282   3280     break;
  3283   3281   }
  3284   3282   
  3285   3283   /* Opcode: OpenEphemeral P1 P2 * P4 P5
  3286   3284   ** Synopsis: nColumn=P2
  3287   3285   **
  3288   3286   ** Open a new cursor P1 to a transient table.
................................................................................
  3349   3347         pCx->isTable = 0;
  3350   3348       }else{
  3351   3349         rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, pCx->pCursor);
  3352   3350         pCx->isTable = 1;
  3353   3351       }
  3354   3352     }
  3355   3353     pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
  3356         -  pCx->isIndex = !pCx->isTable;
  3357   3354     break;
  3358   3355   }
  3359   3356   
  3360   3357   /* Opcode: SorterOpen P1 * * P4 *
  3361   3358   **
  3362   3359   ** This opcode works like OP_OpenEphemeral except that it opens
  3363   3360   ** a transient index that is specifically designed to sort large
................................................................................
  3369   3366     assert( pOp->p1>=0 );
  3370   3367     assert( pOp->p2>=0 );
  3371   3368     pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
  3372   3369     if( pCx==0 ) goto no_mem;
  3373   3370     pCx->pKeyInfo = pOp->p4.pKeyInfo;
  3374   3371     assert( pCx->pKeyInfo->db==db );
  3375   3372     assert( pCx->pKeyInfo->enc==ENC(db) );
  3376         -  pCx->isSorter = 1;
  3377   3373     rc = sqlite3VdbeSorterInit(db, pCx);
  3378   3374     break;
  3379   3375   }
  3380   3376   
  3381   3377   /* Opcode: OpenPseudo P1 P2 P3 * P5
  3382   3378   ** Synopsis: content in r[P2@P3]
  3383   3379   **
................................................................................
  3401   3397     assert( pOp->p1>=0 );
  3402   3398     assert( pOp->p3>=0 );
  3403   3399     pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0);
  3404   3400     if( pCx==0 ) goto no_mem;
  3405   3401     pCx->nullRow = 1;
  3406   3402     pCx->pseudoTableReg = pOp->p2;
  3407   3403     pCx->isTable = 1;
  3408         -  pCx->isIndex = 0;
  3409   3404     pCx->multiPseudo = pOp->p5;
  3410   3405     break;
  3411   3406   }
  3412   3407   
  3413   3408   /* Opcode: Close P1 * * * *
  3414   3409   **
  3415   3410   ** Close a cursor previously opened as P1.  If P1 is not
................................................................................
  3760   3755     rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, pIdxKey, 0, 0, &res);
  3761   3756     if( pOp->p4.i==0 ){
  3762   3757       sqlite3DbFree(db, pFree);
  3763   3758     }
  3764   3759     if( rc!=SQLITE_OK ){
  3765   3760       break;
  3766   3761     }
  3767         -  pC->seekResult = res;
         3762  +  pC->seekResult = res==0 ? 0 : res<0 ? -1 : +1;
  3768   3763     alreadyExists = (res==0);
  3769   3764     pC->nullRow = 1-alreadyExists;
  3770   3765     pC->deferredMoveto = 0;
  3771   3766     pC->cacheStatus = CACHE_STALE;
  3772   3767     if( pOp->opcode==OP_Found ){
  3773   3768       if( alreadyExists ) pc = pOp->p2 - 1;
  3774   3769     }else{
................................................................................
  3814   3809     pC->nullRow = 0;
  3815   3810     pC->cacheStatus = CACHE_STALE;
  3816   3811     pC->deferredMoveto = 0;
  3817   3812     if( res!=0 ){
  3818   3813       pc = pOp->p2 - 1;
  3819   3814       assert( pC->rowidIsValid==0 );
  3820   3815     }
  3821         -  pC->seekResult = res;
         3816  +  pC->seekResult = res==0 ? 0 : res<0 ? -1 : +1;
  3822   3817     break;
  3823   3818   }
  3824   3819   
  3825   3820   /* Opcode: Sequence P1 P2 * * *
  3826   3821   ** Synopsis: r[P2]=rowid
  3827   3822   **
  3828   3823   ** Find the next available sequence number for cursor P1.
................................................................................
  4037   4032   case OP_Insert: 
  4038   4033   case OP_InsertInt: {
  4039   4034     Mem *pData;       /* MEM cell holding data for the record to be inserted */
  4040   4035     Mem *pKey;        /* MEM cell holding key  for the record */
  4041   4036     i64 iKey;         /* The integer ROWID or key for the record to be inserted */
  4042   4037     VdbeCursor *pC;   /* Cursor to table into which insert is written */
  4043   4038     int nZero;        /* Number of zero-bytes to append */
  4044         -  int seekResult;   /* Result of prior seek or 0 if no USESEEKRESULT flag */
         4039  +  i8 seekResult;    /* Result of prior seek or 0 if no USESEEKRESULT flag */
  4045   4040     const char *zDb;  /* database name - used by the update hook */
  4046   4041     const char *zTbl; /* Table name - used by the opdate hook */
  4047   4042     int op;           /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */
  4048   4043   
  4049   4044     pData = &aMem[pOp->p2];
  4050   4045     assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  4051   4046     assert( memIsValid(pData) );
................................................................................
  4217   4212   ** Write into register P2 the current sorter data for sorter cursor P1.
  4218   4213   */
  4219   4214   case OP_SorterData: {
  4220   4215     VdbeCursor *pC;
  4221   4216   
  4222   4217     pOut = &aMem[pOp->p2];
  4223   4218     pC = p->apCsr[pOp->p1];
  4224         -  assert( pC->isSorter );
         4219  +  assert( isSorter(pC) );
  4225   4220     rc = sqlite3VdbeSorterRowkey(pC, pOut);
  4226   4221     break;
  4227   4222   }
  4228   4223   
  4229   4224   /* Opcode: RowData P1 P2 * * *
  4230   4225   ** Synopsis: r[P2]=data
  4231   4226   **
................................................................................
  4257   4252   
  4258   4253     pOut = &aMem[pOp->p2];
  4259   4254     memAboutToChange(p, pOut);
  4260   4255   
  4261   4256     /* Note that RowKey and RowData are really exactly the same instruction */
  4262   4257     assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  4263   4258     pC = p->apCsr[pOp->p1];
  4264         -  assert( pC->isSorter==0 );
         4259  +  assert( isSorter(pC)==0 );
  4265   4260     assert( pC->isTable || pOp->opcode!=OP_RowData );
  4266         -  assert( pC->isIndex || pOp->opcode==OP_RowData );
         4261  +  assert( pC->isTable==0 || pOp->opcode==OP_RowData );
  4267   4262     assert( pC!=0 );
  4268   4263     assert( pC->nullRow==0 );
  4269   4264     assert( pC->pseudoTableReg==0 );
  4270   4265     assert( pC->pCursor!=0 );
  4271   4266     pCrsr = pC->pCursor;
  4272   4267     assert( sqlite3BtreeCursorIsValid(pCrsr) );
  4273   4268   
................................................................................
  4276   4271     ** the cursor.  Hence the following sqlite3VdbeCursorMoveto() call is always
  4277   4272     ** a no-op and can never fail.  But we leave it in place as a safety.
  4278   4273     */
  4279   4274     assert( pC->deferredMoveto==0 );
  4280   4275     rc = sqlite3VdbeCursorMoveto(pC);
  4281   4276     if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
  4282   4277   
  4283         -  if( pC->isIndex ){
         4278  +  if( pC->isTable==0 ){
  4284   4279       assert( !pC->isTable );
  4285   4280       VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &n64);
  4286   4281       assert( rc==SQLITE_OK );    /* True because of CursorMoveto() call above */
  4287   4282       if( n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){
  4288   4283         goto too_big;
  4289   4284       }
  4290   4285       n = (u32)n64;
................................................................................
  4296   4291       }
  4297   4292     }
  4298   4293     if( sqlite3VdbeMemGrow(pOut, n, 0) ){
  4299   4294       goto no_mem;
  4300   4295     }
  4301   4296     pOut->n = n;
  4302   4297     MemSetTypeFlag(pOut, MEM_Blob);
  4303         -  if( pC->isIndex ){
         4298  +  if( pC->isTable==0 ){
  4304   4299       rc = sqlite3BtreeKey(pCrsr, 0, n, pOut->z);
  4305   4300     }else{
  4306   4301       rc = sqlite3BtreeData(pCrsr, 0, n, pOut->z);
  4307   4302     }
  4308   4303     pOut->enc = SQLITE_UTF8;  /* In case the blob is ever cast to text */
  4309   4304     UPDATE_MAX_BLOBSIZE(pOut);
  4310   4305     REGISTER_TRACE(pOp->p2, pOut);
................................................................................
  4445   4440     VdbeCursor *pC;
  4446   4441     BtCursor *pCrsr;
  4447   4442     int res;
  4448   4443   
  4449   4444     assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  4450   4445     pC = p->apCsr[pOp->p1];
  4451   4446     assert( pC!=0 );
  4452         -  assert( pC->isSorter==(pOp->opcode==OP_SorterSort) );
         4447  +  assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) );
  4453   4448     res = 1;
  4454   4449     if( isSorter(pC) ){
  4455   4450       rc = sqlite3VdbeSorterRewind(db, pC, &res);
  4456   4451     }else{
  4457   4452       pCrsr = pC->pCursor;
  4458   4453       assert( pCrsr );
  4459   4454       rc = sqlite3BtreeFirst(pCrsr, &res);
................................................................................
  4509   4504   
  4510   4505     assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  4511   4506     assert( pOp->p5<ArraySize(p->aCounter) );
  4512   4507     pC = p->apCsr[pOp->p1];
  4513   4508     if( pC==0 ){
  4514   4509       break;  /* See ticket #2273 */
  4515   4510     }
  4516         -  assert( pC->isSorter==(pOp->opcode==OP_SorterNext) );
         4511  +  assert( isSorter(pC)==(pOp->opcode==OP_SorterNext) );
  4517   4512     if( isSorter(pC) ){
  4518   4513       assert( pOp->opcode==OP_SorterNext );
  4519   4514       rc = sqlite3VdbeSorterNext(db, pC, &res);
  4520   4515     }else{
  4521   4516       /* res = 1; // Always initialized by the xAdvance() call */
  4522   4517       assert( pC->deferredMoveto==0 );
  4523   4518       assert( pC->pCursor );
................................................................................
  4557   4552     BtCursor *pCrsr;
  4558   4553     int nKey;
  4559   4554     const char *zKey;
  4560   4555   
  4561   4556     assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  4562   4557     pC = p->apCsr[pOp->p1];
  4563   4558     assert( pC!=0 );
  4564         -  assert( pC->isSorter==(pOp->opcode==OP_SorterInsert) );
         4559  +  assert( isSorter(pC)==(pOp->opcode==OP_SorterInsert) );
  4565   4560     pIn2 = &aMem[pOp->p2];
  4566   4561     assert( pIn2->flags & MEM_Blob );
  4567   4562     pCrsr = pC->pCursor;
  4568   4563     if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
  4569   4564     assert( pCrsr!=0 );
  4570   4565     assert( pC->isTable==0 );
  4571   4566     rc = ExpandBlob(pIn2);

Changes to src/vdbeInt.h.

    32     32   ** of the following structure.
    33     33   */
    34     34   typedef struct VdbeOp Op;
    35     35   
    36     36   /*
    37     37   ** Boolean values
    38     38   */
    39         -typedef unsigned char Bool;
           39  +typedef unsigned Bool;
    40     40   
    41     41   /* Opaque type used by code in vdbesort.c */
    42     42   typedef struct VdbeSorter VdbeSorter;
    43     43   
    44     44   /* Opaque type used by the explainer */
    45     45   typedef struct Explain Explain;
    46     46   
................................................................................
    59     59   */
    60     60   struct VdbeCursor {
    61     61     BtCursor *pCursor;    /* The cursor structure of the backend */
    62     62     Btree *pBt;           /* Separate file holding temporary table */
    63     63     KeyInfo *pKeyInfo;    /* Info about index keys needed by index cursors */
    64     64     int pseudoTableReg;   /* Register holding pseudotable content. */
    65     65     i16 nField;           /* Number of fields in the header */
           66  +  u16 nHdrParsed;       /* Number of header fields parsed so far */
    66     67     i8 iDb;               /* Index of cursor database in db->aDb[] (or -1) */
    67         -  Bool rowidIsValid;    /* True if lastRowid is valid */
    68         -  Bool useRandomRowid;  /* Generate new record numbers semi-randomly */
    69         -  Bool nullRow;         /* True if pointing to a row with no data */
    70         -  Bool deferredMoveto;  /* A call to sqlite3BtreeMoveto() is needed */
    71         -  Bool isTable;         /* True if a table requiring integer keys */
    72         -  Bool isIndex;         /* True if an index containing keys only - no data */
    73         -  Bool isOrdered;       /* True if the underlying table is BTREE_UNORDERED */
    74         -  Bool isSorter;        /* True if a new-style sorter */
    75         -  Bool multiPseudo;     /* Multi-register pseudo-cursor */
           68  +  i8 seekResult;        /* Result of previous sqlite3BtreeMoveto() */
           69  +  Bool nullRow:1;       /* True if pointing to a row with no data */
           70  +  Bool rowidIsValid :1; /* True if lastRowid is valid */
           71  +  Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
           72  +  Bool deferredMoveto:1;/* A call to sqlite3BtreeMoveto() is needed */
           73  +  Bool isTable:1;       /* True if a table requiring integer keys */
           74  +  Bool isOrdered:1;     /* True if the underlying table is BTREE_UNORDERED */
           75  +  Bool multiPseudo:1;   /* Multi-register pseudo-cursor */
    76     76     sqlite3_vtab_cursor *pVtabCursor;  /* The cursor for a virtual table */
    77     77     const sqlite3_module *pModule;     /* Module for cursor pVtabCursor */
    78     78     i64 seqCount;         /* Sequence counter */
    79     79     i64 movetoTarget;     /* Argument to the deferred sqlite3BtreeMoveto() */
    80     80     i64 lastRowid;        /* Rowid being deleted by OP_Delete */
    81     81     VdbeSorter *pSorter;  /* Sorter object for OP_SorterOpen cursors */
    82     82   
    83         -  /* Result of last sqlite3BtreeMoveto() done by an OP_NotExists */
    84         -  int seekResult;
    85         -
    86     83     /* Cached information about the header for the data record that the
    87     84     ** cursor is currently pointing to.  Only valid if cacheStatus matches
    88     85     ** Vdbe.cacheCtr.  Vdbe.cacheCtr will never take on the value of
    89     86     ** CACHE_STALE and so setting cacheStatus=CACHE_STALE guarantees that
    90     87     ** the cache is out of date.
    91     88     **
    92     89     ** aRow might point to (ephemeral) data for the current row, or it might
    93     90     ** be NULL.
    94     91     */
    95     92     u32 cacheStatus;      /* Cache is valid if this matches Vdbe.cacheCtr */
    96     93     u32 payloadSize;      /* Total number of bytes in the record */
    97         -  u16 nHdrParsed;       /* Number of header fields parsed so far */
    98         -  u16 nFieldPresent;    /* Number of fields in the record */
    99     94     u32 szRow;            /* Byte available in aRow */
   100     95     u32 iHdrOffset;       /* Offset to next unparsed byte of the header */
   101     96     u32 *aType;           /* Type values for all entries in the record */
   102         -  u32 *aOffset;         /* Cached offsets to the start of each columns data */
   103     97     const u8 *aRow;       /* Data for the current row, if all on one page */
   104     98   };
   105     99   typedef struct VdbeCursor VdbeCursor;
   106    100   
   107    101   /*
   108    102   ** When a sub-program is executed (OP_Program), a structure of this type
   109    103   ** is allocated to store the current value of the program counter, as

Changes to src/vdbeblob.c.

    60     60     ** triggering asserts related to mutexes.
    61     61     */
    62     62     assert( v->aVar[0].flags&MEM_Int );
    63     63     v->aVar[0].u.i = iRow;
    64     64   
    65     65     rc = sqlite3_step(p->pStmt);
    66     66     if( rc==SQLITE_ROW ){
    67         -    u32 type = v->apCsr[0]->aType[p->iCol];
           67  +    VdbeCursor *pC = v->apCsr[0];
           68  +    u32 type = pC->aType[p->iCol];
    68     69       if( type<12 ){
    69     70         zErr = sqlite3MPrintf(p->db, "cannot open value of type %s",
    70     71             type==0?"null": type==7?"real": "integer"
    71     72         );
    72     73         rc = SQLITE_ERROR;
    73     74         sqlite3_finalize(p->pStmt);
    74     75         p->pStmt = 0;
    75     76       }else{
    76         -      p->iOffset = v->apCsr[0]->aOffset[p->iCol];
           77  +      p->iOffset = pC->aType[p->iCol + pC->nField];
    77     78         p->nByte = sqlite3VdbeSerialTypeLen(type);
    78         -      p->pCsr =  v->apCsr[0]->pCursor;
           79  +      p->pCsr =  pC->pCursor;
    79     80         sqlite3BtreeEnterCursor(p->pCsr);
    80     81         sqlite3BtreeCacheOverflow(p->pCsr);
    81     82         sqlite3BtreeLeaveCursor(p->pCsr);
    82     83       }
    83     84     }
    84     85   
    85     86     if( rc==SQLITE_ROW ){