• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
wholenumberConnect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)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 
wholenumberDisconnect(sqlite3_vtab * pVtab)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 */
wholenumberOpen(sqlite3_vtab * p,sqlite3_vtab_cursor ** ppCursor)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 */
wholenumberClose(sqlite3_vtab_cursor * cur)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 */
wholenumberNext(sqlite3_vtab_cursor * cur)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 */
wholenumberColumn(sqlite3_vtab_cursor * cur,sqlite3_context * ctx,int i)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 */
wholenumberRowid(sqlite3_vtab_cursor * cur,sqlite_int64 * pRowid)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 */
wholenumberEof(sqlite3_vtab_cursor * cur)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 */
wholenumberFilter(sqlite3_vtab_cursor * pVtabCursor,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)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 */
wholenumberBestIndex(sqlite3_vtab * tab,sqlite3_index_info * pIdxInfo)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 */
wholenumber_register(sqlite3 * db)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 */
register_wholenumber_module(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])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 */
Sqlitetestwholenumber_Init(Tcl_Interp * interp)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