/ Check-in [2a8f6c89]
Login

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

Overview
Comment:Add temporary code to record and report on the set of b-tree pages read and written by the current transaction. This is likely still buggy.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | transaction-pages
Files: files | file ages | folders
SHA1: 2a8f6c890cfa5f61b491ddf8f560b6ba8c6cdc32
User & Date: dan 2017-01-18 20:14:50
Context
2017-01-19
11:52
Add test cases for the instrumentation on this branch. Fix some OOM handling issues in the same. Leaf check-in: 50ca94b9 user: dan tags: transaction-pages
2017-01-18
20:14
Add temporary code to record and report on the set of b-tree pages read and written by the current transaction. This is likely still buggy. check-in: 2a8f6c89 user: dan tags: transaction-pages
2017-01-17
10:41
Fix a problem that could cause a spurious SQLITE_NOMEM error when attempting to resume an RBU operation if the previous client failed right after completing the incremental checkpoint. Also a "cannot vacuum wal db" error that could occur when resuming an RBU vacuum if an error (OOM or IO error) occurs during the incremental checkpoint. check-in: 681d96eb user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/bitvec.c.

288
289
290
291
292
293
294

























































295
296
297
298
299
300
301
/*
** Return the value of the iSize parameter specified when Bitvec *p
** was created.
*/
u32 sqlite3BitvecSize(Bitvec *p){
  return p->iSize;
}


























































#ifndef SQLITE_UNTESTABLE
/*
** Let V[] be an array of unsigned characters sufficient to hold
** up to N bits.  Let I be an integer between 0 and N.  0<=I<N.
** Then the following macros can be used to set, clear, or test
** individual bits within V.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
/*
** Return the value of the iSize parameter specified when Bitvec *p
** was created.
*/
u32 sqlite3BitvecSize(Bitvec *p){
  return p->iSize;
}

int bitvecAppendArrayElem(int *pnAlloc, int *pnElem, u32 **paElem, u32 iNew){
  if( *pnElem==*pnAlloc ){
    int nNew = *pnAlloc ? (*pnAlloc)*2 : 128;
    u32 *aNew;
    aNew = sqlite3_realloc(*paElem, nNew*sizeof(u32));
    if( aNew==0 ){
      sqlite3_free(*paElem);
      *paElem = 0;
      return SQLITE_NOMEM;
    }
    *paElem = aNew;
    *pnAlloc = nNew;
  }

  (*paElem)[(*pnElem)++] = iNew;
  return SQLITE_OK;
}

#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
int bitvecToArray(Bitvec *p, int iOff, int *pnAlloc, int *pnElem, u32 **paElem){
  int rc = SQLITE_OK;
  int i;
  if( p->iDivisor ){
    for(i=0; rc==SQLITE_OK && i<BITVEC_NPTR; i++){
      if( p->u.apSub[i] ){
        int iOff2 = iOff + i*p->iDivisor;
        rc = bitvecToArray(p->u.apSub[i], iOff2, pnAlloc, pnElem, paElem);
      }
    }
  }else{
    if( p->iSize<=BITVEC_NBIT ){
      for(i=0; rc==SQLITE_OK && i<BITVEC_NBIT; i++){
        if( p->u.aBitmap[i/BITVEC_SZELEM] & (1<<(i&(BITVEC_SZELEM-1))) ){
          rc = bitvecAppendArrayElem(pnAlloc, pnElem, paElem, i+iOff);
        }
      }
    }else{
      for(i=0; rc==SQLITE_OK && i<BITVEC_NINT; i++){
        u32 iVal = p->u.aHash[i];
        if( iVal ){
          rc = bitvecAppendArrayElem(pnAlloc, pnElem, paElem, iVal-1+iOff);
        }
      }
    }
  }

  return rc;
}

int sqlite3BitvecToArray(Bitvec *p, int *pnElem, u32 **paElem){
  int nAlloc = 0;
  *pnElem = 0;
  *paElem = 0;
  return bitvecToArray(p, 1, &nAlloc, pnElem, paElem);
}
#endif

#ifndef SQLITE_UNTESTABLE
/*
** Let V[] be an array of unsigned characters sufficient to hold
** up to N bits.  Let I be an integer between 0 and N.  0<=I<N.
** Then the following macros can be used to set, clear, or test
** individual bits within V.

Changes to src/btree.c.

2022
2023
2024
2025
2026
2027
2028













2029
2030
2031
2032
2033
2034
2035
....
3262
3263
3264
3265
3266
3267
3268















3269
3270
3271
3272
3273
3274
3275
....
3785
3786
3787
3788
3789
3790
3791













3792
3793
3794
3795
3796
3797
3798
....
4412
4413
4414
4415
4416
4417
4418


















4419
4420
4421
4422
4423
4424
4425
....
4489
4490
4491
4492
4493
4494
4495






4496

4497
4498
4499
4500
4501
4502
4503
....
5825
5826
5827
5828
5829
5830
5831










5832
5833
5834
5835
5836
5837
5838
....
6281
6282
6283
6284
6285
6286
6287

6288
6289
6290
6291
6292
6293
6294
....
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
....
7381
7382
7383
7384
7385
7386
7387
7388
7389
7390
7391
7392
7393
7394
7395
....
7751
7752
7753
7754
7755
7756
7757
7758
7759
7760
7761
7762
7763
7764
7765
....
7833
7834
7835
7836
7837
7838
7839
7840
7841
7842
7843
7844
7845
7846
7847
....
8054
8055
8056
8057
8058
8059
8060
8061
8062
8063
8064
8065
8066
8067
8068
....
8234
8235
8236
8237
8238
8239
8240
8241
8242
8243
8244
8245
8246
8247
8248
....
8257
8258
8259
8260
8261
8262
8263
8264
8265
8266
8267
8268
8269
8270
8271
....
8520
8521
8522
8523
8524
8525
8526
8527
8528
8529
8530
8531
8532
8533
8534
....
9722
9723
9724
9725
9726
9727
9728





























9729
9730
9731
9732
9733
9734
9735
  /* If obtaining a child page for a cursor, we must verify that the page is
  ** compatible with the root page. */
  if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){
    rc = SQLITE_CORRUPT_BKPT;
    releasePage(*ppPage);
    goto getAndInitPage_error;
  }













  return SQLITE_OK;

