Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add first cut of sqlite3_declare_vtab(). Not at all well tested yet. (CVS 3213) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
bbeb93b5bb26ba83ee7b7ae439ca5cee |
User & Date: | danielk1977 2006-06-12 11:24:37.000 |
Context
2006-06-12
| ||
12:08 | Add a simple test case (and corresponding bugfix) for the virtual table xConnect and xDisconnect methods. (CVS 3214) (check-in: b63dbc7947 user: danielk1977 tags: trunk) | |
11:24 | Add first cut of sqlite3_declare_vtab(). Not at all well tested yet. (CVS 3213) (check-in: bbeb93b5bb user: danielk1977 tags: trunk) | |
06:09 | Incremental work on parsing/storing and invoking the xCreate callback for virtual tables. (CVS 3212) (check-in: 8ffbab79d5 user: danielk1977 tags: trunk) | |
Changes
Changes to src/build.c.
︙ | ︙ | |||
18 19 20 21 22 23 24 | ** CREATE INDEX ** DROP INDEX ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | ** CREATE INDEX ** DROP INDEX ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** ** $Id: build.c,v 1.397 2006/06/12 11:24:37 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** This routine is called when a new SQL statement is beginning to ** be parsed. Initialize the pParse structure as needed. |
︙ | ︙ | |||
778 779 780 781 782 783 784 | goto begin_table_error; } } #endif /* Make sure the new table name does not collide with an existing ** index or table name in the same database. Issue an error message if | | > > > > | | | | | | | | | | | | | | > > | 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 | goto begin_table_error; } } #endif /* Make sure the new table name does not collide with an existing ** index or table name in the same database. Issue an error message if ** it does. The exception is if the statement being parsed was passed ** to an sqlite3_declare_vtab() call. In that case only the column names ** and types will be used, so there is no need to test for namespace ** collisions. */ if( !IN_DECLARE_VTAB ){ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto begin_table_error; } pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName); if( pTable ){ if( !noErr ){ sqlite3ErrorMsg(pParse, "table %T already exists", pName); } goto begin_table_error; } if( sqlite3FindIndex(db, zName, 0)!=0 && (iDb==0 || !db->init.busy) ){ sqlite3ErrorMsg(pParse, "there is already an index named %s", zName); goto begin_table_error; } } pTable = sqliteMalloc( sizeof(Table) ); if( pTable==0 ){ pParse->rc = SQLITE_NOMEM; pParse->nErr++; goto begin_table_error; } pTable->zName = zName; |
︙ | ︙ | |||
1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 | assert( pTable ); /* A positive nCol means the columns names for this view are ** already known. */ if( pTable->nCol>0 ) return 0; /* A negative nCol is a special marker meaning that we are currently ** trying to compute the column names. If we enter this routine with ** a negative nCol, it means two or more views form a loop, like this: ** ** CREATE VIEW one AS SELECT * FROM two; ** CREATE VIEW two AS SELECT * FROM one; | > > > | 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 | assert( pTable ); /* A positive nCol means the columns names for this view are ** already known. */ if( pTable->nCol>0 ) return 0; #ifndef SQLITE_OMIT_VIRTUALTABLE if( pTable->isVirtual ) return 0; #endif /* A negative nCol is a special marker meaning that we are currently ** trying to compute the column names. If we enter this routine with ** a negative nCol, it means two or more views form a loop, like this: ** ** CREATE VIEW one AS SELECT * FROM two; ** CREATE VIEW two AS SELECT * FROM one; |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the SQLite library ** presents to client programs. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the SQLite library ** presents to client programs. ** ** @(#) $Id: sqlite.h.in,v 1.169 2006/06/12 11:24:37 danielk1977 Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ #include <stdarg.h> /* Needed for the definition of va_list */ /* ** Make sure we can call this stuff from C++. |
︙ | ︙ | |||
1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 | #define SQLITE_INDEX_CONSTRAINT_MATCH 7 int sqlite3_create_module( sqlite3 *db, const char *zName, const sqlite3_module * ); /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double #endif #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif #endif | > | 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 | #define SQLITE_INDEX_CONSTRAINT_MATCH 7 int sqlite3_create_module( sqlite3 *db, const char *zName, const sqlite3_module * ); int sqlite3_declare_vtab(sqlite3*, const char *zCreateTable); /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double #endif #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif #endif |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2001 September 15 ** ** 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.499 2006/06/12 11:24:37 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* ** Extra interface definitions for those who need them */ |
︙ | ︙ | |||
488 489 490 491 492 493 494 495 496 497 498 499 500 501 | #ifndef SQLITE_OMIT_PROGRESS_CALLBACK int (*xProgress)(void *); /* The progress callback */ void *pProgressArg; /* Argument to the progress callback */ int nProgressOps; /* Number of opcodes for progress callback */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE Hash aModule; /* populated by sqlite3_create_module() */ #endif Hash aFunc; /* All functions that can be in SQL exprs */ Hash aCollSeq; /* All collating sequences */ BusyHandler busyHandler; /* Busy callback */ int busyTimeout; /* Busy handler timeout, in msec */ Db aDbStatic[2]; /* Static space for the 2 default backends */ #ifdef SQLITE_SSE | > | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 | #ifndef SQLITE_OMIT_PROGRESS_CALLBACK int (*xProgress)(void *); /* The progress callback */ void *pProgressArg; /* Argument to the progress callback */ int nProgressOps; /* Number of opcodes for progress callback */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE Hash aModule; /* populated by sqlite3_create_module() */ Table *pVTab; /* vtab with active Connect/Create method */ #endif Hash aFunc; /* All functions that can be in SQL exprs */ Hash aCollSeq; /* All collating sequences */ BusyHandler busyHandler; /* Busy callback */ int busyTimeout; /* Busy handler timeout, in msec */ Db aDbStatic[2]; /* Static space for the 2 default backends */ #ifdef SQLITE_SSE |
︙ | ︙ | |||
1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 | Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ TriggerStack *trigStack; /* Trigger actions being coded */ const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */ #ifndef SQLITE_OMIT_VIRTUALTABLE int nArgAlloc; /* Number of bytes allocated for zArg[] */ int nArgUsed; /* Number of bytes of zArg[] used so far */ char *zArg; /* Complete text of a module argument */ #endif }; /* ** An instance of the following structure can be declared on a stack and used ** to save the Parse.zAuthContext value so that it can be restored later. */ struct AuthContext { const char *zAuthContext; /* Put saved Parse.zAuthContext here */ | > > > > > > > | 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 | Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ TriggerStack *trigStack; /* Trigger actions being coded */ const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */ #ifndef SQLITE_OMIT_VIRTUALTABLE int nArgAlloc; /* Number of bytes allocated for zArg[] */ int nArgUsed; /* Number of bytes of zArg[] used so far */ char *zArg; /* Complete text of a module argument */ u8 declareVtab; /* True if inside sqlite3_declare_vtab() */ #endif }; #ifdef SQLITE_OMIT_VIRTUALTABLE #define IN_DECLARE_VTAB 0 #else #define IN_DECLARE_VTAB (pParse->declareVtab) #endif /* ** An instance of the following structure can be declared on a stack and used ** to save the Parse.zAuthContext value so that it can be restored later. */ struct AuthContext { const char *zAuthContext; /* Put saved Parse.zAuthContext here */ |
︙ | ︙ | |||
1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 | void sqlite3VtabClear(Table*); #endif void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*); void sqlite3VtabFinishParse(Parse*, Token*); void sqlite3VtabArgInit(Parse*); void sqlite3VtabArgExtend(Parse*, Token*); int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **); #ifdef SQLITE_SSE #include "sseInt.h" #endif #endif | > | 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 | void sqlite3VtabClear(Table*); #endif void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*); void sqlite3VtabFinishParse(Parse*, Token*); void sqlite3VtabArgInit(Parse*); void sqlite3VtabArgExtend(Parse*, Token*); int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **); int sqlite3VtabCallConnect(Parse*, Table*); #ifdef SQLITE_SSE #include "sseInt.h" #endif #endif |
Changes to src/test8.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the virtual table interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < > > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the virtual table interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test8.c,v 1.3 2006/06/12 11:24:37 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" #include "os.h" #include <stdlib.h> #include <string.h> /* ** Global Tcl variable $echo_module is a list. This routine appends ** the string element zArg to that list in interpreter interp. */ static void appendToEchoModule(const sqlite3_module *pModule, const char *zArg){ int flags = (TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY); Tcl_SetVar((Tcl_Interp *)(pModule->pAux), "echo_module", zArg, flags); } /* ** This function is called from within the echo-modules xCreate and ** xConnect methods. The argc and argv arguments are copies of those ** passed to the calling method. This function is responsible for ** calling sqlite3_declare_vtab() to declare the schema of the virtual ** table being created or connected. ** ** If the constructor was passed just one argument, i.e.: ** ** CREATE TABLE t1 AS echo(t2); ** ** Then t2 is assumed to be the name of a *real* database table. The ** schema of the virtual table is declared by passing a copy of the ** CREATE TABLE statement for the real table to sqlite3_declare_vtab(). ** Hence, the virtual table should have exactly the same column names and ** types as the real table. */ static int echoDeclareVtab(sqlite3 *db, int argc, char **argv){ int rc = SQLITE_OK; if( argc==2 ){ sqlite3_stmt *pStmt = 0; sqlite3_prepare(db, "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?", -1, &pStmt, 0); sqlite3_bind_text(pStmt, 1, argv[1], -1, 0); if( sqlite3_step(pStmt)==SQLITE_ROW ){ const char *zCreateTable = sqlite3_column_text(pStmt, 0); sqlite3_declare_vtab(db, zCreateTable); } else { rc = SQLITE_ERROR; } sqlite3_finalize(pStmt); } return rc; } /* Methods for the echo module */ static int echoCreate( sqlite3 *db, const sqlite3_module *pModule, int argc, char **argv, sqlite3_vtab **ppVtab ){ int i; *ppVtab = pModule->pAux; appendToEchoModule(pModule, "xCreate"); for(i=0; i<argc; i++){ appendToEchoModule(pModule, argv[i]); } echoDeclareVtab(db, argc, argv); return 0; } static int echoConnect( sqlite3 *db, const sqlite3_module *pModule, int argc, char **argv, sqlite3_vtab **ppVtab ){ int i; Tcl_Interp *interp = pModule->pAux; *ppVtab = pModule->pAux; Tcl_SetVar(interp, "echo_module", "xConnect", TCL_GLOBAL_ONLY); for(i=0; i<argc; i++){ Tcl_SetVar(interp, "echo_module", argv[i], TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY); } echoDeclareVtab(db, argc, argv); return 0; } static int echoDisconnect(sqlite3_vtab *pVtab){ Tcl_Interp *interp = (Tcl_Interp*)pVtab; Tcl_SetVar(interp, "echo_module", "xDisconnect", TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY); return 0; |
︙ | ︙ |
Changes to src/tokenize.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** An tokenizer for SQL ** ** This file contains C code that splits an SQL input string up into ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ************************************************************************* ** An tokenizer for SQL ** ** This file contains C code that splits an SQL input string up into ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** ** $Id: tokenize.c,v 1.120 2006/06/12 11:24:37 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" #include <ctype.h> #include <stdlib.h> /* |
︙ | ︙ | |||
479 480 481 482 483 484 485 486 487 488 | #ifndef SQLITE_OMIT_SHARED_CACHE if( pParse->nested==0 ){ sqliteFree(pParse->aTableLock); pParse->aTableLock = 0; pParse->nTableLock = 0; } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE sqliteFree(pParse->zArg); #endif | > > > > > > > | > > | 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 | #ifndef SQLITE_OMIT_SHARED_CACHE if( pParse->nested==0 ){ sqliteFree(pParse->aTableLock); pParse->aTableLock = 0; pParse->nTableLock = 0; } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE sqliteFree(pParse->zArg); #endif if( !IN_DECLARE_VTAB ){ /* If the pParse->declareVtab flag is set, do not delete any table ** structure built up in pParse->pNewTable. The calling code (see vtab.c) ** will take responsibility for freeing the Table structure. */ sqlite3DeleteTable(pParse->db, pParse->pNewTable); } sqlite3DeleteTrigger(pParse->pNewTrigger); sqliteFree(pParse->apVarExpr); if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){ pParse->rc = SQLITE_ERROR; } return nErr; } |
Changes to src/vtab.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2006 June 10 ** ** 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 contains code used to help implement virtual tables. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2006 June 10 ** ** 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 contains code used to help implement virtual tables. ** ** $Id: vtab.c,v 1.3 2006/06/12 11:24:37 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_VIRTUALTABLE #include "sqliteInt.h" /* ** External API function used to create a new virtual-table module. */ |
︙ | ︙ | |||
124 125 126 127 128 129 130 | pParse->nArgAlloc = 0; /* Lookup the module name. */ pTab = pParse->pNewTable; if( pTab==0 ) return; db = pParse->db; if( pTab->nModuleArg<1 ) return; | < | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | pParse->nArgAlloc = 0; /* Lookup the module name. */ pTab = pParse->pNewTable; if( pTab==0 ) return; db = pParse->db; if( pTab->nModuleArg<1 ) return; zModule = pTab->azModuleArg[0]; pTab->pModule = (sqlite3_module*)sqlite3HashFind(&db->aModule, zModule, strlen(zModule)); /* If the CREATE VIRTUAL TABLE statement is being entered for the ** first time (in other words if the virtual table is actually being ** created now instead of just being read out of sqlite_master) then |
︙ | ︙ | |||
184 185 186 187 188 189 190 | } /* If we are rereading the sqlite_master table create the in-memory ** record of the table. ** ** TODO: If the module is already registered, should we call xConnect() ** here, or should it wait until the table is first referenced. Maybe | | > < < < < < > | 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | } /* If we are rereading the sqlite_master table create the in-memory ** record of the table. ** ** TODO: If the module is already registered, should we call xConnect() ** here, or should it wait until the table is first referenced. Maybe ** it's better to be lazy here, in case xConnect() is expensive to call ** and the schema is reparsed a number of times. */ else { Table *pOld; Schema *pSchema = pTab->pSchema; const char *zName = pTab->zName; int nName = strlen(zName) + 1; pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab); if( pOld ){ assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */ return; } pParse->pNewTable = 0; } } /* ** The parser calls this routine when it sees the first token ** of an argument to the module name in a CREATE VIRTUAL TABLE statement. */ |
︙ | ︙ | |||
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | if( pParse->nArgUsed ){ pParse->zArg[pParse->nArgUsed++] = ' '; } memcpy(&pParse->zArg[pParse->nArgUsed], p->z, p->n); pParse->nArgUsed += p->n; pParse->zArg[pParse->nArgUsed] = 0; } /* ** This function is invoked by the vdbe to call the xCreate method ** of the virtual table named zTab in database iDb. ** ** If an error occurs, *pzErr is set to point an an English language ** description of the error and an SQLITE_XXX error code is returned. ** In this case the caller must call sqliteFree() on *pzErr. */ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){ int rc = SQLITE_OK; Table *pTab; sqlite3_module *pModule; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < > > > > > > > > > > > | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 | if( pParse->nArgUsed ){ pParse->zArg[pParse->nArgUsed++] = ' '; } memcpy(&pParse->zArg[pParse->nArgUsed], p->z, p->n); pParse->nArgUsed += p->n; pParse->zArg[pParse->nArgUsed] = 0; } /* ** This function is invoked by the parser to call the xConnect() method ** of table pTab. If an error occurs, an error code is returned and an error ** left in pParse. */ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ sqlite3_module *pModule; const char *zModule; int rc = SQLITE_OK; assert(pTab && pTab->isVirtual); if( pTab->pVtab ){ return SQLITE_OK; } pModule = pTab->pModule; zModule = pTab->azModuleArg[0]; if( !pModule || !pModule->xConnect ){ const char *zModule = pTab->azModuleArg[0]; sqlite3ErrorMsg(pParse, "unknown module: %s", zModule); rc = SQLITE_ERROR; } else { char **azArg = pTab->azModuleArg; int nArg = pTab->nModuleArg; assert( !pParse->db->pVTab ); pParse->db->pVTab = pTab; rc = pModule->xConnect(pParse->db, pModule, nArg, azArg, &pTab->pVtab); pParse->db->pVTab = 0; if( rc ){ sqlite3ErrorMsg(pParse, "module connect failed: %s", zModule); } } return rc; } int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ Parse sParse; int rc = SQLITE_OK; Table *pTab = db->pVTab; char *zErr = 0; if( !pTab ){ sqlite3Error(db, SQLITE_MISUSE, 0); return SQLITE_MISUSE; } assert(pTab->isVirtual && pTab->nCol==0 && pTab->aCol==0); memset(&sParse, 0, sizeof(Parse)); sParse.declareVtab = 1; sParse.db = db; if( SQLITE_OK == sqlite3RunParser(&sParse, zCreateTable, &zErr) && sParse.pNewTable && !sParse.pNewTable->pSelect && !sParse.pNewTable->isVirtual ){ pTab->aCol = sParse.pNewTable->aCol; pTab->nCol = sParse.pNewTable->nCol; sParse.pNewTable->nCol = 0; sParse.pNewTable->aCol = 0; } else { sqlite3Error(db, SQLITE_ERROR, zErr); sqliteFree(zErr); rc = SQLITE_ERROR; } sParse.declareVtab = 0; sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe); sqlite3DeleteTable(0, sParse.pNewTable); sParse.pNewTable = 0; db->pVTab = 0; return rc; } /* ** This function is invoked by the vdbe to call the xCreate method ** of the virtual table named zTab in database iDb. ** ** If an error occurs, *pzErr is set to point an an English language ** description of the error and an SQLITE_XXX error code is returned. ** In this case the caller must call sqliteFree() on *pzErr. */ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){ int rc = SQLITE_OK; Table *pTab; sqlite3_module *pModule; const char *zModule; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); assert(pTab && pTab->isVirtual && !pTab->pVtab); pModule = pTab->pModule; zModule = pTab->azModuleArg[0]; /* If the module has been registered and includes a Create method, ** invoke it now. If the module has not been registered, return an ** error. Otherwise, do nothing. */ if( !pModule ){ *pzErr = sqlite3MPrintf("unknown module: %s", zModule); rc = SQLITE_ERROR; }else if( pModule->xCreate ){ char **azArg = pTab->azModuleArg; int nArg = pTab->nModuleArg; assert( !db->pVTab ); db->pVTab = pTab; rc = sqlite3SafetyOff(db); assert( rc==SQLITE_OK ); rc = pModule->xCreate(db, pModule, nArg, azArg, &pTab->pVtab); db->pVTab = 0; if( rc ){ *pzErr = sqlite3MPrintf("module create failed: %s", zModule); sqlite3SafetyOn(db); } else { rc = sqlite3SafetyOn(db); } } if( SQLITE_OK==rc ){ pTab->needCreate = 0; } return rc; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
Changes to test/vtab1.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2006 June 10 # # 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 regression tests for SQLite library. The # focus of this file is creating and dropping virtual tables. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2006 June 10 # # 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 regression tests for SQLite library. The # focus of this file is creating and dropping virtual tables. # # $Id: vtab1.test,v 1.3 2006/06/12 11:24:38 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # We cannot create a virtual table if the module has not # been registered. # |
︙ | ︙ | |||
43 44 45 46 47 48 49 50 51 | set echo_module } {xCreate echo} do_test vtab1-1.5 { execsql { SELECT name, sql FROM sqlite_master ORDER BY 1 } } {t1 {CREATE VIRTUAL TABLE t1 USING echo}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | set echo_module } {xCreate echo} do_test vtab1-1.5 { execsql { SELECT name, sql FROM sqlite_master ORDER BY 1 } } {t1 {CREATE VIRTUAL TABLE t1 USING echo}} # If a single argument is passed to the echo module during table # creation, it is assumed to be the name of a table in the same # database. The echo module attempts to set the schema of the # new virtual table to be the same as the existing database table. # do_test vtab1-2.1 { execsql { CREATE TABLE template(a, b, c); } execsql { PRAGMA table_info(template); } } [list \ 0 a {} 0 {} 0 \ 1 b {} 0 {} 0 \ 2 c {} 0 {} 0 \ ] do_test vtab1-2.2 { execsql { CREATE VIRTUAL TABLE t2 USING echo(template); } execsql { PRAGMA table_info(t2); } } [list \ 0 a {} 0 {} 0 \ 1 b {} 0 {} 0 \ 2 c {} 0 {} 0 \ ] finish_test |