| /* | |
| ** 2018-04-19 | |
| ** | |
| ** The author disclaims copyright to this source code. In place of | |
| ** a legal notice, here is a blessing: | |
| ** | |
| ** May you do good and not evil. | |
| ** May you find forgiveness for yourself and forgive others. | |
| ** May you share freely, never taking more than you give. | |
| ** | |
| ************************************************************************* | |
| ** | |
| ** This file implements a template virtual-table. | |
| ** Developers can make a copy of this file as a baseline for writing | |
| ** new virtual tables and/or table-valued functions. | |
| ** | |
| ** Steps for writing a new virtual table implementation: | |
| ** | |
| ** (1) Make a copy of this file. Perhaps call it "mynewvtab.c" | |
| ** | |
| ** (2) Replace this header comment with something appropriate for | |
| ** the new virtual table | |
| ** | |
| ** (3) Change every occurrence of "templatevtab" to some other string | |
| ** appropriate for the new virtual table. Ideally, the new string | |
| ** should be the basename of the source file: "mynewvtab". Also | |
| ** globally change "TEMPLATEVTAB" to "MYNEWVTAB". | |
| ** | |
| ** (4) Run a test compilation to make sure the unmodified virtual | |
| ** table works. | |
| ** | |
| ** (5) Begin making incremental changes, testing as you go, to evolve | |
| ** the new virtual table to do what you want it to do. | |
| ** | |
| ** This template is minimal, in the sense that it uses only the required | |
| ** methods on the sqlite3_module object. As a result, templatevtab is | |
| ** a read-only and eponymous-only table. Those limitation can be removed | |
| ** by adding new methods. | |
| ** | |
| ** This template implements an eponymous-only virtual table with a rowid and | |
| ** two columns named "a" and "b". The table as 10 rows with fixed integer | |
| ** values. Usage example: | |
| ** | |
| ** SELECT rowid, a, b FROM templatevtab; | |
| */ | |
| SQLITE_EXTENSION_INIT1 | |
| /* templatevtab_vtab is a subclass of sqlite3_vtab which is | |
| ** underlying representation of the virtual table | |
| */ | |
| typedef struct templatevtab_vtab templatevtab_vtab; | |
| struct templatevtab_vtab { | |
| sqlite3_vtab base; /* Base class - must be first */ | |
| /* Add new fields here, as necessary */ | |
| }; | |
| /* templatevtab_cursor is a subclass of sqlite3_vtab_cursor which will | |
| ** serve as the underlying representation of a cursor that scans | |
| ** over rows of the result | |
| */ | |
| typedef struct templatevtab_cursor templatevtab_cursor; | |
| struct templatevtab_cursor { | |
| sqlite3_vtab_cursor base; /* Base class - must be first */ | |
| /* Insert new fields here. For this templatevtab we only keep track | |
| ** of the rowid */ | |
| sqlite3_int64 iRowid; /* The rowid */ | |
| }; | |
| /* | |
| ** The templatevtabConnect() method is invoked to create a new | |
| ** template virtual table. | |
| ** | |
| ** Think of this routine as the constructor for templatevtab_vtab objects. | |
| ** | |
| ** All this routine needs to do is: | |
| ** | |
| ** (1) Allocate the templatevtab_vtab object and initialize all fields. | |
| ** | |
| ** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the | |
| ** result set of queries against the virtual table will look like. | |
| */ | |
| static int templatevtabConnect( | |
| sqlite3 *db, | |
| void *pAux, | |
| int argc, const char *const*argv, | |
| sqlite3_vtab **ppVtab, | |
| char **pzErr | |
| ){ | |
| templatevtab_vtab *pNew; | |
| int rc; | |
| rc = sqlite3_declare_vtab(db, | |
| "CREATE TABLE x(a,b)" | |
| ); | |
| /* For convenience, define symbolic names for the index to each column. */ | |
| if( rc==SQLITE_OK ){ | |
| pNew = sqlite3_malloc( sizeof(*pNew) ); | |
| *ppVtab = (sqlite3_vtab*)pNew; | |
| if( pNew==0 ) return SQLITE_NOMEM; | |
| memset(pNew, 0, sizeof(*pNew)); | |
| } | |
| return rc; | |
| } | |
| /* | |
| ** This method is the destructor for templatevtab_vtab objects. | |
| */ | |
| static int templatevtabDisconnect(sqlite3_vtab *pVtab){ | |
| templatevtab_vtab *p = (templatevtab_vtab*)pVtab; | |
| sqlite3_free(p); | |
| return SQLITE_OK; | |
| } | |
| /* | |
| ** Constructor for a new templatevtab_cursor object. | |
| */ | |
| static int templatevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ | |
| templatevtab_cursor *pCur; | |
| pCur = sqlite3_malloc( sizeof(*pCur) ); | |
| if( pCur==0 ) return SQLITE_NOMEM; | |
| memset(pCur, 0, sizeof(*pCur)); | |
| *ppCursor = &pCur->base; | |
| return SQLITE_OK; | |
| } | |
| /* | |
| ** Destructor for a templatevtab_cursor. | |
| */ | |
| static int templatevtabClose(sqlite3_vtab_cursor *cur){ | |
| templatevtab_cursor *pCur = (templatevtab_cursor*)cur; | |
| sqlite3_free(pCur); | |
| return SQLITE_OK; | |
| } | |
| /* | |
| ** Advance a templatevtab_cursor to its next row of output. | |
| */ | |
| static int templatevtabNext(sqlite3_vtab_cursor *cur){ | |
| templatevtab_cursor *pCur = (templatevtab_cursor*)cur; | |
| pCur->iRowid++; | |
| return SQLITE_OK; | |
| } | |
| /* | |
| ** Return values of columns for the row at which the templatevtab_cursor | |
| ** is currently pointing. | |
| */ | |
| static int templatevtabColumn( | |
| sqlite3_vtab_cursor *cur, /* The cursor */ | |
| sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ | |
| int i /* Which column to return */ | |
| ){ | |
| templatevtab_cursor *pCur = (templatevtab_cursor*)cur; | |
| switch( i ){ | |
| case TEMPLATEVTAB_A: | |
| sqlite3_result_int(ctx, 1000 + pCur->iRowid); | |
| break; | |
| default: | |
| assert( i==TEMPLATEVTAB_B ); | |
| sqlite3_result_int(ctx, 2000 + pCur->iRowid); | |
| break; | |
| } | |
| return SQLITE_OK; | |
| } | |
| /* | |
| ** Return the rowid for the current row. In this implementation, the | |
| ** rowid is the same as the output value. | |
| */ | |
| static int templatevtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ | |
| templatevtab_cursor *pCur = (templatevtab_cursor*)cur; | |
| *pRowid = pCur->iRowid; | |
| return SQLITE_OK; | |
| } | |
| /* | |
| ** Return TRUE if the cursor has been moved off of the last | |
| ** row of output. | |
| */ | |
| static int templatevtabEof(sqlite3_vtab_cursor *cur){ | |
| templatevtab_cursor *pCur = (templatevtab_cursor*)cur; | |
| return pCur->iRowid>=10; | |
| } | |
| /* | |
| ** This method is called to "rewind" the templatevtab_cursor object back | |
| ** to the first row of output. This method is always called at least | |
| ** once prior to any call to templatevtabColumn() or templatevtabRowid() or | |
| ** templatevtabEof(). | |
| */ | |
| static int templatevtabFilter( | |
| sqlite3_vtab_cursor *pVtabCursor, | |
| int idxNum, const char *idxStr, | |
| int argc, sqlite3_value **argv | |
| ){ | |
| templatevtab_cursor *pCur = (templatevtab_cursor *)pVtabCursor; | |
| pCur->iRowid = 1; | |
| return SQLITE_OK; | |
| } | |
| /* | |
| ** SQLite will invoke this method one or more times while planning a query | |
| ** that uses the virtual table. This routine needs to create | |
| ** a query plan for each invocation and compute an estimated cost for that | |
| ** plan. | |
| */ | |
| static int templatevtabBestIndex( | |
| sqlite3_vtab *tab, | |
| sqlite3_index_info *pIdxInfo | |
| ){ | |
| pIdxInfo->estimatedCost = (double)10; | |
| pIdxInfo->estimatedRows = 10; | |
| return SQLITE_OK; | |
| } | |
| /* | |
| ** This following structure defines all the methods for the | |
| ** virtual table. | |
| */ | |
| static sqlite3_module templatevtabModule = { | |
| /* iVersion */ 0, | |
| /* xCreate */ 0, | |
| /* xConnect */ templatevtabConnect, | |
| /* xBestIndex */ templatevtabBestIndex, | |
| /* xDisconnect */ templatevtabDisconnect, | |
| /* xDestroy */ 0, | |
| /* xOpen */ templatevtabOpen, | |
| /* xClose */ templatevtabClose, | |
| /* xFilter */ templatevtabFilter, | |
| /* xNext */ templatevtabNext, | |
| /* xEof */ templatevtabEof, | |
| /* xColumn */ templatevtabColumn, | |
| /* xRowid */ templatevtabRowid, | |
| /* xUpdate */ 0, | |
| /* xBegin */ 0, | |
| /* xSync */ 0, | |
| /* xCommit */ 0, | |
| /* xRollback */ 0, | |
| /* xFindMethod */ 0, | |
| /* xRename */ 0, | |
| /* xSavepoint */ 0, | |
| /* xRelease */ 0, | |
| /* xRollbackTo */ 0, | |
| /* xShadowName */ 0, | |
| /* xIntegrity */ 0 | |
| }; | |
| __declspec(dllexport) | |
| int sqlite3_templatevtab_init( | |
| sqlite3 *db, | |
| char **pzErrMsg, | |
| const sqlite3_api_routines *pApi | |
| ){ | |
| int rc = SQLITE_OK; | |
| SQLITE_EXTENSION_INIT2(pApi); | |
| rc = sqlite3_create_module(db, "templatevtab", &templatevtabModule, 0); | |
| return rc; | |
| } | |