Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: third_party/sqlite/src/ext/fts5/fts5_hash.c

Issue 2751253002: [sql] Import SQLite 3.17.0. (Closed)
Patch Set: Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698