Annotation of embedaddon/sqlite3/ext/fts3/fts3_aux.c, revision 1.1.1.1

1.1       misho       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: */
                     14: #include "fts3Int.h"
                     15: #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
                     16: 
                     17: #include <string.h>
                     18: #include <assert.h>
                     19: 
                     20: typedef struct Fts3auxTable Fts3auxTable;
                     21: typedef struct Fts3auxCursor Fts3auxCursor;
                     22: 
                     23: struct Fts3auxTable {
                     24:   sqlite3_vtab base;              /* Base class used by SQLite core */
                     25:   Fts3Table *pFts3Tab;
                     26: };
                     27: 
                     28: struct Fts3auxCursor {
                     29:   sqlite3_vtab_cursor base;       /* Base class used by SQLite core */
                     30:   Fts3MultiSegReader csr;        /* Must be right after "base" */
                     31:   Fts3SegFilter filter;
                     32:   char *zStop;
                     33:   int nStop;                      /* Byte-length of string zStop */
                     34:   int isEof;                      /* True if cursor is at EOF */
                     35:   sqlite3_int64 iRowid;           /* Current rowid */
                     36: 
                     37:   int iCol;                       /* Current value of 'col' column */
                     38:   int nStat;                      /* Size of aStat[] array */
                     39:   struct Fts3auxColstats {
                     40:     sqlite3_int64 nDoc;           /* 'documents' values for current csr row */
                     41:     sqlite3_int64 nOcc;           /* 'occurrences' values for current csr row */
                     42:   } *aStat;
                     43: };
                     44: 
                     45: /*
                     46: ** Schema of the terms table.
                     47: */
                     48: #define FTS3_TERMS_SCHEMA "CREATE TABLE x(term, col, documents, occurrences)"
                     49: 
                     50: /*
                     51: ** This function does all the work for both the xConnect and xCreate methods.
                     52: ** These tables have no persistent representation of their own, so xConnect
                     53: ** and xCreate are identical operations.
                     54: */
                     55: static int fts3auxConnectMethod(
                     56:   sqlite3 *db,                    /* Database connection */
                     57:   void *pUnused,                  /* Unused */
                     58:   int argc,                       /* Number of elements in argv array */
                     59:   const char * const *argv,       /* xCreate/xConnect argument array */
                     60:   sqlite3_vtab **ppVtab,          /* OUT: New sqlite3_vtab object */
                     61:   char **pzErr                    /* OUT: sqlite3_malloc'd error message */
                     62: ){
                     63:   char const *zDb;                /* Name of database (e.g. "main") */
                     64:   char const *zFts3;              /* Name of fts3 table */
                     65:   int nDb;                        /* Result of strlen(zDb) */
                     66:   int nFts3;                      /* Result of strlen(zFts3) */
                     67:   int nByte;                      /* Bytes of space to allocate here */
                     68:   int rc;                         /* value returned by declare_vtab() */
                     69:   Fts3auxTable *p;                /* Virtual table object to return */
                     70: 
                     71:   UNUSED_PARAMETER(pUnused);
                     72: 
                     73:   /* The user should specify a single argument - the name of an fts3 table. */
                     74:   if( argc!=4 ){
                     75:     *pzErr = sqlite3_mprintf(
                     76:         "wrong number of arguments to fts4aux constructor"
                     77:     );
                     78:     return SQLITE_ERROR;
                     79:   }
                     80: 
                     81:   zDb = argv[1]; 
                     82:   nDb = strlen(zDb);
                     83:   zFts3 = argv[3];
                     84:   nFts3 = strlen(zFts3);
                     85: 
                     86:   rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA);
                     87:   if( rc!=SQLITE_OK ) return rc;
                     88: 
                     89:   nByte = sizeof(Fts3auxTable) + sizeof(Fts3Table) + nDb + nFts3 + 2;
                     90:   p = (Fts3auxTable *)sqlite3_malloc(nByte);
                     91:   if( !p ) return SQLITE_NOMEM;
                     92:   memset(p, 0, nByte);
                     93: 
                     94:   p->pFts3Tab = (Fts3Table *)&p[1];
                     95:   p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1];
                     96:   p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1];
                     97:   p->pFts3Tab->db = db;
                     98:   p->pFts3Tab->nIndex = 1;
                     99: 
                    100:   memcpy((char *)p->pFts3Tab->zDb, zDb, nDb);
                    101:   memcpy((char *)p->pFts3Tab->zName, zFts3, nFts3);
                    102:   sqlite3Fts3Dequote((char *)p->pFts3Tab->zName);
                    103: 
                    104:   *ppVtab = (sqlite3_vtab *)p;
                    105:   return SQLITE_OK;
                    106: }
                    107: 
                    108: /*
                    109: ** This function does the work for both the xDisconnect and xDestroy methods.
                    110: ** These tables have no persistent representation of their own, so xDisconnect
                    111: ** and xDestroy are identical operations.
                    112: */
                    113: static int fts3auxDisconnectMethod(sqlite3_vtab *pVtab){
                    114:   Fts3auxTable *p = (Fts3auxTable *)pVtab;
                    115:   Fts3Table *pFts3 = p->pFts3Tab;
                    116:   int i;
                    117: 
                    118:   /* Free any prepared statements held */
                    119:   for(i=0; i<SizeofArray(pFts3->aStmt); i++){
                    120:     sqlite3_finalize(pFts3->aStmt[i]);
                    121:   }
                    122:   sqlite3_free(pFts3->zSegmentsTbl);
                    123:   sqlite3_free(p);
                    124:   return SQLITE_OK;
                    125: }
                    126: 
                    127: #define FTS4AUX_EQ_CONSTRAINT 1
                    128: #define FTS4AUX_GE_CONSTRAINT 2
                    129: #define FTS4AUX_LE_CONSTRAINT 4
                    130: 
                    131: /*
                    132: ** xBestIndex - Analyze a WHERE and ORDER BY clause.
                    133: */
                    134: static int fts3auxBestIndexMethod(
                    135:   sqlite3_vtab *pVTab, 
                    136:   sqlite3_index_info *pInfo
                    137: ){
                    138:   int i;
                    139:   int iEq = -1;
                    140:   int iGe = -1;
                    141:   int iLe = -1;
                    142: 
                    143:   UNUSED_PARAMETER(pVTab);
                    144: 
                    145:   /* This vtab delivers always results in "ORDER BY term ASC" order. */
                    146:   if( pInfo->nOrderBy==1 
                    147:    && pInfo->aOrderBy[0].iColumn==0 
                    148:    && pInfo->aOrderBy[0].desc==0
                    149:   ){
                    150:     pInfo->orderByConsumed = 1;
                    151:   }
                    152: 
                    153:   /* Search for equality and range constraints on the "term" column. */
                    154:   for(i=0; i<pInfo->nConstraint; i++){
                    155:     if( pInfo->aConstraint[i].usable && pInfo->aConstraint[i].iColumn==0 ){
                    156:       int op = pInfo->aConstraint[i].op;
                    157:       if( op==SQLITE_INDEX_CONSTRAINT_EQ ) iEq = i;
                    158:       if( op==SQLITE_INDEX_CONSTRAINT_LT ) iLe = i;
                    159:       if( op==SQLITE_INDEX_CONSTRAINT_LE ) iLe = i;
                    160:       if( op==SQLITE_INDEX_CONSTRAINT_GT ) iGe = i;
                    161:       if( op==SQLITE_INDEX_CONSTRAINT_GE ) iGe = i;
                    162:     }
                    163:   }
                    164: 
                    165:   if( iEq>=0 ){
                    166:     pInfo->idxNum = FTS4AUX_EQ_CONSTRAINT;
                    167:     pInfo->aConstraintUsage[iEq].argvIndex = 1;
                    168:     pInfo->estimatedCost = 5;
                    169:   }else{
                    170:     pInfo->idxNum = 0;
                    171:     pInfo->estimatedCost = 20000;
                    172:     if( iGe>=0 ){
                    173:       pInfo->idxNum += FTS4AUX_GE_CONSTRAINT;
                    174:       pInfo->aConstraintUsage[iGe].argvIndex = 1;
                    175:       pInfo->estimatedCost /= 2;
                    176:     }
                    177:     if( iLe>=0 ){
                    178:       pInfo->idxNum += FTS4AUX_LE_CONSTRAINT;
                    179:       pInfo->aConstraintUsage[iLe].argvIndex = 1 + (iGe>=0);
                    180:       pInfo->estimatedCost /= 2;
                    181:     }
                    182:   }
                    183: 
                    184:   return SQLITE_OK;
                    185: }
                    186: 
                    187: /*
                    188: ** xOpen - Open a cursor.
                    189: */
                    190: static int fts3auxOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
                    191:   Fts3auxCursor *pCsr;            /* Pointer to cursor object to return */
                    192: 
                    193:   UNUSED_PARAMETER(pVTab);
                    194: 
                    195:   pCsr = (Fts3auxCursor *)sqlite3_malloc(sizeof(Fts3auxCursor));
                    196:   if( !pCsr ) return SQLITE_NOMEM;
                    197:   memset(pCsr, 0, sizeof(Fts3auxCursor));
                    198: 
                    199:   *ppCsr = (sqlite3_vtab_cursor *)pCsr;
                    200:   return SQLITE_OK;
                    201: }
                    202: 
                    203: /*
                    204: ** xClose - Close a cursor.
                    205: */
                    206: static int fts3auxCloseMethod(sqlite3_vtab_cursor *pCursor){
                    207:   Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab;
                    208:   Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor;
                    209: 
                    210:   sqlite3Fts3SegmentsClose(pFts3);
                    211:   sqlite3Fts3SegReaderFinish(&pCsr->csr);
                    212:   sqlite3_free((void *)pCsr->filter.zTerm);
                    213:   sqlite3_free(pCsr->zStop);
                    214:   sqlite3_free(pCsr->aStat);
                    215:   sqlite3_free(pCsr);
                    216:   return SQLITE_OK;
                    217: }
                    218: 
                    219: static int fts3auxGrowStatArray(Fts3auxCursor *pCsr, int nSize){
                    220:   if( nSize>pCsr->nStat ){
                    221:     struct Fts3auxColstats *aNew;
                    222:     aNew = (struct Fts3auxColstats *)sqlite3_realloc(pCsr->aStat, 
                    223:         sizeof(struct Fts3auxColstats) * nSize
                    224:     );
                    225:     if( aNew==0 ) return SQLITE_NOMEM;
                    226:     memset(&aNew[pCsr->nStat], 0, 
                    227:         sizeof(struct Fts3auxColstats) * (nSize - pCsr->nStat)
                    228:     );
                    229:     pCsr->aStat = aNew;
                    230:     pCsr->nStat = nSize;
                    231:   }
                    232:   return SQLITE_OK;
                    233: }
                    234: 
                    235: /*
                    236: ** xNext - Advance the cursor to the next row, if any.
                    237: */
                    238: static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){
                    239:   Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor;
                    240:   Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab;
                    241:   int rc;
                    242: 
                    243:   /* Increment our pretend rowid value. */
                    244:   pCsr->iRowid++;
                    245: 
                    246:   for(pCsr->iCol++; pCsr->iCol<pCsr->nStat; pCsr->iCol++){
                    247:     if( pCsr->aStat[pCsr->iCol].nDoc>0 ) return SQLITE_OK;
                    248:   }
                    249: 
                    250:   rc = sqlite3Fts3SegReaderStep(pFts3, &pCsr->csr);
                    251:   if( rc==SQLITE_ROW ){
                    252:     int i = 0;
                    253:     int nDoclist = pCsr->csr.nDoclist;
                    254:     char *aDoclist = pCsr->csr.aDoclist;
                    255:     int iCol;
                    256: 
                    257:     int eState = 0;
                    258: 
                    259:     if( pCsr->zStop ){
                    260:       int n = (pCsr->nStop<pCsr->csr.nTerm) ? pCsr->nStop : pCsr->csr.nTerm;
                    261:       int mc = memcmp(pCsr->zStop, pCsr->csr.zTerm, n);
                    262:       if( mc<0 || (mc==0 && pCsr->csr.nTerm>pCsr->nStop) ){
                    263:         pCsr->isEof = 1;
                    264:         return SQLITE_OK;
                    265:       }
                    266:     }
                    267: 
                    268:     if( fts3auxGrowStatArray(pCsr, 2) ) return SQLITE_NOMEM;
                    269:     memset(pCsr->aStat, 0, sizeof(struct Fts3auxColstats) * pCsr->nStat);
                    270:     iCol = 0;
                    271: 
                    272:     while( i<nDoclist ){
                    273:       sqlite3_int64 v = 0;
                    274: 
                    275:       i += sqlite3Fts3GetVarint(&aDoclist[i], &v);
                    276:       switch( eState ){
                    277:         /* State 0. In this state the integer just read was a docid. */
                    278:         case 0:
                    279:           pCsr->aStat[0].nDoc++;
                    280:           eState = 1;
                    281:           iCol = 0;
                    282:           break;
                    283: 
                    284:         /* State 1. In this state we are expecting either a 1, indicating
                    285:         ** that the following integer will be a column number, or the
                    286:         ** start of a position list for column 0.  
                    287:         ** 
                    288:         ** The only difference between state 1 and state 2 is that if the
                    289:         ** integer encountered in state 1 is not 0 or 1, then we need to
                    290:         ** increment the column 0 "nDoc" count for this term.
                    291:         */
                    292:         case 1:
                    293:           assert( iCol==0 );
                    294:           if( v>1 ){
                    295:             pCsr->aStat[1].nDoc++;
                    296:           }
                    297:           eState = 2;
                    298:           /* fall through */
                    299: 
                    300:         case 2:
                    301:           if( v==0 ){       /* 0x00. Next integer will be a docid. */
                    302:             eState = 0;
                    303:           }else if( v==1 ){ /* 0x01. Next integer will be a column number. */
                    304:             eState = 3;
                    305:           }else{            /* 2 or greater. A position. */
                    306:             pCsr->aStat[iCol+1].nOcc++;
                    307:             pCsr->aStat[0].nOcc++;
                    308:           }
                    309:           break;
                    310: 
                    311:         /* State 3. The integer just read is a column number. */
                    312:         default: assert( eState==3 );
                    313:           iCol = (int)v;
                    314:           if( fts3auxGrowStatArray(pCsr, iCol+2) ) return SQLITE_NOMEM;
                    315:           pCsr->aStat[iCol+1].nDoc++;
                    316:           eState = 2;
                    317:           break;
                    318:       }
                    319:     }
                    320: 
                    321:     pCsr->iCol = 0;
                    322:     rc = SQLITE_OK;
                    323:   }else{
                    324:     pCsr->isEof = 1;
                    325:   }
                    326:   return rc;
                    327: }
                    328: 
                    329: /*
                    330: ** xFilter - Initialize a cursor to point at the start of its data.
                    331: */
                    332: static int fts3auxFilterMethod(
                    333:   sqlite3_vtab_cursor *pCursor,   /* The cursor used for this query */
                    334:   int idxNum,                     /* Strategy index */
                    335:   const char *idxStr,             /* Unused */
                    336:   int nVal,                       /* Number of elements in apVal */
                    337:   sqlite3_value **apVal           /* Arguments for the indexing scheme */
                    338: ){
                    339:   Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor;
                    340:   Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab;
                    341:   int rc;
                    342:   int isScan;
                    343: 
                    344:   UNUSED_PARAMETER(nVal);
                    345:   UNUSED_PARAMETER(idxStr);
                    346: 
                    347:   assert( idxStr==0 );
                    348:   assert( idxNum==FTS4AUX_EQ_CONSTRAINT || idxNum==0
                    349:        || idxNum==FTS4AUX_LE_CONSTRAINT || idxNum==FTS4AUX_GE_CONSTRAINT
                    350:        || idxNum==(FTS4AUX_LE_CONSTRAINT|FTS4AUX_GE_CONSTRAINT)
                    351:   );
                    352:   isScan = (idxNum!=FTS4AUX_EQ_CONSTRAINT);
                    353: 
                    354:   /* In case this cursor is being reused, close and zero it. */
                    355:   testcase(pCsr->filter.zTerm);
                    356:   sqlite3Fts3SegReaderFinish(&pCsr->csr);
                    357:   sqlite3_free((void *)pCsr->filter.zTerm);
                    358:   sqlite3_free(pCsr->aStat);
                    359:   memset(&pCsr->csr, 0, ((u8*)&pCsr[1]) - (u8*)&pCsr->csr);
                    360: 
                    361:   pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY;
                    362:   if( isScan ) pCsr->filter.flags |= FTS3_SEGMENT_SCAN;
                    363: 
                    364:   if( idxNum&(FTS4AUX_EQ_CONSTRAINT|FTS4AUX_GE_CONSTRAINT) ){
                    365:     const unsigned char *zStr = sqlite3_value_text(apVal[0]);
                    366:     if( zStr ){
                    367:       pCsr->filter.zTerm = sqlite3_mprintf("%s", zStr);
                    368:       pCsr->filter.nTerm = sqlite3_value_bytes(apVal[0]);
                    369:       if( pCsr->filter.zTerm==0 ) return SQLITE_NOMEM;
                    370:     }
                    371:   }
                    372:   if( idxNum&FTS4AUX_LE_CONSTRAINT ){
                    373:     int iIdx = (idxNum&FTS4AUX_GE_CONSTRAINT) ? 1 : 0;
                    374:     pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iIdx]));
                    375:     pCsr->nStop = sqlite3_value_bytes(apVal[iIdx]);
                    376:     if( pCsr->zStop==0 ) return SQLITE_NOMEM;
                    377:   }
                    378: 
                    379:   rc = sqlite3Fts3SegReaderCursor(pFts3, 0, FTS3_SEGCURSOR_ALL,
                    380:       pCsr->filter.zTerm, pCsr->filter.nTerm, 0, isScan, &pCsr->csr
                    381:   );
                    382:   if( rc==SQLITE_OK ){
                    383:     rc = sqlite3Fts3SegReaderStart(pFts3, &pCsr->csr, &pCsr->filter);
                    384:   }
                    385: 
                    386:   if( rc==SQLITE_OK ) rc = fts3auxNextMethod(pCursor);
                    387:   return rc;
                    388: }
                    389: 
                    390: /*
                    391: ** xEof - Return true if the cursor is at EOF, or false otherwise.
                    392: */
                    393: static int fts3auxEofMethod(sqlite3_vtab_cursor *pCursor){
                    394:   Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor;
                    395:   return pCsr->isEof;
                    396: }
                    397: 
                    398: /*
                    399: ** xColumn - Return a column value.
                    400: */
                    401: static int fts3auxColumnMethod(
                    402:   sqlite3_vtab_cursor *pCursor,   /* Cursor to retrieve value from */
                    403:   sqlite3_context *pContext,      /* Context for sqlite3_result_xxx() calls */
                    404:   int iCol                        /* Index of column to read value from */
                    405: ){
                    406:   Fts3auxCursor *p = (Fts3auxCursor *)pCursor;
                    407: 
                    408:   assert( p->isEof==0 );
                    409:   if( iCol==0 ){        /* Column "term" */
                    410:     sqlite3_result_text(pContext, p->csr.zTerm, p->csr.nTerm, SQLITE_TRANSIENT);
                    411:   }else if( iCol==1 ){  /* Column "col" */
                    412:     if( p->iCol ){
                    413:       sqlite3_result_int(pContext, p->iCol-1);
                    414:     }else{
                    415:       sqlite3_result_text(pContext, "*", -1, SQLITE_STATIC);
                    416:     }
                    417:   }else if( iCol==2 ){  /* Column "documents" */
                    418:     sqlite3_result_int64(pContext, p->aStat[p->iCol].nDoc);
                    419:   }else{                /* Column "occurrences" */
                    420:     sqlite3_result_int64(pContext, p->aStat[p->iCol].nOcc);
                    421:   }
                    422: 
                    423:   return SQLITE_OK;
                    424: }
                    425: 
                    426: /*
                    427: ** xRowid - Return the current rowid for the cursor.
                    428: */
                    429: static int fts3auxRowidMethod(
                    430:   sqlite3_vtab_cursor *pCursor,   /* Cursor to retrieve value from */
                    431:   sqlite_int64 *pRowid            /* OUT: Rowid value */
                    432: ){
                    433:   Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor;
                    434:   *pRowid = pCsr->iRowid;
                    435:   return SQLITE_OK;
                    436: }
                    437: 
                    438: /*
                    439: ** Register the fts3aux module with database connection db. Return SQLITE_OK
                    440: ** if successful or an error code if sqlite3_create_module() fails.
                    441: */
                    442: int sqlite3Fts3InitAux(sqlite3 *db){
                    443:   static const sqlite3_module fts3aux_module = {
                    444:      0,                           /* iVersion      */
                    445:      fts3auxConnectMethod,        /* xCreate       */
                    446:      fts3auxConnectMethod,        /* xConnect      */
                    447:      fts3auxBestIndexMethod,      /* xBestIndex    */
                    448:      fts3auxDisconnectMethod,     /* xDisconnect   */
                    449:      fts3auxDisconnectMethod,     /* xDestroy      */
                    450:      fts3auxOpenMethod,           /* xOpen         */
                    451:      fts3auxCloseMethod,          /* xClose        */
                    452:      fts3auxFilterMethod,         /* xFilter       */
                    453:      fts3auxNextMethod,           /* xNext         */
                    454:      fts3auxEofMethod,            /* xEof          */
                    455:      fts3auxColumnMethod,         /* xColumn       */
                    456:      fts3auxRowidMethod,          /* xRowid        */
                    457:      0,                           /* xUpdate       */
                    458:      0,                           /* xBegin        */
                    459:      0,                           /* xSync         */
                    460:      0,                           /* xCommit       */
                    461:      0,                           /* xRollback     */
                    462:      0,                           /* xFindFunction */
                    463:      0,                           /* xRename       */
                    464:      0,                           /* xSavepoint    */
                    465:      0,                           /* xRelease      */
                    466:      0                            /* xRollbackTo   */
                    467:   };
                    468:   int rc;                         /* Return code */
                    469: 
                    470:   rc = sqlite3_create_module(db, "fts4aux", &fts3aux_module, 0);
                    471:   return rc;
                    472: }
                    473: 
                    474: #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>