Index: third_party/sqlite/src/ext/fts5/fts5_hash.c |
diff --git a/third_party/sqlite/src/ext/fts5/fts5_hash.c b/third_party/sqlite/src/ext/fts5/fts5_hash.c |
index f184957af6d2320ce5536a21005b4cf1a85b63e8..afa2a30739156c3612c7bcf01516f5a0aee8d95f 100644 |
--- a/third_party/sqlite/src/ext/fts5/fts5_hash.c |
+++ b/third_party/sqlite/src/ext/fts5/fts5_hash.c |
@@ -26,6 +26,7 @@ typedef struct Fts5HashEntry Fts5HashEntry; |
struct Fts5Hash { |
+ int eDetail; /* Copy of Fts5Config.eDetail */ |
int *pnByte; /* Pointer to bytes counter */ |
int nEntry; /* Number of entries currently in hash */ |
int nSlot; /* Size of aSlot[] array */ |
@@ -61,9 +62,10 @@ struct Fts5HashEntry { |
int nAlloc; /* Total size of allocation */ |
int iSzPoslist; /* Offset of space for 4-byte poslist size */ |
int nData; /* Total bytes of data (incl. structure) */ |
+ int nKey; /* Length of zKey[] in bytes */ |
u8 bDel; /* Set delete-flag @ iSzPoslist */ |
- |
- int iCol; /* Column of last value written */ |
+ u8 bContent; /* Set content-flag (detail=none mode) */ |
+ i16 iCol; /* Column of last value written */ |
int iPos; /* Position of last value written */ |
i64 iRowid; /* Rowid of last value written */ |
char zKey[8]; /* Nul-terminated entry key */ |
@@ -79,7 +81,7 @@ struct Fts5HashEntry { |
/* |
** Allocate a new hash table. |
*/ |
-int sqlite3Fts5HashNew(Fts5Hash **ppNew, int *pnByte){ |
+int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte){ |
int rc = SQLITE_OK; |
Fts5Hash *pNew; |
@@ -90,6 +92,7 @@ int sqlite3Fts5HashNew(Fts5Hash **ppNew, int *pnByte){ |
int nByte; |
memset(pNew, 0, sizeof(Fts5Hash)); |
pNew->pnByte = pnByte; |
+ pNew->eDetail = pConfig->eDetail; |
pNew->nSlot = 1024; |
nByte = sizeof(Fts5HashEntry*) * pNew->nSlot; |
@@ -182,26 +185,46 @@ static int fts5HashResize(Fts5Hash *pHash){ |
return SQLITE_OK; |
} |
-static void fts5HashAddPoslistSize(Fts5HashEntry *p){ |
+static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){ |
if( p->iSzPoslist ){ |
u8 *pPtr = (u8*)p; |
- int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */ |
- int nPos = nSz*2 + p->bDel; /* Value of nPos field */ |
- |
- assert( p->bDel==0 || p->bDel==1 ); |
- if( nPos<=127 ){ |
- pPtr[p->iSzPoslist] = (u8)nPos; |
+ if( pHash->eDetail==FTS5_DETAIL_NONE ){ |
+ assert( p->nData==p->iSzPoslist ); |
+ if( p->bDel ){ |
+ pPtr[p->nData++] = 0x00; |
+ if( p->bContent ){ |
+ pPtr[p->nData++] = 0x00; |
+ } |
+ } |
}else{ |
- int nByte = sqlite3Fts5GetVarintLen((u32)nPos); |
- memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz); |
- sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos); |
- p->nData += (nByte-1); |
+ int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */ |
+ int nPos = nSz*2 + p->bDel; /* Value of nPos field */ |
+ |
+ assert( p->bDel==0 || p->bDel==1 ); |
+ if( nPos<=127 ){ |
+ pPtr[p->iSzPoslist] = (u8)nPos; |
+ }else{ |
+ int nByte = sqlite3Fts5GetVarintLen((u32)nPos); |
+ memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz); |
+ sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos); |
+ p->nData += (nByte-1); |
+ } |
} |
- p->bDel = 0; |
+ |
p->iSzPoslist = 0; |
+ p->bDel = 0; |
+ p->bContent = 0; |
} |
} |
+/* |
+** Add an entry to the in-memory hash table. The key is the concatenation |
+** of bByte and (pToken/nToken). The value is (iRowid/iCol/iPos). |
+** |
+** (bByte || pToken) -> (iRowid,iCol,iPos) |
+** |
+** Or, if iCol is negative, then the value is a delete marker. |
+*/ |
int sqlite3Fts5HashWrite( |
Fts5Hash *pHash, |
i64 iRowid, /* Rowid for this entry */ |
@@ -214,13 +237,16 @@ int sqlite3Fts5HashWrite( |
Fts5HashEntry *p; |
u8 *pPtr; |
int nIncr = 0; /* Amount to increment (*pHash->pnByte) by */ |
+ int bNew; /* If non-delete entry should be written */ |
+ |
+ bNew = (pHash->eDetail==FTS5_DETAIL_FULL); |
/* Attempt to locate an existing hash entry */ |
iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); |
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ |
if( p->zKey[0]==bByte |
+ && p->nKey==nToken |
&& memcmp(&p->zKey[1], pToken, nToken)==0 |
- && p->zKey[nToken+1]==0 |
){ |
break; |
} |
@@ -228,15 +254,18 @@ int sqlite3Fts5HashWrite( |
/* If an existing hash entry cannot be found, create a new one. */ |
if( p==0 ){ |
+ /* Figure out how much space to allocate */ |
int nByte = FTS5_HASHENTRYSIZE + (nToken+1) + 1 + 64; |
if( nByte<128 ) nByte = 128; |
+ /* Grow the Fts5Hash.aSlot[] array if necessary. */ |
if( (pHash->nEntry*2)>=pHash->nSlot ){ |
int rc = fts5HashResize(pHash); |
if( rc!=SQLITE_OK ) return rc; |
iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); |
} |
+ /* Allocate new Fts5HashEntry and add it to the hash table. */ |
p = (Fts5HashEntry*)sqlite3_malloc(nByte); |
if( !p ) return SQLITE_NOMEM; |
memset(p, 0, FTS5_HASHENTRYSIZE); |
@@ -244,72 +273,98 @@ int sqlite3Fts5HashWrite( |
p->zKey[0] = bByte; |
memcpy(&p->zKey[1], pToken, nToken); |
assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) ); |
+ p->nKey = nToken; |
p->zKey[nToken+1] = '\0'; |
p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE; |
- p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid); |
- p->iSzPoslist = p->nData; |
- p->nData += 1; |
- p->iRowid = iRowid; |
p->pHashNext = pHash->aSlot[iHash]; |
pHash->aSlot[iHash] = p; |
pHash->nEntry++; |
+ |
+ /* Add the first rowid field to the hash-entry */ |
+ p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid); |
+ p->iRowid = iRowid; |
+ |
+ p->iSzPoslist = p->nData; |
+ if( pHash->eDetail!=FTS5_DETAIL_NONE ){ |
+ p->nData += 1; |
+ p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1); |
+ } |
+ |
nIncr += p->nData; |
- } |
+ }else{ |
- /* Check there is enough space to append a new entry. Worst case scenario |
- ** is: |
- ** |
- ** + 9 bytes for a new rowid, |
- ** + 4 byte reserved for the "poslist size" varint. |
- ** + 1 byte for a "new column" byte, |
- ** + 3 bytes for a new column number (16-bit max) as a varint, |
- ** + 5 bytes for the new position offset (32-bit max). |
- */ |
- if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){ |
- int nNew = p->nAlloc * 2; |
- Fts5HashEntry *pNew; |
- Fts5HashEntry **pp; |
- pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew); |
- if( pNew==0 ) return SQLITE_NOMEM; |
- pNew->nAlloc = nNew; |
- for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext); |
- *pp = pNew; |
- p = pNew; |
+ /* Appending to an existing hash-entry. Check that there is enough |
+ ** space to append the largest possible new entry. Worst case scenario |
+ ** is: |
+ ** |
+ ** + 9 bytes for a new rowid, |
+ ** + 4 byte reserved for the "poslist size" varint. |
+ ** + 1 byte for a "new column" byte, |
+ ** + 3 bytes for a new column number (16-bit max) as a varint, |
+ ** + 5 bytes for the new position offset (32-bit max). |
+ */ |
+ if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){ |
+ int nNew = p->nAlloc * 2; |
+ Fts5HashEntry *pNew; |
+ Fts5HashEntry **pp; |
+ pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew); |
+ if( pNew==0 ) return SQLITE_NOMEM; |
+ pNew->nAlloc = nNew; |
+ for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext); |
+ *pp = pNew; |
+ p = pNew; |
+ } |
+ nIncr -= p->nData; |
} |
+ assert( (p->nAlloc - p->nData) >= (9 + 4 + 1 + 3 + 5) ); |
+ |
pPtr = (u8*)p; |
- nIncr -= p->nData; |
/* If this is a new rowid, append the 4-byte size field for the previous |
** entry, and the new rowid for this entry. */ |
if( iRowid!=p->iRowid ){ |
- fts5HashAddPoslistSize(p); |
+ fts5HashAddPoslistSize(pHash, p); |
p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid); |
- p->iSzPoslist = p->nData; |
- p->nData += 1; |
- p->iCol = 0; |
- p->iPos = 0; |
p->iRowid = iRowid; |
+ bNew = 1; |
+ p->iSzPoslist = p->nData; |
+ if( pHash->eDetail!=FTS5_DETAIL_NONE ){ |
+ p->nData += 1; |
+ p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1); |
+ p->iPos = 0; |
+ } |
} |
if( iCol>=0 ){ |
- /* Append a new column value, if necessary */ |
- assert( iCol>=p->iCol ); |
- if( iCol!=p->iCol ){ |
- pPtr[p->nData++] = 0x01; |
- p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol); |
- p->iCol = iCol; |
- p->iPos = 0; |
- } |
+ if( pHash->eDetail==FTS5_DETAIL_NONE ){ |
+ p->bContent = 1; |
+ }else{ |
+ /* Append a new column value, if necessary */ |
+ assert( iCol>=p->iCol ); |
+ if( iCol!=p->iCol ){ |
+ if( pHash->eDetail==FTS5_DETAIL_FULL ){ |
+ pPtr[p->nData++] = 0x01; |
+ p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol); |
+ p->iCol = (i16)iCol; |
+ p->iPos = 0; |
+ }else{ |
+ bNew = 1; |
+ p->iCol = (i16)(iPos = iCol); |
+ } |
+ } |
- /* Append the new position offset */ |
- p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2); |
- p->iPos = iPos; |
+ /* Append the new position offset, if necessary */ |
+ if( bNew ){ |
+ p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2); |
+ p->iPos = iPos; |
+ } |
+ } |
}else{ |
/* This is a delete. Set the delete flag. */ |
p->bDel = 1; |
} |
- nIncr += p->nData; |
+ nIncr += p->nData; |
*pHash->pnByte += nIncr; |
return SQLITE_OK; |
} |
@@ -423,7 +478,7 @@ int sqlite3Fts5HashQuery( |
} |
if( p ){ |
- fts5HashAddPoslistSize(p); |
+ fts5HashAddPoslistSize(pHash, p); |
*ppDoclist = (const u8*)&p->zKey[nTerm+1]; |
*pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1); |
}else{ |
@@ -459,7 +514,7 @@ void sqlite3Fts5HashScanEntry( |
Fts5HashEntry *p; |
if( (p = pHash->pScan) ){ |
int nTerm = (int)strlen(p->zKey); |
- fts5HashAddPoslistSize(p); |
+ fts5HashAddPoslistSize(pHash, p); |
*pzTerm = p->zKey; |
*ppDoclist = (const u8*)&p->zKey[nTerm+1]; |
*pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1); |