getAndInitPage_error:
  if( pCur ) pCur->iPage--;
  testcase( pgno==0 );
  assert( pgno!=0 || rc==SQLITE_CORRUPT );
  return rc;
................................................................................
        if( rc==SQLITE_OK ){
          put4byte(&pPage1->aData[28], pBt->nPage);
        }
      }
    }
  }

















trans_begun:
  if( rc==SQLITE_OK && wrflag ){
    /* This call makes sure that the pager has the correct number of
    ** open savepoints. If the second parameter is greater than 0 and
    ** the sub-journal is not already open, then it will be opened here.
    */
................................................................................
    }

    /* Set the current transaction state to TRANS_NONE and unlock the 
    ** pager if this call closed the only read or write transaction.  */
    p->inTrans = TRANS_NONE;
    unlockBtreeIfUnused(pBt);
  }














  btreeIntegrity(p);
}

/*
** Commit the transaction currently in progress.
**
................................................................................
    memcpy(pPayload, pBuf, nByte);
  }else{
    /* Copy data from page to buffer (a read operation) */
    memcpy(pBuf, pPayload, nByte);
  }
  return SQLITE_OK;
}



















/*
** This function is used to read or overwrite payload information
** for the entry that the pCur cursor is pointing to. The eOp
** argument is interpreted as follows:
**
**   0: The operation is a read. Populate the overflow cache.
................................................................................

  /* Check if data must be read/written to/from the btree page itself. */
  if( offset<pCur->info.nLocal ){
    int a = amt;
    if( a+offset>pCur->info.nLocal ){
      a = pCur->info.nLocal - offset;
    }






    rc = copyPayload(&aPayload[offset], pBuf, a, (eOp & 0x01), pPage->pDbPage);

    offset = 0;
    pBuf += a;
    amt -= a;
  }else{
    offset -= pCur->info.nLocal;
  }

................................................................................
      releasePage(*ppPage);
      *ppPage = 0;
    }
    TRACE(("ALLOCATE: %d from end of file\n", *pPgno));
  }

  assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );











end_allocate_page:
  releasePage(pTrunk);
  releasePage(pPrevTrunk);
  assert( rc!=SQLITE_OK || sqlite3PagerPageRefcount((*ppPage)->pDbPage)<=1 );
  assert( rc!=SQLITE_OK || (*ppPage)->isInit==0 );
  return rc;
................................................................................
                       - pPage->childPtrSize - 8;
  }else{
    memmove(ptr, ptr+2, 2*(pPage->nCell - idx));
    put2byte(&data[hdr+3], pPage->nCell);
    pPage->nFree += 2;
  }
}


