Home | History | Annotate | Download | only in src
      1 /*
      2 ** 2011 April 02
      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 implements a virtual table that returns the whole numbers
     14 ** between 1 and 4294967295, inclusive.
     15 **
     16 ** Example:
     17 **
     18 **     CREATE VIRTUAL TABLE nums USING wholenumber;
     19 **     SELECT value FROM nums WHERE value<10;
     20 **
     21 ** Results in:
     22 **
     23 **     1 2 3 4 5 6 7 8 9
     24 */
     25 #include "sqlite3.h"
     26 #include <assert.h>
     27 #include <string.h>
     28 
     29 #ifndef SQLITE_OMIT_VIRTUALTABLE
     30 
     31 
     32 /* A wholenumber cursor object */
     33 typedef struct wholenumber_cursor wholenumber_cursor;
     34 struct wholenumber_cursor {
     35   sqlite3_vtab_cursor base;  /* Base class - must be first */
     36   unsigned iValue;           /* Current value */
     37   unsigned mxValue;          /* Maximum value */
     38 };
     39 
     40 /* Methods for the wholenumber module */
     41 static int wholenumberConnect(
     42   sqlite3 *db,
     43   void *pAux,
     44   int argc, const char *const*argv,
     45   sqlite3_vtab **ppVtab,
     46   char **pzErr
     47 ){
     48   sqlite3_vtab *pNew;
     49   pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
     50   if( pNew==0 ) return SQLITE_NOMEM;
     51   sqlite3_declare_vtab(db, "CREATE TABLE x(value)");
     52   memset(pNew, 0, sizeof(*pNew));
     53   return SQLITE_OK;
     54 }
     55 /* Note that for this virtual table, the xCreate and xConnect
     56 ** methods are identical. */
     57 
     58 static int wholenumberDisconnect(sqlite3_vtab *pVtab){
     59   sqlite3_free(pVtab);
     60   return SQLITE_OK;
     61 }
     62 /* The xDisconnect and xDestroy methods are also the same */
     63 
     64 
     65 /*
     66 ** Open a new wholenumber cursor.
     67 */
     68 static int wholenumberOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
     69   wholenumber_cursor *pCur;
     70   pCur = sqlite3_malloc( sizeof(*pCur) );
     71   if( pCur==0 ) return SQLITE_NOMEM;
     72   memset(pCur, 0, sizeof(*pCur));
     73   *ppCursor = &pCur->base;
     74   return SQLITE_OK;
     75 }
     76 
     77 /*
     78 ** Close a wholenumber cursor.
     79 */
     80 static int wholenumberClose(sqlite3_vtab_cursor *cur){
     81   sqlite3_free(cur);
     82   return SQLITE_OK;
     83 }
     84 
     85 
     86 /*
     87 ** Advance a cursor to its next row of output
     88 */
     89 static int wholenumberNext(sqlite3_vtab_cursor *cur){
     90   wholenumber_cursor *pCur = (wholenumber_cursor*)cur;
     91   pCur->iValue++;
     92   return SQLITE_OK;
     93 }
     94 
     95 /*
     96 ** Return the value associated with a wholenumber.
     97 */
     98 static int wholenumberColumn(
     99   sqlite3_vtab_cursor *cur,
    100   sqlite3_context *ctx,
    101   int i
    102 ){
    103   wholenumber_cursor *pCur = (wholenumber_cursor*)cur;
    104   sqlite3_result_int64(ctx, pCur->iValue);
    105   return SQLITE_OK;
    106 }
    107 
    108 /*
    109 ** The rowid.
    110 */
    111 static int wholenumberRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
    112   wholenumber_cursor *pCur = (wholenumber_cursor*)cur;
    113   *pRowid = pCur->iValue;
    114   return SQLITE_OK;
    115 }
    116 
    117 /*
    118 ** When the wholenumber_cursor.rLimit value is 0 or less, that is a signal
    119 ** that the cursor has nothing more to output.
    120 */
    121 static int wholenumberEof(sqlite3_vtab_cursor *cur){
    122   wholenumber_cursor *pCur = (wholenumber_cursor*)cur;
    123   return pCur->iValue>pCur->mxValue || pCur->iValue==0;
    124 }
    125 
    126 /*
    127 ** Called to "rewind" a cursor back to the beginning so that
    128 ** it starts its output over again.  Always called at least once
    129 ** prior to any wholenumberColumn, wholenumberRowid, or wholenumberEof call.
    130 **
    131 **    idxNum   Constraints
    132 **    ------   ---------------------
    133 **      0      (none)
    134 **      1      value > $argv0
    135 **      2      value >= $argv0
    136 **      4      value < $argv0
    137 **      8      value <= $argv0
    138 **
    139 **      5      value > $argv0 AND value < $argv1
    140 **      6      value >= $argv0 AND value < $argv1
    141 **      9      value > $argv0 AND value <= $argv1
    142 **     10      value >= $argv0 AND value <= $argv1
    143 */
    144 static int wholenumberFilter(
    145   sqlite3_vtab_cursor *pVtabCursor,
    146   int idxNum, const char *idxStr,
    147   int argc, sqlite3_value **argv
    148 ){
    149   wholenumber_cursor *pCur = (wholenumber_cursor *)pVtabCursor;
    150   sqlite3_int64 v;
    151   int i = 0;
    152   pCur->iValue = 1;
    153   pCur->mxValue = 0xffffffff;  /* 4294967295 */
    154   if( idxNum & 3 ){
    155     v = sqlite3_value_int64(argv[0]) + (idxNum&1);
    156     if( v>pCur->iValue && v<=pCur->mxValue ) pCur->iValue = v;
    157     i++;
    158   }
    159   if( idxNum & 12 ){
    160     v = sqlite3_value_int64(argv[i]) - ((idxNum>>2)&1);
    161     if( v>=pCur->iValue && v<pCur->mxValue ) pCur->mxValue = v;
    162   }
    163   return SQLITE_OK;
    164 }
    165 
    166 /*
    167 ** Search for terms of these forms:
    168 **
    169 **  (1)  value > $value
    170 **  (2)  value >= $value
    171 **  (4)  value < $value
    172 **  (8)  value <= $value
    173 **
    174 ** idxNum is an ORed combination of 1 or 2 with 4 or 8.
    175 */
    176 static int wholenumberBestIndex(
    177   sqlite3_vtab *tab,
    178   sqlite3_index_info *pIdxInfo
    179 ){
    180   int i;
    181   int idxNum = 0;
    182   int argvIdx = 1;
    183   int ltIdx = -1;
    184   int gtIdx = -1;
    185   const struct sqlite3_index_constraint *pConstraint;
    186   pConstraint = pIdxInfo->aConstraint;
    187   for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
    188     if( pConstraint->usable==0 ) continue;
    189     if( (idxNum & 3)==0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_GT ){
    190       idxNum |= 1;
    191       ltIdx = i;
    192     }
    193     if( (idxNum & 3)==0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_GE ){
    194       idxNum |= 2;
    195       ltIdx = i;
    196     }
    197     if( (idxNum & 12)==0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ){
    198       idxNum |= 4;
    199       gtIdx = i;
    200     }
    201     if( (idxNum & 12)==0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE ){
    202       idxNum |= 8;
    203       gtIdx = i;
    204     }
    205   }
    206   pIdxInfo->idxNum = idxNum;
    207   if( ltIdx>=0 ){
    208     pIdxInfo->aConstraintUsage[ltIdx].argvIndex = argvIdx++;
    209     pIdxInfo->aConstraintUsage[ltIdx].omit = 1;
    210   }
    211   if( gtIdx>=0 ){
    212     pIdxInfo->aConstraintUsage[gtIdx].argvIndex = argvIdx;
    213     pIdxInfo->aConstraintUsage[gtIdx].omit = 1;
    214   }
    215   if( pIdxInfo->nOrderBy==1
    216    && pIdxInfo->aOrderBy[0].desc==0
    217   ){
    218     pIdxInfo->orderByConsumed = 1;
    219   }
    220   pIdxInfo->estimatedCost = (double)1;
    221   return SQLITE_OK;
    222 }
    223 
    224 /*
    225 ** A virtual table module that provides read-only access to a
    226 ** Tcl global variable namespace.
    227 */
    228 static sqlite3_module wholenumberModule = {
    229   0,                         /* iVersion */
    230   wholenumberConnect,
    231   wholenumberConnect,
    232   wholenumberBestIndex,
    233   wholenumberDisconnect,
    234   wholenumberDisconnect,
    235   wholenumberOpen,           /* xOpen - open a cursor */
    236   wholenumberClose,          /* xClose - close a cursor */
    237   wholenumberFilter,         /* xFilter - configure scan constraints */
    238   wholenumberNext,           /* xNext - advance a cursor */
    239   wholenumberEof,            /* xEof - check for end of scan */
    240   wholenumberColumn,         /* xColumn - read data */
    241   wholenumberRowid,          /* xRowid - read data */
    242   0,                         /* xUpdate */
    243   0,                         /* xBegin */
    244   0,                         /* xSync */
    245   0,                         /* xCommit */
    246   0,                         /* xRollback */
    247   0,                         /* xFindMethod */
    248   0,                         /* xRename */
    249 };
    250 
    251 #endif /* SQLITE_OMIT_VIRTUALTABLE */
    252 
    253 
    254 /*
    255 ** Register the wholenumber virtual table
    256 */
    257 int wholenumber_register(sqlite3 *db){
    258   int rc = SQLITE_OK;
    259 #ifndef SQLITE_OMIT_VIRTUALTABLE
    260   rc = sqlite3_create_module(db, "wholenumber", &wholenumberModule, 0);
    261 #endif
    262   return rc;
    263 }
    264 
    265 #ifdef SQLITE_TEST
    266 #include <tcl.h>
    267 /*
    268 ** Decode a pointer to an sqlite3 object.
    269 */
    270 extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
    271 
    272 /*
    273 ** Register the echo virtual table module.
    274 */
    275 static int register_wholenumber_module(
    276   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
    277   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
    278   int objc,              /* Number of arguments */
    279   Tcl_Obj *CONST objv[]  /* Command arguments */
    280 ){
    281   sqlite3 *db;
    282   if( objc!=2 ){
    283     Tcl_WrongNumArgs(interp, 1, objv, "DB");
    284     return TCL_ERROR;
    285   }
    286   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
    287   wholenumber_register(db);
    288   return TCL_OK;
    289 }
    290 
    291 
    292 /*
    293 ** Register commands with the TCL interpreter.
    294 */
    295 int Sqlitetestwholenumber_Init(Tcl_Interp *interp){
    296   static struct {
    297      char *zName;
    298      Tcl_ObjCmdProc *xProc;
    299      void *clientData;
    300   } aObjCmd[] = {
    301      { "register_wholenumber_module",   register_wholenumber_module, 0 },
    302   };
    303   int i;
    304   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
    305     Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
    306         aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
    307   }
    308   return TCL_OK;
    309 }
    310 
    311 #endif /* SQLITE_TEST */
    312