/ Changes On Branch btree-refactor
Login

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

Changes In Branch btree-refactor Excluding Merge-Ins

This is equivalent to a diff from b411107a36 to 5e269c2d26

2016-06-06
01:14
Btree interface refactoring: (1) The sqlite3BtreeKeySize() interface is renamed to sqlite3BtreeIntegerKey() and modified to work only for table btrees with a rowid. (2) The sqlite3BtreeDataSize() interface is renamed to sqlite3BtreePayloadSize() and modified to work with any btree. (3) The sqlite3BtreeDataFetch() and sqlite3BtreeKeyFetch() routines are combined into a single sqlite3BtreePayloadFetch() routine. The result of these changes is a smaller binary and fewer CPU cycles needed to run queries. (check-in: 2d831074cf user: drh tags: trunk)
2016-06-04
21:05
Improved comment on cursorOwnsBtShared(). No changes to code. (Closed-Leaf check-in: 5e269c2d26 user: drh tags: btree-refactor)
20:58
Fix a C99-ism and a compiler warning for MSVC. (check-in: aa53a36ea2 user: drh tags: btree-refactor)
20:37
Change the sqlite3BtreeKeySize() interface into sqlite3BtreeIntegerKey() and make it only work for table btrees. Change sqlite3BtreeDataSize() into sqlite3BtreePayloadSize() and make it work for all btrees. Combine sqlite3BtreeDataFetch() and sqlite3BtreeKeyFetch() into a single sqlite3BtreePayloadFetch() routine. These changes seem to make the b-tree interface more rational and they reduce both binary size and CPU usage. (check-in: bef35e18dd user: drh tags: btree-refactor)
17:12
Allocate KeyInfo objects from lookaside if possible. (check-in: b411107a36 user: drh tags: trunk)
16:33
Fix up speedtest1.c so that it will compile and run on SQLite versions prior to 3.6.18 (circa 2009-09-11). (check-in: 9583c0fb39 user: drh tags: trunk)

Changes to src/btree.c.

446
447
448
449
450
451
452









453
454
455
456
457
458
459
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468







+
+
+
+
+
+
+
+
+







**
** Verify that the cursor holds the mutex on its BtShared
*/
#ifdef SQLITE_DEBUG
static int cursorHoldsMutex(BtCursor *p){
  return sqlite3_mutex_held(p->pBt->mutex);
}

/* Verify that the cursor and the BtShared agree about what is the current
** database connetion. This is important in shared-cache mode. If the database 
** connection pointers get out-of-sync, it is possible for routines like
** btreeInitPage() to reference an stale connection pointer that references a
** a connection that has already closed.  This routine is used inside assert()
** statements only and for the purpose of double-checking that the btree code
** does keep the database connection pointers up-to-date.
*/
static int cursorOwnsBtShared(BtCursor *p){
  assert( cursorHoldsMutex(p) );
  return (p->pBtree->db==p->pBt->db);
}
#endif