/*
** Insert a new cell on pPage at cell index "i".  pCell points to the
** content of the cell.
**
** If the cell content will fit on the page, then put it there.  If it
** will not fit, then make a copy of the cell content into pTemp if
................................................................................
    ** sorted order.  This invariants arise because multiple overflows can
    ** only occur when inserting divider cells into the parent page during
    ** balancing, and the dividers are adjacent and sorted.
    */
    assert( j==0 || pPage->aiOvfl[j-1]<(u16)i ); /* Overflows in sorted order */
    assert( j==0 || i==pPage->aiOvfl[j-1]+1 );   /* Overflows are sequential */
  }else{
    int rc = sqlite3PagerWrite(pPage->pDbPage);
    if( rc!=SQLITE_OK ){
      *pRC = rc;
      return;
    }
    assert( sqlite3PagerIswriteable(pPage->pDbPage) );
    data = pPage->aData;
    assert( &data[pPage->cellOffset]==pPage->aCellIdx );
................................................................................
  */
  pageFlags = apOld[0]->aData[0];
  for(i=0; i<k; i++){
    MemPage *pNew;
    if( i<nOld ){
      pNew = apNew[i] = apOld[i];
      apOld[i] = 0;
      rc = sqlite3PagerWrite(pNew->pDbPage);
      nNew++;
      if( rc ) goto balance_cleanup;
    }else{
      assert( i>0 );
      rc = allocateBtreePage(pBt, &pNew, &pgno, (bBulk ? 1 : pgno), 0);
      if( rc ) goto balance_cleanup;
      zeroPage(pNew, pageFlags);
................................................................................
  assert( pRoot->nOverflow>0 );
  assert( sqlite3_mutex_held(pBt->mutex) );

  /* Make pRoot, the root page of the b-tree, writable. Allocate a new 
  ** page that will become the new right-child of pPage. Copy the contents
  ** of the node stored on pRoot into the new child page.
  */
  rc = sqlite3PagerWrite(pRoot->pDbPage);
  if( rc==SQLITE_OK ){
    rc = allocateBtreePage(pBt,&pChild,&pgnoChild,pRoot->pgno,0);
    copyNodeContent(pRoot, pChild, &rc);
    if( ISAUTOVACUUM ){
      ptrmapPut(pBt, pgnoChild, PTRMAP_BTREE, pRoot->pgno, &rc);
    }
  }
................................................................................
      }
    }else if( pPage->nOverflow==0 && pPage->nFree<=nMin ){
      break;
    }else{
      MemPage * const pParent = pCur->apPage[iPage-1];
      int const iIdx = pCur->aiIdx[iPage-1];

      rc = sqlite3PagerWrite(pParent->pDbPage);
      if( rc==SQLITE_OK ){
#ifndef SQLITE_OMIT_QUICKBALANCE
        if( pPage->intKeyLeaf
         && pPage->nOverflow==1
         && pPage->aiOvfl[0]==pPage->nCell
         && pParent->pgno!=1
         && pParent->nCell==iIdx
................................................................................
  if( rc ) goto end_insert;
  assert( szNew==pPage->xCellSize(pPage, newCell) );
  assert( szNew <= MX_CELL_SIZE(pBt) );
  idx = pCur->aiIdx[pCur->iPage];
  if( loc==0 ){
    CellInfo info;
    assert( idx<pPage->nCell );
    rc = sqlite3PagerWrite(pPage->pDbPage);
    if( rc ){
      goto end_insert;
    }
    oldCell = findCell(pPage, idx);
    if( !pPage->leaf ){
      memcpy(newCell, oldCell, 4);
    }
................................................................................
  if( pCur->pKeyInfo==0 ){
    invalidateIncrblobCursors(p, pCur->info.nKey, 0);
  }

  /* Make the page containing the entry to be deleted writable. Then free any
  ** overflow pages associated with the entry and finally remove the cell
  ** itself from within the page.  */
  rc = sqlite3PagerWrite(pPage->pDbPage);
  if( rc ) return rc;
  rc = clearCell(pPage, pCell, &info);
  dropCell(pPage, iCellIdx, info.nSize, &rc);
  if( rc ) return rc;

  /* If the cell deleted was not located on a leaf page, then the cursor
  ** is currently pointing to the largest entry in the sub-tree headed
................................................................................

    pCell = findCell(pLeaf, pLeaf->nCell-1);
    if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT;
    nCell = pLeaf->xCellSize(pLeaf, pCell);
    assert( MX_CELL_SIZE(pBt) >= nCell );
    pTmp = pBt->pTmpSpace;
    assert( pTmp!=0 );
    rc = sqlite3PagerWrite(pLeaf->pDbPage);
    if( rc==SQLITE_OK ){
      insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc);
    }
    dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc);
    if( rc ) return rc;
  }

................................................................................
  }else if( pnChange ){
    assert( pPage->intKey || CORRUPT_DB );
    testcase( !pPage->intKey );
    *pnChange += pPage->nCell;
  }
  if( freePageFlag ){
    freePage(pPage, &rc);
  }else if( (rc = sqlite3PagerWrite(pPage->pDbPage))==0 ){
    zeroPage(pPage, pPage->aData[hdr] | PTF_LEAF);
  }

cleardatabasepage_out:
  pPage->bBusy = 0;
  releasePage(pPage);
  return rc;
................................................................................
}

/*
** Return the size of the header added to each page by this module.
*/
int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }






























#if !defined(SQLITE_OMIT_SHARED_CACHE)
/*
** Return true if the Btree passed as the only argument is sharable.
*/
int sqlite3BtreeSharable(Btree *p){
  return p->sharable;
}







>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
|
>







 







>
>
>
>
>
>
>
>
>
>







 







>







 







|







 







|







 







|







 







|







 







|







 







|







 







|







 







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
....
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
....
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
....
4453
4454
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
....
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
....
5891
5892
5893
5894
5895
5896
5897
5898
5899
5900
5901
5902
5903
5904
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
....
6357
6358
6359
6360
6361
6362
6363
6364
6365
6366
6367
6368
6369
6370
6371
....
6424
6425
6426
6427
6428
6429
6430
6431
6432
6433
6434
6435
6436
6437
6438
....
7458
7459
7460
7461
7462
7463
7464
7465
7466
7467
7468
7469
7470
7471
7472
....
7828
7829
7830
7831
7832
7833
7834
7835
7836
7837
7838
7839
7840
7841
7842
....
7910
7911
7912
7913
7914
7915
7916
7917
7918
7919
7920
7921
7922
7923
7924
....
8131
8132
8133
8134
8135
8136
8137
8138
8139
8140
8141
8142
8143
8144
8145
....
8311
8312
8313
8314
8315
8316
8317
8318
8319
8320
8321
8322
8323
8324
8325
....
8334
8335
8336
8337
8338
8339
8340
8341
8342
8343
8344
8345
8346
8347
8348
....
8597
8598
8599
8600
8601
8602
8603
8604
8605
8606
8607
8608
8609
8610
8611
....
9799
9800
9801
9802
9803
9804
9805
9806
9807
9808
9809
9810
9811
9812
9813
9814
9815
9816
9817
9818
9819
9820
9821
9822
9823
9824
9825
9826
9827
9828
9829
9830
9831
9832
9833
9834
9835
9836
9837
9838
9839
9840
9841
  /* If obtaining a child page for a cursor, we must verify that the page is
  ** compatible with the root page. */
  if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){
    rc = SQLITE_CORRUPT_BKPT;
    releasePage(*ppPage);
    goto getAndInitPage_error;
  }

#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
  if( pBt->inTransaction==TRANS_WRITE 
   && pgno<=sqlite3BitvecSize(pBt->pBtRead) 
  ){
    rc = sqlite3BitvecSet(pBt->pBtRead, pgno);
    if( rc!=SQLITE_OK ){
      releasePage(*ppPage);
      goto getAndInitPage_error;
    }
  }
#endif

  return SQLITE_OK;

getAndInitPage_error:
  if( pCur ) pCur->iPage--;
  testcase( pgno==0 );
  assert( pgno!=0 || rc==SQLITE_CORRUPT );
  return rc;
................................................................................
        if( rc==SQLITE_OK ){
          put4byte(&pPage1->aData[28], pBt->nPage);
        }
      }
    }
  }

