1 /*
2 ** 2016-06-29
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 demonstrates how to create a table-valued-function that
14 ** returns the values in a C-language array.
15 ** Examples:
16 **
17 **      SELECT * FROM carray($ptr,5)
18 **
19 ** The query above returns 5 integers contained in a C-language array
20 ** at the address $ptr.  $ptr is a pointer to the array of integers.
21 ** The pointer value must be assigned to $ptr using the
22 ** sqlite3_bind_pointer() interface with a pointer type of "carray".
23 ** For example:
24 **
25 **    static int aX[] = { 53, 9, 17, 2231, 4, 99 };
26 **    int i = sqlite3_bind_parameter_index(pStmt, "$ptr");
27 **    sqlite3_bind_pointer(pStmt, i, aX, "carray", 0);
28 **
29 ** There is an optional third parameter to determine the datatype of
30 ** the C-language array.  Allowed values of the third parameter are
31 ** 'int32', 'int64', 'double', 'char*'.  Example:
32 **
33 **      SELECT * FROM carray($ptr,10,'char*');
34 **
35 ** The default value of the third parameter is 'int32'.
36 **
37 ** HOW IT WORKS
38 **
39 ** The carray "function" is really a virtual table with the
40 ** following schema:
41 **
42 **     CREATE TABLE carray(
43 **       value,
44 **       pointer HIDDEN,
45 **       count HIDDEN,
46 **       ctype TEXT HIDDEN
47 **     );
48 **
49 ** If the hidden columns "pointer" and "count" are unconstrained, then
50 ** the virtual table has no rows.  Otherwise, the virtual table interprets
51 ** the integer value of "pointer" as a pointer to the array and "count"
52 ** as the number of elements in the array.  The virtual table steps through
53 ** the array, element by element.
54 */
55 #include "sqlite3ext.h"
56 SQLITE_EXTENSION_INIT1
57 #include <assert.h>
58 #include <string.h>
59 
60 #ifndef SQLITE_OMIT_VIRTUALTABLE
61 
62 /*
63 ** Allowed datatypes
64 */
65 #define CARRAY_INT32    0
66 #define CARRAY_INT64    1
67 #define CARRAY_DOUBLE   2
68 #define CARRAY_TEXT     3
69 
70 /*
71 ** Names of types
72 */
73 static const char *azType[] = { "int32", "int64", "double", "char*" };
74 
75 
76 /* carray_cursor is a subclass of sqlite3_vtab_cursor which will
77 ** serve as the underlying representation of a cursor that scans
78 ** over rows of the result
79 */
80 typedef struct carray_cursor carray_cursor;
81 struct carray_cursor {
82   sqlite3_vtab_cursor base;  /* Base class - must be first */
83   sqlite3_int64 iRowid;      /* The rowid */
84   void *pPtr;                /* Pointer to the array of values */
85   sqlite3_int64 iCnt;        /* Number of integers in the array */
86   unsigned char eType;       /* One of the CARRAY_type values */
87 };
88 
89 /*
90 ** The carrayConnect() method is invoked to create a new
91 ** carray_vtab that describes the carray virtual table.
92 **
93 ** Think of this routine as the constructor for carray_vtab objects.
94 **
95 ** All this routine needs to do is:
96 **
97 **    (1) Allocate the carray_vtab object and initialize all fields.
98 **
99 **    (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
100 **        result set of queries against carray will look like.
101 */
carrayConnect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)102 static int carrayConnect(
103   sqlite3 *db,
104   void *pAux,
105   int argc, const char *const*argv,
106   sqlite3_vtab **ppVtab,
107   char **pzErr
108 ){
109   sqlite3_vtab *pNew;
110   int rc;
111 
112 /* Column numbers */
113 #define CARRAY_COLUMN_VALUE   0
114 #define CARRAY_COLUMN_POINTER 1
115 #define CARRAY_COLUMN_COUNT   2
116 #define CARRAY_COLUMN_CTYPE   3
117 
118   rc = sqlite3_declare_vtab(db,
119      "CREATE TABLE x(value,pointer hidden,count hidden,ctype hidden)");
120   if( rc==SQLITE_OK ){
121     pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
122     if( pNew==0 ) return SQLITE_NOMEM;
123     memset(pNew, 0, sizeof(*pNew));
124   }
125   return rc;
126 }
127 
128 /*
129 ** This method is the destructor for carray_cursor objects.
130 */
carrayDisconnect(sqlite3_vtab * pVtab)131 static int carrayDisconnect(sqlite3_vtab *pVtab){
132   sqlite3_free(pVtab);
133   return SQLITE_OK;
134 }
135 
136 /*
137 ** Constructor for a new carray_cursor object.
138 */
carrayOpen(sqlite3_vtab * p,sqlite3_vtab_cursor ** ppCursor)139 static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
140   carray_cursor *pCur;
141   pCur = sqlite3_malloc( sizeof(*pCur) );
142   if( pCur==0 ) return SQLITE_NOMEM;
143   memset(pCur, 0, sizeof(*pCur));
144   *ppCursor = &pCur->base;
145   return SQLITE_OK;
146 }
147 
148 /*
149 ** Destructor for a carray_cursor.
150 */
carrayClose(sqlite3_vtab_cursor * cur)151 static int carrayClose(sqlite3_vtab_cursor *cur){
152   sqlite3_free(cur);
153   return SQLITE_OK;
154 }
155 
156 
157 /*
158 ** Advance a carray_cursor to its next row of output.
159 */
carrayNext(sqlite3_vtab_cursor * cur)160 static int carrayNext(sqlite3_vtab_cursor *cur){
161   carray_cursor *pCur = (carray_cursor*)cur;
162   pCur->iRowid++;
163   return SQLITE_OK;
164 }
165 
166 /*
167 ** Return values of columns for the row at which the carray_cursor
168 ** is currently pointing.
169 */
carrayColumn(sqlite3_vtab_cursor * cur,sqlite3_context * ctx,int i)170 static int carrayColumn(
171   sqlite3_vtab_cursor *cur,   /* The cursor */
172   sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
173   int i                       /* Which column to return */
174 ){
175   carray_cursor *pCur = (carray_cursor*)cur;
176   sqlite3_int64 x = 0;
177   switch( i ){
178     case CARRAY_COLUMN_POINTER:   return SQLITE_OK;
179     case CARRAY_COLUMN_COUNT:     x = pCur->iCnt;   break;
180     case CARRAY_COLUMN_CTYPE: {
181       sqlite3_result_text(ctx, azType[pCur->eType], -1, SQLITE_STATIC);
182       return SQLITE_OK;
183     }
184     default: {
185       switch( pCur->eType ){
186         case CARRAY_INT32: {
187           int *p = (int*)pCur->pPtr;
188           sqlite3_result_int(ctx, p[pCur->iRowid-1]);
189           return SQLITE_OK;
190         }
191         case CARRAY_INT64: {
192           sqlite3_int64 *p = (sqlite3_int64*)pCur->pPtr;
193           sqlite3_result_int64(ctx, p[pCur->iRowid-1]);
194           return SQLITE_OK;
195         }
196         case CARRAY_DOUBLE: {
197           double *p = (double*)pCur->pPtr;
198           sqlite3_result_double(ctx, p[pCur->iRowid-1]);
199           return SQLITE_OK;
200         }
201         case CARRAY_TEXT: {
202           const char **p = (const char**)pCur->pPtr;
203           sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT);
204           return SQLITE_OK;
205         }
206       }
207     }
208   }
209   sqlite3_result_int64(ctx, x);
210   return SQLITE_OK;
211 }
212 
213 /*
214 ** Return the rowid for the current row.  In this implementation, the
215 ** rowid is the same as the output value.
216 */
carrayRowid(sqlite3_vtab_cursor * cur,sqlite_int64 * pRowid)217 static int carrayRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
218   carray_cursor *pCur = (carray_cursor*)cur;
219   *pRowid = pCur->iRowid;
220   return SQLITE_OK;
221 }
222 
223 /*
224 ** Return TRUE if the cursor has been moved off of the last
225 ** row of output.
226 */
carrayEof(sqlite3_vtab_cursor * cur)227 static int carrayEof(sqlite3_vtab_cursor *cur){
228   carray_cursor *pCur = (carray_cursor*)cur;
229   return pCur->iRowid>pCur->iCnt;
230 }
231 
232 /*
233 ** This method is called to "rewind" the carray_cursor object back
234 ** to the first row of output.
235 */
carrayFilter(sqlite3_vtab_cursor * pVtabCursor,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)236 static int carrayFilter(
237   sqlite3_vtab_cursor *pVtabCursor,
238   int idxNum, const char *idxStr,
239   int argc, sqlite3_value **argv
240 ){
241   carray_cursor *pCur = (carray_cursor *)pVtabCursor;
242   if( idxNum ){
243     pCur->pPtr = sqlite3_value_pointer(argv[0], "carray");
244     pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0;
245     if( idxNum<3 ){
246       pCur->eType = CARRAY_INT32;
247     }else{
248       unsigned char i;
249       const char *zType = (const char*)sqlite3_value_text(argv[2]);
250       for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
251         if( sqlite3_stricmp(zType, azType[i])==0 ) break;
252       }
253       if( i>=sizeof(azType)/sizeof(azType[0]) ){
254         pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
255           "unknown datatype: %Q", zType);
256         return SQLITE_ERROR;
257       }else{
258         pCur->eType = i;
259       }
260     }
261   }else{
262     pCur->pPtr = 0;
263     pCur->iCnt = 0;
264   }
265   pCur->iRowid = 1;
266   return SQLITE_OK;
267 }
268 
269 /*
270 ** SQLite will invoke this method one or more times while planning a query
271 ** that uses the carray virtual table.  This routine needs to create
272 ** a query plan for each invocation and compute an estimated cost for that
273 ** plan.
274 **
275 ** In this implementation idxNum is used to represent the
276 ** query plan.  idxStr is unused.
277 **
278 ** idxNum is 2 if the pointer= and count= constraints exist,
279 ** 3 if the ctype= constraint also exists, and is 0 otherwise.
280 ** If idxNum is 0, then carray becomes an empty table.
281 */
carrayBestIndex(sqlite3_vtab * tab,sqlite3_index_info * pIdxInfo)282 static int carrayBestIndex(
283   sqlite3_vtab *tab,
284   sqlite3_index_info *pIdxInfo
285 ){
286   int i;                 /* Loop over constraints */
287   int ptrIdx = -1;       /* Index of the pointer= constraint, or -1 if none */
288   int cntIdx = -1;       /* Index of the count= constraint, or -1 if none */
289   int ctypeIdx = -1;     /* Index of the ctype= constraint, or -1 if none */
290 
291   const struct sqlite3_index_constraint *pConstraint;
292   pConstraint = pIdxInfo->aConstraint;
293   for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
294     if( pConstraint->usable==0 ) continue;
295     if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
296     switch( pConstraint->iColumn ){
297       case CARRAY_COLUMN_POINTER:
298         ptrIdx = i;
299         break;
300       case CARRAY_COLUMN_COUNT:
301         cntIdx = i;
302         break;
303       case CARRAY_COLUMN_CTYPE:
304         ctypeIdx = i;
305         break;
306     }
307   }
308   if( ptrIdx>=0 && cntIdx>=0 ){
309     pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1;
310     pIdxInfo->aConstraintUsage[ptrIdx].omit = 1;
311     pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
312     pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
313     pIdxInfo->estimatedCost = (double)1;
314     pIdxInfo->estimatedRows = 100;
315     pIdxInfo->idxNum = 2;
316     if( ctypeIdx>=0 ){
317       pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
318       pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
319       pIdxInfo->idxNum = 3;
320     }
321   }else{
322     pIdxInfo->estimatedCost = (double)2147483647;
323     pIdxInfo->estimatedRows = 2147483647;
324     pIdxInfo->idxNum = 0;
325   }
326   return SQLITE_OK;
327 }
328 
329 /*
330 ** This following structure defines all the methods for the
331 ** carray virtual table.
332 */
333 static sqlite3_module carrayModule = {
334   0,                         /* iVersion */
335   0,                         /* xCreate */
336   carrayConnect,             /* xConnect */
337   carrayBestIndex,           /* xBestIndex */
338   carrayDisconnect,          /* xDisconnect */
339   0,                         /* xDestroy */
340   carrayOpen,                /* xOpen - open a cursor */
341   carrayClose,               /* xClose - close a cursor */
342   carrayFilter,              /* xFilter - configure scan constraints */
343   carrayNext,                /* xNext - advance a cursor */
344   carrayEof,                 /* xEof - check for end of scan */
345   carrayColumn,              /* xColumn - read data */
346   carrayRowid,               /* xRowid - read data */
347   0,                         /* xUpdate */
348   0,                         /* xBegin */
349   0,                         /* xSync */
350   0,                         /* xCommit */
351   0,                         /* xRollback */
352   0,                         /* xFindMethod */
353   0,                         /* xRename */
354 };
355 
356 /*
357 ** For testing purpose in the TCL test harness, we need a method for
358 ** setting the pointer value.  The inttoptr(X) SQL function accomplishes
359 ** this.  Tcl script will bind an integer to X and the inttoptr() SQL
360 ** function will use sqlite3_result_pointer() to convert that integer into
361 ** a pointer.
362 **
363 ** This is for testing on TCL only.
364 */
365 #ifdef SQLITE_TEST
inttoptrFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)366 static void inttoptrFunc(
367   sqlite3_context *context,
368   int argc,
369   sqlite3_value **argv
370 ){
371   void *p;
372   sqlite3_int64 i64;
373   i64 = sqlite3_value_int64(argv[0]);
374   if( sizeof(i64)==sizeof(p) ){
375     memcpy(&p, &i64, sizeof(p));
376   }else{
377     int i32 = i64 & 0xffffffff;
378     memcpy(&p, &i32, sizeof(p));
379   }
380   sqlite3_result_pointer(context, p, "carray", 0);
381 }
382 #endif /* SQLITE_TEST */
383 
384 #endif /* SQLITE_OMIT_VIRTUALTABLE */
385 
386 #ifdef _WIN32
387 __declspec(dllexport)
388 #endif
sqlite3_carray_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)389 int sqlite3_carray_init(
390   sqlite3 *db,
391   char **pzErrMsg,
392   const sqlite3_api_routines *pApi
393 ){
394   int rc = SQLITE_OK;
395   SQLITE_EXTENSION_INIT2(pApi);
396 #ifndef SQLITE_OMIT_VIRTUALTABLE
397   rc = sqlite3_create_module(db, "carray", &carrayModule, 0);
398 #ifdef SQLITE_TEST
399   if( rc==SQLITE_OK ){
400     rc = sqlite3_create_function(db, "inttoptr", 1, SQLITE_UTF8, 0,
401                                  inttoptrFunc, 0, 0);
402   }
403 #endif /* SQLITE_TEST */
404 #endif /* SQLITE_OMIT_VIRTUALTABLE */
405   return rc;
406 }
407