/*
605
606
607
608
609
610
611
612

613
614
615
616


617

618
619

620
621

622
623
624
625
626



627
628
629
630
631
632
633
614
615
616
617
618
619
620

621
622
623
624
625
626
627

628


629


630





631
632
633
634
635
636
637
638
639
640







-
+




+
+
-
+
-
-
+
-
-
+
-
-
-
-
-
+
+
+







** If the cursor is open on an intkey table, then the integer key
** (the rowid) is stored in pCur->nKey and pCur->pKey is left set to
** NULL. If the cursor is open on a non-intkey table, then pCur->pKey is 
** set to point to a malloced buffer pCur->nKey bytes in size containing 
** the key.
*/
static int saveCursorKey(BtCursor *pCur){
  int rc;
  int rc = SQLITE_OK;
  assert( CURSOR_VALID==pCur->eState );
  assert( 0==pCur->pKey );
  assert( cursorHoldsMutex(pCur) );

  if( pCur->curIntKey ){
    /* Only the rowid is required for a table btree */
  rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
    pCur->nKey = sqlite3BtreeIntegerKey(pCur);
  assert( rc==SQLITE_OK );  /* KeySize() cannot fail */

  }else{
  /* If this is an intKey table, then the above call to BtreeKeySize()
  ** stores the integer key in pCur->nKey. In this case this value is
    /* For an index btree, save the complete key content */
  ** all that is required. Otherwise, if pCur is not open on an intKey
  ** table, then malloc space for and store the pCur->nKey bytes of key 
  ** data.  */
  if( 0==pCur->curIntKey ){
    void *pKey = sqlite3Malloc( pCur->nKey );
    void *pKey;
    pCur->nKey = sqlite3BtreePayloadSize(pCur);
    pKey = sqlite3Malloc( pCur->nKey );
    if( pKey ){
      rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey);
      if( rc==SQLITE_OK ){
        pCur->pKey = pKey;
      }else{
        sqlite3_free(pKey);
      }
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267




4268
4269
4270
4271
4272
4273
4274
4275
4276

4277
4278

4279
4280

4281
4282
4283
4284
4285
4286



4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297


4298
4299
4300
4301
4302
4303

4304
4305
4306
4307
4308
4309
4310
4311
4265
4266
4267
4268
4269
4270
4271



4272
4273
4274
4275







4276

4277
4278
4279
4280
4281

4282

4283
4284
4285


4286
4287
4288
4289
4290
4291
4292




4293


4294
4295
4296



4297

4298

4299
4300
4301
4302
4303
4304
4305







-
-
-
+
+
+
+
-
-
-
-
-
-
-

-
+


+

-
+
-



-
-
+
+
+




-
-
-
-

-
-
+
+

-
-
-

-
+
-







*/
int sqlite3BtreeCursorIsValid(BtCursor *pCur){
  return pCur && pCur->eState==CURSOR_VALID;
}
#endif /* NDEBUG */

/*
** Set *pSize to the size of the buffer needed to hold the value of
** the key for the current entry.  If the cursor is not pointing
** to a valid entry, *pSize is set to 0. 
** Return the value of the integer key or "rowid" for a table btree.
** This routine is only valid for a cursor that is pointing into a
** ordinary table btree.  If the cursor points to an index btree or
** is invalid, the result of this routine is undefined.
**
** For a table with the INTKEY flag set, this routine returns the key
** itself, not the number of bytes in the key.
**
** The caller must position the cursor prior to invoking this routine.
** 
** This routine cannot fail.  It always returns SQLITE_OK.  
*/
int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
i64 sqlite3BtreeIntegerKey(BtCursor *pCur){
  assert( cursorHoldsMutex(pCur) );
  assert( pCur->eState==CURSOR_VALID );
  assert( pCur->curIntKey );
  getCellInfo(pCur);
  *pSize = pCur->info.nKey;
  return pCur->info.nKey;
  return SQLITE_OK;
}

/*
** Set *pSize to the number of bytes of data in the entry the
** cursor currently points to.
** Return the number of bytes of payload for the entry that pCur is
** currently pointing to.  For table btrees, this will be the amount
** of data.  For index btrees, this will be the size of the key.
**
** The caller must guarantee that the cursor is pointing to a non-NULL
** valid entry.  In other words, the calling procedure must guarantee
** that the cursor has Cursor.eState==CURSOR_VALID.
**
** Failure is not possible.  This function always returns SQLITE_OK.
** It might just as well be a procedure (returning void) but we continue
** to return an integer result code for historical reasons.
*/
int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
  assert( cursorOwnsBtShared(pCur) );
u32 sqlite3BtreePayloadSize(BtCursor *pCur){
  assert( cursorHoldsMutex(pCur) );
  assert( pCur->eState==CURSOR_VALID );
  assert( pCur->iPage>=0 );
  assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
  assert( pCur->apPage[pCur->iPage]->intKeyLeaf==1 );
  getCellInfo(pCur);
  *pSize = pCur->info.nPayload;
  return pCur->info.nPayload;
  return SQLITE_OK;
}

/*
** Given the page number of an overflow page in the database (parameter
** ovfl), this function finds the page number of the next page in the 
** linked list of overflow pages. If possible, it uses the auto-vacuum
** pointer-map data instead of reading the content of page ovfl to do so. 
4739
4740
4741
4742
4743
4744
4745
4746

4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4733
4734
4735
4736
4737
4738
4739

4740



4741
4742
4743
4744
4745
4746
4747







-
+
-
-
-







** including calls from other threads against the same cache.
** Hence, a mutex on the BtShared should be held prior to calling
** this routine.
**
** These routines is used to get quick access to key and data
** in the common case where no overflow pages are used.
*/
const void *sqlite3BtreeKeyFetch(BtCursor *pCur, u32 *pAmt){
const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){
  return fetchPayload(pCur, pAmt);
}
const void *sqlite3BtreeDataFetch(BtCursor *pCur, u32 *pAmt){
  return fetchPayload(pCur, pAmt);
}


/*
** Move the cursor down to a new child page.  The newPgno argument is the
** page number of the child page to move to.

Changes to src/btree.h.

280
281
282
283
284
285
286
287

288
289

290
291

292
293
294
295
296
297
298
280
281
282
283
284
285
286

287
288

289


290
291
292
293
294
295
296
297







-
+

-
+
-
-
+







int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload,
                       int bias, int seekResult);
int sqlite3BtreeFirst(BtCursor*, int *pRes);
int sqlite3BtreeLast(BtCursor*, int *pRes);
int sqlite3BtreeNext(BtCursor*, int *pRes);
int sqlite3BtreeEof(BtCursor*);
int sqlite3BtreePrevious(BtCursor*, int *pRes);
int sqlite3BtreeKeySize(BtCursor*, i64 *pSize);
i64 sqlite3BtreeIntegerKey(BtCursor*);
int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
const void *sqlite3BtreeKeyFetch(BtCursor*, u32 *pAmt);
const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
const void *sqlite3BtreeDataFetch(BtCursor*, u32 *pAmt);
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
u32 sqlite3BtreePayloadSize(BtCursor*);
int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);

char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
struct Pager *sqlite3BtreePager(Btree*);

int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
void sqlite3BtreeIncrblobCursor(BtCursor *);

Changes to src/test3.c.

381
382
383
384
385
386
387
388

389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406

407
408
409

410
411
412
413
414
415
416
381
382
383
384
385
386
387

388

389
390
391
392
393
394
395
396
397








398

399

400
401
402
403
404
405
406
407







-
+
-









-
-
-
-
-
-
-
-
+
-

-
+







static int btree_payload_size(
  void *NotUsed,
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int argc,              /* Number of arguments */
  const char **argv      /* Text of each argument */
){
  BtCursor *pCur;
  int n2;
  u32 n;
  u64 n1;
  char zBuf[50];

  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       " ID\"", 0);
    return TCL_ERROR;
  }
  pCur = sqlite3TestTextToPtr(argv[1]);
  sqlite3BtreeEnter(pCur->pBtree);

  /* The cursor may be in "require-seek" state. If this is the case, the
  ** call to BtreeDataSize() will fix it. */
  sqlite3BtreeDataSize(pCur, (u32*)&n2);
  if( pCur->apPage[pCur->iPage]->intKey ){
    n1 = 0;
  }else{
    sqlite3BtreeKeySize(pCur, (i64*)&n1);
  n = sqlite3BtreePayloadSize(pCur);
  }
  sqlite3BtreeLeave(pCur->pBtree);
  sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2));
  sqlite3_snprintf(sizeof(zBuf),zBuf, "%u", n);
  Tcl_AppendResult(interp, zBuf, 0);
  return SQLITE_OK;
}