#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
  if( rc==SQLITE_OK && wrflag ){
    assert( pBt->pBtRead==0 && pBt->pBtWrite==0 );
    pBt->pBtRead = sqlite3BitvecCreate(pBt->nPage);
    pBt->pBtWrite = sqlite3BitvecCreate(pBt->nPage);
    pBt->pBtAlloc = sqlite3BitvecCreate(pBt->nPage);
    if( pBt->pBtRead==0 || pBt->pBtWrite==0 || pBt->pBtAlloc==0 ){
      rc = SQLITE_NOMEM;
      sqlite3BitvecDestroy(pBt->pBtRead);
      sqlite3BitvecDestroy(pBt->pBtWrite);
      sqlite3BitvecDestroy(pBt->pBtAlloc);
      pBt->pBtAlloc = pBt->pBtRead = pBt->pBtWrite = 0;
    }
  }
#endif

trans_begun:
  if( rc==SQLITE_OK && wrflag ){
    /* This call makes sure that the pager has the correct number of
    ** open savepoints. If the second parameter is greater than 0 and
    ** the sub-journal is not already open, then it will be opened here.
    */
................................................................................
    }

    /* Set the current transaction state to TRANS_NONE and unlock the 
    ** pager if this call closed the only read or write transaction.  */
    p->inTrans = TRANS_NONE;
    unlockBtreeIfUnused(pBt);
  }

#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
  if( pBt->inTransaction!=TRANS_WRITE ){
    sqlite3BitvecDestroy(pBt->pBtRead);
    sqlite3BitvecDestroy(pBt->pBtWrite);
    sqlite3BitvecDestroy(pBt->pBtAlloc);
    pBt->pBtAlloc = pBt->pBtRead = pBt->pBtWrite = 0;
    sqlite3_free(pBt->aiRead);
    sqlite3_free(pBt->aiWrite);
    pBt->aiRead = pBt->aiWrite = 0;
    pBt->nRead = pBt->nWrite = 0;
  }
#endif

  btreeIntegrity(p);
}

/*
** Commit the transaction currently in progress.
**
................................................................................
    memcpy(pPayload, pBuf, nByte);
  }else{
    /* Copy data from page to buffer (a read operation) */
    memcpy(pBuf, pPayload, nByte);
  }
  return SQLITE_OK;
}

/*
** Call PagerWrite() on pager page pDbPage. And, if the page is currently
** in the pBtRead bit vector, add it to pBtWrite as well.
*/
static int pagerWrite(BtShared *pBt, DbPage *pDbPage){
  Pgno pgno = sqlite3PagerPagenumber(pDbPage);
  int rc = SQLITE_OK;
#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
  if( sqlite3BitvecTestNotNull(pBt->pBtRead, pgno) ){
    rc = sqlite3BitvecSet(pBt->pBtWrite, pgno);
  }
#endif
  if( rc==SQLITE_OK ){
    rc = sqlite3PagerWrite(pDbPage);
  }
  return rc;
}

/*
** This function is used to read or overwrite payload information
** for the entry that the pCur cursor is pointing to. The eOp
** argument is interpreted as follows:
**
**   0: The operation is a read. Populate the overflow cache.
................................................................................

  /* Check if data must be read/written to/from the btree page itself. */
  if( offset<pCur->info.nLocal ){
    int a = amt;
    if( a+offset>pCur->info.nLocal ){
      a = pCur->info.nLocal - offset;
    }
#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
    if( eOp & 0x01 ){
      rc = pagerWrite(pBt, pPage->pDbPage);
    }
#endif
    if( rc==SQLITE_OK ){
      rc = copyPayload(&aPayload[offset], pBuf, a, (eOp&0x01), pPage->pDbPage);
    }
    offset = 0;
    pBuf += a;
    amt -= a;
  }else{
    offset -= pCur->info.nLocal;
  }

................................................................................
      releasePage(*ppPage);
      *ppPage = 0;
    }
    TRACE(("ALLOCATE: %d from end of file\n", *pPgno));
  }

  assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );

#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
  if( rc==SQLITE_OK && *pPgno<sqlite3BitvecSize(pBt->pBtAlloc) ){
    rc = sqlite3BitvecSet(pBt->pBtAlloc, *pPgno);
    if( rc!=SQLITE_OK ){
      releasePage(*ppPage);
      *ppPage = 0;
    }
  }
#endif

end_allocate_page:
  releasePage(pTrunk);
  releasePage(pPrevTrunk);
  assert( rc!=SQLITE_OK || sqlite3PagerPageRefcount((*ppPage)->pDbPage)<=1 );
  assert( rc!=SQLITE_OK || (*ppPage)->isInit==0 );
  return rc;
................................................................................
                       - pPage->childPtrSize - 8;
  }else{
    memmove(ptr, ptr+2, 2*(pPage->nCell - idx));
    put2byte(&data[hdr+3], pPage->nCell);
    pPage->nFree += 2;
  }
}


