/ Changes On Branch transaction-pages
Login

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

Changes In Branch transaction-pages Excluding Merge-Ins

This is equivalent to a diff from 681d96eb82 to 50ca94b919

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: 50ca94b919 user: dan tags: transaction-pages)
2017-01-18
22:16
Fix handling of initial hidden and/or system files in the opendir() implementation for Windows. No changes to non-test code. (check-in: 26dd42b462 user: mistachkin tags: trunk)
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: 2a8f6c890c user: dan tags: transaction-pages)
17:20
Baseline interface definition for the experimental sqlite3_kv accessor object. (check-in: a435841e71 user: drh tags: sqlite3_kv)
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: 681d96eb82 user: dan tags: trunk)
00:10
Disable intrinsic functions for Windows using Clang, due to reports of linkage errors. This causes a 0.6% performance reduction. We will want to revisit this change in the future. (check-in: 7fd560c6d2 user: drh tags: trunk)

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
  /* 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;







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







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
  /* 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;
3102
3103
3104
3105
3106
3107
3108





















3109
3110
3111
3112
3113
3114
3115
  sqlite3BtreeEnter(p);
  p->pBt->nPage = 0;
  rc = newDatabase(p->pBt);
  sqlite3BtreeLeave(p);
  return rc;
}






















/*
** Attempt to start a new transaction. A write-transaction
** is started if the second argument is nonzero, otherwise a read-
** transaction.  If the second argument is 2 or more and exclusive
** transaction is started, meaning that no other process is allowed
** to access the database.  A preexisting transaction may not be
** upgraded to exclusive by calling this routine a second time - the







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







3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
  sqlite3BtreeEnter(p);
  p->pBt->nPage = 0;
  rc = newDatabase(p->pBt);
  sqlite3BtreeLeave(p);
  return rc;
}

#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
/*
** If the b-tree is not currently in a write transaction, free the various
** resources allocated for the sqlite3_transaction_pages() functionality.
*/
static void freeTransactionPagesBitvec(BtShared *pBt){
  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;
  }
}
#else
# define freeTransactionPagesBitvec(x) 
#endif

/*
** Attempt to start a new transaction. A write-transaction
** is started if the second argument is nonzero, otherwise a read-
** transaction.  If the second argument is 2 or more and exclusive
** transaction is started, meaning that no other process is allowed
** to access the database.  A preexisting transaction may not be
** upgraded to exclusive by calling this routine a second time - the
3186
3187
3188
3189
3190
3191
3192














3193
3194
3195
3196
3197
3198
3199
    if( pBlock ){
      sqlite3ConnectionBlocked(p->db, pBlock);
      rc = SQLITE_LOCKED_SHAREDCACHE;
      goto trans_begun;
    }
  }
#endif















  /* Any read-only or read-write transaction implies a read-lock on 
  ** page 1. So if some other shared-cache client already has a write-lock 
  ** on page 1, the transaction cannot be opened. */
  rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
  if( SQLITE_OK!=rc ) goto trans_begun;








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







3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
    if( pBlock ){
      sqlite3ConnectionBlocked(p->db, pBlock);
      rc = SQLITE_LOCKED_SHAREDCACHE;
      goto trans_begun;
    }
  }
#endif

#ifdef SQLITE_ENABLE_TRANSACTION_PAGES
  if( wrflag ){
    assert( pBt->pBtRead==0 && pBt->pBtWrite==0 && pBt->pBtAlloc==0 );
    assert( rc==SQLITE_OK );
    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;
      goto trans_begun;
    }
  }
#endif

  /* Any read-only or read-write transaction implies a read-lock on 
  ** page 1. So if some other shared-cache client already has a write-lock 
  ** on page 1, the transaction cannot be opened. */
  rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
  if( SQLITE_OK!=rc ) goto trans_begun;

3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278

3279
3280
3281
3282
3283
3284
3285
        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.
    */
    rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint);
  }


  btreeIntegrity(p);
  sqlite3BtreeLeave(p);
  return rc;
}

#ifndef SQLITE_OMIT_AUTOVACUUM








<









>







3310
3311
3312
3313
3314
3315
3316

3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
        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.
    */
    rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint);
  }

  freeTransactionPagesBitvec(pBt);
  btreeIntegrity(p);
  sqlite3BtreeLeave(p);
  return rc;
}

#ifndef SQLITE_OMIT_AUTOVACUUM

3786
3787
3788
3789
3790
3791
3792

3793
3794
3795
3796
3797
3798
3799

    /* 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.
**
** This routine implements the second phase of a 2-phase commit.  The







>







3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848

    /* 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);
  }

  freeTransactionPagesBitvec(pBt);
  btreeIntegrity(p);
}

/*
** Commit the transaction currently in progress.
**
** This routine implements the second phase of a 2-phase commit.  The
4412
4413
4414
4415
4416
4417
4418


















4419
4420
4421
4422
4423
4424
4425
    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.







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







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
4487
4488
4489
4490
4491
4492
    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.
4489
4490
4491
4492
4493
4494
4495






4496

4497
4498
4499
4500
4501
4502
4503

  /* 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;
  }








>
>
>
>
>
>
|
>







4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577

  /* 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;
  }

5825
5826
5827
5828
5829
5830
5831










5832
5833
5834
5835
5836
5837
5838
      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;







>
>
>
>
>
>
>
>
>
>







5899
5900
5901
5902
5903
5904
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
5915
5916
5917
5918
5919
5920
5921
5922
      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;
6281
6282
6283
6284
6285
6286
6287

6288
6289
6290
6291
6292
6293
6294
                       - 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







>







6365
6366
6367
6368
6369
6370
6371
6372
6373
6374
6375
6376
6377
6378
6379
                       - 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
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
    ** 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 );







|







6432
6433
6434
6435
6436
6437
6438
6439
6440
6441
6442
6443
6444
6445
6446
    ** 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 );
7381
7382
7383
7384
7385
7386
7387
7388
7389
7390
7391
7392
7393
7394
7395
  */
  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);