/*
** usage:   varint_test  START  MULTIPLIER  COUNT  INCREMENT
**

Changes to src/vdbe.c.

2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2376
2377
2378
2379
2380
2381
2382

2383
2384
2385
2386
2387
2388
2389







-







**
** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 when
** the result is guaranteed to only be used as the argument of a length()
** or typeof() function, respectively.  The loading of large blobs can be
** skipped for length() and all content loading can be skipped for typeof().
*/
case OP_Column: {
  i64 payloadSize64; /* Number of bytes in the record */
  int p2;            /* column number to retrieve */
  VdbeCursor *pC;    /* The VDBE cursor */
  BtCursor *pCrsr;   /* The BTree cursor */
  u32 *aOffset;      /* aOffset[i] is offset to start of data for i-th column */
  int len;           /* The length of the serialized data for the column */
  int i;             /* Loop counter */
  Mem *pDest;        /* Where to write the extracted value */
2429
2430
2431
2432
2433
2434
2435
2436
2437

2438
2439
2440
2441
2442
2443
2444
2445

2446
2447
2448
2449
2450

2451
2452
2453
2454
2455
2456
2457
2458
2428
2429
2430
2431
2432
2433
2434


2435








2436





2437

2438
2439
2440
2441
2442
2443
2444







-
-
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
+
-







      }else{
        sqlite3VdbeMemSetNull(pDest);
        goto op_column_out;
      }
    }else{
      assert( pC->eCurType==CURTYPE_BTREE );
      assert( pCrsr );
      if( pC->isTable==0 ){
        assert( sqlite3BtreeCursorIsValid(pCrsr) );
      assert( sqlite3BtreeCursorIsValid(pCrsr) );
        VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64);
        assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
        /* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the
        ** payload size, so it is impossible for payloadSize64 to be
        ** larger than 32 bits. */
        assert( (payloadSize64 & SQLITE_MAX_U32)==(u64)payloadSize64 );
        pC->aRow = sqlite3BtreeKeyFetch(pCrsr, &avail);
        pC->payloadSize = (u32)payloadSize64;
      pC->payloadSize = sqlite3BtreePayloadSize(pCrsr);
      }else{
        assert( sqlite3BtreeCursorIsValid(pCrsr) );
        VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &pC->payloadSize);
        assert( rc==SQLITE_OK );   /* DataSize() cannot fail */
        pC->aRow = sqlite3BtreeDataFetch(pCrsr, &avail);
      pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &avail);
      }
      assert( avail<=65536 );  /* Maximum page size is 64KiB */
      if( pC->payloadSize <= (u32)avail ){
        pC->szRow = pC->payloadSize;
      }else if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
        goto too_big;
      }else{
        pC->szRow = avail;
4197
4198
4199
4200
4201
4202
4203
4204

4205
4206
4207
4208
4209
4210
4211
4212
4183
4184
4185
4186
4187
4188
4189

4190

4191
4192
4193
4194
4195
4196
4197







-
+
-







      if( rc!=SQLITE_OK ){
        goto abort_due_to_error;
      }
      if( res ){
        v = 1;   /* IMP: R-61914-48074 */
      }else{
        assert( sqlite3BtreeCursorIsValid(pC->uc.pCursor) );
        rc = sqlite3BtreeKeySize(pC->uc.pCursor, &v);
        v = sqlite3BtreeIntegerKey(pC->uc.pCursor);
        assert( rc==SQLITE_OK );   /* Cannot fail following BtreeLast() */
        if( v>=MAX_ROWID ){
          pC->useRandomRowid = 1;
        }else{
          v++;   /* IMP: R-29538-34987 */
        }
      }
    }