/*
** Insert a new cell on pPage at cell index "i".  pCell points to the
** content of the cell.
**
** If the cell content will fit on the page, then put it there.  If it
** will not fit, then make a copy of the cell content into pTemp if
................................................................................
    ** sorted order.  This invariants arise because multiple overflows can
    ** only occur when inserting divider cells into the parent page during
    ** balancing, and the dividers are adjacent and sorted.
    */
    assert( j==0 || pPage->aiOvfl[j-1]<(u16)i ); /* Overflows in sorted order */
    assert( j==0 || i==pPage->aiOvfl[j-1]+1 );   /* Overflows are sequential */
  }else{
    int rc = pagerWrite(pPage->pBt, pPage->pDbPage);
    if( rc!=SQLITE_OK ){
      *pRC = rc;
      return;
    }
    assert( sqlite3PagerIswriteable(pPage->pDbPage) );
    data = pPage->aData;
    assert( &data[pPage->cellOffset]==pPage->aCellIdx );
................................................................................
  */
  pageFlags = apOld[0]->aData[0];
  for(i=0; i<k; i++){
    MemPage *pNew;
    if( i<nOld ){
      pNew = apNew[i] = apOld[i];
      apOld[i] = 0;
      rc = pagerWrite(pBt, pNew->pDbPage);
      nNew++;
      if( rc ) goto balance_cleanup;
    }else{
      assert( i>0 );
      rc = allocateBtreePage(pBt, &pNew, &pgno, (bBulk ? 1 : pgno), 0);
      if( rc ) goto balance_cleanup;
      zeroPage(pNew, pageFlags);
................................................................................
  assert( pRoot->nOverflow>0 );
  assert( sqlite3_mutex_held(pBt->mutex) );

  /* Make pRoot, the root page of the b-tree, writable. Allocate a new 
  ** page that will become the new right-child of pPage. Copy the contents
  ** of the node stored on pRoot into the new child page.
  */
  rc = pagerWrite(pBt, pRoot->pDbPage);
  if( rc==SQLITE_OK ){
    rc = allocateBtreePage(pBt,&pChild,&pgnoChild,pRoot->pgno,0);
    copyNodeContent(pRoot, pChild, &rc);
    if( ISAUTOVACUUM ){
      ptrmapPut(pBt, pgnoChild, PTRMAP_BTREE, pRoot->pgno, &rc);
    }
  }
................................................................................
      }
    }else if( pPage->nOverflow==0 && pPage->nFree<=nMin ){
      break;
    }else{
      MemPage * const pParent = pCur->apPage[iPage-1];
      int const iIdx = pCur->aiIdx[iPage-1];

      rc = pagerWrite(pParent->pBt, pParent->pDbPage);
      if( rc==SQLITE_OK ){
#ifndef SQLITE_OMIT_QUICKBALANCE
        if( pPage->intKeyLeaf
         && pPage->nOverflow==1
         && pPage->aiOvfl[0]==pPage->nCell
         && pParent->pgno!=1
         && pParent->nCell==iIdx
................................................................................
  if( rc ) goto end_insert;
  assert( szNew==pPage->xCellSize(pPage, newCell) );
  assert( szNew <= MX_CELL_SIZE(pBt) );
  idx = pCur->aiIdx[pCur->iPage];
  if( loc==0 ){
    CellInfo info;
    assert( idx<pPage->nCell );
    rc = pagerWrite(pBt, pPage->pDbPage);
    if( rc ){
      goto end_insert;
    }
    oldCell = findCell(pPage, idx);
    if( !pPage->leaf ){
      memcpy(newCell, oldCell, 4);
    }
................................................................................
  if( pCur->pKeyInfo==0 ){
    invalidateIncrblobCursors(p, pCur->info.nKey, 0);
  }

  /* Make the page containing the entry to be deleted writable. Then free any
  ** overflow pages associated with the entry and finally remove the cell
  ** itself from within the page.  */
  rc = pagerWrite(pBt, pPage->pDbPage);
  if( rc ) return rc;
  rc = clearCell(pPage, pCell, &info);
  dropCell(pPage, iCellIdx, info.nSize, &rc);
  if( rc ) return rc;

  /* If the cell deleted was not located on a leaf page, then the cursor
  ** is currently pointing to the largest entry in the sub-tree headed
................................................................................

    pCell = findCell(pLeaf, pLeaf->nCell-1);
    if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT;
    nCell = pLeaf->xCellSize(pLeaf, pCell);
    assert( MX_CELL_SIZE(pBt) >= nCell );
    pTmp = pBt->pTmpSpace;
    assert( pTmp!=0 );
    rc = pagerWrite(pBt, pLeaf->pDbPage);
    if( rc==SQLITE_OK ){
      insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc);
    }
    dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc);
    if( rc ) return rc;
  }

................................................................................
  }else if( pnChange ){
    assert( pPage->intKey || CORRUPT_DB );
    testcase( !pPage->intKey );
    *pnChange += pPage->nCell;
  }
  if( freePageFlag ){
    freePage(pPage, &rc);
  }else if( (rc = pagerWrite(pBt, pPage->pDbPage))==0 ){
    zeroPage(pPage, pPage->aData[hdr] | PTF_LEAF);
  }

cleardatabasepage_out:
  pPage->bBusy = 0;
  releasePage(pPage);
  return rc;
................................................................................
}

/*
** Return the size of the header added to each page by this module.
*/
int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }

#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
int sqlite3BtreeTransactionPages(
  Btree *pBtree,                  /* Btree handle */
  int *pnRead, u32 **paiRead,     /* OUT: Pages read */
  int *pnWrite, u32 **paiWrite    /* OUT: Pages written */
){
  int rc = SQLITE_OK;
  BtShared *pBt = pBtree->pBt;
  sqlite3BtreeEnter(pBtree);
  sqlite3_free(pBt->aiRead);
  sqlite3_free(pBt->aiWrite);
  pBt->nRead = pBt->nWrite = 0;
  pBt->aiRead = pBt->aiWrite = 0;
  if( pBtree->inTrans==TRANS_WRITE ){
    assert( pBt->inTransaction==TRANS_WRITE );
    rc = sqlite3BitvecToArray(pBt->pBtRead, &pBt->nRead, &pBt->aiRead);
    if( rc==SQLITE_OK ){
      rc = sqlite3BitvecToArray(pBt->pBtWrite, &pBt->nWrite, &pBt->aiWrite);
    }
  }
  *pnRead = pBt->nRead;
  *paiRead = pBt->aiRead;
  *pnWrite = pBt->nWrite;
  *paiWrite = pBt->aiWrite;
  sqlite3BtreeLeave(pBtree);
  return rc;
}
#endif  /* SQLITE_ENABLE_TRANSACTION_PAGES */

#if !defined(SQLITE_OMIT_SHARED_CACHE)
/*
** Return true if the Btree passed as the only argument is sharable.
*/
int sqlite3BtreeSharable(Btree *p){
  return p->sharable;
}

Changes to src/btree.h.

361
362
363
364
365
366
367




368
369
370
# define sqlite3BtreeLeaveCursor(X)
# define sqlite3BtreeLeaveAll(X)

# define sqlite3BtreeHoldsMutex(X) 1
# define sqlite3BtreeHoldsAllMutexes(X) 1
# define sqlite3SchemaMutexHeld(X,Y,Z) 1
#endif






#endif /* SQLITE_BTREE_H */







>
>
>
>



361
362
363
364
365
366
367
368
369
370
371
372
373
374
# define sqlite3BtreeLeaveCursor(X)
# define sqlite3BtreeLeaveAll(X)

# define sqlite3BtreeHoldsMutex(X) 1
# define sqlite3BtreeHoldsAllMutexes(X) 1
# define sqlite3SchemaMutexHeld(X,Y,Z) 1
#endif

#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
  int sqlite3BtreeTransactionPages(Btree*, int*, u32**, int*, u32**);
#endif


#endif /* SQLITE_BTREE_H */

Changes to src/btreeInt.h.

436
437
438
439
440
441
442










443
444
445
446
447
448
449
#ifndef SQLITE_OMIT_SHARED_CACHE
  int nRef;             /* Number of references to this structure */
  BtShared *pNext;      /* Next on a list of sharable BtShared structs */
  BtLock *pLock;        /* List of locks held on this shared-btree struct */
  Btree *pWriter;       /* Btree with currently open write transaction */
#endif
  u8 *pTmpSpace;        /* Temp space sufficient to hold a single cell */










};

/*
** Allowed values for BtShared.btsFlags
*/
#define BTS_READ_ONLY        0x0001   /* Underlying file is readonly */
#define BTS_PAGESIZE_FIXED   0x0002   /* Page size can no longer be changed */







>
>
>
>
>
>
>
>
>
>







436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
#ifndef SQLITE_OMIT_SHARED_CACHE
  int nRef;             /* Number of references to this structure */
  BtShared *pNext;      /* Next on a list of sharable BtShared structs */
  BtLock *pLock;        /* List of locks held on this shared-btree struct */
  Btree *pWriter;       /* Btree with currently open write transaction */
#endif
  u8 *pTmpSpace;        /* Temp space sufficient to hold a single cell */

#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
  Bitvec *pBtRead;      /* Btree pages read during current write transaction */
  Bitvec *pBtWrite;     /* Btree pages written during current transaction */
  Bitvec *pBtAlloc;     /* Btree pages allocated during current transaction */
  int nRead;            /* Number of entries in aiRead[] array */
  u32 *aiRead;          /* Array returned to sqlite3_transaction_pages() */
  int nWrite;           /* Number of entries in aiWrite[] array */
  u32 *aiWrite;         /* Array returned to sqlite3_transaction_pages() */
#endif
};

/*
** Allowed values for BtShared.btsFlags
*/
#define BTS_READ_ONLY        0x0001   /* Underlying file is readonly */
#define BTS_PAGESIZE_FIXED   0x0002   /* Page size can no longer be changed */

Changes to src/main.c.

4073
4074
4075
4076
4077
4078
4079





























4080

/*
** Free a snapshot handle obtained from sqlite3_snapshot_get().
*/
void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){
  sqlite3_free(pSnapshot);
}





























#endif /* SQLITE_ENABLE_SNAPSHOT */







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109

/*
** Free a snapshot handle obtained from sqlite3_snapshot_get().
*/
void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){
  sqlite3_free(pSnapshot);
}

