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