mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Stricter enforcement of cell sizes when doing balancing operations on the
btree, in order to catch file corruption sooner. FossilOrigin-Name: 12713f320b2c1def273dd8b7833dddaaad5331aba779d4b1ec9aa949814f38fe
This commit is contained in:
14
manifest
14
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Fix\sanother\sfts5\scrash\sthat\scan\soccur\sif\sthe\sdatabase\sis\scorrupted.
|
C Stricter\senforcement\sof\scell\ssizes\swhen\sdoing\sbalancing\soperations\son\sthe\nbtree,\sin\sorder\sto\scatch\sfile\scorruption\ssooner.
|
||||||
D 2019-01-23T19:17:05.201
|
D 2019-01-23T19:25:59.893
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F Makefile.in 0e7c107ebcaff26681bc5bcf017557db85aa828d6f7fd652d748b7a78072c298
|
F Makefile.in 0e7c107ebcaff26681bc5bcf017557db85aa828d6f7fd652d748b7a78072c298
|
||||||
@@ -455,7 +455,7 @@ F src/auth.c 0fac71038875693a937e506bceb492c5f136dd7b1249fbd4ae70b4e8da14f9df
|
|||||||
F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab
|
F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab
|
||||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||||
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||||
F src/btree.c 315ccbc0d23ec50c4b65c35bc64ff89f20575ab25a5605a01ae726461ba5dc6f
|
F src/btree.c 60fa67e135492b83c78517502cdd64dd1028da3fb5958cc130d94ba75f140b55
|
||||||
F src/btree.h febb2e817be499570b7a2e32a9bbb4b607a9234f6b84bb9ae84916d4806e96f2
|
F src/btree.h febb2e817be499570b7a2e32a9bbb4b607a9234f6b84bb9ae84916d4806e96f2
|
||||||
F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96
|
F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96
|
||||||
F src/build.c f07c0b154c23737d1699ee63bba31c8ca8b323e2446b957bc6bfec81a62295fc
|
F src/build.c f07c0b154c23737d1699ee63bba31c8ca8b323e2446b957bc6bfec81a62295fc
|
||||||
@@ -1802,7 +1802,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 0387cb3add992b2028efe4f2100188d8f9fdfdcb233329857aa4b46a293cfc97
|
P 44ce8baa47192be03c8f11777904c3c07fa5cc5c97b6d8e81572d380995ac688
|
||||||
R f2949632b0c8dd6250b3de3ff30ae3f1
|
R 394e54d0902bcab8f75c7f1ab86066f4
|
||||||
U dan
|
U drh
|
||||||
Z 76fed8aa680544a51accd6f3b00ea74a
|
Z 2303e2a69753b4d3e54ffe2a91200226
|
||||||
|
@@ -1 +1 @@
|
|||||||
44ce8baa47192be03c8f11777904c3c07fa5cc5c97b6d8e81572d380995ac688
|
12713f320b2c1def273dd8b7833dddaaad5331aba779d4b1ec9aa949814f38fe
|
204
src/btree.c
204
src/btree.c
@@ -6693,9 +6693,72 @@ static void insertCell(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following parameters determine how many adjacent pages get involved
|
||||||
|
** in a balancing operation. NN is the number of neighbors on either side
|
||||||
|
** of the page that participate in the balancing operation. NB is the
|
||||||
|
** total number of pages that participate, including the target page and
|
||||||
|
** NN neighbors on either side.
|
||||||
|
**
|
||||||
|
** The minimum value of NN is 1 (of course). Increasing NN above 1
|
||||||
|
** (to 2 or 3) gives a modest improvement in SELECT and DELETE performance
|
||||||
|
** in exchange for a larger degradation in INSERT and UPDATE performance.
|
||||||
|
** The value of NN appears to give the best results overall.
|
||||||
|
**
|
||||||
|
** (Later:) The description above makes it seem as if these values are
|
||||||
|
** tunable - as if you could change them and recompile and it would all work.
|
||||||
|
** But that is unlikely. NB has been 3 since the inception of SQLite and
|
||||||
|
** we have never tested any other value.
|
||||||
|
*/
|
||||||
|
#define NN 1 /* Number of neighbors on either side of pPage */
|
||||||
|
#define NB 3 /* (NN*2+1): Total pages involved in the balance */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** A CellArray object contains a cache of pointers and sizes for a
|
** A CellArray object contains a cache of pointers and sizes for a
|
||||||
** consecutive sequence of cells that might be held on multiple pages.
|
** consecutive sequence of cells that might be held on multiple pages.
|
||||||
|
**
|
||||||
|
** The cells in this array are the divider cell or cells from the pParent
|
||||||
|
** page plus up to three child pages. There are a total of nCell cells.
|
||||||
|
**
|
||||||
|
** pRef is a pointer to one of the pages that contributes cells. This is
|
||||||
|
** used to access information such as MemPage.intKey and MemPage.pBt->pageSize
|
||||||
|
** which should be common to all pages that contribute cells to this array.
|
||||||
|
**
|
||||||
|
** apCell[] and szCell[] hold, respectively, pointers to the start of each
|
||||||
|
** cell and the size of each cell. Some of the apCell[] pointers might refer
|
||||||
|
** to overflow cells. In other words, some apCel[] pointers might not point
|
||||||
|
** to content area of the pages.
|
||||||
|
**
|
||||||
|
** A szCell[] of zero means the size of that cell has not yet been computed.
|
||||||
|
**
|
||||||
|
** The cells come from as many as four different pages:
|
||||||
|
**
|
||||||
|
** -----------
|
||||||
|
** | Parent |
|
||||||
|
** -----------
|
||||||
|
** / | \
|
||||||
|
** / | \
|
||||||
|
** --------- --------- ---------
|
||||||
|
** |Child-1| |Child-2| |Child-3|
|
||||||
|
** --------- --------- ---------
|
||||||
|
**
|
||||||
|
** The order of cells is in the array is:
|
||||||
|
**
|
||||||
|
** 1. All cells from Child-1 in order
|
||||||
|
** 2. The first divider cell from Parent
|
||||||
|
** 3. All cells from Child-2 in order
|
||||||
|
** 4. The second divider cell from Parent
|
||||||
|
** 5. All cells from Child-3 in order
|
||||||
|
**
|
||||||
|
** The apEnd[] array holds pointer to the end of page for Child-1, the
|
||||||
|
** Parent, Child-2, the Parent (again), and Child-3. The ixNx[] array
|
||||||
|
** holds the number of cells contained in each of these 5 stages, and
|
||||||
|
** all stages to the left. Hence:
|
||||||
|
** ixNx[0] = Number of cells in Child-1.
|
||||||
|
** ixNx[1] = Number of cells in Child-1 plus 1 for first divider.
|
||||||
|
** ixNx[2] = Number of cells in Child-1 and Child-2 + 1 for 1st divider.
|
||||||
|
** ixNx[3] = Number of cells in Child-1 and Child-2 + both divider cells
|
||||||
|
** ixNx[4] = Total number of cells.
|
||||||
*/
|
*/
|
||||||
typedef struct CellArray CellArray;
|
typedef struct CellArray CellArray;
|
||||||
struct CellArray {
|
struct CellArray {
|
||||||
@@ -6703,6 +6766,8 @@ struct CellArray {
|
|||||||
MemPage *pRef; /* Reference page */
|
MemPage *pRef; /* Reference page */
|
||||||
u8 **apCell; /* All cells begin balanced */
|
u8 **apCell; /* All cells begin balanced */
|
||||||
u16 *szCell; /* Local size of all cells in apCell[] */
|
u16 *szCell; /* Local size of all cells in apCell[] */
|
||||||
|
u8 *apEnd[NB*2]; /* MemPage.aDataEnd values */
|
||||||
|
int ixNx[NB*2]; /* Index of at which we move to the next apEnd[] */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -6753,37 +6818,58 @@ static u16 cachedCellSize(CellArray *p, int N){
|
|||||||
** responsibility of the caller to set it correctly.
|
** responsibility of the caller to set it correctly.
|
||||||
*/
|
*/
|
||||||
static int rebuildPage(
|
static int rebuildPage(
|
||||||
MemPage *pPg, /* Edit this page */
|
CellArray *pCArray, /* Content to be added to page pPg */
|
||||||
|
int iFirst, /* First cell in pCArray to use */
|
||||||
int nCell, /* Final number of cells on page */
|
int nCell, /* Final number of cells on page */
|
||||||
u8 **apCell, /* Array of cells */
|
MemPage *pPg /* The page to be reconstructed */
|
||||||
u16 *szCell /* Array of cell sizes */
|
|
||||||
){
|
){
|
||||||
const int hdr = pPg->hdrOffset; /* Offset of header on pPg */
|
const int hdr = pPg->hdrOffset; /* Offset of header on pPg */
|
||||||
u8 * const aData = pPg->aData; /* Pointer to data for pPg */
|
u8 * const aData = pPg->aData; /* Pointer to data for pPg */
|
||||||
const int usableSize = pPg->pBt->usableSize;
|
const int usableSize = pPg->pBt->usableSize;
|
||||||
u8 * const pEnd = &aData[usableSize];
|
u8 * const pEnd = &aData[usableSize];
|
||||||
int i;
|
int i = iFirst; /* Which cell to copy from pCArray*/
|
||||||
|
int j; /* Start of cell content area */
|
||||||
|
int iEnd = i+nCell; /* Loop terminator */
|
||||||
u8 *pCellptr = pPg->aCellIdx;
|
u8 *pCellptr = pPg->aCellIdx;
|
||||||
u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager);
|
u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager);
|
||||||
u8 *pData;
|
u8 *pData;
|
||||||
|
int k; /* Current slot in pCArray->apEnd[] */
|
||||||
|
u8 *pSrcEnd; /* Current pCArray->apEnd[k] value */
|
||||||
|
|
||||||
i = get2byte(&aData[hdr+5]);
|
assert( i<iEnd );
|
||||||
memcpy(&pTmp[i], &aData[i], usableSize - i);
|
j = get2byte(&aData[hdr+5]);
|
||||||
|
memcpy(&pTmp[j], &aData[j], usableSize - j);
|
||||||
|
|
||||||
|
for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
|
||||||
|
pSrcEnd = pCArray->apEnd[k];
|
||||||
|
|
||||||
pData = pEnd;
|
pData = pEnd;
|
||||||
for(i=0; i<nCell; i++){
|
while( 1/*exit by break*/ ){
|
||||||
u8 *pCell = apCell[i];
|
u8 *pCell = pCArray->apCell[i];
|
||||||
|
u16 sz = pCArray->szCell[i];
|
||||||
|
assert( sz>0 );
|
||||||
if( SQLITE_WITHIN(pCell,aData,pEnd) ){
|
if( SQLITE_WITHIN(pCell,aData,pEnd) ){
|
||||||
if( ((uptr)(pCell+szCell[i]))>(uptr)pEnd ) return SQLITE_CORRUPT_BKPT;
|
if( ((uptr)(pCell+sz))>(uptr)pEnd ) return SQLITE_CORRUPT_BKPT;
|
||||||
pCell = &pTmp[pCell - aData];
|
pCell = &pTmp[pCell - aData];
|
||||||
|
}else if( (uptr)(pCell+sz)>(uptr)pSrcEnd
|
||||||
|
&& (uptr)(pCell)<(uptr)pSrcEnd
|
||||||
|
){
|
||||||
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
pData -= szCell[i];
|
|
||||||
|
pData -= sz;
|
||||||
put2byte(pCellptr, (pData - aData));
|
put2byte(pCellptr, (pData - aData));
|
||||||
pCellptr += 2;
|
pCellptr += 2;
|
||||||
if( pData < pCellptr ) return SQLITE_CORRUPT_BKPT;
|
if( pData < pCellptr ) return SQLITE_CORRUPT_BKPT;
|
||||||
memcpy(pData, pCell, szCell[i]);
|
memcpy(pData, pCell, sz);
|
||||||
assert( szCell[i]==pPg->xCellSize(pPg, pCell) || CORRUPT_DB );
|
assert( sz==pPg->xCellSize(pPg, pCell) || CORRUPT_DB );
|
||||||
testcase( szCell[i]!=pPg->xCellSize(pPg,pCell) );
|
testcase( sz!=pPg->xCellSize(pPg,pCell) );
|
||||||
|
i++;
|
||||||
|
if( i>=iEnd ) break;
|
||||||
|
if( pCArray->ixNx[k]<=i ){
|
||||||
|
k++;
|
||||||
|
pSrcEnd = pCArray->apEnd[k];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The pPg->nFree field is now set incorrectly. The caller will fix it. */
|
/* The pPg->nFree field is now set incorrectly. The caller will fix it. */
|
||||||
@@ -6798,12 +6884,11 @@ static int rebuildPage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Array apCell[] contains nCell pointers to b-tree cells. Array szCell
|
** The pCArray objects contains pointers to b-tree cells and the cell sizes.
|
||||||
** contains the size in bytes of each such cell. This function attempts to
|
** This function attempts to add the cells stored in the array to page pPg.
|
||||||
** add the cells stored in the array to page pPg. If it cannot (because
|
** If it cannot (because the page needs to be defragmented before the cells
|
||||||
** the page needs to be defragmented before the cells will fit), non-zero
|
** will fit), non-zero is returned. Otherwise, if the cells are added
|
||||||
** is returned. Otherwise, if the cells are added successfully, zero is
|
** successfully, zero is returned.
|
||||||
** returned.
|
|
||||||
**
|
**
|
||||||
** Argument pCellptr points to the first entry in the cell-pointer array
|
** Argument pCellptr points to the first entry in the cell-pointer array
|
||||||
** (part of page pPg) to populate. After cell apCell[0] is written to the
|
** (part of page pPg) to populate. After cell apCell[0] is written to the
|
||||||
@@ -6825,18 +6910,23 @@ static int rebuildPage(
|
|||||||
static int pageInsertArray(
|
static int pageInsertArray(
|
||||||
MemPage *pPg, /* Page to add cells to */
|
MemPage *pPg, /* Page to add cells to */
|
||||||
u8 *pBegin, /* End of cell-pointer array */
|
u8 *pBegin, /* End of cell-pointer array */
|
||||||
u8 **ppData, /* IN/OUT: Page content -area pointer */
|
u8 **ppData, /* IN/OUT: Page content-area pointer */
|
||||||
u8 *pCellptr, /* Pointer to cell-pointer area */
|
u8 *pCellptr, /* Pointer to cell-pointer area */
|
||||||
int iFirst, /* Index of first cell to add */
|
int iFirst, /* Index of first cell to add */
|
||||||
int nCell, /* Number of cells to add to pPg */
|
int nCell, /* Number of cells to add to pPg */
|
||||||
CellArray *pCArray /* Array of cells */
|
CellArray *pCArray /* Array of cells */
|
||||||
){
|
){
|
||||||
int i;
|
int i = iFirst; /* Loop counter - cell index to insert */
|
||||||
u8 *aData = pPg->aData;
|
u8 *aData = pPg->aData; /* Complete page */
|
||||||
u8 *pData = *ppData;
|
u8 *pData = *ppData; /* Content area. A subset of aData[] */
|
||||||
int iEnd = iFirst + nCell;
|
int iEnd = iFirst + nCell; /* End of loop. One past last cell to ins */
|
||||||
|
int k; /* Current slot in pCArray->apEnd[] */
|
||||||
|
u8 *pEnd; /* Maximum extent of cell data */
|
||||||
assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */
|
assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */
|
||||||
for(i=iFirst; i<iEnd; i++){
|
if( iEnd<=iFirst ) return 0;
|
||||||
|
for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
|
||||||
|
pEnd = pCArray->apEnd[k];
|
||||||
|
while( 1 /*Exit by break*/ ){
|
||||||
int sz, rc;
|
int sz, rc;
|
||||||
u8 *pSlot;
|
u8 *pSlot;
|
||||||
sz = cachedCellSize(pCArray, i);
|
sz = cachedCellSize(pCArray, i);
|
||||||
@@ -6851,20 +6941,33 @@ static int pageInsertArray(
|
|||||||
assert( (pSlot+sz)<=pCArray->apCell[i]
|
assert( (pSlot+sz)<=pCArray->apCell[i]
|
||||||
|| pSlot>=(pCArray->apCell[i]+sz)
|
|| pSlot>=(pCArray->apCell[i]+sz)
|
||||||
|| CORRUPT_DB );
|
|| CORRUPT_DB );
|
||||||
|
if( (uptr)(pCArray->apCell[i]+sz)>(uptr)pEnd
|
||||||
|
&& (uptr)(pCArray->apCell[i])<(uptr)pEnd
|
||||||
|
){
|
||||||
|
assert( CORRUPT_DB );
|
||||||
|
(void)SQLITE_CORRUPT_BKPT;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
memmove(pSlot, pCArray->apCell[i], sz);
|
memmove(pSlot, pCArray->apCell[i], sz);
|
||||||
put2byte(pCellptr, (pSlot - aData));
|
put2byte(pCellptr, (pSlot - aData));
|
||||||
pCellptr += 2;
|
pCellptr += 2;
|
||||||
|
i++;
|
||||||
|
if( i>=iEnd ) break;
|
||||||
|
if( pCArray->ixNx[k]<=i ){
|
||||||
|
k++;
|
||||||
|
pEnd = pCArray->apEnd[k];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*ppData = pData;
|
*ppData = pData;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Array apCell[] contains nCell pointers to b-tree cells. Array szCell
|
** The pCArray object contains pointers to b-tree cells and their sizes.
|
||||||
** contains the size in bytes of each such cell. This function adds the
|
**
|
||||||
** space associated with each cell in the array that is currently stored
|
** This function adds the space associated with each cell in the array
|
||||||
** within the body of pPg to the pPg free-list. The cell-pointers and other
|
** that is currently stored within the body of pPg to the pPg free-list.
|
||||||
** fields of the page are not updated.
|
** The cell-pointers and other fields of the page are not updated.
|
||||||
**
|
**
|
||||||
** This function returns the total number of cells added to the free-list.
|
** This function returns the total number of cells added to the free-list.
|
||||||
*/
|
*/
|
||||||
@@ -6914,9 +7017,9 @@ static int pageFreeArray(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** apCell[] and szCell[] contains pointers to and sizes of all cells in the
|
** pCArray contains pointers to and sizes of all cells in the pages being
|
||||||
** pages being balanced. The current page, pPg, has pPg->nCell cells starting
|
** balanced. The current page, pPg, has pPg->nCell cells starting with
|
||||||
** with apCell[iOld]. After balancing, this page should hold nNew cells
|
** pCArray->apCell[iOld]. After balancing, this page should hold nNew cells
|
||||||
** starting at apCell[iNew].
|
** starting at apCell[iNew].
|
||||||
**
|
**
|
||||||
** This routine makes the necessary adjustments to pPg so that it contains
|
** This routine makes the necessary adjustments to pPg so that it contains
|
||||||
@@ -7016,24 +7119,9 @@ static int editPage(
|
|||||||
editpage_fail:
|
editpage_fail:
|
||||||
/* Unable to edit this page. Rebuild it from scratch instead. */
|
/* Unable to edit this page. Rebuild it from scratch instead. */
|
||||||
populateCellCache(pCArray, iNew, nNew);
|
populateCellCache(pCArray, iNew, nNew);
|
||||||
return rebuildPage(pPg, nNew, &pCArray->apCell[iNew], &pCArray->szCell[iNew]);
|
return rebuildPage(pCArray, iNew, nNew, pPg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
** The following parameters determine how many adjacent pages get involved
|
|
||||||
** in a balancing operation. NN is the number of neighbors on either side
|
|
||||||
** of the page that participate in the balancing operation. NB is the
|
|
||||||
** total number of pages that participate, including the target page and
|
|
||||||
** NN neighbors on either side.
|
|
||||||
**
|
|
||||||
** The minimum value of NN is 1 (of course). Increasing NN above 1
|
|
||||||
** (to 2 or 3) gives a modest improvement in SELECT and DELETE performance
|
|
||||||
** in exchange for a larger degradation in INSERT and UPDATE performance.
|
|
||||||
** The value of NN appears to give the best results overall.
|
|
||||||
*/
|
|
||||||
#define NN 1 /* Number of neighbors on either side of pPage */
|
|
||||||
#define NB (NN*2+1) /* Total pages involved in the balance */
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_QUICKBALANCE
|
#ifndef SQLITE_OMIT_QUICKBALANCE
|
||||||
/*
|
/*
|
||||||
@@ -7083,12 +7171,22 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
|
|||||||
u8 *pCell = pPage->apOvfl[0];
|
u8 *pCell = pPage->apOvfl[0];
|
||||||
u16 szCell = pPage->xCellSize(pPage, pCell);
|
u16 szCell = pPage->xCellSize(pPage, pCell);
|
||||||
u8 *pStop;
|
u8 *pStop;
|
||||||
|
CellArray b;
|
||||||
|
|
||||||
assert( sqlite3PagerIswriteable(pNew->pDbPage) );
|
assert( sqlite3PagerIswriteable(pNew->pDbPage) );
|
||||||
assert( pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) );
|
assert( pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) );
|
||||||
zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF);
|
zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF);
|
||||||
rc = rebuildPage(pNew, 1, &pCell, &szCell);
|
b.nCell = 1;
|
||||||
if( NEVER(rc) ) return rc;
|
b.pRef = pPage;
|
||||||
|
b.apCell = &pCell;
|
||||||
|
b.szCell = &szCell;
|
||||||
|
b.apEnd[0] = pPage->aDataEnd;
|
||||||
|
b.ixNx[0] = 2;
|
||||||
|
rc = rebuildPage(&b, 0, 1, pNew);
|
||||||
|
if( NEVER(rc) ){
|
||||||
|
releasePage(pNew);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
pNew->nFree = pBt->usableSize - pNew->cellOffset - 2 - szCell;
|
pNew->nFree = pBt->usableSize - pNew->cellOffset - 2 - szCell;
|
||||||
|
|
||||||
/* If this is an auto-vacuum database, update the pointer map
|
/* If this is an auto-vacuum database, update the pointer map
|
||||||
@@ -7568,6 +7666,10 @@ static int balance_nonroot(
|
|||||||
usableSpace = pBt->usableSize - 12 + leafCorrection;
|
usableSpace = pBt->usableSize - 12 + leafCorrection;
|
||||||
for(i=0; i<nOld; i++){
|
for(i=0; i<nOld; i++){
|
||||||
MemPage *p = apOld[i];
|
MemPage *p = apOld[i];
|
||||||
|
b.apEnd[i*2] = p->aDataEnd;
|
||||||
|
b.apEnd[i*2+1] = pParent->aDataEnd;
|
||||||
|
b.ixNx[i*2] = cntOld[i];
|
||||||
|
b.ixNx[i*2+1] = cntOld[i]+1;
|
||||||
szNew[i] = usableSpace - p->nFree;
|
szNew[i] = usableSpace - p->nFree;
|
||||||
for(j=0; j<p->nOverflow; j++){
|
for(j=0; j<p->nOverflow; j++){
|
||||||
szNew[i] += 2 + p->xCellSize(p, p->apOvfl[j]);
|
szNew[i] += 2 + p->xCellSize(p, p->apOvfl[j]);
|
||||||
|
Reference in New Issue
Block a user