#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
/*
** Return the pages read and written by the current write transaction.
*/
int sqlite3_transaction_pages(
    sqlite3 *db, const char *zDbName, 
    int *pnRead, unsigned int **paRead,
    int *pnWrite, unsigned int **paWrite
){
  Btree *pBt;                     /* Btree to query */
  int rc;                         /* Return code */
#ifdef SQLITE_ENABLE_API_ARMOR
  if( !sqlite3SafetyCheckOk(db) ){
    (void)SQLITE_MISUSE_BKPT;
    return 0;
  }
#endif

  sqlite3_mutex_enter(db->mutex);
  pBt = sqlite3DbNameToBtree(db, zDbName);
  if( pBt==0 ) return SQLITE_ERROR;
  rc = sqlite3BtreeTransactionPages(pBt, pnRead, paRead, pnWrite, paWrite);
  sqlite3_mutex_leave(db->mutex);

  return rc;
}
#endif  /* SQLITE_ENABLE_TRANSACTION_PAGES */

#endif /* SQLITE_ENABLE_SNAPSHOT */

Changes to src/pager.c.

4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
  assert( !pPager->aSavepoint && !pPager->pInJournal );
  assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) );

  sqlite3_free(pPager);
  return SQLITE_OK;
}

#if !defined(NDEBUG) || defined(SQLITE_TEST)
/*
** Return the page number for page pPg.
*/
Pgno sqlite3PagerPagenumber(DbPage *pPg){
  return pPg->pgno;
}
#endif







|







4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
  assert( !pPager->aSavepoint && !pPager->pInJournal );
  assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) );

  sqlite3_free(pPager);
  return SQLITE_OK;
}

#if !defined(NDEBUG) || defined(SQLITE_TEST) || defined(SQLITE_ENABLE_TRANSACTION_PAGES)
/*
** Return the page number for page pPg.
*/
Pgno sqlite3PagerPagenumber(DbPage *pPg){
  return pPg->pgno;
}
#endif

Changes to src/pager.h.

216
217
218
219
220
221
222
223
224


225
226
227
228
229
230
231
232
233
234
235
236
237
void sqlite3PagerRekey(DbPage*, Pgno, u16);

#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
void *sqlite3PagerCodec(DbPage *);
#endif

