1 /*
2 ** 2018-04-19
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 template virtual-table.
14 ** Developers can make a copy of this file as a baseline for writing
15 ** new virtual tables and/or table-valued functions.
16 **
17 ** Steps for writing a new virtual table implementation:
18 **
19 **     (1)  Make a copy of this file.  Perhaps call it "mynewvtab.c"
20 **
21 **     (2)  Replace this header comment with something appropriate for
22 **          the new virtual table
23 **
24 **     (3)  Change every occurrence of "templatevtab" to some other string
25 **          appropriate for the new virtual table.  Ideally, the new string
26 **          should be the basename of the source file: "mynewvtab".  Also
27 **          globally change "TEMPLATEVTAB" to "MYNEWVTAB".
28 **
29 **     (4)  Run a test compilation to make sure the unmodified virtual
30 **          table works.
31 **
32 **     (5)  Begin making incremental changes, testing as you go, to evolve
33 **          the new virtual table to do what you want it to do.
34 **
35 ** This template is minimal, in the sense that it uses only the required
36 ** methods on the sqlite3_module object.  As a result, templatevtab is
37 ** a read-only and eponymous-only table.  Those limitation can be removed
38 ** by adding new methods.
39 **
40 ** This template implements an eponymous-only virtual table with a rowid and
41 ** two columns named "a" and "b".  The table as 10 rows with fixed integer
42 ** values. Usage example:
43 **
44 **     SELECT rowid, a, b FROM templatevtab;
45 */
46 #if !defined(SQLITEINT_H)
47 #include "sqlite3ext.h"
48 #endif
49 SQLITE_EXTENSION_INIT1
50 #include <string.h>
51 #include <assert.h>
52 
53 /* templatevtab_vtab is a subclass of sqlite3_vtab which is
54 ** underlying representation of the virtual table
55 */
56 typedef struct templatevtab_vtab templatevtab_vtab;
57 struct templatevtab_vtab {
58   sqlite3_vtab base;  /* Base class - must be first */
59   /* Add new fields here, as necessary */
60 };
61 
62 /* templatevtab_cursor is a subclass of sqlite3_vtab_cursor which will
63 ** serve as the underlying representation of a cursor that scans
64 ** over rows of the result
65 */
66 typedef struct templatevtab_cursor templatevtab_cursor;
67 struct templatevtab_cursor {
68   sqlite3_vtab_cursor base;  /* Base class - must be first */
69   /* Insert new fields here.  For this templatevtab we only keep track
70   ** of the rowid */
71   sqlite3_int64 iRowid;      /* The rowid */
72 };
73 
74 /*
75 ** The templatevtabConnect() method is invoked to create a new
76 ** template virtual table.
77 **
78 ** Think of this routine as the constructor for templatevtab_vtab objects.
79 **
80 ** All this routine needs to do is:
81 **
82 **    (1) Allocate the templatevtab_vtab object and initialize all fields.
83 **
84 **    (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
85 **        result set of queries against the virtual table will look like.
86 */
templatevtabConnect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)87 static int templatevtabConnect(
88   sqlite3 *db,
89   void *pAux,
90   int argc, const char *const*argv,
91   sqlite3_vtab **ppVtab,
92   char **pzErr
93 ){
94   templatevtab_vtab *pNew;
95   int rc;
96 
97   rc = sqlite3_declare_vtab(db,
98            "CREATE TABLE x(a,b)"
99        );
100   /* For convenience, define symbolic names for the index to each column. */
101 #define TEMPLATEVTAB_A  0
102 #define TEMPLATEVTAB_B  1
103   if( rc==SQLITE_OK ){
104     pNew = sqlite3_malloc( sizeof(*pNew) );
105     *ppVtab = (sqlite3_vtab*)pNew;
106     if( pNew==0 ) return SQLITE_NOMEM;
107     memset(pNew, 0, sizeof(*pNew));
108   }
109   return rc;
110 }
111 
112 /*
113 ** This method is the destructor for templatevtab_vtab objects.
114 */
templatevtabDisconnect(sqlite3_vtab * pVtab)115 static int templatevtabDisconnect(sqlite3_vtab *pVtab){
116   templatevtab_vtab *p = (templatevtab_vtab*)pVtab;
117   sqlite3_free(p);
118   return SQLITE_OK;
119 }
120 
121 /*
122 ** Constructor for a new templatevtab_cursor object.
123 */
templatevtabOpen(sqlite3_vtab * p,sqlite3_vtab_cursor ** ppCursor)124 static int templatevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
125   templatevtab_cursor *pCur;
126   pCur = sqlite3_malloc( sizeof(*pCur) );
127   if( pCur==0 ) return SQLITE_NOMEM;
128   memset(pCur, 0, sizeof(*pCur));
129   *ppCursor = &pCur->base;
130   return SQLITE_OK;
131 }
132 
133 /*
134 ** Destructor for a templatevtab_cursor.
135 */
templatevtabClose(sqlite3_vtab_cursor * cur)136 static int templatevtabClose(sqlite3_vtab_cursor *cur){
137   templatevtab_cursor *pCur = (templatevtab_cursor*)cur;
138   sqlite3_free(pCur);
139   return SQLITE_OK;
140 }
141 
142 
143 /*
144 ** Advance a templatevtab_cursor to its next row of output.
145 */
templatevtabNext(sqlite3_vtab_cursor * cur)146 static int templatevtabNext(sqlite3_vtab_cursor *cur){
147   templatevtab_cursor *pCur = (templatevtab_cursor*)cur;
148   pCur->iRowid++;
149   return SQLITE_OK;
150 }
151 
152 /*
153 ** Return values of columns for the row at which the templatevtab_cursor
154 ** is currently pointing.
155 */
templatevtabColumn(sqlite3_vtab_cursor * cur,sqlite3_context * ctx,int i)156 static int templatevtabColumn(
157   sqlite3_vtab_cursor *cur,   /* The cursor */
158   sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
159   int i                       /* Which column to return */
160 ){
161   templatevtab_cursor *pCur = (templatevtab_cursor*)cur;
162   switch( i ){
163     case TEMPLATEVTAB_A:
164       sqlite3_result_int(ctx, 1000 + pCur->iRowid);
165       break;
166     default:
167       assert( i==TEMPLATEVTAB_B );
168       sqlite3_result_int(ctx, 2000 + pCur->iRowid);
169       break;
170   }
171   return SQLITE_OK;
172 }
173 
174 /*
175 ** Return the rowid for the current row.  In this implementation, the
176 ** rowid is the same as the output value.
177 */
templatevtabRowid(sqlite3_vtab_cursor * cur,sqlite_int64 * pRowid)178 static int templatevtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
179   templatevtab_cursor *pCur = (templatevtab_cursor*)cur;
180   *pRowid = pCur->iRowid;
181   return SQLITE_OK;
182 }
183 
184 /*
185 ** Return TRUE if the cursor has been moved off of the last
186 ** row of output.
187 */
templatevtabEof(sqlite3_vtab_cursor * cur)188 static int templatevtabEof(sqlite3_vtab_cursor *cur){
189   templatevtab_cursor *pCur = (templatevtab_cursor*)cur;
190   return pCur->iRowid>=10;
191 }
192 
193 /*
194 ** This method is called to "rewind" the templatevtab_cursor object back
195 ** to the first row of output.  This method is always called at least
196 ** once prior to any call to templatevtabColumn() or templatevtabRowid() or
197 ** templatevtabEof().
198 */
templatevtabFilter(sqlite3_vtab_cursor * pVtabCursor,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)199 static int templatevtabFilter(
200   sqlite3_vtab_cursor *pVtabCursor,
201   int idxNum, const char *idxStr,
202   int argc, sqlite3_value **argv
203 ){
204   templatevtab_cursor *pCur = (templatevtab_cursor *)pVtabCursor;
205   pCur->iRowid = 1;
206   return SQLITE_OK;
207 }
208 
209 /*
210 ** SQLite will invoke this method one or more times while planning a query
211 ** that uses the virtual table.  This routine needs to create
212 ** a query plan for each invocation and compute an estimated cost for that
213 ** plan.
214 */
templatevtabBestIndex(sqlite3_vtab * tab,sqlite3_index_info * pIdxInfo)215 static int templatevtabBestIndex(
216   sqlite3_vtab *tab,
217   sqlite3_index_info *pIdxInfo
218 ){
219   pIdxInfo->estimatedCost = (double)10;
220   pIdxInfo->estimatedRows = 10;
221   return SQLITE_OK;
222 }
223 
224 /*
225 ** This following structure defines all the methods for the
226 ** virtual table.
227 */
228 static sqlite3_module templatevtabModule = {
229   /* iVersion    */ 0,
230   /* xCreate     */ 0,
231   /* xConnect    */ templatevtabConnect,
232   /* xBestIndex  */ templatevtabBestIndex,
233   /* xDisconnect */ templatevtabDisconnect,
234   /* xDestroy    */ 0,
235   /* xOpen       */ templatevtabOpen,
236   /* xClose      */ templatevtabClose,
237   /* xFilter     */ templatevtabFilter,
238   /* xNext       */ templatevtabNext,
239   /* xEof        */ templatevtabEof,
240   /* xColumn     */ templatevtabColumn,
241   /* xRowid      */ templatevtabRowid,
242   /* xUpdate     */ 0,
243   /* xBegin      */ 0,
244   /* xSync       */ 0,
245   /* xCommit     */ 0,
246   /* xRollback   */ 0,
247   /* xFindMethod */ 0,
248   /* xRename     */ 0,
249   /* xSavepoint  */ 0,
250   /* xRelease    */ 0,
251   /* xRollbackTo */ 0,
252   /* xShadowName */ 0
253 };
254 
255 
256 #ifdef _WIN32
257 __declspec(dllexport)
258 #endif
sqlite3_templatevtab_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)259 int sqlite3_templatevtab_init(
260   sqlite3 *db,
261   char **pzErrMsg,
262   const sqlite3_api_routines *pApi
263 ){
264   int rc = SQLITE_OK;
265   SQLITE_EXTENSION_INIT2(pApi);
266   rc = sqlite3_create_module(db, "templatevtab", &templatevtabModule, 0);
267   return rc;
268 }
269