mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Fix some problems with using fts5 options 'secure-delete' and detail=none together.
FossilOrigin-Name: 4d3f27ba90aa59837e49ceaae9f36cad426af3a33707d85d1bb848fc1bda6fed
This commit is contained in:
@ -1954,7 +1954,7 @@ static void fts5SegIterNext_None(
|
|||||||
iOff = pIter->iLeafOffset;
|
iOff = pIter->iLeafOffset;
|
||||||
|
|
||||||
/* Next entry is on the next page */
|
/* Next entry is on the next page */
|
||||||
if( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
|
while( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
|
||||||
fts5SegIterNextPage(p, pIter);
|
fts5SegIterNextPage(p, pIter);
|
||||||
if( p->rc || pIter->pLeaf==0 ) return;
|
if( p->rc || pIter->pLeaf==0 ) return;
|
||||||
pIter->iRowid = 0;
|
pIter->iRowid = 0;
|
||||||
@ -4601,6 +4601,7 @@ static void fts5SecureDeleteOverflow(
|
|||||||
int iPgno,
|
int iPgno,
|
||||||
int *pbLastInDoclist
|
int *pbLastInDoclist
|
||||||
){
|
){
|
||||||
|
const int bDetailNone = (p->pConfig->eDetail==FTS5_DETAIL_NONE);
|
||||||
int pgno;
|
int pgno;
|
||||||
Fts5Data *pLeaf = 0;
|
Fts5Data *pLeaf = 0;
|
||||||
assert( iPgno!=1 );
|
assert( iPgno!=1 );
|
||||||
@ -4627,9 +4628,12 @@ static void fts5SecureDeleteOverflow(
|
|||||||
/* The page contains no terms or rowids. Replace it with an empty
|
/* The page contains no terms or rowids. Replace it with an empty
|
||||||
** page and move on to the right-hand peer. */
|
** page and move on to the right-hand peer. */
|
||||||
const u8 aEmpty[] = {0x00, 0x00, 0x00, 0x04};
|
const u8 aEmpty[] = {0x00, 0x00, 0x00, 0x04};
|
||||||
fts5DataWrite(p, iRowid, aEmpty, sizeof(aEmpty));
|
assert_nc( bDetailNone==0 || pLeaf->nn==4 );
|
||||||
|
if( bDetailNone==0 ) fts5DataWrite(p, iRowid, aEmpty, sizeof(aEmpty));
|
||||||
fts5DataRelease(pLeaf);
|
fts5DataRelease(pLeaf);
|
||||||
pLeaf = 0;
|
pLeaf = 0;
|
||||||
|
}else if( bDetailNone ){
|
||||||
|
break;
|
||||||
}else{
|
}else{
|
||||||
int nShift = iNext - 4;
|
int nShift = iNext - 4;
|
||||||
int nPg;
|
int nPg;
|
||||||
@ -4678,6 +4682,245 @@ static void fts5SecureDeleteOverflow(
|
|||||||
fts5DataRelease(pLeaf);
|
fts5DataRelease(pLeaf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Completely remove the entry that pSeg currently points to from
|
||||||
|
** the database.
|
||||||
|
*/
|
||||||
|
static void fts5DoSecureDelete(
|
||||||
|
Fts5Index *p,
|
||||||
|
Fts5Structure *pStruct,
|
||||||
|
Fts5SegIter *pSeg
|
||||||
|
){
|
||||||
|
const int bDetailNone = (p->pConfig->eDetail==FTS5_DETAIL_NONE);
|
||||||
|
int iSegid = pSeg->pSeg->iSegid;
|
||||||
|
u8 *aPg = pSeg->pLeaf->p;
|
||||||
|
int nPg = pSeg->pLeaf->nn;
|
||||||
|
int iPgIdx = pSeg->pLeaf->szLeaf;
|
||||||
|
|
||||||
|
u64 iDelta = 0;
|
||||||
|
u64 iNextDelta = 0;
|
||||||
|
int iNextOff = 0;
|
||||||
|
int iOff = 0;
|
||||||
|
int nIdx = 0;
|
||||||
|
u8 *aIdx = 0;
|
||||||
|
int bLastInDoclist = 0;
|
||||||
|
int iIdx = 0;
|
||||||
|
int iStart = 0;
|
||||||
|
int iKeyOff = 0;
|
||||||
|
int iPrevKeyOff = 0;
|
||||||
|
int iDelKeyOff = 0; /* Offset of deleted key, if any */
|
||||||
|
|
||||||
|
nIdx = nPg-iPgIdx;
|
||||||
|
aIdx = sqlite3Fts5MallocZero(&p->rc, nIdx+16);
|
||||||
|
if( p->rc ) return;
|
||||||
|
memcpy(aIdx, &aPg[iPgIdx], nIdx);
|
||||||
|
|
||||||
|
/* At this point segment iterator pSeg points to the entry
|
||||||
|
** this function should remove from the b-tree segment.
|
||||||
|
**
|
||||||
|
** In detail=full or detail=column mode, pSeg->iLeafOffset is the
|
||||||
|
** offset of the first byte in the position-list for the entry to
|
||||||
|
** remove. Immediately before this comes two varints that will also
|
||||||
|
** need to be removed:
|
||||||
|
**
|
||||||
|
** + the rowid or delta rowid value for the entry, and
|
||||||
|
** + the size of the position list in bytes.
|
||||||
|
**
|
||||||
|
** Or, in detail=none mode, there is a single varint prior to
|
||||||
|
** pSeg->iLeafOffset - the rowid or delta rowid value.
|
||||||
|
**
|
||||||
|
** This block sets the following variables:
|
||||||
|
**
|
||||||
|
** iStart:
|
||||||
|
** iDelta:
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int iSOP;
|
||||||
|
if( pSeg->iLeafPgno==pSeg->iTermLeafPgno ){
|
||||||
|
iStart = pSeg->iTermLeafOffset;
|
||||||
|
}else{
|
||||||
|
iStart = fts5GetU16(&aPg[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
|
||||||
|
assert_nc( iSOP<=pSeg->iLeafOffset );
|
||||||
|
|
||||||
|
if( bDetailNone ){
|
||||||
|
while( iSOP<pSeg->iLeafOffset ){
|
||||||
|
if( aPg[iSOP]==0x00 ) iSOP++;
|
||||||
|
if( aPg[iSOP]==0x00 ) iSOP++;
|
||||||
|
iStart = iSOP;
|
||||||
|
iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
|
||||||
|
}
|
||||||
|
|
||||||
|
iNextOff = iSOP;
|
||||||
|
if( iNextOff<pSeg->iEndofDoclist && aPg[iNextOff]==0x00 ) iNextOff++;
|
||||||
|
if( iNextOff<pSeg->iEndofDoclist && aPg[iNextOff]==0x00 ) iNextOff++;
|
||||||
|
|
||||||
|
}else{
|
||||||
|
int nPos = 0;
|
||||||
|
iSOP += fts5GetVarint32(&aPg[iSOP], nPos);
|
||||||
|
while( iSOP<pSeg->iLeafOffset ){
|
||||||
|
iStart = iSOP + (nPos/2);
|
||||||
|
iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
|
||||||
|
iSOP += fts5GetVarint32(&aPg[iSOP], nPos);
|
||||||
|
}
|
||||||
|
assert_nc( iSOP==pSeg->iLeafOffset );
|
||||||
|
iNextOff = pSeg->iLeafOffset + pSeg->nPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iOff = iStart;
|
||||||
|
if( iNextOff>=iPgIdx ){
|
||||||
|
int pgno = pSeg->iLeafPgno+1;
|
||||||
|
fts5SecureDeleteOverflow(p, pSeg->pSeg, pgno, &bLastInDoclist);
|
||||||
|
iNextOff = iPgIdx;
|
||||||
|
}else{
|
||||||
|
/* Set bLastInDoclist to true if the entry being removed is the last
|
||||||
|
** in its doclist. */
|
||||||
|
for(iIdx=0, iKeyOff=0; iIdx<nIdx; /* no-op */){
|
||||||
|
u32 iVal = 0;
|
||||||
|
iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
|
||||||
|
iKeyOff += iVal;
|
||||||
|
if( iKeyOff==iNextOff ){
|
||||||
|
bLastInDoclist = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( fts5GetU16(&aPg[0])==iStart && (bLastInDoclist||iNextOff==iPgIdx) ){
|
||||||
|
fts5PutU16(&aPg[0], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( bLastInDoclist==0 ){
|
||||||
|
if( iNextOff!=iPgIdx ){
|
||||||
|
iNextOff += fts5GetVarint(&aPg[iNextOff], &iNextDelta);
|
||||||
|
iOff += sqlite3Fts5PutVarint(&aPg[iOff], iDelta + iNextDelta);
|
||||||
|
}
|
||||||
|
}else if(
|
||||||
|
iStart==pSeg->iTermLeafOffset && pSeg->iLeafPgno==pSeg->iTermLeafPgno
|
||||||
|
){
|
||||||
|
/* The entry being removed was the only position list in its
|
||||||
|
** doclist. Therefore the term needs to be removed as well. */
|
||||||
|
int iKey = 0;
|
||||||
|
for(iIdx=0, iKeyOff=0; iIdx<nIdx; iKey++){
|
||||||
|
u32 iVal = 0;
|
||||||
|
iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
|
||||||
|
if( (iKeyOff+iVal)>iStart ) break;
|
||||||
|
iKeyOff += iVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
iDelKeyOff = iOff = iKeyOff;
|
||||||
|
if( iNextOff!=iPgIdx ){
|
||||||
|
int nPrefix = 0;
|
||||||
|
int nSuffix = 0;
|
||||||
|
int nPrefix2 = 0;
|
||||||
|
int nSuffix2 = 0;
|
||||||
|
|
||||||
|
iDelKeyOff = iNextOff;
|
||||||
|
iNextOff += fts5GetVarint32(&aPg[iNextOff], nPrefix2);
|
||||||
|
iNextOff += fts5GetVarint32(&aPg[iNextOff], nSuffix2);
|
||||||
|
|
||||||
|
if( iKey!=1 ){
|
||||||
|
iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nPrefix);
|
||||||
|
}
|
||||||
|
iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nSuffix);
|
||||||
|
|
||||||
|
nPrefix = MIN(nPrefix, nPrefix2);
|
||||||
|
nSuffix = (nPrefix2 + nSuffix2) - nPrefix;
|
||||||
|
|
||||||
|
if( (iKeyOff+nSuffix)>iPgIdx || (iNextOff+nSuffix2)>iPgIdx ){
|
||||||
|
p->rc = FTS5_CORRUPT;
|
||||||
|
}else{
|
||||||
|
if( iKey!=1 ){
|
||||||
|
iOff += sqlite3Fts5PutVarint(&aPg[iOff], nPrefix);
|
||||||
|
}
|
||||||
|
iOff += sqlite3Fts5PutVarint(&aPg[iOff], nSuffix);
|
||||||
|
if( nPrefix2>nPrefix ){
|
||||||
|
memcpy(&aPg[iOff], &pSeg->term.p[nPrefix], nPrefix2-nPrefix);
|
||||||
|
iOff += (nPrefix2-nPrefix);
|
||||||
|
}
|
||||||
|
memmove(&aPg[iOff], &aPg[iNextOff], nSuffix2);
|
||||||
|
iOff += nSuffix2;
|
||||||
|
iNextOff += nSuffix2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else if( iStart==4 ){
|
||||||
|
assert_nc( pSeg->iLeafPgno>pSeg->iTermLeafPgno );
|
||||||
|
/* The entry being removed may be the only position list in
|
||||||
|
** its doclist. */
|
||||||
|
int iPgno = pSeg->iLeafPgno-1;
|
||||||
|
|
||||||
|
for(iPgno=pSeg->iLeafPgno-1; iPgno>pSeg->iTermLeafPgno; iPgno-- ){
|
||||||
|
Fts5Data *pPg = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, iPgno));
|
||||||
|
int bEmpty = (pPg && pPg->nn==4);
|
||||||
|
fts5DataRelease(pPg);
|
||||||
|
if( bEmpty==0 ) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( iPgno==pSeg->iTermLeafPgno ){
|
||||||
|
i64 iId = FTS5_SEGMENT_ROWID(iSegid, pSeg->iTermLeafPgno);
|
||||||
|
Fts5Data *pTerm = fts5DataRead(p, iId);
|
||||||
|
if( pTerm && pTerm->szLeaf==pSeg->iTermLeafOffset ){
|
||||||
|
u8 *aTermIdx = &pTerm->p[pTerm->szLeaf];
|
||||||
|
int nTermIdx = pTerm->nn - pTerm->szLeaf;
|
||||||
|
int iTermIdx = 0;
|
||||||
|
int iTermOff = 0;
|
||||||
|
|
||||||
|
while( 1 ){
|
||||||
|
u32 iVal = 0;
|
||||||
|
int nByte = fts5GetVarint32(&aTermIdx[iTermIdx], iVal);
|
||||||
|
iTermOff += iVal;
|
||||||
|
if( (iTermIdx+nByte)>=nTermIdx ) break;
|
||||||
|
iTermIdx += nByte;
|
||||||
|
}
|
||||||
|
nTermIdx = iTermIdx;
|
||||||
|
|
||||||
|
memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx);
|
||||||
|
fts5PutU16(&pTerm->p[2], iTermOff);
|
||||||
|
|
||||||
|
fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx);
|
||||||
|
if( nTermIdx==0 ){
|
||||||
|
fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fts5DataRelease(pTerm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( p->rc==SQLITE_OK ){
|
||||||
|
const int nMove = nPg - iNextOff;
|
||||||
|
int nShift = 0;
|
||||||
|
|
||||||
|
memmove(&aPg[iOff], &aPg[iNextOff], nMove);
|
||||||
|
iPgIdx -= (iNextOff - iOff);
|
||||||
|
nPg = iPgIdx;
|
||||||
|
fts5PutU16(&aPg[2], iPgIdx);
|
||||||
|
|
||||||
|
nShift = iNextOff - iOff;
|
||||||
|
for(iIdx=0, iKeyOff=0, iPrevKeyOff=0; iIdx<nIdx; /* no-op */){
|
||||||
|
u32 iVal = 0;
|
||||||
|
iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
|
||||||
|
iKeyOff += iVal;
|
||||||
|
if( iKeyOff!=iDelKeyOff ){
|
||||||
|
if( iKeyOff>iOff ){
|
||||||
|
iKeyOff -= nShift;
|
||||||
|
nShift = 0;
|
||||||
|
}
|
||||||
|
nPg += sqlite3Fts5PutVarint(&aPg[nPg], iKeyOff - iPrevKeyOff);
|
||||||
|
iPrevKeyOff = iKeyOff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( iPgIdx==nPg && nIdx>0 && pSeg->iLeafPgno!=1 ){
|
||||||
|
fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iLeafPgno);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_nc( nPg>4 || fts5GetU16(aPg)==0 );
|
||||||
|
fts5DataWrite(p, FTS5_SEGMENT_ROWID(iSegid,pSeg->iLeafPgno), aPg,nPg);
|
||||||
|
}
|
||||||
|
sqlite3_free(aIdx);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This is called as part of flushing a delete to disk in 'secure-delete'
|
** This is called as part of flushing a delete to disk in 'secure-delete'
|
||||||
@ -4706,213 +4949,7 @@ static void fts5FlushSecureDelete(
|
|||||||
&& iRowid==fts5MultiIterRowid(pIter)
|
&& iRowid==fts5MultiIterRowid(pIter)
|
||||||
){
|
){
|
||||||
Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
|
Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
|
||||||
int iSegid = pSeg->pSeg->iSegid;
|
fts5DoSecureDelete(p, pStruct, pSeg);
|
||||||
u8 *aPg = pSeg->pLeaf->p;
|
|
||||||
int nPg = pSeg->pLeaf->nn;
|
|
||||||
int iPgIdx = pSeg->pLeaf->szLeaf;
|
|
||||||
|
|
||||||
u64 iDelta = 0;
|
|
||||||
u64 iNextDelta = 0;
|
|
||||||
int iNextOff = 0;
|
|
||||||
int iOff = 0;
|
|
||||||
int nMove = 0;
|
|
||||||
int nIdx = 0;
|
|
||||||
|
|
||||||
u8 *aIdx = 0;
|
|
||||||
|
|
||||||
nIdx = nPg-iPgIdx;
|
|
||||||
aIdx = sqlite3Fts5MallocZero(&p->rc, nIdx+16);
|
|
||||||
if( aIdx ){
|
|
||||||
int bLastInDoclist = 0;
|
|
||||||
int iIdx = 0;
|
|
||||||
int iStart = 0;
|
|
||||||
int iKeyOff = 0;
|
|
||||||
int iPrevKeyOff = 0;
|
|
||||||
int nShift = 0;
|
|
||||||
int iDelKeyOff = 0; /* Offset of deleted key, if any */
|
|
||||||
memcpy(aIdx, &aPg[iPgIdx], nIdx);
|
|
||||||
|
|
||||||
/* At this point segment iterator pSeg points to the entry
|
|
||||||
** this function should remove from the b-tree segment.
|
|
||||||
**
|
|
||||||
** More specifically, pSeg->iLeafOffset is the offset of the
|
|
||||||
** first byte in the position-list for the entry to remove.
|
|
||||||
** Immediately before this comes two varints that will also
|
|
||||||
** need to be removed:
|
|
||||||
**
|
|
||||||
** + the rowid or delta rowid value for the entry, and
|
|
||||||
** + the size of the position list in bytes.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
int iSOP;
|
|
||||||
int nPos = 0;
|
|
||||||
if( pSeg->iLeafPgno==pSeg->iTermLeafPgno ){
|
|
||||||
iStart = pSeg->iTermLeafOffset;
|
|
||||||
}else{
|
|
||||||
iStart = fts5GetU16(&aPg[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
|
|
||||||
iSOP += fts5GetVarint32(&aPg[iSOP], nPos);
|
|
||||||
assert_nc( iSOP<=pSeg->iLeafOffset );
|
|
||||||
while( iSOP<pSeg->iLeafOffset ){
|
|
||||||
iStart = iSOP + (nPos/2);
|
|
||||||
iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
|
|
||||||
iSOP += fts5GetVarint32(&aPg[iSOP], nPos);
|
|
||||||
}
|
|
||||||
assert_nc( iSOP==pSeg->iLeafOffset );
|
|
||||||
}
|
|
||||||
|
|
||||||
iOff = iStart;
|
|
||||||
iNextOff = pSeg->iLeafOffset + pSeg->nPos;
|
|
||||||
if( iNextOff>=iPgIdx ){
|
|
||||||
int pgno = pSeg->iLeafPgno+1;
|
|
||||||
fts5SecureDeleteOverflow(p, pSeg->pSeg, pgno, &bLastInDoclist);
|
|
||||||
iNextOff = iPgIdx;
|
|
||||||
}else{
|
|
||||||
/* Set bLastInDoclist to true if the entry being removed is the last
|
|
||||||
** in its doclist. */
|
|
||||||
for(iIdx=0, iKeyOff=0; iIdx<nIdx; /* no-op */){
|
|
||||||
u32 iVal = 0;
|
|
||||||
iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
|
|
||||||
iKeyOff += iVal;
|
|
||||||
if( iKeyOff==iNextOff ){
|
|
||||||
bLastInDoclist = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( fts5GetU16(&aPg[0])==iStart && (bLastInDoclist||iNextOff==iPgIdx) ){
|
|
||||||
fts5PutU16(&aPg[0], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( bLastInDoclist==0 ){
|
|
||||||
if( iNextOff!=iPgIdx ){
|
|
||||||
iNextOff += fts5GetVarint(&aPg[iNextOff], &iNextDelta);
|
|
||||||
iOff += sqlite3Fts5PutVarint(&aPg[iOff], iDelta + iNextDelta);
|
|
||||||
}
|
|
||||||
}else if(
|
|
||||||
iStart==pSeg->iTermLeafOffset && pSeg->iLeafPgno==pSeg->iTermLeafPgno
|
|
||||||
){
|
|
||||||
/* The entry being removed was the only position list in its
|
|
||||||
** doclist. Therefore the term needs to be removed as well. */
|
|
||||||
int iKey = 0;
|
|
||||||
for(iIdx=0, iKeyOff=0; iIdx<nIdx; iKey++){
|
|
||||||
u32 iVal = 0;
|
|
||||||
iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
|
|
||||||
if( (iKeyOff+iVal)>iStart ) break;
|
|
||||||
iKeyOff += iVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
iDelKeyOff = iOff = iKeyOff;
|
|
||||||
if( iNextOff!=iPgIdx ){
|
|
||||||
int nPrefix = 0;
|
|
||||||
int nSuffix = 0;
|
|
||||||
int nPrefix2 = 0;
|
|
||||||
int nSuffix2 = 0;
|
|
||||||
|
|
||||||
iDelKeyOff = iNextOff;
|
|
||||||
iNextOff += fts5GetVarint32(&aPg[iNextOff], nPrefix2);
|
|
||||||
iNextOff += fts5GetVarint32(&aPg[iNextOff], nSuffix2);
|
|
||||||
|
|
||||||
if( iKey!=1 ){
|
|
||||||
iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nPrefix);
|
|
||||||
}
|
|
||||||
iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nSuffix);
|
|
||||||
|
|
||||||
nPrefix = MIN(nPrefix, nPrefix2);
|
|
||||||
nSuffix = (nPrefix2 + nSuffix2) - nPrefix;
|
|
||||||
|
|
||||||
if( (iKeyOff+nSuffix)>iPgIdx || (iNextOff+nSuffix2)>iPgIdx ){
|
|
||||||
p->rc = FTS5_CORRUPT;
|
|
||||||
}else{
|
|
||||||
if( iKey!=1 ){
|
|
||||||
iOff += sqlite3Fts5PutVarint(&aPg[iOff], nPrefix);
|
|
||||||
}
|
|
||||||
iOff += sqlite3Fts5PutVarint(&aPg[iOff], nSuffix);
|
|
||||||
if( nPrefix2>nPrefix ){
|
|
||||||
memcpy(&aPg[iOff], &zTerm[nPrefix], nPrefix2-nPrefix);
|
|
||||||
iOff += (nPrefix2-nPrefix);
|
|
||||||
}
|
|
||||||
memmove(&aPg[iOff], &aPg[iNextOff], nSuffix2);
|
|
||||||
iOff += nSuffix2;
|
|
||||||
iNextOff += nSuffix2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}else if( iStart==4 ){
|
|
||||||
assert_nc( pSeg->iLeafPgno>pSeg->iTermLeafPgno );
|
|
||||||
/* The entry being removed may be the only position list in
|
|
||||||
** its doclist. */
|
|
||||||
int iPgno = pSeg->iLeafPgno-1;
|
|
||||||
|
|
||||||
for(iPgno=pSeg->iLeafPgno-1; iPgno>pSeg->iTermLeafPgno; iPgno-- ){
|
|
||||||
Fts5Data *pPg = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, iPgno));
|
|
||||||
int bEmpty = (pPg && pPg->nn==4);
|
|
||||||
fts5DataRelease(pPg);
|
|
||||||
if( bEmpty==0 ) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( iPgno==pSeg->iTermLeafPgno ){
|
|
||||||
i64 iId = FTS5_SEGMENT_ROWID(iSegid, pSeg->iTermLeafPgno);
|
|
||||||
Fts5Data *pTerm = fts5DataRead(p, iId);
|
|
||||||
if( pTerm && pTerm->szLeaf==pSeg->iTermLeafOffset ){
|
|
||||||
u8 *aTermIdx = &pTerm->p[pTerm->szLeaf];
|
|
||||||
int nTermIdx = pTerm->nn - pTerm->szLeaf;
|
|
||||||
int iTermIdx = 0;
|
|
||||||
int iTermOff = 0;
|
|
||||||
|
|
||||||
while( 1 ){
|
|
||||||
u32 iVal = 0;
|
|
||||||
int nByte = fts5GetVarint32(&aTermIdx[iTermIdx], iVal);
|
|
||||||
iTermOff += iVal;
|
|
||||||
if( (iTermIdx+nByte)>=nTermIdx ) break;
|
|
||||||
iTermIdx += nByte;
|
|
||||||
}
|
|
||||||
nTermIdx = iTermIdx;
|
|
||||||
|
|
||||||
memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx);
|
|
||||||
fts5PutU16(&pTerm->p[2], iTermOff);
|
|
||||||
|
|
||||||
fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx);
|
|
||||||
if( nTermIdx==0 ){
|
|
||||||
fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fts5DataRelease(pTerm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( p->rc==SQLITE_OK ){
|
|
||||||
nMove = nPg - iNextOff;
|
|
||||||
memmove(&aPg[iOff], &aPg[iNextOff], nMove);
|
|
||||||
iPgIdx -= (iNextOff - iOff);
|
|
||||||
nPg = iPgIdx;
|
|
||||||
fts5PutU16(&aPg[2], iPgIdx);
|
|
||||||
|
|
||||||
nShift = iNextOff - iOff;
|
|
||||||
for(iIdx=0, iKeyOff=0, iPrevKeyOff=0; iIdx<nIdx; /* no-op */){
|
|
||||||
u32 iVal = 0;
|
|
||||||
iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
|
|
||||||
iKeyOff += iVal;
|
|
||||||
if( iKeyOff!=iDelKeyOff ){
|
|
||||||
if( iKeyOff>iOff ){
|
|
||||||
iKeyOff -= nShift;
|
|
||||||
nShift = 0;
|
|
||||||
}
|
|
||||||
nPg += sqlite3Fts5PutVarint(&aPg[nPg], iKeyOff - iPrevKeyOff);
|
|
||||||
iPrevKeyOff = iKeyOff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( iPgIdx==nPg && nIdx>0 && pSeg->iLeafPgno!=1 ){
|
|
||||||
fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iLeafPgno);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_nc( nPg>4 || fts5GetU16(aPg)==0 );
|
|
||||||
fts5DataWrite(p, FTS5_SEGMENT_ROWID(iSegid,pSeg->iLeafPgno), aPg,nPg);
|
|
||||||
}
|
|
||||||
sqlite3_free(aIdx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4998,11 +5035,24 @@ static void fts5FlushOneHash(Fts5Index *p){
|
|||||||
/* If in secure delete mode, and if this entry in the poslist is
|
/* If in secure delete mode, and if this entry in the poslist is
|
||||||
** in fact a delete, then edit the existing segments directly
|
** in fact a delete, then edit the existing segments directly
|
||||||
** using fts5FlushSecureDelete(). */
|
** using fts5FlushSecureDelete(). */
|
||||||
if( bSecureDelete && (pDoclist[iOff] & 0x01) ){
|
if( bSecureDelete ){
|
||||||
fts5FlushSecureDelete(p, pStruct, zTerm, iRowid);
|
if( eDetail==FTS5_DETAIL_NONE ){
|
||||||
if( p->rc!=SQLITE_OK || pDoclist[iOff]==0x01 ){
|
if( iOff<nDoclist && pDoclist[iOff]==0x00 ){
|
||||||
iOff++;
|
fts5FlushSecureDelete(p, pStruct, zTerm, iRowid);
|
||||||
continue;
|
iOff++;
|
||||||
|
if( iOff<nDoclist && pDoclist[iOff]==0x00 ){
|
||||||
|
iOff++;
|
||||||
|
nDoclist = 0;
|
||||||
|
}else{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else if( (pDoclist[iOff] & 0x01) ){
|
||||||
|
fts5FlushSecureDelete(p, pStruct, zTerm, iRowid);
|
||||||
|
if( p->rc!=SQLITE_OK || pDoclist[iOff]==0x01 ){
|
||||||
|
iOff++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,18 +90,20 @@ do_catchsql_test 1.12 {
|
|||||||
foreach {tn d} {1 full 2 none 3 column} {
|
foreach {tn d} {1 full 2 none 3 column} {
|
||||||
reset_db
|
reset_db
|
||||||
do_execsql_test 2.$tn.1 "
|
do_execsql_test 2.$tn.1 "
|
||||||
CREATE VIRTUAL TABLE x1 USING fts5(xx, yy, zz, detail=$d, prefix='1,2');
|
CREATE VIRTUAL TABLE x1 USING fts5(xx, yy, zz, detail=$d, prefix='10,20');
|
||||||
INSERT INTO x1(x1, rank) VALUES('pgsz', 64);
|
INSERT INTO x1(x1, rank) VALUES('pgsz', 64);
|
||||||
|
INSERT INTO x1(x1, rank) VALUES('secure-delete', 1);
|
||||||
"
|
"
|
||||||
|
|
||||||
do_execsql_test 2.$tn.2 {
|
do_execsql_test 2.$tn.2 {
|
||||||
BEGIN;
|
BEGIN;
|
||||||
INSERT INTO x1 VALUES('a b c', 'd e f', 'a b c');
|
INSERT INTO x1(xx, yy, zz) VALUES('a b c', 'd e f', 'a b c');
|
||||||
INSERT INTO x1 VALUES('a b c', 'd e f', 'a b c');
|
INSERT INTO x1(xx, yy, zz) VALUES('a b c', 'd e f', 'a b c');
|
||||||
INSERT INTO x1 VALUES('a b c', 'd e f', 'a b c');
|
INSERT INTO x1(xx, yy, zz) VALUES('a b c', 'd e f', 'a b c');
|
||||||
INSERT INTO x1 VALUES('a b c', 'd e f', 'a b c');
|
INSERT INTO x1(xx, yy, zz) VALUES('a b c', 'd e f', 'a b c');
|
||||||
INSERT INTO x1 VALUES('a b c', 'd e f', 'a b c');
|
INSERT INTO x1(xx, yy, zz) VALUES('a b c', 'd e f', 'a b c');
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
INSERT INTO x1(x1) VALUES('integrity-check');
|
||||||
}
|
}
|
||||||
|
|
||||||
do_execsql_test 2.$tn.3 {
|
do_execsql_test 2.$tn.3 {
|
||||||
|
129
ext/fts5/test/fts5secure5.test
Normal file
129
ext/fts5/test/fts5secure5.test
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
# 2023 April 14
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
#*************************************************************************
|
||||||
|
#
|
||||||
|
|
||||||
|
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||||
|
return_if_no_fts5
|
||||||
|
set ::testprefix fts5secure5
|
||||||
|
return_if_no_fts5
|
||||||
|
|
||||||
|
proc dump {} {
|
||||||
|
execsql_pp {
|
||||||
|
SELECT id, quote(block), fts5_decode_none(id, block) FROM ft1_data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.0 {
|
||||||
|
CREATE VIRTUAL TABLE ft1 USING fts5(a, detail=none);
|
||||||
|
INSERT INTO ft1(ft1, rank) VALUES('secure-delete', 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.1 {
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO ft1(rowid, a) VALUES(1, 'abcd');
|
||||||
|
INSERT INTO ft1(rowid, a) VALUES(2, 'abcd');
|
||||||
|
INSERT INTO ft1(rowid, a) VALUES(3, 'abcd');
|
||||||
|
COMMIT;
|
||||||
|
}
|
||||||
|
do_execsql_test 1.2 {
|
||||||
|
DELETE FROM ft1 WHERE rowid=1;
|
||||||
|
}
|
||||||
|
do_execsql_test 1.3 {
|
||||||
|
INSERT INTO ft1(ft1) VALUES('integrity-check');
|
||||||
|
}
|
||||||
|
do_execsql_test 1.4 {
|
||||||
|
DELETE FROM ft1 WHERE rowid=3;
|
||||||
|
}
|
||||||
|
do_execsql_test 1.5 {
|
||||||
|
INSERT INTO ft1(ft1) VALUES('integrity-check');
|
||||||
|
}
|
||||||
|
do_execsql_test 1.6 {
|
||||||
|
DELETE FROM ft1 WHERE rowid=3;
|
||||||
|
}
|
||||||
|
do_execsql_test 1.7 {
|
||||||
|
INSERT INTO ft1(ft1) VALUES('integrity-check');
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
reset_db
|
||||||
|
do_execsql_test 2.0 {
|
||||||
|
CREATE VIRTUAL TABLE ft1 USING fts5(a, detail=none);
|
||||||
|
INSERT INTO ft1(ft1, rank) VALUES('secure-delete', 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 2.1 {
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO ft1(rowid, a) VALUES(1, 'abcd one');
|
||||||
|
INSERT INTO ft1(rowid, a) VALUES(2, 'abcd two');
|
||||||
|
INSERT INTO ft1(rowid, a) VALUES(3, 'abcd two');
|
||||||
|
INSERT INTO ft1(rowid, a) VALUES(4, 'abcd two');
|
||||||
|
INSERT INTO ft1(rowid, a) VALUES(5, 'abcd three');
|
||||||
|
COMMIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 2.2a {
|
||||||
|
DELETE FROM ft1 WHERE rowid=3;
|
||||||
|
}
|
||||||
|
do_execsql_test 2.2b {
|
||||||
|
INSERT INTO ft1(ft1) VALUES('integrity-check');
|
||||||
|
}
|
||||||
|
do_execsql_test 2.3a {
|
||||||
|
DELETE FROM ft1 WHERE rowid=2;
|
||||||
|
}
|
||||||
|
do_execsql_test 2.3b {
|
||||||
|
INSERT INTO ft1(ft1) VALUES('integrity-check');
|
||||||
|
}
|
||||||
|
do_execsql_test 2.4a {
|
||||||
|
DELETE FROM ft1 WHERE rowid=4;
|
||||||
|
}
|
||||||
|
do_execsql_test 2.4b {
|
||||||
|
INSERT INTO ft1(ft1) VALUES('integrity-check');
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
reset_db
|
||||||
|
do_execsql_test 3.0 {
|
||||||
|
CREATE VIRTUAL TABLE ft1 USING fts5(a, detail=none, prefix=1);
|
||||||
|
INSERT INTO ft1(ft1, rank) VALUES('secure-delete', 1);
|
||||||
|
INSERT INTO ft1(ft1, rank) VALUES('pgsz', 64);
|
||||||
|
}
|
||||||
|
do_execsql_test 3.1 {
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO ft1(a) VALUES('c');
|
||||||
|
COMMIT;
|
||||||
|
}
|
||||||
|
do_execsql_test 3.2 {
|
||||||
|
DELETE FROM ft1 WHERE rowid IN (1);
|
||||||
|
INSERT INTO ft1(ft1) VALUES('integrity-check');
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
reset_db
|
||||||
|
do_execsql_test 4.0 {
|
||||||
|
CREATE VIRTUAL TABLE ft1 USING fts5(a, detail=none);
|
||||||
|
INSERT INTO ft1(ft1, rank) VALUES('secure-delete', 1);
|
||||||
|
INSERT INTO ft1(ft1, rank) VALUES('pgsz', 64);
|
||||||
|
|
||||||
|
WITH s(i) AS (
|
||||||
|
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500
|
||||||
|
)
|
||||||
|
INSERT INTO ft1 SELECT 'abcdefg' FROM s;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_test 4.1 {
|
||||||
|
for {set i 500} {$i > 0} {incr i -1} {
|
||||||
|
execsql { DELETE FROM ft1 WHERE rowid=$i }
|
||||||
|
execsql { INSERT INTO ft1(ft1) VALUES('integrity-check') }
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
finish_test
|
||||||
|
|
15
manifest
15
manifest
@ -1,5 +1,5 @@
|
|||||||
C Fix\sproblems\shandling\scorrupt\srecords\sin\snew\sfts5\scode.
|
C Fix\ssome\sproblems\swith\susing\sfts5\soptions\s'secure-delete'\sand\sdetail=none\stogether.
|
||||||
D 2023-04-17T11:41:42.438
|
D 2023-04-17T18:32:22.329
|
||||||
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 LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||||
@ -92,7 +92,7 @@ F ext/fts5/fts5_buffer.c 3001fbabb585d6de52947b44b455235072b741038391f830d6b7292
|
|||||||
F ext/fts5/fts5_config.c 46af0b3c3c3f00bfc5bdd307434d7c5f0fa0678a034dd48345cd83b20068efbd
|
F ext/fts5/fts5_config.c 46af0b3c3c3f00bfc5bdd307434d7c5f0fa0678a034dd48345cd83b20068efbd
|
||||||
F ext/fts5/fts5_expr.c 48e8e45261c6030cf5c77f606217a22722b1a4d0b34e2ba6cbfc386581627989
|
F ext/fts5/fts5_expr.c 48e8e45261c6030cf5c77f606217a22722b1a4d0b34e2ba6cbfc386581627989
|
||||||
F ext/fts5/fts5_hash.c d4fb70940359f2120ccd1de7ffe64cc3efe65de9e8995b822cd536ff64c96982
|
F ext/fts5/fts5_hash.c d4fb70940359f2120ccd1de7ffe64cc3efe65de9e8995b822cd536ff64c96982
|
||||||
F ext/fts5/fts5_index.c 13c4ea17f9e6b155d3c6d78b54ae4e5ed22e1692041958f3ec71a5712172d915
|
F ext/fts5/fts5_index.c 2a59602a7ea830ae40b742277f4d89cae60a646bb2fb9c2ce895aea5e7ca89ce
|
||||||
F ext/fts5/fts5_main.c b4dba04a36aaf9b8e8cef0100b6dbb422cc74753eacc11d6401cac7a87c0f38d
|
F ext/fts5/fts5_main.c b4dba04a36aaf9b8e8cef0100b6dbb422cc74753eacc11d6401cac7a87c0f38d
|
||||||
F ext/fts5/fts5_storage.c 76c6085239eb44424004c022e9da17a5ecd5aaec859fba90ad47d3b08f4c8082
|
F ext/fts5/fts5_storage.c 76c6085239eb44424004c022e9da17a5ecd5aaec859fba90ad47d3b08f4c8082
|
||||||
F ext/fts5/fts5_tcl.c b1445cbe69908c411df8084a10b2485500ac70a9c747cdc8cda175a3da59d8ae
|
F ext/fts5/fts5_tcl.c b1445cbe69908c411df8084a10b2485500ac70a9c747cdc8cda175a3da59d8ae
|
||||||
@ -190,7 +190,8 @@ F ext/fts5/test/fts5savepoint.test fc02929f238d02a22df4172625704e029f7c1e0e92e33
|
|||||||
F ext/fts5/test/fts5secure.test 214a561519d1b1817f146efd1057e2a97cc896e75c2accc77157d874154bda64
|
F ext/fts5/test/fts5secure.test 214a561519d1b1817f146efd1057e2a97cc896e75c2accc77157d874154bda64
|
||||||
F ext/fts5/test/fts5secure2.test 2e961d7eef939f294c56b5d895cac7f1c3a60b934ee2cfd5e5e620bdf1ba6bbc
|
F ext/fts5/test/fts5secure2.test 2e961d7eef939f294c56b5d895cac7f1c3a60b934ee2cfd5e5e620bdf1ba6bbc
|
||||||
F ext/fts5/test/fts5secure3.test c7e1080a6912f2a3ac68f2e05b88b72a99de38543509b2bbf427cac5c9c1c610
|
F ext/fts5/test/fts5secure3.test c7e1080a6912f2a3ac68f2e05b88b72a99de38543509b2bbf427cac5c9c1c610
|
||||||
F ext/fts5/test/fts5secure4.test 58638eab7e80571649d08673e7924d85ec293566377a9e7f49160857f001d529
|
F ext/fts5/test/fts5secure4.test 0d10a80590c07891478700af7793b232962042677432b9846cf7fc8337b67c97
|
||||||
|
F ext/fts5/test/fts5secure5.test c07a68ced5951567ac116c22f2d2aafae497e47fe9fcb6a335c22f9c7a4f2c3a
|
||||||
F ext/fts5/test/fts5securefault.test 7208daed4171de8a54a293ef800411e3cec1ffc6e9d34209b53e56a70ee554da
|
F ext/fts5/test/fts5securefault.test 7208daed4171de8a54a293ef800411e3cec1ffc6e9d34209b53e56a70ee554da
|
||||||
F ext/fts5/test/fts5simple.test a298670508c1458b88ce6030440f26a30673931884eb5f4094ac1773b3ba217b
|
F ext/fts5/test/fts5simple.test a298670508c1458b88ce6030440f26a30673931884eb5f4094ac1773b3ba217b
|
||||||
F ext/fts5/test/fts5simple2.test 258a1b0c590409bfa5271e872c79572b319d2a56554d0585f68f146a0da603f0
|
F ext/fts5/test/fts5simple2.test 258a1b0c590409bfa5271e872c79572b319d2a56554d0585f68f146a0da603f0
|
||||||
@ -2057,8 +2058,8 @@ 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 e8de2774463c07b76cd6b9a44ab32a583fe973f42a21b21af46fe82ab177c1b8
|
P 2f63d4a8bac6dc72197df32efd84c148adbc4794943088dff08da57b15dd7900
|
||||||
R e73db0b2fec49cf21caca2b40145b9f4
|
R 94f7d6e08b83dc7ea2e9a235119af696
|
||||||
U dan
|
U dan
|
||||||
Z 8d23b3253d2a52bc5cc6c258ff86d3c2
|
Z 7915ab356b23565aa915e2ae0ad516a8
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
@ -1 +1 @@
|
|||||||
2f63d4a8bac6dc72197df32efd84c148adbc4794943088dff08da57b15dd7900
|
4d3f27ba90aa59837e49ceaae9f36cad426af3a33707d85d1bb848fc1bda6fed
|
Reference in New Issue
Block a user