|
|
@@ -676,7 +676,7 @@ extern "C" {
|
|
|
*/
|
|
|
#define SQLITE_VERSION "3.7.16"
|
|
|
#define SQLITE_VERSION_NUMBER 3007016
|
|
|
-#define SQLITE_SOURCE_ID "2013-02-19 22:26:51 06bd91305ed6752315c5224be5f89e87cafa6687"
|
|
|
+#define SQLITE_SOURCE_ID "2013-02-26 12:57:42 c2d5a23b1ab39918e97c596cf75c42f86a5fe2b7"
|
|
|
|
|
|
/*
|
|
|
** CAPI3REF: Run-Time Library Version Numbers
|
|
|
@@ -39386,6 +39386,8 @@ static int pager_error(Pager *pPager, int rc){
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
+static int pager_truncate(Pager *pPager, Pgno nPage);
|
|
|
+
|
|
|
/*
|
|
|
** This routine ends a transaction. A transaction is usually ended by
|
|
|
** either a COMMIT or a ROLLBACK operation. This routine may be called
|
|
|
@@ -39439,7 +39441,7 @@ static int pager_error(Pager *pPager, int rc){
|
|
|
** to the first error encountered (the journal finalization one) is
|
|
|
** returned.
|
|
|
*/
|
|
|
-static int pager_end_transaction(Pager *pPager, int hasMaster){
|
|
|
+static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
|
|
|
int rc = SQLITE_OK; /* Error code from journal finalization operation */
|
|
|
int rc2 = SQLITE_OK; /* Error code from db file unlock operation */
|
|
|
|
|
|
@@ -39525,7 +39527,17 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
|
|
|
*/
|
|
|
rc2 = sqlite3WalEndWriteTransaction(pPager->pWal);
|
|
|
assert( rc2==SQLITE_OK );
|
|
|
+ }else if( rc==SQLITE_OK && bCommit && pPager->dbFileSize>pPager->dbSize ){
|
|
|
+ /* This branch is taken when committing a transaction in rollback-journal
|
|
|
+ ** mode if the database file on disk is larger than the database image.
|
|
|
+ ** At this point the journal has been finalized and the transaction
|
|
|
+ ** successfully committed, but the EXCLUSIVE lock is still held on the
|
|
|
+ ** file. So it is safe to truncate the database file to its minimum
|
|
|
+ ** required size. */
|
|
|
+ assert( pPager->eLock==EXCLUSIVE_LOCK );
|
|
|
+ rc = pager_truncate(pPager, pPager->dbSize);
|
|
|
}
|
|
|
+
|
|
|
if( !pPager->exclusiveMode
|
|
|
&& (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
|
|
|
){
|
|
|
@@ -39564,7 +39576,7 @@ static void pagerUnlockAndRollback(Pager *pPager){
|
|
|
sqlite3EndBenignMalloc();
|
|
|
}else if( !pPager->exclusiveMode ){
|
|
|
assert( pPager->eState==PAGER_READER );
|
|
|
- pager_end_transaction(pPager, 0);
|
|
|
+ pager_end_transaction(pPager, 0, 0);
|
|
|
}
|
|
|
}
|
|
|
pager_unlock(pPager);
|
|
|
@@ -40339,7 +40351,7 @@ end_playback:
|
|
|
rc = sqlite3PagerSync(pPager);
|
|
|
}
|
|
|
if( rc==SQLITE_OK ){
|
|
|
- rc = pager_end_transaction(pPager, zMaster[0]!='\0');
|
|
|
+ rc = pager_end_transaction(pPager, zMaster[0]!='\0', 0);
|
|
|
testcase( rc!=SQLITE_OK );
|
|
|
}
|
|
|
if( rc==SQLITE_OK && zMaster[0] && res ){
|
|
|
@@ -43433,36 +43445,6 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
|
|
|
#endif
|
|
|
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
|
|
|
|
|
- /* If this transaction has made the database smaller, then all pages
|
|
|
- ** being discarded by the truncation must be written to the journal
|
|
|
- ** file.
|
|
|
- **
|
|
|
- ** Before reading the pages with page numbers larger than the
|
|
|
- ** current value of Pager.dbSize, set dbSize back to the value
|
|
|
- ** that it took at the start of the transaction. Otherwise, the
|
|
|
- ** calls to sqlite3PagerGet() return zeroed pages instead of
|
|
|
- ** reading data from the database file.
|
|
|
- */
|
|
|
- if( pPager->dbSize<pPager->dbOrigSize
|
|
|
- && pPager->journalMode!=PAGER_JOURNALMODE_OFF
|
|
|
- ){
|
|
|
- Pgno i; /* Iterator variable */
|
|
|
- const Pgno iSkip = PAGER_MJ_PGNO(pPager); /* Pending lock page */
|
|
|
- const Pgno dbSize = pPager->dbSize; /* Database image size */
|
|
|
- pPager->dbSize = pPager->dbOrigSize;
|
|
|
- for( i=dbSize+1; i<=pPager->dbOrigSize; i++ ){
|
|
|
- if( !sqlite3BitvecTest(pPager->pInJournal, i) && i!=iSkip ){
|
|
|
- PgHdr *pPage; /* Page to journal */
|
|
|
- rc = sqlite3PagerGet(pPager, i, &pPage);
|
|
|
- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
|
|
- rc = sqlite3PagerWrite(pPage);
|
|
|
- sqlite3PagerUnref(pPage);
|
|
|
- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
|
|
- }
|
|
|
- }
|
|
|
- pPager->dbSize = dbSize;
|
|
|
- }
|
|
|
-
|
|
|
/* Write the master journal name into the journal file. If a master
|
|
|
** journal file name has already been written to the journal file,
|
|
|
** or if zMaster is NULL (no master journal), then this call is a no-op.
|
|
|
@@ -43490,11 +43472,14 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
|
|
|
goto commit_phase_one_exit;
|
|
|
}
|
|
|
sqlite3PcacheCleanAll(pPager->pPCache);
|
|
|
-
|
|
|
- /* If the file on disk is not the same size as the database image,
|
|
|
- ** then use pager_truncate to grow or shrink the file here.
|
|
|
- */
|
|
|
- if( pPager->dbSize!=pPager->dbFileSize ){
|
|
|
+
|
|
|
+ /* If the file on disk is smaller than the database image, use
|
|
|
+ ** pager_truncate to grow the file here. This can happen if the database
|
|
|
+ ** image was extended as part of the current transaction and then the
|
|
|
+ ** last page in the db image moved to the free-list. In this case the
|
|
|
+ ** last page is never written out to disk, leaving the database file
|
|
|
+ ** undersized. Fix this now if it is the case. */
|
|
|
+ if( pPager->dbSize>pPager->dbFileSize ){
|
|
|
Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager));
|
|
|
assert( pPager->eState==PAGER_WRITER_DBMOD );
|
|
|
rc = pager_truncate(pPager, nNew);
|
|
|
@@ -43567,7 +43552,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){
|
|
|
}
|
|
|
|
|
|
PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
|
|
|
- rc = pager_end_transaction(pPager, pPager->setMaster);
|
|
|
+ rc = pager_end_transaction(pPager, pPager->setMaster, 1);
|
|
|
return pager_error(pPager, rc);
|
|
|
}
|
|
|
|
|
|
@@ -43612,11 +43597,11 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
|
|
|
if( pagerUseWal(pPager) ){
|
|
|
int rc2;
|
|
|
rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
|
|
|
- rc2 = pager_end_transaction(pPager, pPager->setMaster);
|
|
|
+ rc2 = pager_end_transaction(pPager, pPager->setMaster, 0);
|
|
|
if( rc==SQLITE_OK ) rc = rc2;
|
|
|
}else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){
|
|
|
int eState = pPager->eState;
|
|
|
- rc = pager_end_transaction(pPager, 0);
|
|
|
+ rc = pager_end_transaction(pPager, 0, 0);
|
|
|
if( !MEMDB && eState>PAGER_WRITER_LOCKED ){
|
|
|
/* This can happen using journal_mode=off. Move the pager to the error
|
|
|
** state to indicate that the contents of the cache may not be trusted.
|
|
|
@@ -48018,6 +48003,7 @@ struct BtShared {
|
|
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
|
u8 autoVacuum; /* True if auto-vacuum is enabled */
|
|
|
u8 incrVacuum; /* True if incr-vacuum is enabled */
|
|
|
+ u8 bDoTruncate; /* True to truncate db on commit */
|
|
|
#endif
|
|
|
u8 inTransaction; /* Transaction state */
|
|
|
u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
|
|
|
@@ -51136,6 +51122,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
|
|
|
if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){
|
|
|
goto trans_begun;
|
|
|
}
|
|
|
+ assert( pBt->bDoTruncate==0 );
|
|
|
|
|
|
/* Write transactions are not possible on a read-only database */
|
|
|
if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){
|
|
|
@@ -51450,26 +51437,28 @@ static int relocatePage(
|
|
|
|
|
|
/* Forward declaration required by incrVacuumStep(). */
|
|
|
static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
|
|
|
+#define BTALLOC_ANY 0 /* Allocate any page */
|
|
|
+#define BTALLOC_EXACT 1 /* Allocate exact page if possible */
|
|
|
+#define BTALLOC_LE 2 /* Allocate any page <= the parameter */
|
|
|
|
|
|
/*
|
|
|
-** Perform a single step of an incremental-vacuum. If successful,
|
|
|
-** return SQLITE_OK. If there is no work to do (and therefore no
|
|
|
-** point in calling this function again), return SQLITE_DONE.
|
|
|
+** Perform a single step of an incremental-vacuum. If successful, return
|
|
|
+** SQLITE_OK. If there is no work to do (and therefore no point in
|
|
|
+** calling this function again), return SQLITE_DONE. Or, if an error
|
|
|
+** occurs, return some other error code.
|
|
|
+**
|
|
|
+** More specificly, this function attempts to re-organize the database so
|
|
|
+** that the last page of the file currently in use is no longer in use.
|
|
|
**
|
|
|
-** More specificly, this function attempts to re-organize the
|
|
|
-** database so that the last page of the file currently in use
|
|
|
-** is no longer in use.
|
|
|
+** Parameter nFin is the number of pages that this database would contain
|
|
|
+** were this function called until it returns SQLITE_DONE.
|
|
|
**
|
|
|
-** If the nFin parameter is non-zero, this function assumes
|
|
|
-** that the caller will keep calling incrVacuumStep() until
|
|
|
-** it returns SQLITE_DONE or an error, and that nFin is the
|
|
|
-** number of pages the database file will contain after this
|
|
|
-** process is complete. If nFin is zero, it is assumed that
|
|
|
-** incrVacuumStep() will be called a finite amount of times
|
|
|
-** which may or may not empty the freelist. A full autovacuum
|
|
|
-** has nFin>0. A "PRAGMA incremental_vacuum" has nFin==0.
|
|
|
+** If the bCommit parameter is non-zero, this function assumes that the
|
|
|
+** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE
|
|
|
+** or an error. bCommit is passed true for an auto-vacuum-on-commmit
|
|
|
+** operation, or false for an incremental vacuum.
|
|
|
*/
|
|
|
-static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
|
|
|
+static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
|
|
|
Pgno nFreeList; /* Number of pages still on the free-list */
|
|
|
int rc;
|
|
|
|
|
|
@@ -51494,15 +51483,15 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
|
|
|
}
|
|
|
|
|
|
if( eType==PTRMAP_FREEPAGE ){
|
|
|
- if( nFin==0 ){
|
|
|
+ if( bCommit==0 ){
|
|
|
/* Remove the page from the files free-list. This is not required
|
|
|
- ** if nFin is non-zero. In that case, the free-list will be
|
|
|
+ ** if bCommit is non-zero. In that case, the free-list will be
|
|
|
** truncated to zero after this function returns, so it doesn't
|
|
|
** matter if it still contains some garbage entries.
|
|
|
*/
|
|
|
Pgno iFreePg;
|
|
|
MemPage *pFreePg;
|
|
|
- rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, 1);
|
|
|
+ rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, BTALLOC_EXACT);
|
|
|
if( rc!=SQLITE_OK ){
|
|
|
return rc;
|
|
|
}
|
|
|
@@ -51512,34 +51501,37 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
|
|
|
} else {
|
|
|
Pgno iFreePg; /* Index of free page to move pLastPg to */
|
|
|
MemPage *pLastPg;
|
|
|
+ u8 eMode = BTALLOC_ANY; /* Mode parameter for allocateBtreePage() */
|
|
|
+ Pgno iNear = 0; /* nearby parameter for allocateBtreePage() */
|
|
|
|
|
|
rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0);
|
|
|
if( rc!=SQLITE_OK ){
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
- /* If nFin is zero, this loop runs exactly once and page pLastPg
|
|
|
+ /* If bCommit is zero, this loop runs exactly once and page pLastPg
|
|
|
** is swapped with the first free page pulled off the free list.
|
|
|
**
|
|
|
- ** On the other hand, if nFin is greater than zero, then keep
|
|
|
+ ** On the other hand, if bCommit is greater than zero, then keep
|
|
|
** looping until a free-page located within the first nFin pages
|
|
|
** of the file is found.
|
|
|
*/
|
|
|
+ if( bCommit==0 ){
|
|
|
+ eMode = BTALLOC_LE;
|
|
|
+ iNear = nFin;
|
|
|
+ }
|
|
|
do {
|
|
|
MemPage *pFreePg;
|
|
|
- rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, 0, 0);
|
|
|
+ rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iNear, eMode);
|
|
|
if( rc!=SQLITE_OK ){
|
|
|
releasePage(pLastPg);
|
|
|
return rc;
|
|
|
}
|
|
|
releasePage(pFreePg);
|
|
|
- }while( nFin!=0 && iFreePg>nFin );
|
|
|
+ }while( bCommit && iFreePg>nFin );
|
|
|
assert( iFreePg<iLastPg );
|
|
|
|
|
|
- rc = sqlite3PagerWrite(pLastPg->pDbPage);
|
|
|
- if( rc==SQLITE_OK ){
|
|
|
- rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, nFin!=0);
|
|
|
- }
|
|
|
+ rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, nFin!=0);
|
|
|
releasePage(pLastPg);
|
|
|
if( rc!=SQLITE_OK ){
|
|
|
return rc;
|
|
|
@@ -51547,29 +51539,39 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if( nFin==0 ){
|
|
|
- iLastPg--;
|
|
|
- while( iLastPg==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, iLastPg) ){
|
|
|
- if( PTRMAP_ISPAGE(pBt, iLastPg) ){
|
|
|
- MemPage *pPg;
|
|
|
- rc = btreeGetPage(pBt, iLastPg, &pPg, 0);
|
|
|
- if( rc!=SQLITE_OK ){
|
|
|
- return rc;
|
|
|
- }
|
|
|
- rc = sqlite3PagerWrite(pPg->pDbPage);
|
|
|
- releasePage(pPg);
|
|
|
- if( rc!=SQLITE_OK ){
|
|
|
- return rc;
|
|
|
- }
|
|
|
- }
|
|
|
+ if( bCommit==0 ){
|
|
|
+ do {
|
|
|
iLastPg--;
|
|
|
- }
|
|
|
- sqlite3PagerTruncateImage(pBt->pPager, iLastPg);
|
|
|
+ }while( iLastPg==PENDING_BYTE_PAGE(pBt) || PTRMAP_ISPAGE(pBt, iLastPg) );
|
|
|
+ pBt->bDoTruncate = 1;
|
|
|
pBt->nPage = iLastPg;
|
|
|
}
|
|
|
return SQLITE_OK;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+** The database opened by the first argument is an auto-vacuum database
|
|
|
+** nOrig pages in size containing nFree free pages. Return the expected
|
|
|
+** size of the database in pages following an auto-vacuum operation.
|
|
|
+*/
|
|
|
+static Pgno finalDbSize(BtShared *pBt, Pgno nOrig, Pgno nFree){
|
|
|
+ int nEntry; /* Number of entries on one ptrmap page */
|
|
|
+ Pgno nPtrmap; /* Number of PtrMap pages to be freed */
|
|
|
+ Pgno nFin; /* Return value */
|
|
|
+
|
|
|
+ nEntry = pBt->usableSize/5;
|
|
|
+ nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+nEntry)/nEntry;
|
|
|
+ nFin = nOrig - nFree - nPtrmap;
|
|
|
+ if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<PENDING_BYTE_PAGE(pBt) ){
|
|
|
+ nFin--;
|
|
|
+ }
|
|
|
+ while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){
|
|
|
+ nFin--;
|
|
|
+ }
|
|
|
+
|
|
|
+ return nFin;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
** A write-transaction must be opened before calling this function.
|
|
|
** It performs a single unit of work towards an incremental vacuum.
|
|
|
@@ -51587,11 +51589,21 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){
|
|
|
if( !pBt->autoVacuum ){
|
|
|
rc = SQLITE_DONE;
|
|
|
}else{
|
|
|
- invalidateAllOverflowCache(pBt);
|
|
|
- rc = incrVacuumStep(pBt, 0, btreePagecount(pBt));
|
|
|
- if( rc==SQLITE_OK ){
|
|
|
- rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
|
|
- put4byte(&pBt->pPage1->aData[28], pBt->nPage);
|
|
|
+ Pgno nOrig = btreePagecount(pBt);
|
|
|
+ Pgno nFree = get4byte(&pBt->pPage1->aData[36]);
|
|
|
+ Pgno nFin = finalDbSize(pBt, nOrig, nFree);
|
|
|
+
|
|
|
+ if( nOrig<nFin ){
|
|
|
+ rc = SQLITE_CORRUPT_BKPT;
|
|
|
+ }else if( nFree>0 ){
|
|
|
+ invalidateAllOverflowCache(pBt);
|
|
|
+ rc = incrVacuumStep(pBt, nFin, nOrig, 0);
|
|
|
+ if( rc==SQLITE_OK ){
|
|
|
+ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
|
|
+ put4byte(&pBt->pPage1->aData[28], pBt->nPage);
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ rc = SQLITE_DONE;
|
|
|
}
|
|
|
}
|
|
|
sqlite3BtreeLeave(p);
|
|
|
@@ -51618,9 +51630,7 @@ static int autoVacuumCommit(BtShared *pBt){
|
|
|
if( !pBt->incrVacuum ){
|
|
|
Pgno nFin; /* Number of pages in database after autovacuuming */
|
|
|
Pgno nFree; /* Number of pages on the freelist initially */
|
|
|
- Pgno nPtrmap; /* Number of PtrMap pages to be freed */
|
|
|
Pgno iFree; /* The next page to be freed */
|
|
|
- int nEntry; /* Number of entries on one ptrmap page */
|
|
|
Pgno nOrig; /* Database size before freeing */
|
|
|
|
|
|
nOrig = btreePagecount(pBt);
|
|
|
@@ -51633,26 +51643,18 @@ static int autoVacuumCommit(BtShared *pBt){
|
|
|
}
|
|
|
|
|
|
nFree = get4byte(&pBt->pPage1->aData[36]);
|
|
|
- nEntry = pBt->usableSize/5;
|
|
|
- nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+nEntry)/nEntry;
|
|
|
- nFin = nOrig - nFree - nPtrmap;
|
|
|
- if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<PENDING_BYTE_PAGE(pBt) ){
|
|
|
- nFin--;
|
|
|
- }
|
|
|
- while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){
|
|
|
- nFin--;
|
|
|
- }
|
|
|
+ nFin = finalDbSize(pBt, nOrig, nFree);
|
|
|
if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT;
|
|
|
|
|
|
for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){
|
|
|
- rc = incrVacuumStep(pBt, nFin, iFree);
|
|
|
+ rc = incrVacuumStep(pBt, nFin, iFree, 1);
|
|
|
}
|
|
|
if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){
|
|
|
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
|
|
put4byte(&pBt->pPage1->aData[32], 0);
|
|
|
put4byte(&pBt->pPage1->aData[36], 0);
|
|
|
put4byte(&pBt->pPage1->aData[28], nFin);
|
|
|
- sqlite3PagerTruncateImage(pBt->pPager, nFin);
|
|
|
+ pBt->bDoTruncate = 1;
|
|
|
pBt->nPage = nFin;
|
|
|
}
|
|
|
if( rc!=SQLITE_OK ){
|
|
|
@@ -51707,6 +51709,9 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){
|
|
|
return rc;
|
|
|
}
|
|
|
}
|
|
|
+ if( pBt->bDoTruncate ){
|
|
|
+ sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage);
|
|
|
+ }
|
|
|
#endif
|
|
|
rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0);
|
|
|
sqlite3BtreeLeave(p);
|
|
|
@@ -51722,6 +51727,9 @@ static void btreeEndTransaction(Btree *p){
|
|
|
BtShared *pBt = p->pBt;
|
|
|
assert( sqlite3BtreeHoldsMutex(p) );
|
|
|
|
|
|
+#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
|
+ pBt->bDoTruncate = 0;
|
|
|
+#endif
|
|
|
btreeClearHasContent(pBt);
|
|
|
if( p->inTrans>TRANS_NONE && p->db->activeVdbeCnt>1 ){
|
|
|
/* If there are other active statements that belong to this database
|
|
|
@@ -53408,7 +53416,7 @@ static int allocateBtreePage(
|
|
|
MemPage **ppPage,
|
|
|
Pgno *pPgno,
|
|
|
Pgno nearby,
|
|
|
- u8 exact
|
|
|
+ u8 eMode
|
|
|
){
|
|
|
MemPage *pPage1;
|
|
|
int rc;
|
|
|
@@ -53436,16 +53444,19 @@ static int allocateBtreePage(
|
|
|
** the entire-list will be searched for that page.
|
|
|
*/
|
|
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
|
- if( exact && nearby<=mxPage ){
|
|
|
- u8 eType;
|
|
|
- assert( nearby>0 );
|
|
|
- assert( pBt->autoVacuum );
|
|
|
- rc = ptrmapGet(pBt, nearby, &eType, 0);
|
|
|
- if( rc ) return rc;
|
|
|
- if( eType==PTRMAP_FREEPAGE ){
|
|
|
- searchList = 1;
|
|
|
+ if( eMode==BTALLOC_EXACT ){
|
|
|
+ if( nearby<=mxPage ){
|
|
|
+ u8 eType;
|
|
|
+ assert( nearby>0 );
|
|
|
+ assert( pBt->autoVacuum );
|
|
|
+ rc = ptrmapGet(pBt, nearby, &eType, 0);
|
|
|
+ if( rc ) return rc;
|
|
|
+ if( eType==PTRMAP_FREEPAGE ){
|
|
|
+ searchList = 1;
|
|
|
+ }
|
|
|
}
|
|
|
- *pPgno = nearby;
|
|
|
+ }else if( eMode==BTALLOC_LE ){
|
|
|
+ searchList = 1;
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
@@ -53500,11 +53511,13 @@ static int allocateBtreePage(
|
|
|
rc = SQLITE_CORRUPT_BKPT;
|
|
|
goto end_allocate_page;
|
|
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
|
- }else if( searchList && nearby==iTrunk ){
|
|
|
+ }else if( searchList
|
|
|
+ && (nearby==iTrunk || (iTrunk<nearby && eMode==BTALLOC_LE))
|
|
|
+ ){
|
|
|
/* The list is being searched and this trunk page is the page
|
|
|
** to allocate, regardless of whether it has leaves.
|
|
|
*/
|
|
|
- assert( *pPgno==iTrunk );
|
|
|
+ *pPgno = iTrunk;
|
|
|
*ppPage = pTrunk;
|
|
|
searchList = 0;
|
|
|
rc = sqlite3PagerWrite(pTrunk->pDbPage);
|
|
|
@@ -53567,14 +53580,24 @@ static int allocateBtreePage(
|
|
|
unsigned char *aData = pTrunk->aData;
|
|
|
if( nearby>0 ){
|
|
|
u32 i;
|
|
|
- int dist;
|
|
|
closest = 0;
|
|
|
- dist = sqlite3AbsInt32(get4byte(&aData[8]) - nearby);
|
|
|
- for(i=1; i<k; i++){
|
|
|
- int d2 = sqlite3AbsInt32(get4byte(&aData[8+i*4]) - nearby);
|
|
|
- if( d2<dist ){
|
|
|
- closest = i;
|
|
|
- dist = d2;
|
|
|
+ if( eMode==BTALLOC_LE ){
|
|
|
+ for(i=0; i<k; i++){
|
|
|
+ iPage = get4byte(&aData[8+i*4]);
|
|
|
+ if( iPage<=nearby ){
|
|
|
+ closest = i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ int dist;
|
|
|
+ dist = sqlite3AbsInt32(get4byte(&aData[8]) - nearby);
|
|
|
+ for(i=1; i<k; i++){
|
|
|
+ int d2 = sqlite3AbsInt32(get4byte(&aData[8+i*4]) - nearby);
|
|
|
+ if( d2<dist ){
|
|
|
+ closest = i;
|
|
|
+ dist = d2;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}else{
|
|
|
@@ -53588,7 +53611,9 @@ static int allocateBtreePage(
|
|
|
goto end_allocate_page;
|
|
|
}
|
|
|
testcase( iPage==mxPage );
|
|
|
- if( !searchList || iPage==nearby ){
|
|
|
+ if( !searchList
|
|
|
+ || (iPage==nearby || (iPage<nearby && eMode==BTALLOC_LE))
|
|
|
+ ){
|
|
|
int noContent;
|
|
|
*pPgno = iPage;
|
|
|
TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
|
|
|
@@ -53615,8 +53640,26 @@ static int allocateBtreePage(
|
|
|
pPrevTrunk = 0;
|
|
|
}while( searchList );
|
|
|
}else{
|
|
|
- /* There are no pages on the freelist, so create a new page at the
|
|
|
- ** end of the file */
|
|
|
+ /* There are no pages on the freelist, so append a new page to the
|
|
|
+ ** database image.
|
|
|
+ **
|
|
|
+ ** Normally, new pages allocated by this block can be requested from the
|
|
|
+ ** pager layer with the 'no-content' flag set. This prevents the pager
|
|
|
+ ** from trying to read the pages content from disk. However, if the
|
|
|
+ ** current transaction has already run one or more incremental-vacuum
|
|
|
+ ** steps, then the page we are about to allocate may contain content
|
|
|
+ ** that is required in the event of a rollback. In this case, do
|
|
|
+ ** not set the no-content flag. This causes the pager to load and journal
|
|
|
+ ** the current page content before overwriting it.
|
|
|
+ **
|
|
|
+ ** Note that the pager will not actually attempt to load or journal
|
|
|
+ ** content for any page that really does lie past the end of the database
|
|
|
+ ** file on disk. So the effects of disabling the no-content optimization
|
|
|
+ ** here are confined to those pages that lie between the end of the
|
|
|
+ ** database image and the end of the database file.
|
|
|
+ */
|
|
|
+ int bNoContent = (0==pBt->bDoTruncate);
|
|
|
+
|
|
|
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
|
|
if( rc ) return rc;
|
|
|
pBt->nPage++;
|
|
|
@@ -53631,7 +53674,7 @@ static int allocateBtreePage(
|
|
|
MemPage *pPg = 0;
|
|
|
TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
|
|
|
assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
|
|
|
- rc = btreeGetPage(pBt, pBt->nPage, &pPg, 1);
|
|
|
+ rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent);
|
|
|
if( rc==SQLITE_OK ){
|
|
|
rc = sqlite3PagerWrite(pPg->pDbPage);
|
|
|
releasePage(pPg);
|
|
|
@@ -53645,7 +53688,7 @@ static int allocateBtreePage(
|
|
|
*pPgno = pBt->nPage;
|
|
|
|
|
|
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
|
|
|
- rc = btreeGetPage(pBt, *pPgno, ppPage, 1);
|
|
|
+ rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent);
|
|
|
if( rc ) return rc;
|
|
|
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
|
|
|
if( rc!=SQLITE_OK ){
|
|
|
@@ -55660,7 +55703,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
|
|
|
** be moved to the allocated page (unless the allocated page happens
|
|
|
** to reside at pgnoRoot).
|
|
|
*/
|
|
|
- rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, 1);
|
|
|
+ rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, BTALLOC_EXACT);
|
|
|
if( rc!=SQLITE_OK ){
|
|
|
return rc;
|
|
|
}
|
|
|
@@ -57352,7 +57395,6 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
|
|
nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
|
|
|
}
|
|
|
assert( nDestTruncate>0 );
|
|
|
- sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
|
|
|
|
|
|
if( pgszSrc<pgszDest ){
|
|
|
/* If the source page-size is smaller than the destination page-size,
|
|
|
@@ -57366,6 +57408,8 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
|
|
*/
|
|
|
const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
|
|
|
sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
|
|
|
+ Pgno iPg;
|
|
|
+ int nDstPage;
|
|
|
i64 iOff;
|
|
|
i64 iEnd;
|
|
|
|
|
|
@@ -57376,13 +57420,26 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
|
|
&& iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
|
|
|
));
|
|
|
|
|
|
- /* This call ensures that all data required to recreate the original
|
|
|
+ /* This block ensures that all data required to recreate the original
|
|
|
** database has been stored in the journal for pDestPager and the
|
|
|
** journal synced to disk. So at this point we may safely modify
|
|
|
** the database file in any way, knowing that if a power failure
|
|
|
** occurs, the original database will be reconstructed from the
|
|
|
** journal file. */
|
|
|
- rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1);
|
|
|
+ sqlite3PagerPagecount(pDestPager, &nDstPage);
|
|
|
+ for(iPg=nDestTruncate; rc==SQLITE_OK && iPg<=(Pgno)nDstPage; iPg++){
|
|
|
+ if( iPg!=PENDING_BYTE_PAGE(p->pDest->pBt) ){
|
|
|
+ DbPage *pPg;
|
|
|
+ rc = sqlite3PagerGet(pDestPager, iPg, &pPg);
|
|
|
+ if( rc==SQLITE_OK ){
|
|
|
+ rc = sqlite3PagerWrite(pPg);
|
|
|
+ sqlite3PagerUnref(pPg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if( rc==SQLITE_OK ){
|
|
|
+ rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1);
|
|
|
+ }
|
|
|
|
|
|
/* Write the extra pages and truncate the database file as required */
|
|
|
iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
|
|
|
@@ -57409,6 +57466,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
|
|
rc = sqlite3PagerSync(pDestPager);
|
|
|
}
|
|
|
}else{
|
|
|
+ sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
|
|
|
rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0);
|
|
|
}
|
|
|
|
|
|
@@ -72888,12 +72946,12 @@ SQLITE_PRIVATE int sqlite3MatchSpanName(
|
|
|
){
|
|
|
int n;
|
|
|
for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
|
|
|
- if( zDb && sqlite3StrNICmp(zSpan, zDb, n)!=0 ){
|
|
|
+ if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){
|
|
|
return 0;
|
|
|
}
|
|
|
zSpan += n+1;
|
|
|
for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
|
|
|
- if( zTab && sqlite3StrNICmp(zSpan, zTab, n)!=0 ){
|
|
|
+ if( zTab && (sqlite3StrNICmp(zSpan, zTab, n)!=0 || zTab[n]!=0) ){
|
|
|
return 0;
|
|
|
}
|
|
|
zSpan += n+1;
|
|
|
@@ -87030,6 +87088,56 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+** The unicode() function. Return the integer unicode code-point value
|
|
|
+** for the first character of the input string.
|
|
|
+*/
|
|
|
+static void unicodeFunc(
|
|
|
+ sqlite3_context *context,
|
|
|
+ int argc,
|
|
|
+ sqlite3_value **argv
|
|
|
+){
|
|
|
+ const unsigned char *z = sqlite3_value_text(argv[0]);
|
|
|
+ if( z && z[0] ) sqlite3_result_int(context, sqlite3Utf8Read(&z));
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+** The char() function takes zero or more arguments, each of which is
|
|
|
+** an integer. It constructs a string where each character of the string
|
|
|
+** is the unicode character for the corresponding integer argument.
|
|
|
+*/
|
|
|
+static void charFunc(
|
|
|
+ sqlite3_context *context,
|
|
|
+ int argc,
|
|
|
+ sqlite3_value **argv
|
|
|
+){
|
|
|
+ unsigned char *z, *zOut;
|
|
|
+ int i;
|
|
|
+ zOut = z = sqlite3_malloc( argc*4 );
|
|
|
+ if( z==0 ){
|
|
|
+ sqlite3_result_error_nomem(context);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ for(i=0; i<argc; i++){
|
|
|
+ sqlite3_int64 x;
|
|
|
+ unsigned c;
|
|
|
+ x = sqlite3_value_int64(argv[i]);
|
|
|
+ if( x<0 || x>0x10ffff ) x = 0xfffd;
|
|
|
+ c = (unsigned)(x & 0x1fffff);
|
|
|
+ if( c<=0xFFFF ){
|
|
|
+ *zOut++ = (u8)(c&0x00FF);
|
|
|
+ *zOut++ = (u8)((c>>8)&0x00FF);
|
|
|
+ }else{
|
|
|
+ if( c>=0xd800 && c<=0xdbff ) c = 0xfffd;
|
|
|
+ *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0));
|
|
|
+ *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03));
|
|
|
+ *zOut++ = (u8)(c&0x00FF);
|
|
|
+ *zOut++ = (u8)(0x00DC + ((c>>8)&0x03));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ sqlite3_result_text16le(context, (char*)z, (int)(zOut-z), sqlite3_free);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
** The hex() function. Interpret the argument as a blob. Return
|
|
|
** a hexadecimal rendering as text.
|
|
|
@@ -87657,6 +87765,8 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
|
|
|
FUNCTION(instr, 2, 0, 0, instrFunc ),
|
|
|
FUNCTION(substr, 2, 0, 0, substrFunc ),
|
|
|
FUNCTION(substr, 3, 0, 0, substrFunc ),
|
|
|
+ FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
|
|
|
+ FUNCTION(char, -1, 0, 0, charFunc ),
|
|
|
FUNCTION(abs, 1, 0, 0, absFunc ),
|
|
|
#ifndef SQLITE_OMIT_FLOATING_POINT
|
|
|
FUNCTION(round, 1, 0, 0, roundFunc ),
|