4455
4456
4457
4458
4459
4460
4461
4462

4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479

4480
4481
4482
4483
4484
4485
4486
4440
4441
4442
4443
4444
4445
4446

4447

4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462

4463
4464
4465
4466
4467
4468
4469
4470







-
+
-















-
+







  assert( pC->deferredMoveto==0 );

#ifdef SQLITE_DEBUG
  if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){
    /* If p5 is zero, the seek operation that positioned the cursor prior to
    ** OP_Delete will have also set the pC->movetoTarget field to the rowid of
    ** the row that is being deleted */
    i64 iKey = 0;
    i64 iKey = sqlite3BtreeIntegerKey(pC->uc.pCursor);
    sqlite3BtreeKeySize(pC->uc.pCursor, &iKey);
    assert( pC->movetoTarget==iKey );
  }
#endif

  /* If the update-hook or pre-update-hook will be invoked, set zDb to
  ** the name of the db to pass as to it. Also set local pTab to a copy
  ** of p4.pTab. Finally, if p5 is true, indicating that this cursor was
  ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set 
  ** VdbeCursor.movetoTarget to the current rowid.  */
  if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
    assert( pC->iDb>=0 );
    assert( pOp->p4.pTab!=0 );
    zDb = db->aDb[pC->iDb].zName;
    pTab = pOp->p4.pTab;
    if( (pOp->p5 & OPFLAG_SAVEPOSITION)!=0 && pC->isTable ){
      sqlite3BtreeKeySize(pC->uc.pCursor, &pC->movetoTarget);
      pC->movetoTarget = sqlite3BtreeIntegerKey(pC->uc.pCursor);
    }
  }else{
    zDb = 0;   /* Not needed.  Silence a compiler warning. */
    pTab = 0;  /* Not needed.  Silence a compiler warning. */
  }

