modernc.org/cc@v1.0.1/v2/testdata/_sqlite/ext/fts3/fts3_term.c (about) 1 /* 2 ** 2011 Jan 27 3 ** 4 ** The author disclaims copyright to this source code. In place of 5 ** a legal notice, here is a blessing: 6 ** 7 ** May you do good and not evil. 8 ** May you find forgiveness for yourself and forgive others. 9 ** May you share freely, never taking more than you give. 10 ** 11 ****************************************************************************** 12 ** 13 ** This file is not part of the production FTS code. It is only used for 14 ** testing. It contains a virtual table implementation that provides direct 15 ** access to the full-text index of an FTS table. 16 */ 17 18 #include "fts3Int.h" 19 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) 20 #ifdef SQLITE_TEST 21 22 #include <string.h> 23 #include <assert.h> 24 #include <stdlib.h> 25 26 typedef struct Fts3termTable Fts3termTable; 27 typedef struct Fts3termCursor Fts3termCursor; 28 29 struct Fts3termTable { 30 sqlite3_vtab base; /* Base class used by SQLite core */ 31 int iIndex; /* Index for Fts3Table.aIndex[] */ 32 Fts3Table *pFts3Tab; 33 }; 34 35 struct Fts3termCursor { 36 sqlite3_vtab_cursor base; /* Base class used by SQLite core */ 37 Fts3MultiSegReader csr; /* Must be right after "base" */ 38 Fts3SegFilter filter; 39 40 int isEof; /* True if cursor is at EOF */ 41 char *pNext; 42 43 sqlite3_int64 iRowid; /* Current 'rowid' value */ 44 sqlite3_int64 iDocid; /* Current 'docid' value */ 45 int iCol; /* Current 'col' value */ 46 int iPos; /* Current 'pos' value */ 47 }; 48 49 /* 50 ** Schema of the terms table. 51 */ 52 #define FTS3_TERMS_SCHEMA "CREATE TABLE x(term, docid, col, pos)" 53 54 /* 55 ** This function does all the work for both the xConnect and xCreate methods. 56 ** These tables have no persistent representation of their own, so xConnect 57 ** and xCreate are identical operations. 58 */ 59 static int fts3termConnectMethod( 60 sqlite3 *db, /* Database connection */ 61 void *pCtx, /* Non-zero for an fts4prefix table */ 62 int argc, /* Number of elements in argv array */ 63 const char * const *argv, /* xCreate/xConnect argument array */ 64 sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ 65 char **pzErr /* OUT: sqlite3_malloc'd error message */ 66 ){ 67 char const *zDb; /* Name of database (e.g. "main") */ 68 char const *zFts3; /* Name of fts3 table */ 69 int nDb; /* Result of strlen(zDb) */ 70 int nFts3; /* Result of strlen(zFts3) */ 71 int nByte; /* Bytes of space to allocate here */ 72 int rc; /* value returned by declare_vtab() */ 73 Fts3termTable *p; /* Virtual table object to return */ 74 int iIndex = 0; 75 76 UNUSED_PARAMETER(pCtx); 77 if( argc==5 ){ 78 iIndex = atoi(argv[4]); 79 argc--; 80 } 81 82 /* The user should specify a single argument - the name of an fts3 table. */ 83 if( argc!=4 ){ 84 sqlite3Fts3ErrMsg(pzErr, 85 "wrong number of arguments to fts4term constructor" 86 ); 87 return SQLITE_ERROR; 88 } 89 90 zDb = argv[1]; 91 nDb = (int)strlen(zDb); 92 zFts3 = argv[3]; 93 nFts3 = (int)strlen(zFts3); 94 95 rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA); 96 if( rc!=SQLITE_OK ) return rc; 97 98 nByte = sizeof(Fts3termTable) + sizeof(Fts3Table) + nDb + nFts3 + 2; 99 p = (Fts3termTable *)sqlite3_malloc(nByte); 100 if( !p ) return SQLITE_NOMEM; 101 memset(p, 0, nByte); 102 103 p->pFts3Tab = (Fts3Table *)&p[1]; 104 p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1]; 105 p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1]; 106 p->pFts3Tab->db = db; 107 p->pFts3Tab->nIndex = iIndex+1; 108 p->iIndex = iIndex; 109 110 memcpy((char *)p->pFts3Tab->zDb, zDb, nDb); 111 memcpy((char *)p->pFts3Tab->zName, zFts3, nFts3); 112 sqlite3Fts3Dequote((char *)p->pFts3Tab->zName); 113 114 *ppVtab = (sqlite3_vtab *)p; 115 return SQLITE_OK; 116 } 117 118 /* 119 ** This function does the work for both the xDisconnect and xDestroy methods. 120 ** These tables have no persistent representation of their own, so xDisconnect 121 ** and xDestroy are identical operations. 122 */ 123 static int fts3termDisconnectMethod(sqlite3_vtab *pVtab){ 124 Fts3termTable *p = (Fts3termTable *)pVtab; 125 Fts3Table *pFts3 = p->pFts3Tab; 126 int i; 127 128 /* Free any prepared statements held */ 129 for(i=0; i<SizeofArray(pFts3->aStmt); i++){ 130 sqlite3_finalize(pFts3->aStmt[i]); 131 } 132 sqlite3_free(pFts3->zSegmentsTbl); 133 sqlite3_free(p); 134 return SQLITE_OK; 135 } 136 137 #define FTS4AUX_EQ_CONSTRAINT 1 138 #define FTS4AUX_GE_CONSTRAINT 2 139 #define FTS4AUX_LE_CONSTRAINT 4 140 141 /* 142 ** xBestIndex - Analyze a WHERE and ORDER BY clause. 143 */ 144 static int fts3termBestIndexMethod( 145 sqlite3_vtab *pVTab, 146 sqlite3_index_info *pInfo 147 ){ 148 UNUSED_PARAMETER(pVTab); 149 150 /* This vtab naturally does "ORDER BY term, docid, col, pos". */ 151 if( pInfo->nOrderBy ){ 152 int i; 153 for(i=0; i<pInfo->nOrderBy; i++){ 154 if( pInfo->aOrderBy[i].iColumn!=i || pInfo->aOrderBy[i].desc ) break; 155 } 156 if( i==pInfo->nOrderBy ){ 157 pInfo->orderByConsumed = 1; 158 } 159 } 160 161 return SQLITE_OK; 162 } 163 164 /* 165 ** xOpen - Open a cursor. 166 */ 167 static int fts3termOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ 168 Fts3termCursor *pCsr; /* Pointer to cursor object to return */ 169 170 UNUSED_PARAMETER(pVTab); 171 172 pCsr = (Fts3termCursor *)sqlite3_malloc(sizeof(Fts3termCursor)); 173 if( !pCsr ) return SQLITE_NOMEM; 174 memset(pCsr, 0, sizeof(Fts3termCursor)); 175 176 *ppCsr = (sqlite3_vtab_cursor *)pCsr; 177 return SQLITE_OK; 178 } 179 180 /* 181 ** xClose - Close a cursor. 182 */ 183 static int fts3termCloseMethod(sqlite3_vtab_cursor *pCursor){ 184 Fts3Table *pFts3 = ((Fts3termTable *)pCursor->pVtab)->pFts3Tab; 185 Fts3termCursor *pCsr = (Fts3termCursor *)pCursor; 186 187 sqlite3Fts3SegmentsClose(pFts3); 188 sqlite3Fts3SegReaderFinish(&pCsr->csr); 189 sqlite3_free(pCsr); 190 return SQLITE_OK; 191 } 192 193 /* 194 ** xNext - Advance the cursor to the next row, if any. 195 */ 196 static int fts3termNextMethod(sqlite3_vtab_cursor *pCursor){ 197 Fts3termCursor *pCsr = (Fts3termCursor *)pCursor; 198 Fts3Table *pFts3 = ((Fts3termTable *)pCursor->pVtab)->pFts3Tab; 199 int rc; 200 sqlite3_int64 v; 201 202 /* Increment our pretend rowid value. */ 203 pCsr->iRowid++; 204 205 /* Advance to the next term in the full-text index. */ 206 if( pCsr->csr.aDoclist==0 207 || pCsr->pNext>=&pCsr->csr.aDoclist[pCsr->csr.nDoclist-1] 208 ){ 209 rc = sqlite3Fts3SegReaderStep(pFts3, &pCsr->csr); 210 if( rc!=SQLITE_ROW ){ 211 pCsr->isEof = 1; 212 return rc; 213 } 214 215 pCsr->iCol = 0; 216 pCsr->iPos = 0; 217 pCsr->iDocid = 0; 218 pCsr->pNext = pCsr->csr.aDoclist; 219 220 /* Read docid */ 221 pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &pCsr->iDocid); 222 } 223 224 pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v); 225 if( v==0 ){ 226 pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v); 227 pCsr->iDocid += v; 228 pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v); 229 pCsr->iCol = 0; 230 pCsr->iPos = 0; 231 } 232 233 if( v==1 ){ 234 pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v); 235 pCsr->iCol += (int)v; 236 pCsr->iPos = 0; 237 pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v); 238 } 239 240 pCsr->iPos += (int)(v - 2); 241 242 return SQLITE_OK; 243 } 244 245 /* 246 ** xFilter - Initialize a cursor to point at the start of its data. 247 */ 248 static int fts3termFilterMethod( 249 sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ 250 int idxNum, /* Strategy index */ 251 const char *idxStr, /* Unused */ 252 int nVal, /* Number of elements in apVal */ 253 sqlite3_value **apVal /* Arguments for the indexing scheme */ 254 ){ 255 Fts3termCursor *pCsr = (Fts3termCursor *)pCursor; 256 Fts3termTable *p = (Fts3termTable *)pCursor->pVtab; 257 Fts3Table *pFts3 = p->pFts3Tab; 258 int rc; 259 260 UNUSED_PARAMETER(nVal); 261 UNUSED_PARAMETER(idxNum); 262 UNUSED_PARAMETER(idxStr); 263 UNUSED_PARAMETER(apVal); 264 265 assert( idxStr==0 && idxNum==0 ); 266 267 /* In case this cursor is being reused, close and zero it. */ 268 testcase(pCsr->filter.zTerm); 269 sqlite3Fts3SegReaderFinish(&pCsr->csr); 270 memset(&pCsr->csr, 0, ((u8*)&pCsr[1]) - (u8*)&pCsr->csr); 271 272 pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY; 273 pCsr->filter.flags |= FTS3_SEGMENT_SCAN; 274 275 rc = sqlite3Fts3SegReaderCursor(pFts3, 0, p->iIndex, FTS3_SEGCURSOR_ALL, 276 pCsr->filter.zTerm, pCsr->filter.nTerm, 0, 1, &pCsr->csr 277 ); 278 if( rc==SQLITE_OK ){ 279 rc = sqlite3Fts3SegReaderStart(pFts3, &pCsr->csr, &pCsr->filter); 280 } 281 if( rc==SQLITE_OK ){ 282 rc = fts3termNextMethod(pCursor); 283 } 284 return rc; 285 } 286 287 /* 288 ** xEof - Return true if the cursor is at EOF, or false otherwise. 289 */ 290 static int fts3termEofMethod(sqlite3_vtab_cursor *pCursor){ 291 Fts3termCursor *pCsr = (Fts3termCursor *)pCursor; 292 return pCsr->isEof; 293 } 294 295 /* 296 ** xColumn - Return a column value. 297 */ 298 static int fts3termColumnMethod( 299 sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ 300 sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ 301 int iCol /* Index of column to read value from */ 302 ){ 303 Fts3termCursor *p = (Fts3termCursor *)pCursor; 304 305 assert( iCol>=0 && iCol<=3 ); 306 switch( iCol ){ 307 case 0: 308 sqlite3_result_text(pCtx, p->csr.zTerm, p->csr.nTerm, SQLITE_TRANSIENT); 309 break; 310 case 1: 311 sqlite3_result_int64(pCtx, p->iDocid); 312 break; 313 case 2: 314 sqlite3_result_int64(pCtx, p->iCol); 315 break; 316 default: 317 sqlite3_result_int64(pCtx, p->iPos); 318 break; 319 } 320 321 return SQLITE_OK; 322 } 323 324 /* 325 ** xRowid - Return the current rowid for the cursor. 326 */ 327 static int fts3termRowidMethod( 328 sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ 329 sqlite_int64 *pRowid /* OUT: Rowid value */ 330 ){ 331 Fts3termCursor *pCsr = (Fts3termCursor *)pCursor; 332 *pRowid = pCsr->iRowid; 333 return SQLITE_OK; 334 } 335 336 /* 337 ** Register the fts3term module with database connection db. Return SQLITE_OK 338 ** if successful or an error code if sqlite3_create_module() fails. 339 */ 340 int sqlite3Fts3InitTerm(sqlite3 *db){ 341 static const sqlite3_module fts3term_module = { 342 0, /* iVersion */ 343 fts3termConnectMethod, /* xCreate */ 344 fts3termConnectMethod, /* xConnect */ 345 fts3termBestIndexMethod, /* xBestIndex */ 346 fts3termDisconnectMethod, /* xDisconnect */ 347 fts3termDisconnectMethod, /* xDestroy */ 348 fts3termOpenMethod, /* xOpen */ 349 fts3termCloseMethod, /* xClose */ 350 fts3termFilterMethod, /* xFilter */ 351 fts3termNextMethod, /* xNext */ 352 fts3termEofMethod, /* xEof */ 353 fts3termColumnMethod, /* xColumn */ 354 fts3termRowidMethod, /* xRowid */ 355 0, /* xUpdate */ 356 0, /* xBegin */ 357 0, /* xSync */ 358 0, /* xCommit */ 359 0, /* xRollback */ 360 0, /* xFindFunction */ 361 0, /* xRename */ 362 0, /* xSavepoint */ 363 0, /* xRelease */ 364 0 /* xRollbackTo */ 365 }; 366 int rc; /* Return code */ 367 368 rc = sqlite3_create_module(db, "fts4term", &fts3term_module, 0); 369 return rc; 370 } 371 372 #endif 373 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */