OLD | NEW |
1 /* | 1 /* |
2 ** 2011 Jan 27 | 2 ** 2011 Jan 27 |
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 #include "fts3Int.h" |
15 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) | 15 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) |
16 | 16 |
17 #include "fts3Int.h" | |
18 #include <string.h> | 17 #include <string.h> |
19 #include <assert.h> | 18 #include <assert.h> |
20 | 19 |
21 typedef struct Fts3auxTable Fts3auxTable; | 20 typedef struct Fts3auxTable Fts3auxTable; |
22 typedef struct Fts3auxCursor Fts3auxCursor; | 21 typedef struct Fts3auxCursor Fts3auxCursor; |
23 | 22 |
24 struct Fts3auxTable { | 23 struct Fts3auxTable { |
25 sqlite3_vtab base; /* Base class used by SQLite core */ | 24 sqlite3_vtab base; /* Base class used by SQLite core */ |
26 Fts3Table *pFts3Tab; | 25 Fts3Table *pFts3Tab; |
27 }; | 26 }; |
28 | 27 |
29 struct Fts3auxCursor { | 28 struct Fts3auxCursor { |
30 sqlite3_vtab_cursor base; /* Base class used by SQLite core */ | 29 sqlite3_vtab_cursor base; /* Base class used by SQLite core */ |
31 Fts3SegReaderCursor csr; /* Must be right after "base" */ | 30 Fts3MultiSegReader csr; /* Must be right after "base" */ |
32 Fts3SegFilter filter; | 31 Fts3SegFilter filter; |
33 char *zStop; | 32 char *zStop; |
34 int nStop; /* Byte-length of string zStop */ | 33 int nStop; /* Byte-length of string zStop */ |
| 34 int iLangid; /* Language id to query */ |
35 int isEof; /* True if cursor is at EOF */ | 35 int isEof; /* True if cursor is at EOF */ |
36 sqlite3_int64 iRowid; /* Current rowid */ | 36 sqlite3_int64 iRowid; /* Current rowid */ |
37 | 37 |
38 int iCol; /* Current value of 'col' column */ | 38 int iCol; /* Current value of 'col' column */ |
39 int nStat; /* Size of aStat[] array */ | 39 int nStat; /* Size of aStat[] array */ |
40 struct Fts3auxColstats { | 40 struct Fts3auxColstats { |
41 sqlite3_int64 nDoc; /* 'documents' values for current csr row */ | 41 sqlite3_int64 nDoc; /* 'documents' values for current csr row */ |
42 sqlite3_int64 nOcc; /* 'occurrences' values for current csr row */ | 42 sqlite3_int64 nOcc; /* 'occurrences' values for current csr row */ |
43 } *aStat; | 43 } *aStat; |
44 }; | 44 }; |
45 | 45 |
46 /* | 46 /* |
47 ** Schema of the terms table. | 47 ** Schema of the terms table. |
48 */ | 48 */ |
49 #define FTS3_TERMS_SCHEMA "CREATE TABLE x(term, col, documents, occurrences)" | 49 #define FTS3_AUX_SCHEMA \ |
| 50 "CREATE TABLE x(term, col, documents, occurrences, languageid HIDDEN)" |
50 | 51 |
51 /* | 52 /* |
52 ** This function does all the work for both the xConnect and xCreate methods. | 53 ** This function does all the work for both the xConnect and xCreate methods. |
53 ** These tables have no persistent representation of their own, so xConnect | 54 ** These tables have no persistent representation of their own, so xConnect |
54 ** and xCreate are identical operations. | 55 ** and xCreate are identical operations. |
55 */ | 56 */ |
56 static int fts3auxConnectMethod( | 57 static int fts3auxConnectMethod( |
57 sqlite3 *db, /* Database connection */ | 58 sqlite3 *db, /* Database connection */ |
58 void *pUnused, /* Unused */ | 59 void *pUnused, /* Unused */ |
59 int argc, /* Number of elements in argv array */ | 60 int argc, /* Number of elements in argv array */ |
60 const char * const *argv, /* xCreate/xConnect argument array */ | 61 const char * const *argv, /* xCreate/xConnect argument array */ |
61 sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ | 62 sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ |
62 char **pzErr /* OUT: sqlite3_malloc'd error message */ | 63 char **pzErr /* OUT: sqlite3_malloc'd error message */ |
63 ){ | 64 ){ |
64 char const *zDb; /* Name of database (e.g. "main") */ | 65 char const *zDb; /* Name of database (e.g. "main") */ |
65 char const *zFts3; /* Name of fts3 table */ | 66 char const *zFts3; /* Name of fts3 table */ |
66 int nDb; /* Result of strlen(zDb) */ | 67 int nDb; /* Result of strlen(zDb) */ |
67 int nFts3; /* Result of strlen(zFts3) */ | 68 int nFts3; /* Result of strlen(zFts3) */ |
68 int nByte; /* Bytes of space to allocate here */ | 69 int nByte; /* Bytes of space to allocate here */ |
69 int rc; /* value returned by declare_vtab() */ | 70 int rc; /* value returned by declare_vtab() */ |
70 Fts3auxTable *p; /* Virtual table object to return */ | 71 Fts3auxTable *p; /* Virtual table object to return */ |
71 | 72 |
72 UNUSED_PARAMETER(pUnused); | 73 UNUSED_PARAMETER(pUnused); |
73 | 74 |
74 /* The user should specify a single argument - the name of an fts3 table. */ | 75 /* The user should invoke this in one of two forms: |
75 if( argc!=4 ){ | 76 ** |
76 *pzErr = sqlite3_mprintf( | 77 ** CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table); |
77 "wrong number of arguments to fts4aux constructor" | 78 ** CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table-db, fts4-table); |
78 ); | 79 */ |
79 return SQLITE_ERROR; | 80 if( argc!=4 && argc!=5 ) goto bad_args; |
80 } | |
81 | 81 |
82 zDb = argv[1]; | 82 zDb = argv[1]; |
83 nDb = strlen(zDb); | 83 nDb = (int)strlen(zDb); |
84 zFts3 = argv[3]; | 84 if( argc==5 ){ |
85 nFts3 = strlen(zFts3); | 85 if( nDb==4 && 0==sqlite3_strnicmp("temp", zDb, 4) ){ |
| 86 zDb = argv[3]; |
| 87 nDb = (int)strlen(zDb); |
| 88 zFts3 = argv[4]; |
| 89 }else{ |
| 90 goto bad_args; |
| 91 } |
| 92 }else{ |
| 93 zFts3 = argv[3]; |
| 94 } |
| 95 nFts3 = (int)strlen(zFts3); |
86 | 96 |
87 rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA); | 97 rc = sqlite3_declare_vtab(db, FTS3_AUX_SCHEMA); |
88 if( rc!=SQLITE_OK ) return rc; | 98 if( rc!=SQLITE_OK ) return rc; |
89 | 99 |
90 nByte = sizeof(Fts3auxTable) + sizeof(Fts3Table) + nDb + nFts3 + 2; | 100 nByte = sizeof(Fts3auxTable) + sizeof(Fts3Table) + nDb + nFts3 + 2; |
91 p = (Fts3auxTable *)sqlite3_malloc(nByte); | 101 p = (Fts3auxTable *)sqlite3_malloc(nByte); |
92 if( !p ) return SQLITE_NOMEM; | 102 if( !p ) return SQLITE_NOMEM; |
93 memset(p, 0, nByte); | 103 memset(p, 0, nByte); |
94 | 104 |
95 p->pFts3Tab = (Fts3Table *)&p[1]; | 105 p->pFts3Tab = (Fts3Table *)&p[1]; |
96 p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1]; | 106 p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1]; |
97 p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1]; | 107 p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1]; |
98 p->pFts3Tab->db = db; | 108 p->pFts3Tab->db = db; |
| 109 p->pFts3Tab->nIndex = 1; |
99 | 110 |
100 memcpy((char *)p->pFts3Tab->zDb, zDb, nDb); | 111 memcpy((char *)p->pFts3Tab->zDb, zDb, nDb); |
101 memcpy((char *)p->pFts3Tab->zName, zFts3, nFts3); | 112 memcpy((char *)p->pFts3Tab->zName, zFts3, nFts3); |
102 sqlite3Fts3Dequote((char *)p->pFts3Tab->zName); | 113 sqlite3Fts3Dequote((char *)p->pFts3Tab->zName); |
103 | 114 |
104 *ppVtab = (sqlite3_vtab *)p; | 115 *ppVtab = (sqlite3_vtab *)p; |
105 return SQLITE_OK; | 116 return SQLITE_OK; |
| 117 |
| 118 bad_args: |
| 119 *pzErr = sqlite3_mprintf("invalid arguments to fts4aux constructor"); |
| 120 return SQLITE_ERROR; |
106 } | 121 } |
107 | 122 |
108 /* | 123 /* |
109 ** This function does the work for both the xDisconnect and xDestroy methods. | 124 ** This function does the work for both the xDisconnect and xDestroy methods. |
110 ** These tables have no persistent representation of their own, so xDisconnect | 125 ** These tables have no persistent representation of their own, so xDisconnect |
111 ** and xDestroy are identical operations. | 126 ** and xDestroy are identical operations. |
112 */ | 127 */ |
113 static int fts3auxDisconnectMethod(sqlite3_vtab *pVtab){ | 128 static int fts3auxDisconnectMethod(sqlite3_vtab *pVtab){ |
114 Fts3auxTable *p = (Fts3auxTable *)pVtab; | 129 Fts3auxTable *p = (Fts3auxTable *)pVtab; |
115 Fts3Table *pFts3 = p->pFts3Tab; | 130 Fts3Table *pFts3 = p->pFts3Tab; |
(...skipping 16 matching lines...) Expand all Loading... |
132 ** xBestIndex - Analyze a WHERE and ORDER BY clause. | 147 ** xBestIndex - Analyze a WHERE and ORDER BY clause. |
133 */ | 148 */ |
134 static int fts3auxBestIndexMethod( | 149 static int fts3auxBestIndexMethod( |
135 sqlite3_vtab *pVTab, | 150 sqlite3_vtab *pVTab, |
136 sqlite3_index_info *pInfo | 151 sqlite3_index_info *pInfo |
137 ){ | 152 ){ |
138 int i; | 153 int i; |
139 int iEq = -1; | 154 int iEq = -1; |
140 int iGe = -1; | 155 int iGe = -1; |
141 int iLe = -1; | 156 int iLe = -1; |
| 157 int iLangid = -1; |
| 158 int iNext = 1; /* Next free argvIndex value */ |
142 | 159 |
143 UNUSED_PARAMETER(pVTab); | 160 UNUSED_PARAMETER(pVTab); |
144 | 161 |
145 /* This vtab delivers always results in "ORDER BY term ASC" order. */ | 162 /* This vtab delivers always results in "ORDER BY term ASC" order. */ |
146 if( pInfo->nOrderBy==1 | 163 if( pInfo->nOrderBy==1 |
147 && pInfo->aOrderBy[0].iColumn==0 | 164 && pInfo->aOrderBy[0].iColumn==0 |
148 && pInfo->aOrderBy[0].desc==0 | 165 && pInfo->aOrderBy[0].desc==0 |
149 ){ | 166 ){ |
150 pInfo->orderByConsumed = 1; | 167 pInfo->orderByConsumed = 1; |
151 } | 168 } |
152 | 169 |
153 /* Search for equality and range constraints on the "term" column. */ | 170 /* Search for equality and range constraints on the "term" column. |
| 171 ** And equality constraints on the hidden "languageid" column. */ |
154 for(i=0; i<pInfo->nConstraint; i++){ | 172 for(i=0; i<pInfo->nConstraint; i++){ |
155 if( pInfo->aConstraint[i].usable && pInfo->aConstraint[i].iColumn==0 ){ | 173 if( pInfo->aConstraint[i].usable ){ |
156 int op = pInfo->aConstraint[i].op; | 174 int op = pInfo->aConstraint[i].op; |
157 if( op==SQLITE_INDEX_CONSTRAINT_EQ ) iEq = i; | 175 int iCol = pInfo->aConstraint[i].iColumn; |
158 if( op==SQLITE_INDEX_CONSTRAINT_LT ) iLe = i; | 176 |
159 if( op==SQLITE_INDEX_CONSTRAINT_LE ) iLe = i; | 177 if( iCol==0 ){ |
160 if( op==SQLITE_INDEX_CONSTRAINT_GT ) iGe = i; | 178 if( op==SQLITE_INDEX_CONSTRAINT_EQ ) iEq = i; |
161 if( op==SQLITE_INDEX_CONSTRAINT_GE ) iGe = i; | 179 if( op==SQLITE_INDEX_CONSTRAINT_LT ) iLe = i; |
| 180 if( op==SQLITE_INDEX_CONSTRAINT_LE ) iLe = i; |
| 181 if( op==SQLITE_INDEX_CONSTRAINT_GT ) iGe = i; |
| 182 if( op==SQLITE_INDEX_CONSTRAINT_GE ) iGe = i; |
| 183 } |
| 184 if( iCol==4 ){ |
| 185 if( op==SQLITE_INDEX_CONSTRAINT_EQ ) iLangid = i; |
| 186 } |
162 } | 187 } |
163 } | 188 } |
164 | 189 |
165 if( iEq>=0 ){ | 190 if( iEq>=0 ){ |
166 pInfo->idxNum = FTS4AUX_EQ_CONSTRAINT; | 191 pInfo->idxNum = FTS4AUX_EQ_CONSTRAINT; |
167 pInfo->aConstraintUsage[iEq].argvIndex = 1; | 192 pInfo->aConstraintUsage[iEq].argvIndex = iNext++; |
168 pInfo->estimatedCost = 5; | 193 pInfo->estimatedCost = 5; |
169 }else{ | 194 }else{ |
170 pInfo->idxNum = 0; | 195 pInfo->idxNum = 0; |
171 pInfo->estimatedCost = 20000; | 196 pInfo->estimatedCost = 20000; |
172 if( iGe>=0 ){ | 197 if( iGe>=0 ){ |
173 pInfo->idxNum += FTS4AUX_GE_CONSTRAINT; | 198 pInfo->idxNum += FTS4AUX_GE_CONSTRAINT; |
174 pInfo->aConstraintUsage[iGe].argvIndex = 1; | 199 pInfo->aConstraintUsage[iGe].argvIndex = iNext++; |
175 pInfo->estimatedCost /= 2; | 200 pInfo->estimatedCost /= 2; |
176 } | 201 } |
177 if( iLe>=0 ){ | 202 if( iLe>=0 ){ |
178 pInfo->idxNum += FTS4AUX_LE_CONSTRAINT; | 203 pInfo->idxNum += FTS4AUX_LE_CONSTRAINT; |
179 pInfo->aConstraintUsage[iLe].argvIndex = 1 + (iGe>=0); | 204 pInfo->aConstraintUsage[iLe].argvIndex = iNext++; |
180 pInfo->estimatedCost /= 2; | 205 pInfo->estimatedCost /= 2; |
181 } | 206 } |
182 } | 207 } |
| 208 if( iLangid>=0 ){ |
| 209 pInfo->aConstraintUsage[iLangid].argvIndex = iNext++; |
| 210 pInfo->estimatedCost--; |
| 211 } |
183 | 212 |
184 return SQLITE_OK; | 213 return SQLITE_OK; |
185 } | 214 } |
186 | 215 |
187 /* | 216 /* |
188 ** xOpen - Open a cursor. | 217 ** xOpen - Open a cursor. |
189 */ | 218 */ |
190 static int fts3auxOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ | 219 static int fts3auxOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ |
191 Fts3auxCursor *pCsr; /* Pointer to cursor object to return */ | 220 Fts3auxCursor *pCsr; /* Pointer to cursor object to return */ |
192 | 221 |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
332 static int fts3auxFilterMethod( | 361 static int fts3auxFilterMethod( |
333 sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ | 362 sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ |
334 int idxNum, /* Strategy index */ | 363 int idxNum, /* Strategy index */ |
335 const char *idxStr, /* Unused */ | 364 const char *idxStr, /* Unused */ |
336 int nVal, /* Number of elements in apVal */ | 365 int nVal, /* Number of elements in apVal */ |
337 sqlite3_value **apVal /* Arguments for the indexing scheme */ | 366 sqlite3_value **apVal /* Arguments for the indexing scheme */ |
338 ){ | 367 ){ |
339 Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; | 368 Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; |
340 Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab; | 369 Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab; |
341 int rc; | 370 int rc; |
342 int isScan; | 371 int isScan = 0; |
| 372 int iLangVal = 0; /* Language id to query */ |
| 373 |
| 374 int iEq = -1; /* Index of term=? value in apVal */ |
| 375 int iGe = -1; /* Index of term>=? value in apVal */ |
| 376 int iLe = -1; /* Index of term<=? value in apVal */ |
| 377 int iLangid = -1; /* Index of languageid=? value in apVal */ |
| 378 int iNext = 0; |
343 | 379 |
344 UNUSED_PARAMETER(nVal); | 380 UNUSED_PARAMETER(nVal); |
| 381 UNUSED_PARAMETER(idxStr); |
345 | 382 |
346 assert( idxStr==0 ); | 383 assert( idxStr==0 ); |
347 assert( idxNum==FTS4AUX_EQ_CONSTRAINT || idxNum==0 | 384 assert( idxNum==FTS4AUX_EQ_CONSTRAINT || idxNum==0 |
348 || idxNum==FTS4AUX_LE_CONSTRAINT || idxNum==FTS4AUX_GE_CONSTRAINT | 385 || idxNum==FTS4AUX_LE_CONSTRAINT || idxNum==FTS4AUX_GE_CONSTRAINT |
349 || idxNum==(FTS4AUX_LE_CONSTRAINT|FTS4AUX_GE_CONSTRAINT) | 386 || idxNum==(FTS4AUX_LE_CONSTRAINT|FTS4AUX_GE_CONSTRAINT) |
350 ); | 387 ); |
351 isScan = (idxNum!=FTS4AUX_EQ_CONSTRAINT); | 388 |
| 389 if( idxNum==FTS4AUX_EQ_CONSTRAINT ){ |
| 390 iEq = iNext++; |
| 391 }else{ |
| 392 isScan = 1; |
| 393 if( idxNum & FTS4AUX_GE_CONSTRAINT ){ |
| 394 iGe = iNext++; |
| 395 } |
| 396 if( idxNum & FTS4AUX_LE_CONSTRAINT ){ |
| 397 iLe = iNext++; |
| 398 } |
| 399 } |
| 400 if( iNext<nVal ){ |
| 401 iLangid = iNext++; |
| 402 } |
352 | 403 |
353 /* In case this cursor is being reused, close and zero it. */ | 404 /* In case this cursor is being reused, close and zero it. */ |
354 testcase(pCsr->filter.zTerm); | 405 testcase(pCsr->filter.zTerm); |
355 sqlite3Fts3SegReaderFinish(&pCsr->csr); | 406 sqlite3Fts3SegReaderFinish(&pCsr->csr); |
356 sqlite3_free((void *)pCsr->filter.zTerm); | 407 sqlite3_free((void *)pCsr->filter.zTerm); |
357 sqlite3_free(pCsr->aStat); | 408 sqlite3_free(pCsr->aStat); |
358 memset(&pCsr->csr, 0, ((u8*)&pCsr[1]) - (u8*)&pCsr->csr); | 409 memset(&pCsr->csr, 0, ((u8*)&pCsr[1]) - (u8*)&pCsr->csr); |
359 | 410 |
360 pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY; | 411 pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY; |
361 if( isScan ) pCsr->filter.flags |= FTS3_SEGMENT_SCAN; | 412 if( isScan ) pCsr->filter.flags |= FTS3_SEGMENT_SCAN; |
362 | 413 |
363 if( idxNum&(FTS4AUX_EQ_CONSTRAINT|FTS4AUX_GE_CONSTRAINT) ){ | 414 if( iEq>=0 || iGe>=0 ){ |
364 const unsigned char *zStr = sqlite3_value_text(apVal[0]); | 415 const unsigned char *zStr = sqlite3_value_text(apVal[0]); |
| 416 assert( (iEq==0 && iGe==-1) || (iEq==-1 && iGe==0) ); |
365 if( zStr ){ | 417 if( zStr ){ |
366 pCsr->filter.zTerm = sqlite3_mprintf("%s", zStr); | 418 pCsr->filter.zTerm = sqlite3_mprintf("%s", zStr); |
367 pCsr->filter.nTerm = sqlite3_value_bytes(apVal[0]); | 419 pCsr->filter.nTerm = sqlite3_value_bytes(apVal[0]); |
368 if( pCsr->filter.zTerm==0 ) return SQLITE_NOMEM; | 420 if( pCsr->filter.zTerm==0 ) return SQLITE_NOMEM; |
369 } | 421 } |
370 } | 422 } |
371 if( idxNum&FTS4AUX_LE_CONSTRAINT ){ | 423 |
372 int iIdx = (idxNum&FTS4AUX_GE_CONSTRAINT) ? 1 : 0; | 424 if( iLe>=0 ){ |
373 pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iIdx])); | 425 pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iLe])); |
374 pCsr->nStop = sqlite3_value_bytes(apVal[iIdx]); | 426 pCsr->nStop = sqlite3_value_bytes(apVal[iLe]); |
375 if( pCsr->zStop==0 ) return SQLITE_NOMEM; | 427 if( pCsr->zStop==0 ) return SQLITE_NOMEM; |
376 } | 428 } |
| 429 |
| 430 if( iLangid>=0 ){ |
| 431 iLangVal = sqlite3_value_int(apVal[iLangid]); |
377 | 432 |
378 rc = sqlite3Fts3SegReaderCursor(pFts3, FTS3_SEGCURSOR_ALL, | 433 /* If the user specified a negative value for the languageid, use zero |
| 434 ** instead. This works, as the "languageid=?" constraint will also |
| 435 ** be tested by the VDBE layer. The test will always be false (since |
| 436 ** this module will not return a row with a negative languageid), and |
| 437 ** so the overall query will return zero rows. */ |
| 438 if( iLangVal<0 ) iLangVal = 0; |
| 439 } |
| 440 pCsr->iLangid = iLangVal; |
| 441 |
| 442 rc = sqlite3Fts3SegReaderCursor(pFts3, iLangVal, 0, FTS3_SEGCURSOR_ALL, |
379 pCsr->filter.zTerm, pCsr->filter.nTerm, 0, isScan, &pCsr->csr | 443 pCsr->filter.zTerm, pCsr->filter.nTerm, 0, isScan, &pCsr->csr |
380 ); | 444 ); |
381 if( rc==SQLITE_OK ){ | 445 if( rc==SQLITE_OK ){ |
382 rc = sqlite3Fts3SegReaderStart(pFts3, &pCsr->csr, &pCsr->filter); | 446 rc = sqlite3Fts3SegReaderStart(pFts3, &pCsr->csr, &pCsr->filter); |
383 } | 447 } |
384 | 448 |
385 if( rc==SQLITE_OK ) rc = fts3auxNextMethod(pCursor); | 449 if( rc==SQLITE_OK ) rc = fts3auxNextMethod(pCursor); |
386 return rc; | 450 return rc; |
387 } | 451 } |
388 | 452 |
389 /* | 453 /* |
390 ** xEof - Return true if the cursor is at EOF, or false otherwise. | 454 ** xEof - Return true if the cursor is at EOF, or false otherwise. |
391 */ | 455 */ |
392 static int fts3auxEofMethod(sqlite3_vtab_cursor *pCursor){ | 456 static int fts3auxEofMethod(sqlite3_vtab_cursor *pCursor){ |
393 Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; | 457 Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; |
394 return pCsr->isEof; | 458 return pCsr->isEof; |
395 } | 459 } |
396 | 460 |
397 /* | 461 /* |
398 ** xColumn - Return a column value. | 462 ** xColumn - Return a column value. |
399 */ | 463 */ |
400 static int fts3auxColumnMethod( | 464 static int fts3auxColumnMethod( |
401 sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ | 465 sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ |
402 sqlite3_context *pContext, /* Context for sqlite3_result_xxx() calls */ | 466 sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ |
403 int iCol /* Index of column to read value from */ | 467 int iCol /* Index of column to read value from */ |
404 ){ | 468 ){ |
405 Fts3auxCursor *p = (Fts3auxCursor *)pCursor; | 469 Fts3auxCursor *p = (Fts3auxCursor *)pCursor; |
406 | 470 |
407 assert( p->isEof==0 ); | 471 assert( p->isEof==0 ); |
408 if( iCol==0 ){ /* Column "term" */ | 472 switch( iCol ){ |
409 sqlite3_result_text(pContext, p->csr.zTerm, p->csr.nTerm, SQLITE_TRANSIENT); | 473 case 0: /* term */ |
410 }else if( iCol==1 ){ /* Column "col" */ | 474 sqlite3_result_text(pCtx, p->csr.zTerm, p->csr.nTerm, SQLITE_TRANSIENT); |
411 if( p->iCol ){ | 475 break; |
412 sqlite3_result_int(pContext, p->iCol-1); | 476 |
413 }else{ | 477 case 1: /* col */ |
414 sqlite3_result_text(pContext, "*", -1, SQLITE_STATIC); | 478 if( p->iCol ){ |
415 } | 479 sqlite3_result_int(pCtx, p->iCol-1); |
416 }else if( iCol==2 ){ /* Column "documents" */ | 480 }else{ |
417 sqlite3_result_int64(pContext, p->aStat[p->iCol].nDoc); | 481 sqlite3_result_text(pCtx, "*", -1, SQLITE_STATIC); |
418 }else{ /* Column "occurrences" */ | 482 } |
419 sqlite3_result_int64(pContext, p->aStat[p->iCol].nOcc); | 483 break; |
| 484 |
| 485 case 2: /* documents */ |
| 486 sqlite3_result_int64(pCtx, p->aStat[p->iCol].nDoc); |
| 487 break; |
| 488 |
| 489 case 3: /* occurrences */ |
| 490 sqlite3_result_int64(pCtx, p->aStat[p->iCol].nOcc); |
| 491 break; |
| 492 |
| 493 default: /* languageid */ |
| 494 assert( iCol==4 ); |
| 495 sqlite3_result_int(pCtx, p->iLangid); |
| 496 break; |
420 } | 497 } |
421 | 498 |
422 return SQLITE_OK; | 499 return SQLITE_OK; |
423 } | 500 } |
424 | 501 |
425 /* | 502 /* |
426 ** xRowid - Return the current rowid for the cursor. | 503 ** xRowid - Return the current rowid for the cursor. |
427 */ | 504 */ |
428 static int fts3auxRowidMethod( | 505 static int fts3auxRowidMethod( |
429 sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ | 506 sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ |
(...skipping 22 matching lines...) Expand all Loading... |
452 fts3auxNextMethod, /* xNext */ | 529 fts3auxNextMethod, /* xNext */ |
453 fts3auxEofMethod, /* xEof */ | 530 fts3auxEofMethod, /* xEof */ |
454 fts3auxColumnMethod, /* xColumn */ | 531 fts3auxColumnMethod, /* xColumn */ |
455 fts3auxRowidMethod, /* xRowid */ | 532 fts3auxRowidMethod, /* xRowid */ |
456 0, /* xUpdate */ | 533 0, /* xUpdate */ |
457 0, /* xBegin */ | 534 0, /* xBegin */ |
458 0, /* xSync */ | 535 0, /* xSync */ |
459 0, /* xCommit */ | 536 0, /* xCommit */ |
460 0, /* xRollback */ | 537 0, /* xRollback */ |
461 0, /* xFindFunction */ | 538 0, /* xFindFunction */ |
462 0 /* xRename */ | 539 0, /* xRename */ |
| 540 0, /* xSavepoint */ |
| 541 0, /* xRelease */ |
| 542 0 /* xRollbackTo */ |
463 }; | 543 }; |
464 int rc; /* Return code */ | 544 int rc; /* Return code */ |
465 | 545 |
466 rc = sqlite3_create_module(db, "fts4aux", &fts3aux_module, 0); | 546 rc = sqlite3_create_module(db, "fts4aux", &fts3aux_module, 0); |
467 return rc; | 547 return rc; |
468 } | 548 } |
469 | 549 |
470 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ | 550 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ |
OLD | NEW |