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 681d96eb to 50ca94b9
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
| ||
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: 26dd42b4 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: 2a8f6c89 user: dan tags: transaction-pages) | |
17:20 | Baseline interface definition for the experimental sqlite3_kv accessor object. (check-in: a435841e 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: 681d96eb 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: 7fd560c6 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 | if( rc==SQLITE_OK ){ put4byte(&pPage1->aData[28], pBt->nPage); } } } } | < > | 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 | /* 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; } | > > > > > > | > | 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 | ** 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{ | | | 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 | */ pageFlags = apOld[0]->aData[0]; for(i=0; i<k; i++){ MemPage *pNew; if( i<nOld ){ pNew = apNew[i] = apOld[i]; apOld[i] = 0; | | | 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 | 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. */ | | | 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 | } }else if( pPage->nOverflow==0 && pPage->nFree<=nMin ){ break; }else{ MemPage * const pParent = pCur->apPage[iPage-1]; int const iIdx = pCur->aiIdx[iPage-1]; | | | 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 | 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 ); | | | 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 | 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. */ | | | 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 | 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 ); | | | 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 | }else if( pnChange ){ assert( pPage->intKey || CORRUPT_DB ); testcase( !pPage->intKey ); *pnChange += pPage->nCell; } if( freePageFlag ){ freePage(pPage, &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 | assert( !pPager->aSavepoint && !pPager->pInJournal ); assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) ); sqlite3_free(pPager); return SQLITE_OK; } | | | 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 | void sqlite3PagerRekey(DbPage*, Pgno, u16); #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) void *sqlite3PagerCodec(DbPage *); #endif /* Functions to support testing and debugging. */ | | > > | 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 |