|







7466
7467
7468
7469
7470
7471
7472
7473
7474
7475
7476
7477
7478
7479
7480
  */
  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);
7751
7752
7753
7754
7755
7756
7757
7758
7759
7760
7761
7762
7763
7764
7765
  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);
    }
  }







|







7836
7837
7838
7839
7840
7841
7842
7843
7844
7845
7846
7847
7848
7849
7850
  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);
    }
  }
7833
7834
7835
7836
7837
7838
7839
7840
7841
7842
7843
7844
7845
7846
7847
      }
    }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







|







7918
7919
7920
7921
7922
7923
7924
7925
7926
7927
7928
7929
7930
7931
7932
      }
    }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
8054
8055
8056
8057
8058
8059
8060
8061
8062
8063
8064
8065
8066
8067
8068
  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);
    }







|







8139
8140
8141
8142
8143
8144
8145
8146
8147
8148
8149
8150
8151
8152
8153
  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);
    }
8234
8235
8236
8237
8238
8239
8240
8241
8242
8243
8244
8245
8246
8247
8248
  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







|







8319
8320
8321
8322
8323
8324
8325
8326
8327
8328
8329
8330
8331
8332
8333
  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
8257
8258
8259
8260
8261
8262
8263
8264
8265
8266
8267
8268
8269
8270
8271

    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;
  }








|







8342
8343
8344
8345
8346
8347
8348
8349
8350
8351
8352
8353
8354
8355
8356

    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;
  }

8520
8521
8522
8523
8524
8525
8526
8527
8528
8529
8530
8531
8532
8533
8534
  }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;







|







8605
8606
8607
8608
8609
8610
8611
8612
8613
8614
8615
8616
8617
8618
8619
  }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;
9722
9723
9724
9725
9726
9727
9728





























9729
9730
9731
9732
9733
9734
9735
}

/*
** 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;
}







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







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
9842
9843
9844
9845
9846
9847
9848
9849
}

/*
** 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
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);







|

>
>







216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
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);

Changes to src/sqlite.h.in.

8443
8444
8445
8446
8447
8448
8449















































8450
8451
8452
8453
8454
8455
8456
** 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







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







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
** 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

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
  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,







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







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
  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,
7682
7683
7684
7685
7686
7687
7688



7689
7690
7691
7692
7693
7694
7695
     { "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;







>
>
>







7731
7732
7733
7734
7735
7736
7737
7738
7739
7740
7741
7742
7743
7744
7745
7746
7747
     { "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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# 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
}

#-------------------------------------------------------------------------
#
proc do_transaction_pages_test {tn sql pages} {
  uplevel [list execsql $sql]
  uplevel [list \
    do_test $tn {sqlite3_transaction_pages db main} [list {*}$pages]
  ]
}
reset_db
do_transaction_pages_test 2.0 {
  PRAGMA auto_vacuum = 0;
  PRAGMA page_size = 1024;
  CREATE TABLE t1(x);
  BEGIN;
    INSERT INTO t1 VALUES(randomblob(1500));
} {2 2}

do_transaction_pages_test 2.1 {
  COMMIT;
  BEGIN;
    DELETE FROM t1;
} {2 2}

reset_db
do_execsql_test 2.2 {
  PRAGMA auto_vacuum = 0;
  PRAGMA page_size = 1024;
  CREATE TABLE t1(x);
  INSERT INTO t1 VALUES(randomblob(900));
  INSERT INTO t1 VALUES(randomblob(900));
  CREATE TABLE t2(y);
}  

do_transaction_pages_test 2.3 {
  BEGIN;
    UPDATE t1 SET x=randomblob(899);
} {{2 3 4} {3 4}}

do_transaction_pages_test 2.4 {
    DELETE FROM t1;
  COMMIT;
} {{} {}}

do_transaction_pages_test 2.5 {
  BEGIN;
    INSERT INTO t2 VALUES(randomblob(900));
    INSERT INTO t2 VALUES(randomblob(900));
} {5 5}

do_transaction_pages_test 2.6 {
  COMMIT;
  BEGIN;
    INSERT INTO t1 VALUES(randomblob(900));
} {2 2}

do_transaction_pages_test 2.7 {
    INSERT INTO t1 VALUES(randomblob(900));
    INSERT INTO t1 VALUES(randomblob(900));
    INSERT INTO t1 VALUES(randomblob(900));
    INSERT INTO t1 VALUES(randomblob(900));
} {2 2}

finish_test