xref: /sqlite-3.40.0/ext/misc/wholenumber.c (revision 49e6e5a0)
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 "sqlite3ext.h"
26 SQLITE_EXTENSION_INIT1
27 #include <assert.h>
28 #include <string.h>
29 
30 #ifndef SQLITE_OMIT_VIRTUALTABLE
31 
32 
33 /* A wholenumber cursor object */
34 typedef struct wholenumber_cursor wholenumber_cursor;
35 struct wholenumber_cursor {
36   sqlite3_vtab_cursor base;  /* Base class - must be first */
37   sqlite3_int64 iValue;      /* Current value */
38   sqlite3_int64 mxValue;     /* Maximum value */
39 };
40 
41 /* Methods for the wholenumber module */
wholenumberConnect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)42 static int wholenumberConnect(
43   sqlite3 *db,
44   void *pAux,
45   int argc, const char *const*argv,
46   sqlite3_vtab **ppVtab,
47   char **pzErr
48 ){
49   sqlite3_vtab *pNew;
50   pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
51   if( pNew==0 ) return SQLITE_NOMEM;
52   sqlite3_declare_vtab(db, "CREATE TABLE x(value)");
53   sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
54   memset(pNew, 0, sizeof(*pNew));
55   return SQLITE_OK;
56 }
57 /* Note that for this virtual table, the xCreate and xConnect
58 ** methods are identical. */
59 
wholenumberDisconnect(sqlite3_vtab * pVtab)60 static int wholenumberDisconnect(sqlite3_vtab *pVtab){
61   sqlite3_free(pVtab);
62   return SQLITE_OK;
63 }
64 /* The xDisconnect and xDestroy methods are also the same */
65 
66 
67 /*
68 ** Open a new wholenumber cursor.
69 */
wholenumberOpen(sqlite3_vtab * p,sqlite3_vtab_cursor ** ppCursor)70 static int wholenumberOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
71   wholenumber_cursor *pCur;
72   pCur = sqlite3_malloc( sizeof(*pCur) );
73   if( pCur==0 ) return SQLITE_NOMEM;
74   memset(pCur, 0, sizeof(*pCur));
75   *ppCursor = &pCur->base;
76   return SQLITE_OK;
77 }
78 
79 /*
80 ** Close a wholenumber cursor.
81 */
wholenumberClose(sqlite3_vtab_cursor * cur)82 static int wholenumberClose(sqlite3_vtab_cursor *cur){
83   sqlite3_free(cur);
84   return SQLITE_OK;
85 }
86 
87 
88 /*
89 ** Advance a cursor to its next row of output
90 */
wholenumberNext(sqlite3_vtab_cursor * cur)91 static int wholenumberNext(sqlite3_vtab_cursor *cur){
92   wholenumber_cursor *pCur = (wholenumber_cursor*)cur;
93   pCur->iValue++;
94   return SQLITE_OK;
95 }
96 
97 /*
98 ** Return the value associated with a wholenumber.
99 */
wholenumberColumn(sqlite3_vtab_cursor * cur,sqlite3_context * ctx,int i)100 static int wholenumberColumn(
101   sqlite3_vtab_cursor *cur,
102   sqlite3_context *ctx,
103   int i
104 ){
105   wholenumber_cursor *pCur = (wholenumber_cursor*)cur;
106   sqlite3_result_int64(ctx, pCur->iValue);
107   return SQLITE_OK;
108 }
109 
110 /*
111 ** The rowid.
112 */
wholenumberRowid(sqlite3_vtab_cursor * cur,sqlite_int64 * pRowid)113 static int wholenumberRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
114   wholenumber_cursor *pCur = (wholenumber_cursor*)cur;
115   *pRowid = pCur->iValue;
116   return SQLITE_OK;
117 }
118 
119 /*
120 ** When the wholenumber_cursor.rLimit value is 0 or less, that is a signal
121 ** that the cursor has nothing more to output.
122 */
wholenumberEof(sqlite3_vtab_cursor * cur)123 static int wholenumberEof(sqlite3_vtab_cursor *cur){
124   wholenumber_cursor *pCur = (wholenumber_cursor*)cur;
125   return pCur->iValue>pCur->mxValue || pCur->iValue==0;
126 }
127 
128 /*
129 ** Called to "rewind" a cursor back to the beginning so that
130 ** it starts its output over again.  Always called at least once
131 ** prior to any wholenumberColumn, wholenumberRowid, or wholenumberEof call.
132 **
133 **    idxNum   Constraints
134 **    ------   ---------------------
135 **      0      (none)
136 **      1      value > $argv0
137 **      2      value >= $argv0
138 **      4      value < $argv0
139 **      8      value <= $argv0
140 **
141 **      5      value > $argv0 AND value < $argv1
142 **      6      value >= $argv0 AND value < $argv1
143 **      9      value > $argv0 AND value <= $argv1
144 **     10      value >= $argv0 AND value <= $argv1
145 */
wholenumberFilter(sqlite3_vtab_cursor * pVtabCursor,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)146 static int wholenumberFilter(
147   sqlite3_vtab_cursor *pVtabCursor,
148   int idxNum, const char *idxStr,
149   int argc, sqlite3_value **argv
150 ){
151   wholenumber_cursor *pCur = (wholenumber_cursor *)pVtabCursor;
152   sqlite3_int64 v;
153   int i = 0;
154   pCur->iValue = 1;
155   pCur->mxValue = 0xffffffff;  /* 4294967295 */
156   if( idxNum & 3 ){
157     v = sqlite3_value_int64(argv[0]) + (idxNum&1);
158     if( v>pCur->iValue && v<=pCur->mxValue ) pCur->iValue = v;
159     i++;
160   }
161   if( idxNum & 12 ){
162     v = sqlite3_value_int64(argv[i]) - ((idxNum>>2)&1);
163     if( v>=pCur->iValue && v<pCur->mxValue ) pCur->mxValue = v;
164   }
165   return SQLITE_OK;
166 }
167 
168 /*
169 ** Search for terms of these forms:
170 **
171 **  (1)  value > $value
172 **  (2)  value >= $value
173 **  (4)  value < $value
174 **  (8)  value <= $value
175 **
176 ** idxNum is an ORed combination of 1 or 2 with 4 or 8.
177 */
wholenumberBestIndex(sqlite3_vtab * tab,sqlite3_index_info * pIdxInfo)178 static int wholenumberBestIndex(
179   sqlite3_vtab *tab,
180   sqlite3_index_info *pIdxInfo
181 ){
182   int i;
183   int idxNum = 0;
184   int argvIdx = 1;
185   int ltIdx = -1;
186   int gtIdx = -1;
187   const struct sqlite3_index_constraint *pConstraint;
188   pConstraint = pIdxInfo->aConstraint;
189   for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
190     if( pConstraint->usable==0 ) continue;
191     if( (idxNum & 3)==0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_GT ){
192       idxNum |= 1;
193       ltIdx = i;
194     }
195     if( (idxNum & 3)==0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_GE ){
196       idxNum |= 2;
197       ltIdx = i;
198     }
199     if( (idxNum & 12)==0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ){
200       idxNum |= 4;
201       gtIdx = i;
202     }
203     if( (idxNum & 12)==0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE ){
204       idxNum |= 8;
205       gtIdx = i;
206     }
207   }
208   pIdxInfo->idxNum = idxNum;
209   if( ltIdx>=0 ){
210     pIdxInfo->aConstraintUsage[ltIdx].argvIndex = argvIdx++;
211     pIdxInfo->aConstraintUsage[ltIdx].omit = 1;
212   }
213   if( gtIdx>=0 ){
214     pIdxInfo->aConstraintUsage[gtIdx].argvIndex = argvIdx;
215     pIdxInfo->aConstraintUsage[gtIdx].omit = 1;
216   }
217   if( pIdxInfo->nOrderBy==1
218    && pIdxInfo->aOrderBy[0].desc==0
219   ){
220     pIdxInfo->orderByConsumed = 1;
221   }
222   if( (idxNum & 12)==0 ){
223     pIdxInfo->estimatedCost = 1e99;
224   }else if( (idxNum & 3)==0 ){
225     pIdxInfo->estimatedCost = (double)5;
226   }else{
227     pIdxInfo->estimatedCost = (double)1;
228   }
229   return SQLITE_OK;
230 }
231 
232 /*
233 ** A virtual table module that provides read-only access to a
234 ** Tcl global variable namespace.
235 */
236 static sqlite3_module wholenumberModule = {
237   0,                         /* iVersion */
238   wholenumberConnect,
239   wholenumberConnect,
240   wholenumberBestIndex,
241   wholenumberDisconnect,
242   wholenumberDisconnect,
243   wholenumberOpen,           /* xOpen - open a cursor */
244   wholenumberClose,          /* xClose - close a cursor */
245   wholenumberFilter,         /* xFilter - configure scan constraints */
246   wholenumberNext,           /* xNext - advance a cursor */
247   wholenumberEof,            /* xEof - check for end of scan */
248   wholenumberColumn,         /* xColumn - read data */
249   wholenumberRowid,          /* xRowid - read data */
250   0,                         /* xUpdate */
251   0,                         /* xBegin */
252   0,                         /* xSync */
253   0,                         /* xCommit */
254   0,                         /* xRollback */
255   0,                         /* xFindMethod */
256   0,                         /* xRename */
257 };
258 
259 #endif /* SQLITE_OMIT_VIRTUALTABLE */
260 
261 #ifdef _WIN32
262 __declspec(dllexport)
263 #endif
sqlite3_wholenumber_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)264 int sqlite3_wholenumber_init(
265   sqlite3 *db,
266   char **pzErrMsg,
267   const sqlite3_api_routines *pApi
268 ){
269   int rc = SQLITE_OK;
270   SQLITE_EXTENSION_INIT2(pApi);
271 #ifndef SQLITE_OMIT_VIRTUALTABLE
272   rc = sqlite3_create_module(db, "wholenumber", &wholenumberModule, 0);
273 #endif
274   return rc;
275 }
276