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