/* Functions to support testing and debugging. */
#if !defined(NDEBUG) || defined(SQLITE_TEST)
  Pgno sqlite3PagerPagenumber(DbPage*);


  int sqlite3PagerIswriteable(DbPage*);
#endif
#ifdef SQLITE_TEST
  int *sqlite3PagerStats(Pager*);
  void sqlite3PagerRefdump(Pager*);
  void disable_simulated_io_errors(void);
  void enable_simulated_io_errors(void);
#else
# define disable_simulated_io_errors()
# define enable_simulated_io_errors()
#endif

#endif /* SQLITE_PAGER_H */







|

>
>













216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
void sqlite3PagerRekey(DbPage*, Pgno, u16);

#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
void *sqlite3PagerCodec(DbPage *);
#endif

/* Functions to support testing and debugging. */
#if !defined(NDEBUG) || defined(SQLITE_TEST) || defined(SQLITE_ENABLE_TRANSACTION_PAGES)
  Pgno sqlite3PagerPagenumber(DbPage*);
#endif
#if !defined(NDEBUG) || defined(SQLITE_TEST)
  int sqlite3PagerIswriteable(DbPage*);
#endif
#ifdef SQLITE_TEST
  int *sqlite3PagerStats(Pager*);
  void sqlite3PagerRefdump(Pager*);
  void disable_simulated_io_errors(void);
  void enable_simulated_io_errors(void);
#else
# define disable_simulated_io_errors()
# define enable_simulated_io_errors()
#endif

#endif /* SQLITE_PAGER_H */

Changes to src/sqlite.h.in.

8443
8444
8445
8446
8447
8448
8449















































8450
8451
8452
8453
8454
8455
8456
8457
8458
8459
8460
8461
8462
** sqlite3_snapshot_open(). It is an error if there is already a read
** transaction open on the database, or if the database is not a wal mode
** database.
**
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
*/
SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
















































/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
*/
#ifdef SQLITE_OMIT_FLOATING_POINT
# undef double
#endif

#ifdef __cplusplus
}  /* End of the 'extern "C"' block */
#endif
#endif /* SQLITE3_H */







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>













8443
8444
8445
8446
8447
8448
8449
8450
8451
8452
8453
8454
8455
8456
8457
8458
8459
8460
8461
8462
8463
8464
8465
8466
8467
8468
8469
8470
8471
8472
8473
8474
8475
8476
8477
8478
8479
8480
8481
8482
8483
8484
8485
8486
8487
8488
8489
8490
8491
8492
8493
8494
8495
8496
8497
8498
8499
8500
8501
8502
8503
8504
8505
8506
8507
8508
8509
** sqlite3_snapshot_open(). It is an error if there is already a read
** transaction open on the database, or if the database is not a wal mode
** database.
**
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
*/
SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);


/*
** THIS API IS A HACK ONLY. 
**
** Return the page numbers of all b-tree pages read from or written to
** database zDb ("main", "temp" etc.) belonging to handle db since the 
** current write transaction was started. A page is only reported on if:
**
**   + It is a b-tree page, not an overflow, free or pointer-map page, and
**
**   + it was a b-tree page when the transaction was started (i.e. is not a 
**     b-tree page created by reusing free page or extending the database 
**     file).
**
** If successful, this function returns SQLITE_OK and sets the four output
** variables as follows:
**
**   + (*paRead) is set to point to an array containing the page numbers
**     of all pages read since the current write transaction was opened.
**     (*pnRead) is set to the number of elements in this array.
**
**   + (*paWrite) is set to point to an array containing the page numbers
**     of all pages written since the current write transaction was opened.
**     (*paRead) is set to the number of elements in this array.
**
** The array references are valid until the next call to this API function
** on the same database or until the database is DETACHed from the database 
** handle.
**
** If this function is called when there is no write transaction opened
** on the specified database, all four output parameters are set to 0.
**
** If an error occurs, an SQLite error code is returned (e.g. SQLITE_NOMEM)
** and the final values of the four output parameters are undefined.
**
** This function is only enabled if SQLITE_ENABLE_TRANSACTION_PAGES is
** defined during compilation.
*/
SQLITE_EXPERIMENTAL int sqlite3_transaction_pages(
    sqlite3 *db, const char *zDb, 
    int *pnRead, unsigned int **paRead,
    int *pnWrite, unsigned int **paWrite
);




/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
*/
#ifdef SQLITE_OMIT_FLOATING_POINT
# undef double
#endif

#ifdef __cplusplus
}  /* End of the 'extern "C"' block */
#endif
#endif /* SQLITE3_H */

Changes to src/sqliteInt.h.

3626
3627
3628
3629
3630
3631
3632




3633
3634
3635
3636
3637
3638
3639
int sqlite3BitvecSet(Bitvec*, u32);
void sqlite3BitvecClear(Bitvec*, u32, void*);
void sqlite3BitvecDestroy(Bitvec*);
u32 sqlite3BitvecSize(Bitvec*);
#ifndef SQLITE_UNTESTABLE
int sqlite3BitvecBuiltinTest(int,int*);
#endif





RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int);
void sqlite3RowSetClear(RowSet*);
void sqlite3RowSetInsert(RowSet*, i64);
int sqlite3RowSetTest(RowSet*, int iBatch, i64);
int sqlite3RowSetNext(RowSet*, i64*);








>
>
>
>







3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
int sqlite3BitvecSet(Bitvec*, u32);
void sqlite3BitvecClear(Bitvec*, u32, void*);
void sqlite3BitvecDestroy(Bitvec*);
u32 sqlite3BitvecSize(Bitvec*);
#ifndef SQLITE_UNTESTABLE
int sqlite3BitvecBuiltinTest(int,int*);
#endif

#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
  int sqlite3BitvecToArray(Bitvec *p, int *pnElem, u32 **paElem);
#endif

RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int);
void sqlite3RowSetClear(RowSet*);
void sqlite3RowSetInsert(RowSet*, i64);
int sqlite3RowSetTest(RowSet*, int iBatch, i64);
int sqlite3RowSetNext(RowSet*, i64*);

Changes to src/test1.c.

2546
2547
2548
2549
2550
2551
2552

















































2553
2554
2555
2556
2557
2558
2559
....
7682
7683
7684
7685
7686
7687
7688



7689
7690
7691
7692
7693
7694
7695
  zFile = (const char*)Tcl_GetString(objv[1]);
  rc = sqlite3_delete_database(zFile);

  Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
  return TCL_OK;
}


















































/*
** Usage:  sqlite3_next_stmt  DB  STMT
**
** Return the next statment in sequence after STMT.
*/
static int SQLITE_TCLAPI test_next_stmt(
  void * clientData,
................................................................................
     { "sqlite3_snapshot_cmp", test_snapshot_cmp, 0 },
     { "sqlite3_snapshot_recover", test_snapshot_recover, 0 },
     { "sqlite3_snapshot_get_blob", test_snapshot_get_blob, 0 },
     { "sqlite3_snapshot_open_blob", test_snapshot_open_blob, 0 },
     { "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 },
#endif
     { "sqlite3_delete_database", test_delete_database, 0 },



  };
  static int bitmask_size = sizeof(Bitmask)*8;
  static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
  int i;
  extern int sqlite3_sync_count, sqlite3_fullsync_count;
  extern int sqlite3_opentemp_count;
  extern int sqlite3_like_count;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>







2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
....
7731
7732
7733
7734
7735
7736
7737
7738
7739
7740
7741
7742
7743
7744
7745
7746
7747
  zFile = (const char*)Tcl_GetString(objv[1]);
  rc = sqlite3_delete_database(zFile);

  Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
  return TCL_OK;
}

/*
** Usage: sqlite3_transaction_pages DB FILENAME
*/
#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
static int SQLITE_TCLAPI test_transaction_pages(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  const char *zDb;
  sqlite3 *db;
  int rc;

  int nRead;
  int nWrite;
  unsigned int *aiRead;
  unsigned int *aiWrite;

  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB FILE");
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  zDb = (const char*)Tcl_GetString(objv[2]);

  rc = sqlite3_transaction_pages(db, zDb, &nRead, &aiRead, &nWrite, &aiWrite);
  if( rc==SQLITE_OK ){
    Tcl_Obj *pList = Tcl_NewObj();
    Tcl_Obj *p = Tcl_NewObj();
    int i;
    for(i=0; i<nRead; i++){
      Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj((int)aiRead[i]));
    }
    Tcl_ListObjAppendElement(interp, pList, p);
    p = Tcl_NewObj();
    for(i=0; i<nWrite; i++){
      Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj((int)aiWrite[i]));
    }
    Tcl_ListObjAppendElement(interp, pList, p);
    Tcl_SetObjResult(interp, pList);
  }else{
    Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
    return TCL_ERROR;
  }
  return TCL_OK;
}
#endif

/*
** Usage:  sqlite3_next_stmt  DB  STMT
**
** Return the next statment in sequence after STMT.
*/
static int SQLITE_TCLAPI test_next_stmt(
  void * clientData,
................................................................................
     { "sqlite3_snapshot_cmp", test_snapshot_cmp, 0 },
     { "sqlite3_snapshot_recover", test_snapshot_recover, 0 },
     { "sqlite3_snapshot_get_blob", test_snapshot_get_blob, 0 },
     { "sqlite3_snapshot_open_blob", test_snapshot_open_blob, 0 },
     { "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 },
#endif
     { "sqlite3_delete_database", test_delete_database, 0 },
#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
     { "sqlite3_transaction_pages", test_transaction_pages, 0 },
#endif
  };
  static int bitmask_size = sizeof(Bitmask)*8;
  static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
  int i;
  extern int sqlite3_sync_count, sqlite3_fullsync_count;
  extern int sqlite3_opentemp_count;
  extern int sqlite3_like_count;

Added test/tpages.test.











































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# 2017-01-19
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix tpages

sqlite3_test_control_pending_byte 0x1000000

proc integers {iFirst n} {
  set ret [list]
  for {set i $iFirst} {$i<$iFirst+$n} {incr i} {
    lappend ret $i
  }
  set ret
}

do_execsql_test 1.0 {
  CREATE TABLE t1(a, b, c);
  WITH s(i) AS (
    SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<99
  )
  INSERT INTO t1 SELECT randomblob(10), randomblob(400), randomblob(400) FROM s;
}

foreach {n1 n2} {
      0   10 
     10   20
   5000   20
   5000 5000
   5001 5001
  60000 5001
  60000    5
   5000 1000
   6000 1000
   7000 1000
} {

  set n1 [expr $n1]
  set n2 [expr $n2]

  reset_db
  do_execsql_test 1.$n1.1 {
    CREATE TABLE t1(a, b, c);
    WITH s(i) AS (
        SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<$n1
    )
    INSERT INTO t1 
    SELECT randomblob(10), randomblob(400), randomblob(400) FROM s;
  }

  set iFirst [expr [db one {PRAGMA page_count}] + 1]
  do_execsql_test 1.$n1.2 {
    CREATE TABLE t2(a, b, c);
    WITH s(i) AS (
        SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<$n2
    )
    INSERT INTO t2 
    SELECT randomblob(10), randomblob(400), randomblob(400) FROM s;
  }
  set nInt [expr [db one {PRAGMA page_count}] - $iFirst + 1]

  do_test 1.$n1.3 {
    execsql {
      BEGIN IMMEDIATE;
      SELECT * FROM t2;
    }
    sqlite3_transaction_pages db main
  } [list [integers $iFirst $nInt] {}]
  execsql cOMMIT
}




finish_test