| OLD | NEW |
| 1 /* | 1 /* |
| 2 ** 2015 May 08 | 2 ** 2015 May 08 |
| 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 ** |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 177 int nByte; /* Bytes of space to allocate */ | 177 int nByte; /* Bytes of space to allocate */ |
| 178 const char *zDb = bDb ? argv[3] : argv[1]; | 178 const char *zDb = bDb ? argv[3] : argv[1]; |
| 179 const char *zTab = bDb ? argv[4] : argv[3]; | 179 const char *zTab = bDb ? argv[4] : argv[3]; |
| 180 const char *zType = bDb ? argv[5] : argv[4]; | 180 const char *zType = bDb ? argv[5] : argv[4]; |
| 181 int nDb = (int)strlen(zDb)+1; | 181 int nDb = (int)strlen(zDb)+1; |
| 182 int nTab = (int)strlen(zTab)+1; | 182 int nTab = (int)strlen(zTab)+1; |
| 183 int eType = 0; | 183 int eType = 0; |
| 184 | 184 |
| 185 rc = fts5VocabTableType(zType, pzErr, &eType); | 185 rc = fts5VocabTableType(zType, pzErr, &eType); |
| 186 if( rc==SQLITE_OK ){ | 186 if( rc==SQLITE_OK ){ |
| 187 assert( eType>=0 && eType<sizeof(azSchema)/sizeof(azSchema[0]) ); | 187 assert( eType>=0 && eType<ArraySize(azSchema) ); |
| 188 rc = sqlite3_declare_vtab(db, azSchema[eType]); | 188 rc = sqlite3_declare_vtab(db, azSchema[eType]); |
| 189 } | 189 } |
| 190 | 190 |
| 191 nByte = sizeof(Fts5VocabTable) + nDb + nTab; | 191 nByte = sizeof(Fts5VocabTable) + nDb + nTab; |
| 192 pRet = sqlite3Fts5MallocZero(&rc, nByte); | 192 pRet = sqlite3Fts5MallocZero(&rc, nByte); |
| 193 if( pRet ){ | 193 if( pRet ){ |
| 194 pRet->pGlobal = (Fts5Global*)pAux; | 194 pRet->pGlobal = (Fts5Global*)pAux; |
| 195 pRet->eType = eType; | 195 pRet->eType = eType; |
| 196 pRet->db = db; | 196 pRet->db = db; |
| 197 pRet->zFts5Tbl = (char*)&pRet[1]; | 197 pRet->zFts5Tbl = (char*)&pRet[1]; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ | 230 sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ |
| 231 char **pzErr /* OUT: sqlite3_malloc'd error message */ | 231 char **pzErr /* OUT: sqlite3_malloc'd error message */ |
| 232 ){ | 232 ){ |
| 233 return fts5VocabInitVtab(db, pAux, argc, argv, ppVtab, pzErr); | 233 return fts5VocabInitVtab(db, pAux, argc, argv, ppVtab, pzErr); |
| 234 } | 234 } |
| 235 | 235 |
| 236 /* | 236 /* |
| 237 ** Implementation of the xBestIndex method. | 237 ** Implementation of the xBestIndex method. |
| 238 */ | 238 */ |
| 239 static int fts5VocabBestIndexMethod( | 239 static int fts5VocabBestIndexMethod( |
| 240 sqlite3_vtab *pVTab, | 240 sqlite3_vtab *pUnused, |
| 241 sqlite3_index_info *pInfo | 241 sqlite3_index_info *pInfo |
| 242 ){ | 242 ){ |
| 243 int i; | 243 int i; |
| 244 int iTermEq = -1; | 244 int iTermEq = -1; |
| 245 int iTermGe = -1; | 245 int iTermGe = -1; |
| 246 int iTermLe = -1; | 246 int iTermLe = -1; |
| 247 int idxNum = 0; | 247 int idxNum = 0; |
| 248 int nArg = 0; | 248 int nArg = 0; |
| 249 | 249 |
| 250 UNUSED_PARAM(pUnused); |
| 251 |
| 250 for(i=0; i<pInfo->nConstraint; i++){ | 252 for(i=0; i<pInfo->nConstraint; i++){ |
| 251 struct sqlite3_index_constraint *p = &pInfo->aConstraint[i]; | 253 struct sqlite3_index_constraint *p = &pInfo->aConstraint[i]; |
| 252 if( p->usable==0 ) continue; | 254 if( p->usable==0 ) continue; |
| 253 if( p->iColumn==0 ){ /* term column */ | 255 if( p->iColumn==0 ){ /* term column */ |
| 254 if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ) iTermEq = i; | 256 if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ) iTermEq = i; |
| 255 if( p->op==SQLITE_INDEX_CONSTRAINT_LE ) iTermLe = i; | 257 if( p->op==SQLITE_INDEX_CONSTRAINT_LE ) iTermLe = i; |
| 256 if( p->op==SQLITE_INDEX_CONSTRAINT_LT ) iTermLe = i; | 258 if( p->op==SQLITE_INDEX_CONSTRAINT_LT ) iTermLe = i; |
| 257 if( p->op==SQLITE_INDEX_CONSTRAINT_GE ) iTermGe = i; | 259 if( p->op==SQLITE_INDEX_CONSTRAINT_GE ) iTermGe = i; |
| 258 if( p->op==SQLITE_INDEX_CONSTRAINT_GT ) iTermGe = i; | 260 if( p->op==SQLITE_INDEX_CONSTRAINT_GT ) iTermGe = i; |
| 259 } | 261 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 270 pInfo->aConstraintUsage[iTermGe].argvIndex = ++nArg; | 272 pInfo->aConstraintUsage[iTermGe].argvIndex = ++nArg; |
| 271 pInfo->estimatedCost = pInfo->estimatedCost / 2; | 273 pInfo->estimatedCost = pInfo->estimatedCost / 2; |
| 272 } | 274 } |
| 273 if( iTermLe>=0 ){ | 275 if( iTermLe>=0 ){ |
| 274 idxNum |= FTS5_VOCAB_TERM_LE; | 276 idxNum |= FTS5_VOCAB_TERM_LE; |
| 275 pInfo->aConstraintUsage[iTermLe].argvIndex = ++nArg; | 277 pInfo->aConstraintUsage[iTermLe].argvIndex = ++nArg; |
| 276 pInfo->estimatedCost = pInfo->estimatedCost / 2; | 278 pInfo->estimatedCost = pInfo->estimatedCost / 2; |
| 277 } | 279 } |
| 278 } | 280 } |
| 279 | 281 |
| 282 /* This virtual table always delivers results in ascending order of |
| 283 ** the "term" column (column 0). So if the user has requested this |
| 284 ** specifically - "ORDER BY term" or "ORDER BY term ASC" - set the |
| 285 ** sqlite3_index_info.orderByConsumed flag to tell the core the results |
| 286 ** are already in sorted order. */ |
| 287 if( pInfo->nOrderBy==1 |
| 288 && pInfo->aOrderBy[0].iColumn==0 |
| 289 && pInfo->aOrderBy[0].desc==0 |
| 290 ){ |
| 291 pInfo->orderByConsumed = 1; |
| 292 } |
| 293 |
| 280 pInfo->idxNum = idxNum; | 294 pInfo->idxNum = idxNum; |
| 281 | |
| 282 return SQLITE_OK; | 295 return SQLITE_OK; |
| 283 } | 296 } |
| 284 | 297 |
| 285 /* | 298 /* |
| 286 ** Implementation of xOpen method. | 299 ** Implementation of xOpen method. |
| 287 */ | 300 */ |
| 288 static int fts5VocabOpenMethod( | 301 static int fts5VocabOpenMethod( |
| 289 sqlite3_vtab *pVTab, | 302 sqlite3_vtab *pVTab, |
| 290 sqlite3_vtab_cursor **ppCsr | 303 sqlite3_vtab_cursor **ppCsr |
| 291 ){ | 304 ){ |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ | 385 static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ |
| 373 Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; | 386 Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; |
| 374 Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab; | 387 Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab; |
| 375 int rc = SQLITE_OK; | 388 int rc = SQLITE_OK; |
| 376 int nCol = pCsr->pConfig->nCol; | 389 int nCol = pCsr->pConfig->nCol; |
| 377 | 390 |
| 378 pCsr->rowid++; | 391 pCsr->rowid++; |
| 379 | 392 |
| 380 if( pTab->eType==FTS5_VOCAB_COL ){ | 393 if( pTab->eType==FTS5_VOCAB_COL ){ |
| 381 for(pCsr->iCol++; pCsr->iCol<nCol; pCsr->iCol++){ | 394 for(pCsr->iCol++; pCsr->iCol<nCol; pCsr->iCol++){ |
| 382 if( pCsr->aCnt[pCsr->iCol] ) break; | 395 if( pCsr->aDoc[pCsr->iCol] ) break; |
| 383 } | 396 } |
| 384 } | 397 } |
| 385 | 398 |
| 386 if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=nCol ){ | 399 if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=nCol ){ |
| 387 if( sqlite3Fts5IterEof(pCsr->pIter) ){ | 400 if( sqlite3Fts5IterEof(pCsr->pIter) ){ |
| 388 pCsr->bEof = 1; | 401 pCsr->bEof = 1; |
| 389 }else{ | 402 }else{ |
| 390 const char *zTerm; | 403 const char *zTerm; |
| 391 int nTerm; | 404 int nTerm; |
| 392 | 405 |
| 393 zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); | 406 zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); |
| 394 if( pCsr->nLeTerm>=0 ){ | 407 if( pCsr->nLeTerm>=0 ){ |
| 395 int nCmp = MIN(nTerm, pCsr->nLeTerm); | 408 int nCmp = MIN(nTerm, pCsr->nLeTerm); |
| 396 int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp); | 409 int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp); |
| 397 if( bCmp<0 || (bCmp==0 && pCsr->nLeTerm<nTerm) ){ | 410 if( bCmp<0 || (bCmp==0 && pCsr->nLeTerm<nTerm) ){ |
| 398 pCsr->bEof = 1; | 411 pCsr->bEof = 1; |
| 399 return SQLITE_OK; | 412 return SQLITE_OK; |
| 400 } | 413 } |
| 401 } | 414 } |
| 402 | 415 |
| 403 sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm); | 416 sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm); |
| 404 memset(pCsr->aCnt, 0, nCol * sizeof(i64)); | 417 memset(pCsr->aCnt, 0, nCol * sizeof(i64)); |
| 405 memset(pCsr->aDoc, 0, nCol * sizeof(i64)); | 418 memset(pCsr->aDoc, 0, nCol * sizeof(i64)); |
| 406 pCsr->iCol = 0; | 419 pCsr->iCol = 0; |
| 407 | 420 |
| 408 assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW ); | 421 assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW ); |
| 409 while( rc==SQLITE_OK ){ | 422 while( rc==SQLITE_OK ){ |
| 410 i64 dummy; | |
| 411 const u8 *pPos; int nPos; /* Position list */ | 423 const u8 *pPos; int nPos; /* Position list */ |
| 412 i64 iPos = 0; /* 64-bit position read from poslist */ | 424 i64 iPos = 0; /* 64-bit position read from poslist */ |
| 413 int iOff = 0; /* Current offset within position list */ | 425 int iOff = 0; /* Current offset within position list */ |
| 414 | 426 |
| 415 rc = sqlite3Fts5IterPoslist(pCsr->pIter, 0, &pPos, &nPos, &dummy); | 427 pPos = pCsr->pIter->pData; |
| 416 if( rc==SQLITE_OK ){ | 428 nPos = pCsr->pIter->nData; |
| 417 if( pTab->eType==FTS5_VOCAB_ROW ){ | 429 switch( pCsr->pConfig->eDetail ){ |
| 418 while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ | 430 case FTS5_DETAIL_FULL: |
| 419 pCsr->aCnt[0]++; | 431 pPos = pCsr->pIter->pData; |
| 420 } | 432 nPos = pCsr->pIter->nData; |
| 421 pCsr->aDoc[0]++; | 433 if( pTab->eType==FTS5_VOCAB_ROW ){ |
| 422 }else{ | 434 while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ |
| 423 int iCol = -1; | 435 pCsr->aCnt[0]++; |
| 424 while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ | 436 } |
| 425 int ii = FTS5_POS2COLUMN(iPos); | 437 pCsr->aDoc[0]++; |
| 426 pCsr->aCnt[ii]++; | 438 }else{ |
| 427 if( iCol!=ii ){ | 439 int iCol = -1; |
| 428 pCsr->aDoc[ii]++; | 440 while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ |
| 429 iCol = ii; | 441 int ii = FTS5_POS2COLUMN(iPos); |
| 442 pCsr->aCnt[ii]++; |
| 443 if( iCol!=ii ){ |
| 444 if( ii>=nCol ){ |
| 445 rc = FTS5_CORRUPT; |
| 446 break; |
| 447 } |
| 448 pCsr->aDoc[ii]++; |
| 449 iCol = ii; |
| 450 } |
| 430 } | 451 } |
| 431 } | 452 } |
| 432 } | 453 break; |
| 454 |
| 455 case FTS5_DETAIL_COLUMNS: |
| 456 if( pTab->eType==FTS5_VOCAB_ROW ){ |
| 457 pCsr->aDoc[0]++; |
| 458 }else{ |
| 459 while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff,&iPos) ){ |
| 460 assert_nc( iPos>=0 && iPos<nCol ); |
| 461 if( iPos>=nCol ){ |
| 462 rc = FTS5_CORRUPT; |
| 463 break; |
| 464 } |
| 465 pCsr->aDoc[iPos]++; |
| 466 } |
| 467 } |
| 468 break; |
| 469 |
| 470 default: |
| 471 assert( pCsr->pConfig->eDetail==FTS5_DETAIL_NONE ); |
| 472 pCsr->aDoc[0]++; |
| 473 break; |
| 474 } |
| 475 |
| 476 if( rc==SQLITE_OK ){ |
| 433 rc = sqlite3Fts5IterNextScan(pCsr->pIter); | 477 rc = sqlite3Fts5IterNextScan(pCsr->pIter); |
| 434 } | 478 } |
| 435 | 479 |
| 436 if( rc==SQLITE_OK ){ | 480 if( rc==SQLITE_OK ){ |
| 437 zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); | 481 zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); |
| 438 if( nTerm!=pCsr->term.n || memcmp(zTerm, pCsr->term.p, nTerm) ){ | 482 if( nTerm!=pCsr->term.n || memcmp(zTerm, pCsr->term.p, nTerm) ){ |
| 439 break; | 483 break; |
| 440 } | 484 } |
| 441 if( sqlite3Fts5IterEof(pCsr->pIter) ) break; | 485 if( sqlite3Fts5IterEof(pCsr->pIter) ) break; |
| 442 } | 486 } |
| 443 } | 487 } |
| 444 } | 488 } |
| 445 } | 489 } |
| 446 | 490 |
| 447 if( pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){ | 491 if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){ |
| 448 while( pCsr->aCnt[pCsr->iCol]==0 ) pCsr->iCol++; | 492 while( pCsr->aDoc[pCsr->iCol]==0 ) pCsr->iCol++; |
| 449 assert( pCsr->iCol<pCsr->pConfig->nCol ); | 493 assert( pCsr->iCol<pCsr->pConfig->nCol ); |
| 450 } | 494 } |
| 451 return rc; | 495 return rc; |
| 452 } | 496 } |
| 453 | 497 |
| 454 /* | 498 /* |
| 455 ** This is the xFilter implementation for the virtual table. | 499 ** This is the xFilter implementation for the virtual table. |
| 456 */ | 500 */ |
| 457 static int fts5VocabFilterMethod( | 501 static int fts5VocabFilterMethod( |
| 458 sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ | 502 sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ |
| 459 int idxNum, /* Strategy index */ | 503 int idxNum, /* Strategy index */ |
| 460 const char *idxStr, /* Unused */ | 504 const char *zUnused, /* Unused */ |
| 461 int nVal, /* Number of elements in apVal */ | 505 int nUnused, /* Number of elements in apVal */ |
| 462 sqlite3_value **apVal /* Arguments for the indexing scheme */ | 506 sqlite3_value **apVal /* Arguments for the indexing scheme */ |
| 463 ){ | 507 ){ |
| 464 Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; | 508 Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; |
| 465 int rc = SQLITE_OK; | 509 int rc = SQLITE_OK; |
| 466 | 510 |
| 467 int iVal = 0; | 511 int iVal = 0; |
| 468 int f = FTS5INDEX_QUERY_SCAN; | 512 int f = FTS5INDEX_QUERY_SCAN; |
| 469 const char *zTerm = 0; | 513 const char *zTerm = 0; |
| 470 int nTerm = 0; | 514 int nTerm = 0; |
| 471 | 515 |
| 472 sqlite3_value *pEq = 0; | 516 sqlite3_value *pEq = 0; |
| 473 sqlite3_value *pGe = 0; | 517 sqlite3_value *pGe = 0; |
| 474 sqlite3_value *pLe = 0; | 518 sqlite3_value *pLe = 0; |
| 475 | 519 |
| 520 UNUSED_PARAM2(zUnused, nUnused); |
| 521 |
| 476 fts5VocabResetCursor(pCsr); | 522 fts5VocabResetCursor(pCsr); |
| 477 if( idxNum & FTS5_VOCAB_TERM_EQ ) pEq = apVal[iVal++]; | 523 if( idxNum & FTS5_VOCAB_TERM_EQ ) pEq = apVal[iVal++]; |
| 478 if( idxNum & FTS5_VOCAB_TERM_GE ) pGe = apVal[iVal++]; | 524 if( idxNum & FTS5_VOCAB_TERM_GE ) pGe = apVal[iVal++]; |
| 479 if( idxNum & FTS5_VOCAB_TERM_LE ) pLe = apVal[iVal++]; | 525 if( idxNum & FTS5_VOCAB_TERM_LE ) pLe = apVal[iVal++]; |
| 480 | 526 |
| 481 if( pEq ){ | 527 if( pEq ){ |
| 482 zTerm = (const char *)sqlite3_value_text(pEq); | 528 zTerm = (const char *)sqlite3_value_text(pEq); |
| 483 nTerm = sqlite3_value_bytes(pEq); | 529 nTerm = sqlite3_value_bytes(pEq); |
| 484 f = 0; | 530 f = 0; |
| 485 }else{ | 531 }else{ |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 518 Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; | 564 Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; |
| 519 return pCsr->bEof; | 565 return pCsr->bEof; |
| 520 } | 566 } |
| 521 | 567 |
| 522 static int fts5VocabColumnMethod( | 568 static int fts5VocabColumnMethod( |
| 523 sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ | 569 sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ |
| 524 sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ | 570 sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ |
| 525 int iCol /* Index of column to read value from */ | 571 int iCol /* Index of column to read value from */ |
| 526 ){ | 572 ){ |
| 527 Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; | 573 Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; |
| 574 int eDetail = pCsr->pConfig->eDetail; |
| 575 int eType = ((Fts5VocabTable*)(pCursor->pVtab))->eType; |
| 576 i64 iVal = 0; |
| 528 | 577 |
| 529 if( iCol==0 ){ | 578 if( iCol==0 ){ |
| 530 sqlite3_result_text( | 579 sqlite3_result_text( |
| 531 pCtx, (const char*)pCsr->term.p, pCsr->term.n, SQLITE_TRANSIENT | 580 pCtx, (const char*)pCsr->term.p, pCsr->term.n, SQLITE_TRANSIENT |
| 532 ); | 581 ); |
| 533 } | 582 }else if( eType==FTS5_VOCAB_COL ){ |
| 534 else if( ((Fts5VocabTable*)(pCursor->pVtab))->eType==FTS5_VOCAB_COL ){ | |
| 535 assert( iCol==1 || iCol==2 || iCol==3 ); | 583 assert( iCol==1 || iCol==2 || iCol==3 ); |
| 536 if( iCol==1 ){ | 584 if( iCol==1 ){ |
| 537 const char *z = pCsr->pConfig->azCol[pCsr->iCol]; | 585 if( eDetail!=FTS5_DETAIL_NONE ){ |
| 538 sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC); | 586 const char *z = pCsr->pConfig->azCol[pCsr->iCol]; |
| 587 sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC); |
| 588 } |
| 539 }else if( iCol==2 ){ | 589 }else if( iCol==2 ){ |
| 540 sqlite3_result_int64(pCtx, pCsr->aDoc[pCsr->iCol]); | 590 iVal = pCsr->aDoc[pCsr->iCol]; |
| 541 }else{ | 591 }else{ |
| 542 sqlite3_result_int64(pCtx, pCsr->aCnt[pCsr->iCol]); | 592 iVal = pCsr->aCnt[pCsr->iCol]; |
| 543 } | 593 } |
| 544 }else{ | 594 }else{ |
| 545 assert( iCol==1 || iCol==2 ); | 595 assert( iCol==1 || iCol==2 ); |
| 546 if( iCol==1 ){ | 596 if( iCol==1 ){ |
| 547 sqlite3_result_int64(pCtx, pCsr->aDoc[0]); | 597 iVal = pCsr->aDoc[0]; |
| 548 }else{ | 598 }else{ |
| 549 sqlite3_result_int64(pCtx, pCsr->aCnt[0]); | 599 iVal = pCsr->aCnt[0]; |
| 550 } | 600 } |
| 551 } | 601 } |
| 602 |
| 603 if( iVal>0 ) sqlite3_result_int64(pCtx, iVal); |
| 552 return SQLITE_OK; | 604 return SQLITE_OK; |
| 553 } | 605 } |
| 554 | 606 |
| 555 /* | 607 /* |
| 556 ** This is the xRowid method. The SQLite core calls this routine to | 608 ** This is the xRowid method. The SQLite core calls this routine to |
| 557 ** retrieve the rowid for the current row of the result set. The | 609 ** retrieve the rowid for the current row of the result set. The |
| 558 ** rowid should be written to *pRowid. | 610 ** rowid should be written to *pRowid. |
| 559 */ | 611 */ |
| 560 static int fts5VocabRowidMethod( | 612 static int fts5VocabRowidMethod( |
| 561 sqlite3_vtab_cursor *pCursor, | 613 sqlite3_vtab_cursor *pCursor, |
| (...skipping 29 matching lines...) Expand all Loading... |
| 591 /* xSavepoint */ 0, | 643 /* xSavepoint */ 0, |
| 592 /* xRelease */ 0, | 644 /* xRelease */ 0, |
| 593 /* xRollbackTo */ 0, | 645 /* xRollbackTo */ 0, |
| 594 }; | 646 }; |
| 595 void *p = (void*)pGlobal; | 647 void *p = (void*)pGlobal; |
| 596 | 648 |
| 597 return sqlite3_create_module_v2(db, "fts5vocab", &fts5Vocab, p, 0); | 649 return sqlite3_create_module_v2(db, "fts5vocab", &fts5Vocab, p, 0); |
| 598 } | 650 } |
| 599 | 651 |
| 600 | 652 |
| OLD | NEW |