OLD | NEW |
1 /* | 1 /* |
2 ** 2014 August 11 | 2 ** 2014 August 11 |
3 ** | 3 ** |
4 ** The author disclaims copyright to this source code. In place of | 4 ** The author disclaims copyright to this source code. In place of |
5 ** a legal notice, here is a blessing: | 5 ** a legal notice, here is a blessing: |
6 ** | 6 ** |
7 ** May you do good and not evil. | 7 ** May you do good and not evil. |
8 ** May you find forgiveness for yourself and forgive others. | 8 ** May you find forgiveness for yourself and forgive others. |
9 ** May you share freely, never taking more than you give. | 9 ** May you share freely, never taking more than you give. |
10 ** | 10 ** |
11 ****************************************************************************** | 11 ****************************************************************************** |
12 ** | 12 ** |
13 */ | 13 */ |
14 | 14 |
15 | 15 |
16 | 16 |
17 #include "fts5Int.h" | 17 #include "fts5Int.h" |
18 | 18 |
19 typedef struct Fts5HashEntry Fts5HashEntry; | 19 typedef struct Fts5HashEntry Fts5HashEntry; |
20 | 20 |
21 /* | 21 /* |
22 ** This file contains the implementation of an in-memory hash table used | 22 ** This file contains the implementation of an in-memory hash table used |
23 ** to accumuluate "term -> doclist" content before it is flused to a level-0 | 23 ** to accumuluate "term -> doclist" content before it is flused to a level-0 |
24 ** segment. | 24 ** segment. |
25 */ | 25 */ |
26 | 26 |
27 | 27 |
28 struct Fts5Hash { | 28 struct Fts5Hash { |
| 29 int eDetail; /* Copy of Fts5Config.eDetail */ |
29 int *pnByte; /* Pointer to bytes counter */ | 30 int *pnByte; /* Pointer to bytes counter */ |
30 int nEntry; /* Number of entries currently in hash */ | 31 int nEntry; /* Number of entries currently in hash */ |
31 int nSlot; /* Size of aSlot[] array */ | 32 int nSlot; /* Size of aSlot[] array */ |
32 Fts5HashEntry *pScan; /* Current ordered scan item */ | 33 Fts5HashEntry *pScan; /* Current ordered scan item */ |
33 Fts5HashEntry **aSlot; /* Array of hash slots */ | 34 Fts5HashEntry **aSlot; /* Array of hash slots */ |
34 }; | 35 }; |
35 | 36 |
36 /* | 37 /* |
37 ** Each entry in the hash table is represented by an object of the | 38 ** Each entry in the hash table is represented by an object of the |
38 ** following type. Each object, its key (zKey[]) and its current data | 39 ** following type. Each object, its key (zKey[]) and its current data |
(...skipping 15 matching lines...) Expand all Loading... |
54 ** nData: | 55 ** nData: |
55 ** Bytes of data written since iRowidOff. | 56 ** Bytes of data written since iRowidOff. |
56 */ | 57 */ |
57 struct Fts5HashEntry { | 58 struct Fts5HashEntry { |
58 Fts5HashEntry *pHashNext; /* Next hash entry with same hash-key */ | 59 Fts5HashEntry *pHashNext; /* Next hash entry with same hash-key */ |
59 Fts5HashEntry *pScanNext; /* Next entry in sorted order */ | 60 Fts5HashEntry *pScanNext; /* Next entry in sorted order */ |
60 | 61 |
61 int nAlloc; /* Total size of allocation */ | 62 int nAlloc; /* Total size of allocation */ |
62 int iSzPoslist; /* Offset of space for 4-byte poslist size */ | 63 int iSzPoslist; /* Offset of space for 4-byte poslist size */ |
63 int nData; /* Total bytes of data (incl. structure) */ | 64 int nData; /* Total bytes of data (incl. structure) */ |
| 65 int nKey; /* Length of zKey[] in bytes */ |
64 u8 bDel; /* Set delete-flag @ iSzPoslist */ | 66 u8 bDel; /* Set delete-flag @ iSzPoslist */ |
65 | 67 u8 bContent; /* Set content-flag (detail=none mode) */ |
66 int iCol; /* Column of last value written */ | 68 i16 iCol; /* Column of last value written */ |
67 int iPos; /* Position of last value written */ | 69 int iPos; /* Position of last value written */ |
68 i64 iRowid; /* Rowid of last value written */ | 70 i64 iRowid; /* Rowid of last value written */ |
69 char zKey[8]; /* Nul-terminated entry key */ | 71 char zKey[8]; /* Nul-terminated entry key */ |
70 }; | 72 }; |
71 | 73 |
72 /* | 74 /* |
73 ** Size of Fts5HashEntry without the zKey[] array. | 75 ** Size of Fts5HashEntry without the zKey[] array. |
74 */ | 76 */ |
75 #define FTS5_HASHENTRYSIZE (sizeof(Fts5HashEntry)-8) | 77 #define FTS5_HASHENTRYSIZE (sizeof(Fts5HashEntry)-8) |
76 | 78 |
77 | 79 |
78 | 80 |
79 /* | 81 /* |
80 ** Allocate a new hash table. | 82 ** Allocate a new hash table. |
81 */ | 83 */ |
82 int sqlite3Fts5HashNew(Fts5Hash **ppNew, int *pnByte){ | 84 int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte){ |
83 int rc = SQLITE_OK; | 85 int rc = SQLITE_OK; |
84 Fts5Hash *pNew; | 86 Fts5Hash *pNew; |
85 | 87 |
86 *ppNew = pNew = (Fts5Hash*)sqlite3_malloc(sizeof(Fts5Hash)); | 88 *ppNew = pNew = (Fts5Hash*)sqlite3_malloc(sizeof(Fts5Hash)); |
87 if( pNew==0 ){ | 89 if( pNew==0 ){ |
88 rc = SQLITE_NOMEM; | 90 rc = SQLITE_NOMEM; |
89 }else{ | 91 }else{ |
90 int nByte; | 92 int nByte; |
91 memset(pNew, 0, sizeof(Fts5Hash)); | 93 memset(pNew, 0, sizeof(Fts5Hash)); |
92 pNew->pnByte = pnByte; | 94 pNew->pnByte = pnByte; |
| 95 pNew->eDetail = pConfig->eDetail; |
93 | 96 |
94 pNew->nSlot = 1024; | 97 pNew->nSlot = 1024; |
95 nByte = sizeof(Fts5HashEntry*) * pNew->nSlot; | 98 nByte = sizeof(Fts5HashEntry*) * pNew->nSlot; |
96 pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc(nByte); | 99 pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc(nByte); |
97 if( pNew->aSlot==0 ){ | 100 if( pNew->aSlot==0 ){ |
98 sqlite3_free(pNew); | 101 sqlite3_free(pNew); |
99 *ppNew = 0; | 102 *ppNew = 0; |
100 rc = SQLITE_NOMEM; | 103 rc = SQLITE_NOMEM; |
101 }else{ | 104 }else{ |
102 memset(pNew->aSlot, 0, nByte); | 105 memset(pNew->aSlot, 0, nByte); |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 apNew[iHash] = p; | 178 apNew[iHash] = p; |
176 } | 179 } |
177 } | 180 } |
178 | 181 |
179 sqlite3_free(apOld); | 182 sqlite3_free(apOld); |
180 pHash->nSlot = nNew; | 183 pHash->nSlot = nNew; |
181 pHash->aSlot = apNew; | 184 pHash->aSlot = apNew; |
182 return SQLITE_OK; | 185 return SQLITE_OK; |
183 } | 186 } |
184 | 187 |
185 static void fts5HashAddPoslistSize(Fts5HashEntry *p){ | 188 static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){ |
186 if( p->iSzPoslist ){ | 189 if( p->iSzPoslist ){ |
187 u8 *pPtr = (u8*)p; | 190 u8 *pPtr = (u8*)p; |
188 int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */ | 191 if( pHash->eDetail==FTS5_DETAIL_NONE ){ |
189 int nPos = nSz*2 + p->bDel; /* Value of nPos field */ | 192 assert( p->nData==p->iSzPoslist ); |
| 193 if( p->bDel ){ |
| 194 pPtr[p->nData++] = 0x00; |
| 195 if( p->bContent ){ |
| 196 pPtr[p->nData++] = 0x00; |
| 197 } |
| 198 } |
| 199 }else{ |
| 200 int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */ |
| 201 int nPos = nSz*2 + p->bDel; /* Value of nPos field */ |
190 | 202 |
191 assert( p->bDel==0 || p->bDel==1 ); | 203 assert( p->bDel==0 || p->bDel==1 ); |
192 if( nPos<=127 ){ | 204 if( nPos<=127 ){ |
193 pPtr[p->iSzPoslist] = (u8)nPos; | 205 pPtr[p->iSzPoslist] = (u8)nPos; |
194 }else{ | 206 }else{ |
195 int nByte = sqlite3Fts5GetVarintLen((u32)nPos); | 207 int nByte = sqlite3Fts5GetVarintLen((u32)nPos); |
196 memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz); | 208 memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz); |
197 sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos); | 209 sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos); |
198 p->nData += (nByte-1); | 210 p->nData += (nByte-1); |
| 211 } |
199 } | 212 } |
| 213 |
| 214 p->iSzPoslist = 0; |
200 p->bDel = 0; | 215 p->bDel = 0; |
201 p->iSzPoslist = 0; | 216 p->bContent = 0; |
202 } | 217 } |
203 } | 218 } |
204 | 219 |
| 220 /* |
| 221 ** Add an entry to the in-memory hash table. The key is the concatenation |
| 222 ** of bByte and (pToken/nToken). The value is (iRowid/iCol/iPos). |
| 223 ** |
| 224 ** (bByte || pToken) -> (iRowid,iCol,iPos) |
| 225 ** |
| 226 ** Or, if iCol is negative, then the value is a delete marker. |
| 227 */ |
205 int sqlite3Fts5HashWrite( | 228 int sqlite3Fts5HashWrite( |
206 Fts5Hash *pHash, | 229 Fts5Hash *pHash, |
207 i64 iRowid, /* Rowid for this entry */ | 230 i64 iRowid, /* Rowid for this entry */ |
208 int iCol, /* Column token appears in (-ve -> delete) */ | 231 int iCol, /* Column token appears in (-ve -> delete) */ |
209 int iPos, /* Position of token within column */ | 232 int iPos, /* Position of token within column */ |
210 char bByte, /* First byte of token */ | 233 char bByte, /* First byte of token */ |
211 const char *pToken, int nToken /* Token to add or remove to or from index */ | 234 const char *pToken, int nToken /* Token to add or remove to or from index */ |
212 ){ | 235 ){ |
213 unsigned int iHash; | 236 unsigned int iHash; |
214 Fts5HashEntry *p; | 237 Fts5HashEntry *p; |
215 u8 *pPtr; | 238 u8 *pPtr; |
216 int nIncr = 0; /* Amount to increment (*pHash->pnByte) by */ | 239 int nIncr = 0; /* Amount to increment (*pHash->pnByte) by */ |
| 240 int bNew; /* If non-delete entry should be written */ |
| 241 |
| 242 bNew = (pHash->eDetail==FTS5_DETAIL_FULL); |
217 | 243 |
218 /* Attempt to locate an existing hash entry */ | 244 /* Attempt to locate an existing hash entry */ |
219 iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); | 245 iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); |
220 for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ | 246 for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ |
221 if( p->zKey[0]==bByte | 247 if( p->zKey[0]==bByte |
| 248 && p->nKey==nToken |
222 && memcmp(&p->zKey[1], pToken, nToken)==0 | 249 && memcmp(&p->zKey[1], pToken, nToken)==0 |
223 && p->zKey[nToken+1]==0 | |
224 ){ | 250 ){ |
225 break; | 251 break; |
226 } | 252 } |
227 } | 253 } |
228 | 254 |
229 /* If an existing hash entry cannot be found, create a new one. */ | 255 /* If an existing hash entry cannot be found, create a new one. */ |
230 if( p==0 ){ | 256 if( p==0 ){ |
| 257 /* Figure out how much space to allocate */ |
231 int nByte = FTS5_HASHENTRYSIZE + (nToken+1) + 1 + 64; | 258 int nByte = FTS5_HASHENTRYSIZE + (nToken+1) + 1 + 64; |
232 if( nByte<128 ) nByte = 128; | 259 if( nByte<128 ) nByte = 128; |
233 | 260 |
| 261 /* Grow the Fts5Hash.aSlot[] array if necessary. */ |
234 if( (pHash->nEntry*2)>=pHash->nSlot ){ | 262 if( (pHash->nEntry*2)>=pHash->nSlot ){ |
235 int rc = fts5HashResize(pHash); | 263 int rc = fts5HashResize(pHash); |
236 if( rc!=SQLITE_OK ) return rc; | 264 if( rc!=SQLITE_OK ) return rc; |
237 iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); | 265 iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); |
238 } | 266 } |
239 | 267 |
| 268 /* Allocate new Fts5HashEntry and add it to the hash table. */ |
240 p = (Fts5HashEntry*)sqlite3_malloc(nByte); | 269 p = (Fts5HashEntry*)sqlite3_malloc(nByte); |
241 if( !p ) return SQLITE_NOMEM; | 270 if( !p ) return SQLITE_NOMEM; |
242 memset(p, 0, FTS5_HASHENTRYSIZE); | 271 memset(p, 0, FTS5_HASHENTRYSIZE); |
243 p->nAlloc = nByte; | 272 p->nAlloc = nByte; |
244 p->zKey[0] = bByte; | 273 p->zKey[0] = bByte; |
245 memcpy(&p->zKey[1], pToken, nToken); | 274 memcpy(&p->zKey[1], pToken, nToken); |
246 assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) ); | 275 assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) ); |
| 276 p->nKey = nToken; |
247 p->zKey[nToken+1] = '\0'; | 277 p->zKey[nToken+1] = '\0'; |
248 p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE; | 278 p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE; |
249 p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid); | |
250 p->iSzPoslist = p->nData; | |
251 p->nData += 1; | |
252 p->iRowid = iRowid; | |
253 p->pHashNext = pHash->aSlot[iHash]; | 279 p->pHashNext = pHash->aSlot[iHash]; |
254 pHash->aSlot[iHash] = p; | 280 pHash->aSlot[iHash] = p; |
255 pHash->nEntry++; | 281 pHash->nEntry++; |
| 282 |
| 283 /* Add the first rowid field to the hash-entry */ |
| 284 p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid); |
| 285 p->iRowid = iRowid; |
| 286 |
| 287 p->iSzPoslist = p->nData; |
| 288 if( pHash->eDetail!=FTS5_DETAIL_NONE ){ |
| 289 p->nData += 1; |
| 290 p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1); |
| 291 } |
| 292 |
256 nIncr += p->nData; | 293 nIncr += p->nData; |
| 294 }else{ |
| 295 |
| 296 /* Appending to an existing hash-entry. Check that there is enough |
| 297 ** space to append the largest possible new entry. Worst case scenario |
| 298 ** is: |
| 299 ** |
| 300 ** + 9 bytes for a new rowid, |
| 301 ** + 4 byte reserved for the "poslist size" varint. |
| 302 ** + 1 byte for a "new column" byte, |
| 303 ** + 3 bytes for a new column number (16-bit max) as a varint, |
| 304 ** + 5 bytes for the new position offset (32-bit max). |
| 305 */ |
| 306 if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){ |
| 307 int nNew = p->nAlloc * 2; |
| 308 Fts5HashEntry *pNew; |
| 309 Fts5HashEntry **pp; |
| 310 pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew); |
| 311 if( pNew==0 ) return SQLITE_NOMEM; |
| 312 pNew->nAlloc = nNew; |
| 313 for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext); |
| 314 *pp = pNew; |
| 315 p = pNew; |
| 316 } |
| 317 nIncr -= p->nData; |
257 } | 318 } |
| 319 assert( (p->nAlloc - p->nData) >= (9 + 4 + 1 + 3 + 5) ); |
258 | 320 |
259 /* Check there is enough space to append a new entry. Worst case scenario | |
260 ** is: | |
261 ** | |
262 ** + 9 bytes for a new rowid, | |
263 ** + 4 byte reserved for the "poslist size" varint. | |
264 ** + 1 byte for a "new column" byte, | |
265 ** + 3 bytes for a new column number (16-bit max) as a varint, | |
266 ** + 5 bytes for the new position offset (32-bit max). | |
267 */ | |
268 if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){ | |
269 int nNew = p->nAlloc * 2; | |
270 Fts5HashEntry *pNew; | |
271 Fts5HashEntry **pp; | |
272 pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew); | |
273 if( pNew==0 ) return SQLITE_NOMEM; | |
274 pNew->nAlloc = nNew; | |
275 for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext); | |
276 *pp = pNew; | |
277 p = pNew; | |
278 } | |
279 pPtr = (u8*)p; | 321 pPtr = (u8*)p; |
280 nIncr -= p->nData; | |
281 | 322 |
282 /* If this is a new rowid, append the 4-byte size field for the previous | 323 /* If this is a new rowid, append the 4-byte size field for the previous |
283 ** entry, and the new rowid for this entry. */ | 324 ** entry, and the new rowid for this entry. */ |
284 if( iRowid!=p->iRowid ){ | 325 if( iRowid!=p->iRowid ){ |
285 fts5HashAddPoslistSize(p); | 326 fts5HashAddPoslistSize(pHash, p); |
286 p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid); | 327 p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid); |
| 328 p->iRowid = iRowid; |
| 329 bNew = 1; |
287 p->iSzPoslist = p->nData; | 330 p->iSzPoslist = p->nData; |
288 p->nData += 1; | 331 if( pHash->eDetail!=FTS5_DETAIL_NONE ){ |
289 p->iCol = 0; | 332 p->nData += 1; |
290 p->iPos = 0; | 333 p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1); |
291 p->iRowid = iRowid; | 334 p->iPos = 0; |
| 335 } |
292 } | 336 } |
293 | 337 |
294 if( iCol>=0 ){ | 338 if( iCol>=0 ){ |
295 /* Append a new column value, if necessary */ | 339 if( pHash->eDetail==FTS5_DETAIL_NONE ){ |
296 assert( iCol>=p->iCol ); | 340 p->bContent = 1; |
297 if( iCol!=p->iCol ){ | 341 }else{ |
298 pPtr[p->nData++] = 0x01; | 342 /* Append a new column value, if necessary */ |
299 p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol); | 343 assert( iCol>=p->iCol ); |
300 p->iCol = iCol; | 344 if( iCol!=p->iCol ){ |
301 p->iPos = 0; | 345 if( pHash->eDetail==FTS5_DETAIL_FULL ){ |
| 346 pPtr[p->nData++] = 0x01; |
| 347 p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol); |
| 348 p->iCol = (i16)iCol; |
| 349 p->iPos = 0; |
| 350 }else{ |
| 351 bNew = 1; |
| 352 p->iCol = (i16)(iPos = iCol); |
| 353 } |
| 354 } |
| 355 |
| 356 /* Append the new position offset, if necessary */ |
| 357 if( bNew ){ |
| 358 p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2); |
| 359 p->iPos = iPos; |
| 360 } |
302 } | 361 } |
303 | |
304 /* Append the new position offset */ | |
305 p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2); | |
306 p->iPos = iPos; | |
307 }else{ | 362 }else{ |
308 /* This is a delete. Set the delete flag. */ | 363 /* This is a delete. Set the delete flag. */ |
309 p->bDel = 1; | 364 p->bDel = 1; |
310 } | 365 } |
| 366 |
311 nIncr += p->nData; | 367 nIncr += p->nData; |
312 | |
313 *pHash->pnByte += nIncr; | 368 *pHash->pnByte += nIncr; |
314 return SQLITE_OK; | 369 return SQLITE_OK; |
315 } | 370 } |
316 | 371 |
317 | 372 |
318 /* | 373 /* |
319 ** Arguments pLeft and pRight point to linked-lists of hash-entry objects, | 374 ** Arguments pLeft and pRight point to linked-lists of hash-entry objects, |
320 ** each sorted in key order. This function merges the two lists into a | 375 ** each sorted in key order. This function merges the two lists into a |
321 ** single list and returns a pointer to its first element. | 376 ** single list and returns a pointer to its first element. |
322 */ | 377 */ |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 int *pnDoclist /* OUT: Size of doclist in bytes */ | 471 int *pnDoclist /* OUT: Size of doclist in bytes */ |
417 ){ | 472 ){ |
418 unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm); | 473 unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm); |
419 Fts5HashEntry *p; | 474 Fts5HashEntry *p; |
420 | 475 |
421 for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ | 476 for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ |
422 if( memcmp(p->zKey, pTerm, nTerm)==0 && p->zKey[nTerm]==0 ) break; | 477 if( memcmp(p->zKey, pTerm, nTerm)==0 && p->zKey[nTerm]==0 ) break; |
423 } | 478 } |
424 | 479 |
425 if( p ){ | 480 if( p ){ |
426 fts5HashAddPoslistSize(p); | 481 fts5HashAddPoslistSize(pHash, p); |
427 *ppDoclist = (const u8*)&p->zKey[nTerm+1]; | 482 *ppDoclist = (const u8*)&p->zKey[nTerm+1]; |
428 *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1); | 483 *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1); |
429 }else{ | 484 }else{ |
430 *ppDoclist = 0; | 485 *ppDoclist = 0; |
431 *pnDoclist = 0; | 486 *pnDoclist = 0; |
432 } | 487 } |
433 | 488 |
434 return SQLITE_OK; | 489 return SQLITE_OK; |
435 } | 490 } |
436 | 491 |
(...skipping 15 matching lines...) Expand all Loading... |
452 | 507 |
453 void sqlite3Fts5HashScanEntry( | 508 void sqlite3Fts5HashScanEntry( |
454 Fts5Hash *pHash, | 509 Fts5Hash *pHash, |
455 const char **pzTerm, /* OUT: term (nul-terminated) */ | 510 const char **pzTerm, /* OUT: term (nul-terminated) */ |
456 const u8 **ppDoclist, /* OUT: pointer to doclist */ | 511 const u8 **ppDoclist, /* OUT: pointer to doclist */ |
457 int *pnDoclist /* OUT: size of doclist in bytes */ | 512 int *pnDoclist /* OUT: size of doclist in bytes */ |
458 ){ | 513 ){ |
459 Fts5HashEntry *p; | 514 Fts5HashEntry *p; |
460 if( (p = pHash->pScan) ){ | 515 if( (p = pHash->pScan) ){ |
461 int nTerm = (int)strlen(p->zKey); | 516 int nTerm = (int)strlen(p->zKey); |
462 fts5HashAddPoslistSize(p); | 517 fts5HashAddPoslistSize(pHash, p); |
463 *pzTerm = p->zKey; | 518 *pzTerm = p->zKey; |
464 *ppDoclist = (const u8*)&p->zKey[nTerm+1]; | 519 *ppDoclist = (const u8*)&p->zKey[nTerm+1]; |
465 *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1); | 520 *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1); |
466 }else{ | 521 }else{ |
467 *pzTerm = 0; | 522 *pzTerm = 0; |
468 *ppDoclist = 0; | 523 *ppDoclist = 0; |
469 *pnDoclist = 0; | 524 *pnDoclist = 0; |
470 } | 525 } |
471 } | 526 } |
472 | 527 |
OLD | NEW |