#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4610
4611
4612
4613
4614
4615
4616

4617
4618
4619
4620
4621
4622
4623







-







** of a real table, not a pseudo-table.
*/
case OP_RowKey:
case OP_RowData: {
  VdbeCursor *pC;
  BtCursor *pCrsr;
  u32 n;
  i64 n64;

  pOut = &aMem[pOp->p2];
  memAboutToChange(p, pOut);

  /* Note that RowKey and RowData are really exactly the same instruction */
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667

4668
4669
4670
4671
4672
4673
4674
4675
4676
4677


4678
4679
4680
4681
4682
4683
4684
4685
4641
4642
4643
4644
4645
4646
4647



4648










4649
4650

4651
4652
4653
4654
4655
4656
4657







-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
+
-







  assert( pC->deferredMoveto==0 );
  assert( sqlite3BtreeCursorIsValid(pCrsr) );
#if 0  /* Not required due to the previous to assert() statements */
  rc = sqlite3VdbeCursorMoveto(pC);
  if( rc!=SQLITE_OK ) goto abort_due_to_error;
#endif

  if( pC->isTable==0 ){
    assert( !pC->isTable );
    VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &n64);
  n = sqlite3BtreePayloadSize(pCrsr);
    assert( rc==SQLITE_OK );    /* True because of CursorMoveto() call above */
    if( n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){
      goto too_big;
    }
    n = (u32)n64;
  }else{
    VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &n);
    assert( rc==SQLITE_OK );    /* DataSize() cannot fail */
    if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
      goto too_big;
  if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
    goto too_big;
    }
  }
  testcase( n==0 );
  if( sqlite3VdbeMemClearAndResize(pOut, MAX(n,32)) ){
    goto no_mem;
  }
  pOut->n = n;
  MemSetTypeFlag(pOut, MEM_Blob);
4736
4737
4738
4739
4740
4741
4742
4743

4744
4745
4746
4747
4748
4749
4750
4751
4708
4709
4710
4711
4712
4713
4714

4715

4716
4717
4718
4719
4720
4721
4722







-
+
-







    assert( pC->uc.pCursor!=0 );
    rc = sqlite3VdbeCursorRestore(pC);
    if( rc ) goto abort_due_to_error;
    if( pC->nullRow ){
      pOut->flags = MEM_Null;
      break;
    }
    rc = sqlite3BtreeKeySize(pC->uc.pCursor, &v);
    v = sqlite3BtreeIntegerKey(pC->uc.pCursor);
    assert( rc==SQLITE_OK );  /* Always so because of CursorRestore() above */
  }
  pOut->u.i = v;
  break;
}

/* Opcode: NullRow P1 * * * *
**

Changes to src/vdbeapi.c.

1646
1647
1648
1649
1650
1651
1652
1653

1654
1655
1656
1657
1658
1659
1660
1661
1646
1647
1648
1649
1650
1651
1652

1653

1654
1655
1656
1657
1658
1659
1660







-
+
-







  }

  /* If the old.* record has not yet been loaded into memory, do so now. */
  if( p->pUnpacked==0 ){
    u32 nRec;
    u8 *aRec;

    rc = sqlite3BtreeDataSize(p->pCsr->uc.pCursor, &nRec);
    nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor);
    if( rc!=SQLITE_OK ) goto preupdate_old_out;
    aRec = sqlite3DbMallocRaw(db, nRec);
    if( !aRec ) goto preupdate_old_out;
    rc = sqlite3BtreeData(p->pCsr->uc.pCursor, 0, nRec, aRec);
    if( rc==SQLITE_OK ){
      p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec);
      if( !p->pUnpacked ) rc = SQLITE_NOMEM;
    }

