/ Check-in [7c914e39]
Login

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

Overview
Comment:Refactoring the OP_Column opcode for improved performance and maintainability.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | OP_Column-refactor
Files: files | file ages | folders
SHA1:7c914e3997d2b28164a2fa7eb4398262b6ddb4b2
User & Date: drh 2013-11-20 17:25:55
Context
2013-11-20
19:28
Further performance tweaks to OP_Column. check-in: 0e3f5df6 user: drh tags: OP_Column-refactor
17:25
Refactoring the OP_Column opcode for improved performance and maintainability. check-in: 7c914e39 user: drh tags: OP_Column-refactor
02:53
Simplifications to the VdbeCursor object. check-in: 5562cd34 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/vdbe.c.

   210    210     Mem *pMem = &p->aMem[p->nMem-iCur];
   211    211   
   212    212     int nByte;
   213    213     VdbeCursor *pCx = 0;
   214    214     nByte = 
   215    215         ROUND8(sizeof(VdbeCursor)) + 
   216    216         (isBtreeCursor?sqlite3BtreeCursorSize():0) + 
   217         -      2*nField*sizeof(u32);
          217  +      (2*nField+2)*sizeof(u32);
   218    218   
   219    219     assert( iCur<p->nCursor );
   220    220     if( p->apCsr[iCur] ){
   221    221       sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
   222    222       p->apCsr[iCur] = 0;
   223    223     }
   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;
   231    232       }
   232    233       if( isBtreeCursor ){
   233    234         pCx->pCursor = (BtCursor*)
   234         -          &pMem->z[ROUND8(sizeof(VdbeCursor))+2*nField*sizeof(u32)];
          235  +          &pMem->z[ROUND8(sizeof(VdbeCursor))+(2*nField+2)*sizeof(u32)];
   235    236         sqlite3BtreeCursorZero(pCx->pCursor);
   236    237       }
   237    238     }
   238    239     return pCx;
   239    240   }
   240    241   
   241    242   /*
................................................................................
  2249   2250   **
  2250   2251   ** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 when
  2251   2252   ** the result is guaranteed to only be used as the argument of a length()
  2252   2253   ** or typeof() function, respectively.  The loading of large blobs can be
  2253   2254   ** skipped for length() and all content loading can be skipped for typeof().
  2254   2255   */
  2255   2256   case OP_Column: {
  2256         -  u32 payloadSize;   /* Number of bytes in the record */
  2257   2257     i64 payloadSize64; /* Number of bytes in the record */
  2258   2258     int p1;            /* P1 value of the opcode */
  2259   2259     int p2;            /* column number to retrieve */
  2260   2260     VdbeCursor *pC;    /* The VDBE cursor */
  2261         -  char *zRec;        /* Pointer to complete record-data */
  2262   2261     BtCursor *pCrsr;   /* The BTree cursor */
  2263   2262     u32 *aType;        /* aType[i] holds the numeric type of the i-th column */
  2264   2263     u32 *aOffset;      /* aOffset[i] is offset to start of data for i-th column */
  2265   2264     int nField;        /* number of fields in the record */
  2266   2265     int len;           /* The length of the serialized data for the column */
  2267   2266     int i;             /* Loop counter */
  2268         -  char *zData;       /* Part of the record being decoded */
  2269   2267     Mem *pDest;        /* Where to write the extracted value */
  2270   2268     Mem sMem;          /* For storing the record being decoded */
  2271         -  u8 *zIdx;          /* Index into header */
  2272         -  u8 *zEndHdr;       /* Pointer to first byte after the header */
         2269  +  const u8 *zData;   /* Part of the record being decoded */
         2270  +  const u8 *zHdr;    /* Next unparsed byte of the header */
         2271  +  const u8 *zEndHdr; /* Pointer to first byte after the header */
  2273   2272     u32 offset;        /* Offset into the data */
  2274   2273     u32 szField;       /* Number of bytes in the content of a field */
  2275         -  int szHdr;         /* Size of the header size field at start of record */
  2276   2274     int avail;         /* Number of bytes of available data */
  2277   2275     u32 t;             /* A type code from the record header */
  2278   2276     Mem *pReg;         /* PseudoTable input register */
  2279   2277   
  2280         -
  2281   2278     p1 = pOp->p1;
         2279  +  assert( p1<p->nCursor );
  2282   2280     p2 = pOp->p2;
  2283         -  pC = 0;
  2284         -  memset(&sMem, 0, sizeof(sMem));
  2285         -  assert( p1<p->nCursor );
         2281  +  sMem.zMalloc = 0;
  2286   2282     assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
  2287   2283     pDest = &aMem[pOp->p3];
  2288   2284     memAboutToChange(p, pDest);
  2289         -  zRec = 0;
  2290         -
  2291         -  /* This block sets the variable payloadSize to be the total number of
  2292         -  ** bytes in the record.
  2293         -  **
  2294         -  ** zRec is set to be the complete text of the record if it is available.
  2295         -  ** The complete record text is always available for pseudo-tables
  2296         -  ** If the record is stored in a cursor, the complete record text
  2297         -  ** might be available in the  pC->aRow cache.  Or it might not be.
  2298         -  ** If the data is unavailable,  zRec is set to NULL.
  2299         -  **
  2300         -  ** We also compute the number of columns in the record.  For cursors,
  2301         -  ** the number of columns is stored in the VdbeCursor.nField element.
  2302         -  */
  2303   2285     pC = p->apCsr[p1];
  2304   2286     assert( pC!=0 );
         2287  +  nField = pC->nField;
         2288  +  assert( p2<nField );
         2289  +  aType = pC->aType;
         2290  +  aOffset = pC->aOffset;
  2305   2291   #ifndef SQLITE_OMIT_VIRTUALTABLE
  2306   2292     assert( pC->pVtabCursor==0 );
  2307   2293   #endif
  2308   2294     pCrsr = pC->pCursor;
  2309         -  if( pCrsr!=0 ){
  2310         -    /* The record is stored in a B-Tree */
  2311         -    rc = sqlite3VdbeCursorMoveto(pC);
  2312         -    if( rc ) goto abort_due_to_error;
  2313         -    if( pC->nullRow ){
  2314         -      payloadSize = 0;
  2315         -    }else if( pC->cacheStatus==p->cacheCtr ){
  2316         -      payloadSize = pC->payloadSize;
  2317         -      zRec = (char*)pC->aRow;
  2318         -    }else if( pC->isIndex ){
  2319         -      assert( sqlite3BtreeCursorIsValid(pCrsr) );
  2320         -      VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64);
  2321         -      assert( rc==SQLITE_OK );   /* True because of CursorMoveto() call above */
  2322         -      /* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the
  2323         -      ** payload size, so it is impossible for payloadSize64 to be
  2324         -      ** larger than 32 bits. */
  2325         -      assert( (payloadSize64 & SQLITE_MAX_U32)==(u64)payloadSize64 );
  2326         -      payloadSize = (u32)payloadSize64;
  2327         -    }else{
  2328         -      assert( sqlite3BtreeCursorIsValid(pCrsr) );
  2329         -      VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &payloadSize);
  2330         -      assert( rc==SQLITE_OK );   /* DataSize() cannot fail */
  2331         -    }
  2332         -  }else{
  2333         -    assert( pC->pseudoTableReg>0 );
  2334         -    pReg = &aMem[pC->pseudoTableReg];
  2335         -    if( pC->multiPseudo ){
  2336         -      sqlite3VdbeMemShallowCopy(pDest, pReg+p2, MEM_Ephem);
  2337         -      Deephemeralize(pDest);
  2338         -      goto op_column_out;
  2339         -    }
  2340         -    assert( pReg->flags & MEM_Blob );
  2341         -    assert( memIsValid(pReg) );
  2342         -    payloadSize = pReg->n;
  2343         -    zRec = pReg->z;
  2344         -    pC->cacheStatus = (pOp->p5&OPFLAG_CLEARCACHE) ? CACHE_STALE : p->cacheCtr;
  2345         -    assert( payloadSize==0 || zRec!=0 );
  2346         -  }
  2347         -
  2348         -  /* If payloadSize is 0, then just store a NULL.  This can happen because of
  2349         -  ** nullRow or because of a corrupt database. */
  2350         -  if( payloadSize==0 ){
  2351         -    MemSetTypeFlag(pDest, MEM_Null);
  2352         -    goto op_column_out;
  2353         -  }
  2354         -  assert( db->aLimit[SQLITE_LIMIT_LENGTH]>=0 );
  2355         -  if( payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
  2356         -    goto too_big;
  2357         -  }
  2358         -
  2359         -  nField = pC->nField;
  2360         -  assert( p2<nField );
  2361         -
  2362         -  /* Read and parse the table header.  Store the results of the parse
  2363         -  ** into the record header cache fields of the cursor.
  2364         -  */
  2365         -  aType = pC->aType;
  2366         -  if( pC->cacheStatus==p->cacheCtr ){
  2367         -    aOffset = pC->aOffset;
  2368         -  }else{
  2369         -    assert(aType);
  2370         -    avail = 0;
  2371         -    pC->aOffset = aOffset = &aType[nField];
  2372         -    pC->payloadSize = payloadSize;
  2373         -    pC->cacheStatus = p->cacheCtr;
  2374         -
  2375         -    /* Figure out how many bytes are in the header */
  2376         -    if( zRec ){
  2377         -      zData = zRec;
         2295  +  assert( pCrsr!=0 || pC->pseudoTableReg>0 );
         2296  +
         2297  +  /* If the cursor cache is stale, bring it up-to-date */
         2298  +  rc = sqlite3VdbeCursorMoveto(pC);
         2299  +  if( rc ) goto abort_due_to_error;
         2300  +  if( pC->cacheStatus!=p->cacheCtr || (pOp->p5&OPFLAG_CLEARCACHE)!=0 ){
         2301  +    if( pCrsr==0 ){
         2302  +      assert( pC->pseudoTableReg>0 );
         2303  +      pReg = &aMem[pC->pseudoTableReg];
         2304  +      if( pC->multiPseudo ){
         2305  +        sqlite3VdbeMemShallowCopy(pDest, pReg+p2, MEM_Ephem);
         2306  +        Deephemeralize(pDest);
         2307  +        goto op_column_out;
         2308  +      }
         2309  +      assert( pReg->flags & MEM_Blob );
         2310  +      assert( memIsValid(pReg) );
         2311  +      pC->payloadSize = pC->szRow = avail = pReg->n;
         2312  +      pC->aRow = (u8*)pReg->z;
         2313  +    }else if( pC->nullRow ){
         2314  +      MemSetTypeFlag(pDest, MEM_Null);
         2315  +      goto op_column_out;
  2378   2316       }else{
  2379   2317         if( pC->isIndex ){
  2380         -        zData = (char*)sqlite3BtreeKeyFetch(pCrsr, &avail);
         2318  +        assert( sqlite3BtreeCursorIsValid(pCrsr) );
         2319  +        VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64);
         2320  +        assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
         2321  +        /* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the
         2322  +        ** payload size, so it is impossible for payloadSize64 to be
         2323  +        ** larger than 32 bits. */
         2324  +        assert( (payloadSize64 & SQLITE_MAX_U32)==(u64)payloadSize64 );
         2325  +        pC->aRow = sqlite3BtreeKeyFetch(pCrsr, &avail);
         2326  +        pC->payloadSize = (u32)payloadSize64;
  2381   2327         }else{
  2382         -        zData = (char*)sqlite3BtreeDataFetch(pCrsr, &avail);
         2328  +        assert( sqlite3BtreeCursorIsValid(pCrsr) );
         2329  +        VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &pC->payloadSize);
         2330  +        assert( rc==SQLITE_OK );   /* DataSize() cannot fail */
         2331  +        pC->aRow = sqlite3BtreeDataFetch(pCrsr, &avail);
  2383   2332         }
  2384         -      /* If KeyFetch()/DataFetch() managed to get the entire payload,
  2385         -      ** save the payload in the pC->aRow cache.  That will save us from
  2386         -      ** having to make additional calls to fetch the content portion of
  2387         -      ** the record.
  2388         -      */
  2389         -      assert( avail>=0 );
  2390         -      if( payloadSize <= (u32)avail ){
  2391         -        zRec = zData;
  2392         -        pC->aRow = (u8*)zData;
         2333  +      assert( avail<=65536 );  /* Maximum page size is 64KiB */
         2334  +      if( pC->payloadSize <= (u32)avail ){
         2335  +        pC->szRow = pC->payloadSize;
  2393   2336         }else{
  2394         -        pC->aRow = 0;
         2337  +        pC->szRow = avail;
         2338  +      }
         2339  +      if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
         2340  +        goto too_big;
  2395   2341         }
  2396   2342       }
  2397         -    /* The following assert is true in all cases except when
  2398         -    ** the database file has been corrupted externally.
  2399         -    **    assert( zRec!=0 || avail>=payloadSize || avail>=9 ); */
  2400         -    szHdr = getVarint32((u8*)zData, offset);
         2343  +      
         2344  +    pC->cacheStatus = p->cacheCtr;
         2345  +    pC->iHdrOffset = getVarint32(pC->aRow, offset);
         2346  +    pC->nHdrParsed = 0;
         2347  +    aOffset[0] = offset;
         2348  +    if( avail<offset ){
         2349  +      pC->aRow = 0;
         2350  +      pC->szRow = 0;
         2351  +    }
  2401   2352   
  2402   2353       /* Make sure a corrupt database has not given us an oversize header.
  2403   2354       ** Do this now to avoid an oversize memory allocation.
  2404   2355       **
  2405   2356       ** Type entries can be between 1 and 5 bytes each.  But 4 and 5 byte
  2406   2357       ** types use so much data space that there can only be 4096 and 32 of
  2407   2358       ** them, respectively.  So the maximum header length results from a
  2408   2359       ** 3-byte type for each of the maximum of 32768 columns plus three
  2409   2360       ** extra bytes for the header length itself.  32768*3 + 3 = 98307.
  2410   2361       */
  2411         -    if( offset > 98307 ){
         2362  +    if( offset > 98307 || offset > pC->payloadSize ){
  2412   2363         rc = SQLITE_CORRUPT_BKPT;
  2413   2364         goto op_column_out;
  2414   2365       }
         2366  +  }
  2415   2367   
  2416         -    /* Compute in len the number of bytes of data we need to read in order
  2417         -    ** to get nField type values.  offset is an upper bound on this.  But
  2418         -    ** nField might be significantly less than the true number of columns
  2419         -    ** in the table, and in that case, 5*nField+3 might be smaller than offset.
  2420         -    ** We want to minimize len in order to limit the size of the memory
  2421         -    ** allocation, especially if a corrupt database file has caused offset
  2422         -    ** to be oversized. Offset is limited to 98307 above.  But 98307 might
  2423         -    ** still exceed Robson memory allocation limits on some configurations.
  2424         -    ** On systems that cannot tolerate large memory allocations, nField*5+3
  2425         -    ** will likely be much smaller since nField will likely be less than
  2426         -    ** 20 or so.  This insures that Robson memory allocation limits are
  2427         -    ** not exceeded even for corrupt database files.
  2428         -    */
  2429         -    len = nField*5 + 3;
  2430         -    if( len > (int)offset ) len = (int)offset;
  2431         -
  2432         -    /* The KeyFetch() or DataFetch() above are fast and will get the entire
  2433         -    ** record header in most cases.  But they will fail to get the complete
  2434         -    ** record header if the record header does not fit on a single page
  2435         -    ** in the B-Tree.  When that happens, use sqlite3VdbeMemFromBtree() to
  2436         -    ** acquire the complete header text.
  2437         -    */
  2438         -    if( !zRec && avail<len ){
  2439         -      sMem.flags = 0;
  2440         -      sMem.db = 0;
  2441         -      rc = sqlite3VdbeMemFromBtree(pCrsr, 0, len, pC->isIndex, &sMem);
         2368  +  /* Make sure at least the first p2+1 entries of the header have been
         2369  +  ** parsed and valid information is in aOffset[] and aType[].
         2370  +  */
         2371  +  if( pC->nHdrParsed<=p2 && pC->iHdrOffset<aOffset[0] ){
         2372  +    /* Make sure zData points to enough of the record to cover the header. */
         2373  +    if( pC->aRow==0 ){
         2374  +      memset(&sMem, 0, sizeof(sMem));
         2375  +      rc = sqlite3VdbeMemFromBtree(pCrsr, 0, pC->aOffset[0], pC->isIndex,&sMem);
  2442   2376         if( rc!=SQLITE_OK ){
  2443   2377           goto op_column_out;
  2444   2378         }
  2445         -      zData = sMem.z;
         2379  +      zData = (u8*)sMem.z;
         2380  +    }else{
         2381  +      zData = pC->aRow;
  2446   2382       }
  2447         -    zEndHdr = (u8 *)&zData[len];
  2448         -    zIdx = (u8 *)&zData[szHdr];
  2449   2383   
  2450         -    /* Scan the header and use it to fill in the aType[] and aOffset[]
  2451         -    ** arrays.  aType[i] will contain the type integer for the i-th
  2452         -    ** column and aOffset[i] will contain the offset from the beginning
  2453         -    ** of the record to the start of the data for the i-th column
  2454         -    */
  2455         -    for(i=0; i<nField; i++){
  2456         -      if( zIdx<zEndHdr ){
  2457         -        aOffset[i] = offset;
  2458         -        if( zIdx[0]<0x80 ){
  2459         -          t = zIdx[0];
  2460         -          zIdx++;
  2461         -        }else{
  2462         -          zIdx += sqlite3GetVarint32(zIdx, &t);
  2463         -        }
  2464         -        aType[i] = t;
  2465         -        szField = sqlite3VdbeSerialTypeLen(t);
  2466         -        offset += szField;
  2467         -        if( offset<szField ){  /* True if offset overflows */
  2468         -          zIdx = &zEndHdr[1];  /* Forces SQLITE_CORRUPT return below */
  2469         -          break;
  2470         -        }
         2384  +    /* Fill in aType[i] and aOffset[i] values through the p2-th field. */
         2385  +    i = pC->nHdrParsed;
         2386  +    offset = aOffset[i];
         2387  +    zHdr = zData + pC->iHdrOffset;
         2388  +    zEndHdr = zData + pC->aOffset[0];
         2389  +    for(; i<=p2 && zHdr<zEndHdr; i++){
         2390  +      if( zHdr[0]<0x80 ){
         2391  +        t = zHdr[0];
         2392  +        zHdr++;
  2471   2393         }else{
  2472         -        /* If i is less that nField, then there are fewer fields in this
  2473         -        ** record than SetNumColumns indicated there are columns in the
  2474         -        ** table. Set the offset for any extra columns not present in
  2475         -        ** the record to 0. This tells code below to store the default value
  2476         -        ** for the column instead of deserializing a value from the record.
  2477         -        */
  2478         -        aOffset[i] = 0;
         2394  +        zHdr += sqlite3GetVarint32(zHdr, &t);
  2479   2395         }
         2396  +      aType[i] = t;
         2397  +      szField = sqlite3VdbeSerialTypeLen(t);
         2398  +      offset += szField;
         2399  +      if( offset<szField ){  /* True if offset overflows */
         2400  +        zHdr = &zEndHdr[1];  /* Forces SQLITE_CORRUPT return below */
         2401  +        break;
         2402  +      }
         2403  +      aOffset[i+1] = offset;
  2480   2404       }
  2481         -    sqlite3VdbeMemRelease(&sMem);
  2482         -    sMem.flags = MEM_Null;
         2405  +    pC->nHdrParsed = i;
         2406  +    pC->iHdrOffset = (u32)(zHdr - zData);
         2407  +    if( pC->aRow==0 ){
         2408  +      sqlite3VdbeMemRelease(&sMem);
         2409  +      sMem.flags = MEM_Null;
         2410  +    }
  2483   2411   
  2484   2412       /* If we have read more header data than was contained in the header,
  2485   2413       ** or if the end of the last field appears to be past the end of the
  2486   2414       ** record, or if the end of the last field appears to be before the end
  2487   2415       ** of the record (when all fields present), then we must be dealing 
  2488   2416       ** with a corrupt database.
  2489   2417       */
  2490         -    if( (zIdx > zEndHdr) || (offset > payloadSize)
  2491         -         || (zIdx==zEndHdr && offset!=payloadSize) ){
         2418  +    if( (zHdr > zEndHdr)
         2419  +     || (offset > pC->payloadSize)
         2420  +     || (zHdr==zEndHdr && offset!=pC->payloadSize)
         2421  +    ){
  2492   2422         rc = SQLITE_CORRUPT_BKPT;
  2493   2423         goto op_column_out;
  2494   2424       }
  2495   2425     }
  2496   2426   
  2497   2427     /* Get the column information. If aOffset[p2] is non-zero, then 
  2498   2428     ** deserialize the value from the record. If aOffset[p2] is zero,
  2499   2429     ** then there are not enough fields in the record to satisfy the
  2500   2430     ** request.  In this case, set the value NULL or to P4 if P4 is
  2501   2431     ** a pointer to a Mem object.
  2502   2432     */
  2503         -  if( aOffset[p2] ){
         2433  +  if( p2<pC->nHdrParsed ){
  2504   2434       assert( rc==SQLITE_OK );
  2505         -    if( zRec ){
         2435  +    if( pC->szRow>=aOffset[p2+1] ){
  2506   2436         /* This is the common case where the whole row fits on a single page */
  2507   2437         VdbeMemRelease(pDest);
  2508         -      sqlite3VdbeSerialGet((u8 *)&zRec[aOffset[p2]], aType[p2], pDest);
         2438  +      sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
  2509   2439       }else{
  2510   2440         /* This branch happens only when the row overflows onto multiple pages */
  2511   2441         t = aType[p2];
  2512   2442         if( (pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
  2513   2443          && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)
  2514   2444         ){
  2515   2445           /* Content is irrelevant for the typeof() function and for
  2516   2446           ** the length(X) function if X is a blob.  So we might as well use
  2517   2447           ** bogus content rather than reading content from disk.  NULL works
  2518   2448           ** for text and blob and whatever is in the payloadSize64 variable
  2519   2449           ** will work for everything else. */
  2520         -        zData = t<12 ? (char*)&payloadSize64 : 0;
         2450  +        zData = t<12 ? (u8*)&payloadSize64 : 0;
  2521   2451         }else{
  2522   2452           len = sqlite3VdbeSerialTypeLen(t);
         2453  +        memset(&sMem, 0, sizeof(sMem));
  2523   2454           sqlite3VdbeMemMove(&sMem, pDest);
  2524   2455           rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len,  pC->isIndex,
  2525   2456                                        &sMem);
  2526   2457           if( rc!=SQLITE_OK ){
  2527   2458             goto op_column_out;
  2528   2459           }
  2529         -        zData = sMem.z;
         2460  +        zData = (u8*)sMem.z;
  2530   2461         }
  2531         -      sqlite3VdbeSerialGet((u8*)zData, t, pDest);
         2462  +      sqlite3VdbeSerialGet(zData, t, pDest);
  2532   2463       }
  2533   2464       pDest->enc = encoding;
  2534   2465     }else{
  2535   2466       if( pOp->p4type==P4_MEM ){
  2536   2467         sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static);
  2537   2468       }else{
  2538   2469         MemSetTypeFlag(pDest, MEM_Null);
................................................................................
  3308   3239       assert( pKeyInfo->enc==ENC(db) );
  3309   3240       assert( pKeyInfo->db==db );
  3310   3241       nField = pKeyInfo->nField+pKeyInfo->nXField;
  3311   3242     }else if( pOp->p4type==P4_INT32 ){
  3312   3243       nField = pOp->p4.i;
  3313   3244     }
  3314   3245     assert( pOp->p1>=0 );
         3246  +  assert( nField>=0 );
         3247  +  testcase( nField==0 );  /* Table with INTEGER PRIMARY KEY and nothing else */
  3315   3248     pCur = allocateCursor(p, pOp->p1, nField, iDb, 1);
  3316   3249     if( pCur==0 ) goto no_mem;
  3317   3250     pCur->nullRow = 1;
  3318   3251     pCur->isOrdered = 1;
  3319   3252     rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor);
  3320   3253     pCur->pKeyInfo = pKeyInfo;
  3321   3254     assert( OPFLAG_BULKCSR==BTREE_BULKLOAD );
................................................................................
  3368   3301     static const int vfsFlags = 
  3369   3302         SQLITE_OPEN_READWRITE |
  3370   3303         SQLITE_OPEN_CREATE |
  3371   3304         SQLITE_OPEN_EXCLUSIVE |
  3372   3305         SQLITE_OPEN_DELETEONCLOSE |
  3373   3306         SQLITE_OPEN_TRANSIENT_DB;
  3374   3307     assert( pOp->p1>=0 );
         3308  +  assert( pOp->p2>=0 );
  3375   3309     pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
  3376   3310     if( pCx==0 ) goto no_mem;
  3377   3311     pCx->nullRow = 1;
  3378   3312     rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt, 
  3379   3313                           BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
  3380   3314     if( rc==SQLITE_OK ){
  3381   3315       rc = sqlite3BtreeBeginTrans(pCx->pBt, 1);
................................................................................
  3413   3347   ** This opcode works like OP_OpenEphemeral except that it opens
  3414   3348   ** a transient index that is specifically designed to sort large
  3415   3349   ** tables using an external merge-sort algorithm.
  3416   3350   */
  3417   3351   case OP_SorterOpen: {
  3418   3352     VdbeCursor *pCx;
  3419   3353   
         3354  +  assert( pOp->p1>=0 );
         3355  +  assert( pOp->p2>=0 );
  3420   3356     pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
  3421   3357     if( pCx==0 ) goto no_mem;
  3422   3358     pCx->pKeyInfo = pOp->p4.pKeyInfo;
  3423   3359     assert( pCx->pKeyInfo->db==db );
  3424   3360     assert( pCx->pKeyInfo->enc==ENC(db) );
  3425   3361     pCx->isSorter = 1;
  3426   3362     rc = sqlite3VdbeSorterInit(db, pCx);
................................................................................
  3444   3380   ** P3 is the number of fields in the records that will be stored by
  3445   3381   ** the pseudo-table.
  3446   3382   */
  3447   3383   case OP_OpenPseudo: {
  3448   3384     VdbeCursor *pCx;
  3449   3385   
  3450   3386     assert( pOp->p1>=0 );
         3387  +  assert( pOp->p3>=0 );
  3451   3388     pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0);
  3452   3389     if( pCx==0 ) goto no_mem;
  3453   3390     pCx->nullRow = 1;
  3454   3391     pCx->pseudoTableReg = pOp->p2;
  3455   3392     pCx->isTable = 1;
  3456   3393     pCx->isIndex = 0;
  3457   3394     pCx->multiPseudo = pOp->p5;
................................................................................
  4417   4354     VdbeCursor *pC;
  4418   4355   
  4419   4356     assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  4420   4357     pC = p->apCsr[pOp->p1];
  4421   4358     assert( pC!=0 );
  4422   4359     pC->nullRow = 1;
  4423   4360     pC->rowidIsValid = 0;
         4361  +  pC->cacheStatus = CACHE_STALE;
  4424   4362     assert( pC->pCursor || pC->pVtabCursor );
  4425   4363     if( pC->pCursor ){
  4426   4364       sqlite3BtreeClearCursor(pC->pCursor);
  4427   4365     }
  4428   4366     break;
  4429   4367   }
  4430   4368   

Changes to src/vdbeInt.h.

    89     89     ** CACHE_STALE and so setting cacheStatus=CACHE_STALE guarantees that
    90     90     ** the cache is out of date.
    91     91     **
    92     92     ** aRow might point to (ephemeral) data for the current row, or it might
    93     93     ** be NULL.
    94     94     */
    95     95     u32 cacheStatus;      /* Cache is valid if this matches Vdbe.cacheCtr */
    96         -  int payloadSize;      /* Total number of bytes in the record */
           96  +  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  +  u32 szRow;            /* Byte available in aRow */
          100  +  u32 iHdrOffset;       /* Offset to next unparsed byte of the header */
    97    101     u32 *aType;           /* Type values for all entries in the record */
    98    102     u32 *aOffset;         /* Cached offsets to the start of each columns data */
    99         -  u8 *aRow;             /* Data for the current row, if all on one page */
          103  +  const u8 *aRow;       /* Data for the current row, if all on one page */
   100    104   };
   101    105   typedef struct VdbeCursor VdbeCursor;
   102    106   
   103    107   /*
   104    108   ** When a sub-program is executed (OP_Program), a structure of this type
   105    109   ** is allocated to store the current value of the program counter, as
   106    110   ** well as the current memory cell array and various other frame specific

Changes to src/vdbeaux.c.

  2654   2654       if( res!=0 ) return SQLITE_CORRUPT_BKPT;
  2655   2655       p->rowidIsValid = 1;
  2656   2656   #ifdef SQLITE_TEST
  2657   2657       sqlite3_search_count++;
  2658   2658   #endif
  2659   2659       p->deferredMoveto = 0;
  2660   2660       p->cacheStatus = CACHE_STALE;
  2661         -  }else if( ALWAYS(p->pCursor) ){
         2661  +  }else if( p->pCursor ){
  2662   2662       int hasMoved;
  2663   2663       int rc = sqlite3BtreeCursorHasMoved(p->pCursor, &hasMoved);
  2664   2664       if( rc ) return rc;
  2665   2665       if( hasMoved ){
  2666   2666         p->cacheStatus = CACHE_STALE;
  2667   2667         p->nullRow = 1;
  2668   2668       }