Changes to src/vdbeaux.c.

4311
4312
4313
4314
4315
4316
4317
4318

4319
4320
4321
4322
4323
4324
4325
4326
4311
4312
4313
4314
4315
4316
4317

4318

4319
4320
4321
4322
4323
4324
4325







-
+
-








  /* Get the size of the index entry.  Only indices entries of less
  ** than 2GiB are support - anything large must be database corruption.
  ** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so
  ** this code can safely assume that nCellKey is 32-bits  
  */
  assert( sqlite3BtreeCursorIsValid(pCur) );
  VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey);
  nCellKey = sqlite3BtreePayloadSize(pCur);
  assert( rc==SQLITE_OK );     /* pCur is always valid so KeySize cannot fail */
  assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey );

  /* Read in the complete content of the index entry */
  sqlite3VdbeMemInit(&m, db, 0);
  rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m);
  if( rc ){
    return rc;
4389
4390
4391
4392
4393
4394
4395
4396

4397
4398
4399
4400
4401
4402
4403
4404
4388
4389
4390
4391
4392
4393
4394

4395

4396
4397
4398
4399
4400
4401
4402







-
+
-







  int rc;
  BtCursor *pCur;
  Mem m;

  assert( pC->eCurType==CURTYPE_BTREE );
  pCur = pC->uc.pCursor;
  assert( sqlite3BtreeCursorIsValid(pCur) );
  VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey);
  nCellKey = sqlite3BtreePayloadSize(pCur);
  assert( rc==SQLITE_OK );    /* pCur is always valid so KeySize cannot fail */
  /* nCellKey will always be between 0 and 0xffffffff because of the way
  ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */
  if( nCellKey<=0 || nCellKey>0x7fffffff ){
    *res = 0;
    return SQLITE_CORRUPT_BKPT;
  }
  sqlite3VdbeMemInit(&m, db, 0);

Changes to src/vdbeblob.c.

411
412
413
414
415
416
417
418

419
420
421
422
423
424
425
411
412
413
414
415
416
417

418
419
420
421
422
423
424
425







-
+







      ** SQLITE_UPDATE where the PK columns do not change is handled in the 
      ** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually
      ** slightly more efficient). Since you cannot write to a PK column
      ** using the incremental-blob API, this works. For the sessions module
      ** anyhow.
      */
      sqlite3_int64 iKey;
      sqlite3BtreeKeySize(p->pCsr, &iKey);
      iKey = sqlite3BtreeIntegerKey(p->pCsr);
      sqlite3VdbePreUpdateHook(
          v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1
      );
    }
#endif

    rc = xCall(p->pCsr, iOffset+p->iOffset, n, z);

Changes to src/vdbemem.c.

987
988
989
990
991
992
993
994
995

996
997
998
999
1000
1001
1002
1003
1004
1005
987
988
989
990
991
992
993


994



995
996
997
998
999
1000
1001







-
-
+
-
-
-








  assert( sqlite3BtreeCursorIsValid(pCur) );
  assert( !VdbeMemDynamic(pMem) );

  /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() 
  ** that both the BtShared and database handle mutexes are held. */
  assert( (pMem->flags & MEM_RowSet)==0 );
  if( key ){
    zData = (char *)sqlite3BtreeKeyFetch(pCur, &available);
  zData = (char *)sqlite3BtreePayloadFetch(pCur, &available);
  }else{
    zData = (char *)sqlite3BtreeDataFetch(pCur, &available);
  }
  assert( zData!=0 );

  if( offset+amt<=available ){
    pMem->z = &zData[offset];
    pMem->flags = MEM_Blob|MEM_Ephem;
    pMem->n = (int)amt;
  }else{