diff options
author | drh <drh@noemail.net> | 2006-06-11 23:41:55 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2006-06-11 23:41:55 +0000 |
commit | b9bb7c187e5cc9cce7d4e6fac38533339e865f33 (patch) | |
tree | 3d12b363c1d5496178d24a45ff90913049986880 /src | |
parent | e09daa90ac013c75806e582d7a073bf4d98783c2 (diff) | |
download | sqlite-b9bb7c187e5cc9cce7d4e6fac38533339e865f33.tar.gz sqlite-b9bb7c187e5cc9cce7d4e6fac38533339e865f33.zip |
Progress toward CREATE VIRTUAL TABLE. Still not even close to working... (CVS 3211)
FossilOrigin-Name: 898ec36b4102aaa03979f8f5c510936e57e2ae48
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 23 | ||||
-rw-r--r-- | src/delete.c | 4 | ||||
-rw-r--r-- | src/expr.c | 14 | ||||
-rw-r--r-- | src/insert.c | 4 | ||||
-rw-r--r-- | src/main.c | 8 | ||||
-rw-r--r-- | src/parse.y | 19 | ||||
-rw-r--r-- | src/select.c | 96 | ||||
-rw-r--r-- | src/sqlite.h.in | 8 | ||||
-rw-r--r-- | src/sqliteInt.h | 53 | ||||
-rw-r--r-- | src/tclsqlite.c | 4 | ||||
-rw-r--r-- | src/test1.c | 8 | ||||
-rw-r--r-- | src/test8.c | 136 | ||||
-rw-r--r-- | src/tokenize.c | 5 | ||||
-rw-r--r-- | src/update.c | 4 | ||||
-rw-r--r-- | src/vdbe.c | 38 | ||||
-rw-r--r-- | src/vdbe.h | 4 | ||||
-rw-r--r-- | src/vtab.c | 211 | ||||
-rw-r--r-- | src/where.c | 6 |
18 files changed, 533 insertions, 112 deletions
diff --git a/src/build.c b/src/build.c index 74cf00acc..0be7c92f9 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.395 2006/06/10 13:29:32 drh Exp $ +** $Id: build.c,v 1.396 2006/06/11 23:41:55 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -533,12 +533,7 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ #ifndef SQLITE_OMIT_CHECK sqlite3ExprDelete(pTable->pCheck); #endif -#ifndef SQLITE_OMIT_MODULE - sqliteFree(pTable->zModuleName); - if( pTable->pMod && pTable->pVTab ){ - pTable->pMod->xDisconnect(pTable->pVTab); - } -#endif SQLITE_OMIT_MODULE + sqlite3VtabClear(pTable); sqliteFree(pTable); } @@ -810,10 +805,7 @@ void sqlite3StartTable( goto begin_table_error; } pTable->zName = zName; - pTable->nCol = 0; - pTable->aCol = 0; pTable->iPKey = -1; - pTable->pIndex = 0; pTable->pSchema = db->aDb[iDb].pSchema; pTable->nRef = 1; if( pParse->pNewTable ) sqlite3DeleteTable(db, pParse->pNewTable); @@ -1378,7 +1370,7 @@ void sqlite3EndTable( assert( !db->init.busy || !pSelect ); - iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); + iDb = sqlite3SchemaToIndex(db, p->pSchema); #ifndef SQLITE_OMIT_CHECK /* Resolve names in all CHECK constraint expressions. @@ -1974,7 +1966,14 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ /* Remove the table entry from SQLite's internal schema and modify ** the schema cookie. */ - sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0); +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( pTab->isEphem ){ + sqlite3VdbeOp3(v, OP_VDestroy, iDb, 0, pTab->zName, 0); + }else +#endif + { + sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0); + } sqlite3ChangeCookie(db, v, iDb); } sqliteViewResetAll(db, iDb); diff --git a/src/delete.c b/src/delete.c index 237c0f19d..e16597d8a 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** -** $Id: delete.c,v 1.122 2006/02/24 02:53:50 drh Exp $ +** $Id: delete.c,v 1.123 2006/06/11 23:41:55 drh Exp $ */ #include "sqliteInt.h" @@ -190,7 +190,7 @@ void sqlite3DeleteFrom( */ if( isView ){ Select *pView = sqlite3SelectDup(pTab->pSelect); - sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0); + sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0); sqlite3SelectDelete(pView); } diff --git a/src/expr.c b/src/expr.c index 0577737a3..5a721ab85 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.258 2006/05/23 23:22:29 drh Exp $ +** $Id: expr.c,v 1.259 2006/06/11 23:41:55 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -547,12 +547,12 @@ Select *sqlite3SelectDup(Select *p){ pNew->iOffset = -1; pNew->isResolved = p->isResolved; pNew->isAgg = p->isAgg; - pNew->usesVirt = 0; + pNew->usesEphm = 0; pNew->disallowOrderBy = 0; pNew->pRightmost = 0; - pNew->addrOpenVirt[0] = -1; - pNew->addrOpenVirt[1] = -1; - pNew->addrOpenVirt[2] = -1; + pNew->addrOpenEphm[0] = -1; + pNew->addrOpenEphm[1] = -1; + pNew->addrOpenEphm[2] = -1; return pNew; } #else @@ -1316,7 +1316,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ case TK_IN: { char affinity; KeyInfo keyInfo; - int addr; /* Address of OP_OpenVirtual instruction */ + int addr; /* Address of OP_OpenEphemeral instruction */ affinity = sqlite3ExprAffinity(pExpr->pLeft); @@ -1334,7 +1334,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ ** is used. */ pExpr->iTable = pParse->nTab++; - addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, pExpr->iTable, 0); + addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, pExpr->iTable, 0); memset(&keyInfo, 0, sizeof(keyInfo)); keyInfo.nField = 1; sqlite3VdbeAddOp(v, OP_SetNumColumns, pExpr->iTable, 1); diff --git a/src/insert.c b/src/insert.c index c8c5090e9..295d753d3 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.164 2006/03/15 16:26:10 drh Exp $ +** $Id: insert.c,v 1.165 2006/06/11 23:41:55 drh Exp $ */ #include "sqliteInt.h" @@ -371,7 +371,7 @@ void sqlite3Insert( ** back up and execute the SELECT code above. */ sqlite3VdbeJumpHere(v, iInitCode); - sqlite3VdbeAddOp(v, OP_OpenVirtual, srcTab, 0); + sqlite3VdbeAddOp(v, OP_OpenEphemeral, srcTab, 0); sqlite3VdbeAddOp(v, OP_SetNumColumns, srcTab, nColumn); sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop); sqlite3VdbeResolveLabel(v, iCleanup); diff --git a/src/main.c b/src/main.c index 9d6cbd971..6eb047df6 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.341 2006/06/08 15:48:01 drh Exp $ +** $Id: main.c,v 1.342 2006/06/11 23:41:55 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -159,6 +159,9 @@ int sqlite3_close(sqlite3 *db){ sqliteFree(pColl); } sqlite3HashClear(&db->aCollSeq); +#ifndef SQLITE_OMIT_VIRTUALTABLE + sqlite3HashClear(&db->aModule); +#endif sqlite3HashClear(&db->aFunc); sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */ @@ -818,6 +821,9 @@ static int openDatabase( db->flags |= SQLITE_ShortColNames; sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0); +#ifndef SQLITE_OMIT_VIRTUALTABLE + sqlite3HashInit(&db->aModule, SQLITE_HASH_STRING, 0); +#endif /* Add the default collation sequence BINARY. BINARY works for both UTF-8 ** and UTF-16, so add a version for each to avoid any unnecessary diff --git a/src/parse.y b/src/parse.y index 922d4730b..ce3a69dba 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.201 2006/06/10 13:29:33 drh Exp $ +** @(#) $Id: parse.y,v 1.202 2006/06/11 23:41:55 drh Exp $ */ // All token codes are small integers with #defines that begin with "TK_" @@ -1062,11 +1062,18 @@ kwcolumn_opt ::= COLUMNKW. //////////////////////// CREATE VIRTUAL TABLE ... ///////////////////////////// %ifndef SQLITE_OMIT_VIRTUALTABLE -cmd ::= CREATE VIRTUAL TABLE nm(X) dbnm(Y) USING nm(Z) vtabargsopt. -vtabargsopt ::= . -vtabargsopt ::= LP vtabarglist RP. +cmd ::= create_vtab. {sqlite3VtabFinishParse(pParse,0);} +cmd ::= create_vtab LP vtabarglist RP(X). {sqlite3VtabFinishParse(pParse,&X);} +create_vtab ::= CREATE VIRTUAL TABLE nm(X) dbnm(Y) USING nm(Z). { + sqlite3VtabBeginParse(pParse, &X, &Y, &Z); +} vtabarglist ::= vtabarg. vtabarglist ::= vtabarglist COMMA vtabarg. -vtabarg ::= ANY. -vtabarg ::= vtabarg ANY. +vtabarg ::= . {sqlite3VtabArgInit(pParse);} +vtabarg ::= vtabarg vtabargtoken. +vtabargtoken ::= ANY(X). {sqlite3VtabArgExtend(pParse,&X);} +vtabargtoken ::= lp anylist RP(X). {sqlite3VtabArgExtend(pParse,&X);} +lp ::= LP(X). {sqlite3VtabArgExtend(pParse,&X);} +anylist ::= . +anylist ::= anylist ANY(X). {sqlite3VtabArgExtend(pParse,&X);} %endif diff --git a/src/select.c b/src/select.c index 2fda13400..5dd23d46f 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.313 2006/04/26 17:39:34 drh Exp $ +** $Id: select.c,v 1.314 2006/06/11 23:41:56 drh Exp $ */ #include "sqliteInt.h" @@ -72,9 +72,9 @@ Select *sqlite3SelectNew( pNew->pOffset = pOffset; pNew->iLimit = -1; pNew->iOffset = -1; - pNew->addrOpenVirt[0] = -1; - pNew->addrOpenVirt[1] = -1; - pNew->addrOpenVirt[2] = -1; + pNew->addrOpenEphm[0] = -1; + pNew->addrOpenEphm[1] = -1; + pNew->addrOpenEphm[2] = -1; if( pNew==&standin) { clearSelect(pNew); pNew = 0; @@ -522,7 +522,7 @@ static int selectInnerLoop( /* Store the result as data using a unique key. */ case SRT_Table: - case SRT_VirtualTab: { + case SRT_EphemTab: { sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); if( pOrderBy ){ pushOntoSorter(pParse, pOrderBy, p); @@ -705,7 +705,7 @@ static void generateSortTail( sqlite3VdbeAddOp(v, OP_Column, iTab, pOrderBy->nExpr + 1); switch( eDest ){ case SRT_Table: - case SRT_VirtualTab: { + case SRT_EphemTab: { sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0); sqlite3VdbeAddOp(v, OP_Pull, 1, 0); sqlite3VdbeAddOp(v, OP_Insert, iParm, 0); @@ -1201,11 +1201,11 @@ static int prepSelectStmt(Parse *pParse, Select *p){ if( pTab==0 ){ return 1; } - /* The isTransient flag indicates that the Table structure has been + /* The isEphem flag indicates that the Table structure has been ** dynamically allocated and may be freed at any time. In other words, ** pTab is not pointing to a persistent table structure that defines ** part of the schema. */ - pTab->isTransient = 1; + pTab->isEphem = 1; #endif }else{ /* An ordinary table or view name in the FROM clause */ @@ -1538,10 +1538,10 @@ static void createSortingIndex(Parse *pParse, Select *p, ExprList *pOrderBy){ int addr; assert( pOrderBy->iECursor==0 ); pOrderBy->iECursor = pParse->nTab++; - addr = sqlite3VdbeAddOp(pParse->pVdbe, OP_OpenVirtual, + addr = sqlite3VdbeAddOp(pParse->pVdbe, OP_OpenEphemeral, pOrderBy->iECursor, pOrderBy->nExpr+1); - assert( p->addrOpenVirt[2] == -1 ); - p->addrOpenVirt[2] = addr; + assert( p->addrOpenEphm[2] == -1 ); + p->addrOpenEphm[2] = addr; } } @@ -1647,10 +1647,10 @@ static int multiSelect( /* Create the destination temporary table if necessary */ - if( eDest==SRT_VirtualTab ){ + if( eDest==SRT_EphemTab ){ assert( p->pEList ); assert( nSetP2<sizeof(aSetP2)/sizeof(aSetP2[0]) ); - aSetP2[nSetP2++] = sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, 0); + aSetP2[nSetP2++] = sqlite3VdbeAddOp(v, OP_OpenEphemeral, iParm, 0); eDest = SRT_Table; } @@ -1712,14 +1712,14 @@ static int multiSelect( rc = 1; goto multi_select_end; } - addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, unionTab, 0); + addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, unionTab, 0); if( priorOp==SRT_Table ){ assert( nSetP2<sizeof(aSetP2)/sizeof(aSetP2[0]) ); aSetP2[nSetP2++] = addr; }else{ - assert( p->addrOpenVirt[0] == -1 ); - p->addrOpenVirt[0] = addr; - p->pRightmost->usesVirt = 1; + assert( p->addrOpenEphm[0] == -1 ); + p->addrOpenEphm[0] = addr; + p->pRightmost->usesEphm = 1; } createSortingIndex(pParse, p, pOrderBy); assert( p->pEList ); @@ -1808,10 +1808,10 @@ static int multiSelect( } createSortingIndex(pParse, p, pOrderBy); - addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, tab1, 0); - assert( p->addrOpenVirt[0] == -1 ); - p->addrOpenVirt[0] = addr; - p->pRightmost->usesVirt = 1; + addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, tab1, 0); + assert( p->addrOpenEphm[0] == -1 ); + p->addrOpenEphm[0] = addr; + p->pRightmost->usesEphm = 1; assert( p->pEList ); /* Code the SELECTs to our left into temporary table "tab1". @@ -1823,9 +1823,9 @@ static int multiSelect( /* Code the current SELECT into temporary table "tab2" */ - addr = sqlite3VdbeAddOp(v, OP_OpenVirtual, tab2, 0); - assert( p->addrOpenVirt[1] == -1 ); - p->addrOpenVirt[1] = addr; + addr = sqlite3VdbeAddOp(v, OP_OpenEphemeral, tab2, 0); + assert( p->addrOpenEphm[1] == -1 ); + p->addrOpenEphm[1] = addr; p->pPrior = 0; pLimit = p->pLimit; p->pLimit = 0; @@ -1899,7 +1899,7 @@ static int multiSelect( ** SELECT might also skip this part if it has no ORDER BY clause and ** no temp tables are required. */ - if( pOrderBy || p->usesVirt ){ + if( pOrderBy || p->usesEphm ){ int i; /* Loop counter */ KeyInfo *pKeyInfo; /* Collating sequence for the result set */ Select *pLoop; /* For looping through SELECT statements */ @@ -1925,11 +1925,11 @@ static int multiSelect( for(pLoop=p; pLoop; pLoop=pLoop->pPrior){ for(i=0; i<2; i++){ - int addr = pLoop->addrOpenVirt[i]; + int addr = pLoop->addrOpenEphm[i]; if( addr<0 ){ /* If [0] is unused then [1] is also unused. So we can ** always safely abort as soon as the first unused slot is found */ - assert( pLoop->addrOpenVirt[1]<0 ); + assert( pLoop->addrOpenEphm[1]<0 ); break; } sqlite3VdbeChangeP2(v, addr, nCol); @@ -1959,8 +1959,8 @@ static int multiSelect( *pSortOrder = pOTerm->sortOrder; } assert( p->pRightmost==p ); - assert( p->addrOpenVirt[2]>=0 ); - addr = p->addrOpenVirt[2]; + assert( p->addrOpenEphm[2]>=0 ); + addr = p->addrOpenEphm[2]; sqlite3VdbeChangeP2(v, addr, p->pEList->nExpr+2); pKeyInfo->nField = nOrderByExpr; sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO_HANDOFF); @@ -2394,8 +2394,8 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ /* If the output is destined for a temporary table, open that table. */ - if( eDest==SRT_VirtualTab ){ - sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, 1); + if( eDest==SRT_EphemTab ){ + sqlite3VdbeAddOp(v, OP_OpenEphemeral, iParm, 1); } /* Generating code to find the min or the max. Basically all we have @@ -2404,7 +2404,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ ** or last entry in the main table. */ iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - assert( iDb>=0 || pTab->isTransient ); + assert( iDb>=0 || pTab->isEphem ); sqlite3CodeVerifySchema(pParse, iDb); sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); base = pSrc->a[0].iCursor; @@ -2631,7 +2631,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ pFunc->iDistinct = -1; }else{ KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->pList); - sqlite3VdbeOp3(v, OP_OpenVirtual, pFunc->iDistinct, 0, + sqlite3VdbeOp3(v, OP_OpenEphemeral, pFunc->iDistinct, 0, (char*)pKeyInfo, P3_KEYINFO_HANDOFF); } } @@ -2780,7 +2780,7 @@ int sqlite3Select( int isDistinct; /* True if the DISTINCT keyword is present */ int distinct; /* Table to use for the distinct set */ int rc = 1; /* Value to return from this function */ - int addrSortIndex; /* Address of an OP_OpenVirtual instruction */ + int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */ AggInfo sAggInfo; /* Information used by aggregate queries */ int iEnd; /* Address of the end of the query */ @@ -2868,7 +2868,7 @@ int sqlite3Select( }else{ needRestoreContext = 0; } - sqlite3Select(pParse, pItem->pSelect, SRT_VirtualTab, + sqlite3Select(pParse, pItem->pSelect, SRT_EphemTab, pItem->iCursor, p, i, &isAgg, 0); if( needRestoreContext ){ pParse->zAuthContext = zSavedAuthContext; @@ -2908,7 +2908,7 @@ int sqlite3Select( ** ** This sorting index might end up being unused if the data can be ** extracted in pre-sorted order. If that is the case, then the - ** OP_OpenVirtual instruction will be changed to an OP_Noop once + ** OP_OpenEphemeral instruction will be changed to an OP_Noop once ** we figure out that the sorting index is not needed. The addrSortIndex ** variable is used to facilitate that change. */ @@ -2925,8 +2925,8 @@ int sqlite3Select( } pKeyInfo = keyInfoFromExprList(pParse, pOrderBy); pOrderBy->iECursor = pParse->nTab++; - p->addrOpenVirt[2] = addrSortIndex = - sqlite3VdbeOp3(v, OP_OpenVirtual, pOrderBy->iECursor, pOrderBy->nExpr+2, + p->addrOpenEphm[2] = addrSortIndex = + sqlite3VdbeOp3(v, OP_OpenEphemeral, pOrderBy->iECursor, pOrderBy->nExpr+2, (char*)pKeyInfo, P3_KEYINFO_HANDOFF); }else{ addrSortIndex = -1; @@ -2934,8 +2934,8 @@ int sqlite3Select( /* If the output is destined for a temporary table, open that table. */ - if( eDest==SRT_VirtualTab ){ - sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, pEList->nExpr); + if( eDest==SRT_EphemTab ){ + sqlite3VdbeAddOp(v, OP_OpenEphemeral, iParm, pEList->nExpr); } /* Set the limiter. @@ -2949,7 +2949,7 @@ int sqlite3Select( KeyInfo *pKeyInfo; distinct = pParse->nTab++; pKeyInfo = keyInfoFromExprList(pParse, p->pEList); - sqlite3VdbeOp3(v, OP_OpenVirtual, distinct, 0, + sqlite3VdbeOp3(v, OP_OpenEphemeral, distinct, 0, (char*)pKeyInfo, P3_KEYINFO_HANDOFF); }else{ distinct = -1; @@ -2963,13 +2963,13 @@ int sqlite3Select( pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy); if( pWInfo==0 ) goto select_end; - /* If sorting index that was created by a prior OP_OpenVirtual - ** instruction ended up not being needed, then change the OP_OpenVirtual + /* If sorting index that was created by a prior OP_OpenEphemeral + ** instruction ended up not being needed, then change the OP_OpenEphemeral ** into an OP_Noop. */ if( addrSortIndex>=0 && pOrderBy==0 ){ sqlite3VdbeChangeToNoop(v, addrSortIndex, 1); - p->addrOpenVirt[2] = -1; + p->addrOpenEphm[2] = -1; } /* Use the standard inner loop @@ -3003,7 +3003,7 @@ int sqlite3Select( int addrGroupByChange; /* Code that runs when any GROUP BY term changes */ int addrProcessRow; /* Code to process a single input row */ int addrEnd; /* End of all processing */ - int addrSortingIdx; /* The OP_OpenVirtual for the sorting index */ + int addrSortingIdx; /* The OP_OpenEphemeral for the sorting index */ int addrReset; /* Subroutine for resetting the accumulator */ addrEnd = sqlite3VdbeMakeLabel(v); @@ -3050,13 +3050,13 @@ int sqlite3Select( /* If there is a GROUP BY clause we might need a sorting index to ** implement it. Allocate that sorting index now. If it turns out - ** that we do not need it after all, the OpenVirtual instruction + ** that we do not need it after all, the OpenEphemeral instruction ** will be converted into a Noop. */ sAggInfo.sortingIdx = pParse->nTab++; pKeyInfo = keyInfoFromExprList(pParse, pGroupBy); addrSortingIdx = - sqlite3VdbeOp3(v, OP_OpenVirtual, sAggInfo.sortingIdx, + sqlite3VdbeOp3(v, OP_OpenEphemeral, sAggInfo.sortingIdx, sAggInfo.nSortingColumn, (char*)pKeyInfo, P3_KEYINFO_HANDOFF); @@ -3119,7 +3119,7 @@ int sqlite3Select( if( pWInfo==0 ) goto select_end; if( pGroupBy==0 ){ /* The optimizer is able to deliver rows in group by order so - ** we do not have to sort. The OP_OpenVirtual table will be + ** we do not have to sort. The OP_OpenEphemeral table will be ** cancelled later because we still need to use the pKeyInfo */ pGroupBy = p->pGroupBy; diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 6a25f67cc..3f8a6d7be 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -12,7 +12,7 @@ ** This header file defines the interface that the SQLite library ** presents to client programs. ** -** @(#) $Id: sqlite.h.in,v 1.167 2006/06/10 13:29:33 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.168 2006/06/11 23:41:56 drh Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ @@ -1517,6 +1517,7 @@ typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor; typedef struct sqlite3_module sqlite3_module; struct sqlite3_module { int iVersion; + const char *zName; void *pAux; int (*xCreate)(sqlite3*, const sqlite3_module *pModule, int argc, char **argv, @@ -1568,6 +1569,11 @@ struct sqlite3_index_info { #define SQLITE_INDEX_CONSTRAINT_LT 5 #define SQLITE_INDEX_CONSTRAINT_GE 6 #define SQLITE_INDEX_CONSTRAINT_MATCH 7 +int sqlite3_create_module( + sqlite3 *db, + const char *zName, + const sqlite3_module * +); /* diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 6e78e0782..9a2de4875 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.496 2006/06/10 13:29:33 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.497 2006/06/11 23:41:56 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -490,13 +490,13 @@ struct sqlite3 { void *pProgressArg; /* Argument to the progress callback */ int nProgressOps; /* Number of opcodes for progress callback */ #endif -#ifndef SQLITE_OMIT_GLOBALRECOVER - sqlite3 *pNext; /* Linked list of open db handles. */ +#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 */ + int busyTimeout; /* Busy handler timeout, in msec */ Db aDbStatic[2]; /* Static space for the 2 default backends */ #ifdef SQLITE_SSE sqlite3_stmt *pFetch; /* Used by SSE to fetch stored statements */ @@ -672,7 +672,7 @@ struct CollSeq { ** Table.tnum is the page number for the root BTree page of the table in the ** database file. If Table.iDb is the index of the database table backend ** in sqlite.aDb[]. 0 is for the main database and 1 is for the file that -** holds temporary tables and indices. If Table.isTransient +** holds temporary tables and indices. If Table.isEphem ** is true, then the table is stored in a file that is automatically deleted ** when the VDBE cursor to the table is closed. In this case Table.tnum ** refers VDBE cursor number that holds the table open, not to the root @@ -689,7 +689,7 @@ struct Table { int tnum; /* Root BTree node for this table (see note above) */ Select *pSelect; /* NULL for tables. Points to definition if a view. */ u8 readOnly; /* True if this table should not be written by the user */ - u8 isTransient; /* True if automatically deleted when VDBE finishes */ + u8 isEphem; /* True if created using OP_OpenEphermeral */ u8 hasPrimKey; /* True if there exists a primary key */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ u8 autoInc; /* True if the integer primary key is autoincrement */ @@ -704,10 +704,12 @@ struct Table { int addColOffset; /* Offset in CREATE TABLE statement to add a new column */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE - char *zModuleName; /* Name of module implementing this virtual table */ - sqlite3_module *pMod; /* Pointer to the implementation of the module */ - sqlite3_vtab *pVTab; /* Pointer to the module instance */ - u8 needCreate; /* Need to call pMod->xCreate() */ + sqlite3_module *pModule; /* Pointer to the implementation of the module */ + sqlite3_vtab *pVtab; /* Pointer to the module instance */ + int nModuleArg; /* Number of arguments to the module */ + char **azModuleArg; /* Text of all module args. [0] is module name */ + u8 needCreate; /* Need to call pMod->xCreate() */ + u8 isVirtual; /* True if this is a virtual table */ #endif Schema *pSchema; }; @@ -903,7 +905,7 @@ struct AggInfo { Expr *pExpr; /* Expression encoding the function */ FuncDef *pFunc; /* The aggregate function implementation */ int iMem; /* Memory location that acts as accumulator */ - int iDistinct; /* Virtual table used to enforce DISTINCT */ + int iDistinct; /* Ephermeral table used to enforce DISTINCT */ } *aFunc; int nFunc; /* Number of entries in aFunc[] */ int nFuncAlloc; /* Number of slots allocated for aFunc[] */ @@ -1171,14 +1173,14 @@ struct NameContext { ** offset). But later on, nLimit and nOffset become the memory locations ** in the VDBE that record the limit and offset counters. ** -** addrOpenVirt[] entries contain the address of OP_OpenVirtual opcodes. +** addrOpenEphm[] entries contain the address of OP_OpenEphemeral opcodes. ** These addresses must be stored so that we can go back and fill in ** the P3_KEYINFO and P2 parameters later. Neither the KeyInfo nor ** the number of columns in P2 can be computed at the same time -** as the OP_OpenVirtual instruction is coded because not +** as the OP_OpenEphm instruction is coded because not ** enough information about the compound query is known at that point. -** The KeyInfo for addrOpenVirt[0] and [1] contains collating sequences -** for the result set. The KeyInfo for addrOpenVirt[2] contains collating +** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences +** for the result set. The KeyInfo for addrOpenTran[2] contains collating ** sequences for the ORDER BY clause. */ struct Select { @@ -1187,7 +1189,7 @@ struct Select { u8 isDistinct; /* True if the DISTINCT keyword is present */ u8 isResolved; /* True once sqlite3SelectResolve() has run. */ u8 isAgg; /* True if this is an aggregate query */ - u8 usesVirt; /* True if uses an OpenVirtual opcode */ + u8 usesEphm; /* True if uses an OpenEphemeral opcode */ u8 disallowOrderBy; /* Do not allow an ORDER BY to be attached if TRUE */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ @@ -1199,7 +1201,7 @@ struct Select { Expr *pLimit; /* LIMIT expression. NULL means not used. */ Expr *pOffset; /* OFFSET expression. NULL means not used. */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ - int addrOpenVirt[3]; /* OP_OpenVirtual opcodes related to this select */ + int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */ }; /* @@ -1216,7 +1218,7 @@ struct Select { #define SRT_Mem 5 /* Store result in a memory cell */ #define SRT_Set 6 /* Store non-null results as keys in an index */ #define SRT_Table 7 /* Store result as data with an automatic rowid */ -#define SRT_VirtualTab 8 /* Create virtual table and store like SRT_Table */ +#define SRT_EphemTab 8 /* Create transient tab and store like SRT_Table */ #define SRT_Subroutine 9 /* Call a subroutine to handle results */ #define SRT_Exists 10 /* Store 1 if the result is not empty */ @@ -1277,6 +1279,11 @@ struct Parse { 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 }; /* @@ -1774,6 +1781,16 @@ void sqlite3CloseExtensions(sqlite3*); #define sqlite3ThreadSafeFree sqlite3FreeX #endif +#ifdef SQLITE_OMIT_VIRTUALTABLE +# define sqlite3VtabClear(X) +#else + void sqlite3VtabClear(Table*); +#endif +void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*); +void sqlite3VtabFinishParse(Parse*, Token*); +void sqlite3VtabArgInit(Parse*); +void sqlite3VtabArgExtend(Parse*, Token*); + #ifdef SQLITE_SSE #include "sseInt.h" #endif diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 875890d81..07783c1e4 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -11,7 +11,7 @@ ************************************************************************* ** A TCL Interface to SQLite ** -** $Id: tclsqlite.c,v 1.156 2006/05/10 14:39:14 drh Exp $ +** $Id: tclsqlite.c,v 1.157 2006/06/11 23:41:56 drh Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ @@ -2151,6 +2151,7 @@ int TCLSH_MAIN(int argc, char **argv){ extern int Sqlitetest5_Init(Tcl_Interp*); extern int Sqlitetest6_Init(Tcl_Interp*); extern int Sqlitetest7_Init(Tcl_Interp*); + extern int Sqlitetest8_Init(Tcl_Interp*); extern int Md5_Init(Tcl_Interp*); extern int Sqlitetestsse_Init(Tcl_Interp*); extern int Sqlitetestasync_Init(Tcl_Interp*); @@ -2162,6 +2163,7 @@ int TCLSH_MAIN(int argc, char **argv){ Sqlitetest5_Init(interp); Sqlitetest6_Init(interp); Sqlitetest7_Init(interp); + Sqlitetest8_Init(interp); Sqlitetestasync_Init(interp); Md5_Init(interp); #ifdef SQLITE_SSE diff --git a/src/test1.c b/src/test1.c index 01dc6d782..0c18ea129 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.209 2006/03/19 13:00:25 drh Exp $ +** $Id: test1.c,v 1.210 2006/06/11 23:41:56 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -3538,6 +3538,12 @@ static void set_options(Tcl_Interp *interp){ #else Tcl_SetVar2(interp, "sqlite_options", "view", "1", TCL_GLOBAL_ONLY); #endif + +#ifdef SQLITE_OMIT_VIRTUALTABLE + Tcl_SetVar2(interp, "sqlite_options", "vtab", "0", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "vtab", "1", TCL_GLOBAL_ONLY); +#endif } /* diff --git a/src/test8.c b/src/test8.c new file mode 100644 index 000000000..c0d08a469 --- /dev/null +++ b/src/test8.c @@ -0,0 +1,136 @@ +/* +** 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. +** +************************************************************************* +** 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.1 2006/06/11 23:41:56 drh Exp $ +*/ +#include "sqliteInt.h" +#include "tcl.h" +#include "os.h" +#include <stdlib.h> +#include <string.h> + +/* Methods for the echo module */ +static int echoCreate( + 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", "xCreate", 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); + } + 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); + } + 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; +} +static int echoDestroy(sqlite3_vtab *pVtab){ + Tcl_Interp *interp = (Tcl_Interp*)pVtab; + Tcl_SetVar(interp, "echo_module", "xDestroy", + TCL_APPEND_VALUE | TCL_LIST_ELEMENT | TCL_GLOBAL_ONLY); + return 0; +} + +/* +** A virtual table module that merely echos method calls into TCL +** variables. +*/ +static sqlite3_module echoModule = { + 0, + "echo", + 0, + echoCreate, + echoConnect, + 0, + echoDisconnect, + echoDestroy, +}; + +/* +** Decode a pointer to an sqlite3 object. +*/ +static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){ + *ppDb = (sqlite3*)sqlite3TextToPtr(zA); + return TCL_OK; +} + + +/* +** Register the echo virtual table module. +*/ +static int register_echo_module( + ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3 *db; + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB"); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; + echoModule.pAux = interp; +#ifndef SQLITE_OMIT_VIRTUALTABLE + sqlite3_create_module(db, "echo", &echoModule); +#endif + return TCL_OK; +} + + +/* +** Register commands with the TCL interpreter. +*/ +int Sqlitetest8_Init(Tcl_Interp *interp){ + static struct { + char *zName; + Tcl_ObjCmdProc *xProc; + void *clientData; + } aObjCmd[] = { + { "register_echo_module", register_echo_module, 0 }, + }; + int i; + for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ + Tcl_CreateObjCommand(interp, aObjCmd[i].zName, + aObjCmd[i].xProc, aObjCmd[i].clientData, 0); + } + return TCL_OK; +} diff --git a/src/tokenize.c b/src/tokenize.c index 6076e7c65..2d49fe8cd 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -15,7 +15,7 @@ ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** -** $Id: tokenize.c,v 1.118 2006/04/04 01:54:55 drh Exp $ +** $Id: tokenize.c,v 1.119 2006/06/11 23:41:56 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -483,6 +483,9 @@ abort_parse: pParse->nTableLock = 0; } #endif +#ifndef SQLITE_OMIT_VIRTUALTABLE + sqliteFree(pParse->zArg); +#endif sqlite3DeleteTable(pParse->db, pParse->pNewTable); sqlite3DeleteTrigger(pParse->pNewTrigger); sqliteFree(pParse->apVarExpr); diff --git a/src/update.c b/src/update.c index b3cd7aed0..f1662eb1a 100644 --- a/src/update.c +++ b/src/update.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** -** $Id: update.c,v 1.123 2006/02/24 02:53:50 drh Exp $ +** $Id: update.c,v 1.124 2006/06/11 23:41:56 drh Exp $ */ #include "sqliteInt.h" @@ -268,7 +268,7 @@ void sqlite3Update( if( isView ){ Select *pView; pView = sqlite3SelectDup(pTab->pSelect); - sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0); + sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0); sqlite3SelectDelete(pView); } diff --git a/src/vdbe.c b/src/vdbe.c index fc6fd97ef..a85d30315 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.550 2006/06/03 18:04:17 drh Exp $ +** $Id: vdbe.c,v 1.551 2006/06/11 23:41:56 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -2640,9 +2640,9 @@ case OP_OpenWrite: { /* no-push */ break; } -/* Opcode: OpenVirtual P1 P2 P3 +/* Opcode: OpenEphemeral P1 P2 P3 ** -** Open a new cursor P1 to a transient or virtual table. +** Open a new cursor P1 to a transient table. ** The cursor is always opened read/write even if ** the main database is read-only. The transient or virtual ** table is deleted automatically when the cursor is closed. @@ -2651,8 +2651,14 @@ case OP_OpenWrite: { /* no-push */ ** The cursor points to a BTree table if P3==0 and to a BTree index ** if P3 is not 0. If P3 is not NULL, it points to a KeyInfo structure ** that defines the format of keys in the index. +** +** This opcode was once called OpenTemp. But that created +** confusion because the term "temp table", might refer either +** to a TEMP table at the SQL level, or to a table opened by +** this opcode. Then this opcode was call OpenVirtual. But +** that created confusion with the whole virtual-table idea. */ -case OP_OpenVirtual: { /* no-push */ +case OP_OpenEphemeral: { /* no-push */ int i = pOp->p1; Cursor *pCx; assert( i>=0 ); @@ -4525,7 +4531,29 @@ case OP_TableLock: { /* no-push */ } break; } -#endif /* SHARED_OMIT_SHARED_CACHE */ +#endif /* SQLITE_OMIT_SHARED_CACHE */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* Opcode: VCreate * * P3 +** +** P3 is the name of a virtual table. Call the xCreate method for +** that table. +*/ +case OP_VCreate: { + break; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* Opcode: VDestroy * * P3 +** +** P3 is the name of a virtual table. Call the xCreate method for +** that table. +*/ +case OP_VDestroy: { + break; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ /* An other opcode is illegal... */ diff --git a/src/vdbe.h b/src/vdbe.h index 46045423d..3097022f6 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -15,7 +15,7 @@ ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** -** $Id: vdbe.h,v 1.102 2006/03/17 13:56:34 drh Exp $ +** $Id: vdbe.h,v 1.103 2006/06/11 23:41:56 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -69,7 +69,7 @@ typedef struct VdbeOpList VdbeOpList; #define P3_KEYINFO (-6) /* P3 is a pointer to a KeyInfo structure */ #define P3_VDBEFUNC (-7) /* P3 is a pointer to a VdbeFunc structure */ #define P3_MEM (-8) /* P3 is a pointer to a Mem* structure */ -#define P3_TRANSIENT (-9) /* P3 is a pointer to a transient string */ +#define P3_TRANSIENT (-9) /* P3 is a pointer to a transient string */ /* When adding a P3 argument using P3_KEYINFO, a copy of the KeyInfo structure ** is made. That copy is freed when the Vdbe is finalized. But if the diff --git a/src/vtab.c b/src/vtab.c new file mode 100644 index 000000000..d7d7515bd --- /dev/null +++ b/src/vtab.c @@ -0,0 +1,211 @@ +/* +** 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.1 2006/06/11 23:41:56 drh Exp $ +*/ +#ifndef SQLITE_OMIT_VIRTUALTABLE +#include "sqliteInt.h" + +/* +** External API function used to create a new virtual-table module. +*/ +int sqlite3_create_module( + sqlite3 *db, /* Database in which module is registered */ + const char *zName, /* Name assigned to this module */ + const sqlite3_module *pModule /* The definition of the module */ +){ + sqlite3HashInsert(&db->aModule, zName, strlen(zName), (void*)pModule); + sqlite3ResetInternalSchema(db, 0); + return SQLITE_OK; +} + + +/* +** Clear any and all virtual-table information from the Table record. +** This routine is called, for example, just before deleting the Table +** record. +*/ +void sqlite3VtabClear(Table *p){ + if( p->pVtab ){ + assert( p->pModule!=0 ); + p->pModule->xDisconnect(p->pVtab); + } + if( p->azModuleArg ){ + int i; + for(i=0; i<p->nModuleArg; i++){ + sqliteFree(p->azModuleArg[i]); + } + sqliteFree(p->azModuleArg); + } +} + +/* +** Add a new module argument to pTable->azModuleArg[]. +** The string is not copied - the pointer is stored. The +** string will be freed automatically when the table is +** deleted. +*/ +static void addModuleArgument(Table *pTable, char *zArg){ + int i = pTable->nModuleArg++; + pTable->azModuleArg = sqliteRealloc(pTable->azModuleArg, + sizeof(char*)*(pTable->nModuleArg+1)); + if( pTable->azModuleArg==0 ){ + pTable->nModuleArg = 0; + sqliteFree(zArg); + }else{ + pTable->azModuleArg[i] = zArg; + pTable->azModuleArg[i+1] = 0; + } +} + +/* +** The parser calls this routine when it first sees a CREATE VIRTUAL TABLE +** statement. The module name has been parsed, but the optional list +** of parameters that follow the module name are still pending. +*/ +void sqlite3VtabBeginParse( + Parse *pParse, /* Parsing context */ + Token *pName1, /* Name of new table, or database name */ + Token *pName2, /* Name of new table or NULL */ + Token *pModuleName /* Name of the module for the virtual table */ +){ + Table *pTable; /* The new virtual table */ + + sqlite3StartTable(pParse, pName1, pName2, 0, 0, 0); + pTable = pParse->pNewTable; + if( pTable==0 ) return; + pTable->isVirtual = 1; + pTable->nModuleArg = 0; + addModuleArgument(pTable, sqlite3NameFromToken(pModuleName)); + pParse->sNameToken.n = pModuleName->z + pModuleName->n - pName1->z; +} + +/* +** This routine takes the module argument that has been accumulating +** in pParse->zArg[] and appends it to the list of arguments on the +** virtual table currently under construction in pParse->pTable. +*/ +static void addArgumentToVtab(Parse *pParse){ + if( pParse->nArgUsed && pParse->pNewTable ){ + addModuleArgument(pParse->pNewTable, sqliteStrDup(pParse->zArg)); + } + pParse->nArgUsed = 0; +} + +/* +** The parser calls this routine after the CREATE VIRTUAL TABLE statement +** has been completely parsed. +*/ +void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ + Table *pTab; /* The table being constructed */ + sqlite3 *db; /* The database connection */ + char *zModule; /* The module name of the table: USING modulename */ + + addArgumentToVtab(pParse); + sqliteFree(pParse->zArg); + pParse->zArg = 0; + pParse->nArgAlloc = 0; + + /* Lookup the module name. */ + pTab = pParse->pNewTable; + if( pTab==0 ) return; + db = pParse->db; + if( pTab->nModuleArg<1 ) return; + pParse->pNewTable = 0; + 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 + ** do additional initialization work and store the statement text + ** in the sqlite_master table. + */ + if( !db->init.busy ){ + char *zStmt; + int iDb; + Vdbe *v; + if( pTab->pModule==0 ){ + sqlite3ErrorMsg(pParse, "unknown module: %s", zModule); + } + + /* Compute the complete text of the CREATE VIRTUAL TABLE statement */ + if( pEnd ){ + pParse->sNameToken.n = pEnd->z - pParse->sNameToken.z + pEnd->n; + } + zStmt = sqlite3MPrintf("CREATE VIRTUAL TABLE %T", &pParse->sNameToken); + + /* A slot for the record has already been allocated in the + ** SQLITE_MASTER table. We just need to update that slot with all + ** the information we've collected. The rowid for the preallocated + ** slot is the top the stack. + */ + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + sqlite3NestedParse(pParse, + "UPDATE %Q.%s " + "SET type='table', name=%Q, tbl_name=%Q, rootpage=NULL, sql=%Q " + "WHERE rowid=#0", + db->aDb[iDb].zName, SCHEMA_TABLE(iDb), + pTab->zName, + pTab->zName, + zStmt + ); + sqliteFree(zStmt); + v = sqlite3GetVdbe(pParse); + sqlite3VdbeOp3(v, OP_VCreate, 0, 0, pTab->zName, P3_DYNAMIC); + sqlite3ChangeCookie(db, v, iDb); + } + + /* If we are rereading the sqlite_master table and we happen to + ** currently know the module for the new table, create an + ** sqlite3_vtab instance. + */ + else if( pTab->pModule ){ + sqlite3_module *pMod = pTab->pModule; + assert( pMod->xConnect ); + pMod->xConnect(db, pMod, pTab->nModuleArg, pTab->azModuleArg, &pTab->pVtab); + } +} + +/* +** The parser calls this routine when it sees the first token +** of an argument to the module name in a CREATE VIRTUAL TABLE statement. +*/ +void sqlite3VtabArgInit(Parse *pParse){ + addArgumentToVtab(pParse); + pParse->nArgUsed = 0; +} + +/* +** The parser calls this routine for each token after the first token +** in an argument to the module name in a CREATE VIRTUAL TABLE statement. +*/ +void sqlite3VtabArgExtend(Parse *pParse, Token *p){ + if( pParse->nArgUsed + p->n + 2 >= pParse->nArgAlloc ){ + pParse->nArgAlloc = pParse->nArgAlloc*2 + p->n + 200; + pParse->zArg = sqliteRealloc(pParse->zArg, pParse->nArgAlloc); + if( pParse->zArg==0 ){ + pParse->nArgAlloc = 0; + return; + } + } + 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; +} + +#endif /* SQLITE_OMIT_VIRTUALTABLE */ diff --git a/src/where.c b/src/where.c index 4ba6338ed..515ed4421 100644 --- a/src/where.c +++ b/src/where.c @@ -16,7 +16,7 @@ ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** -** $Id: where.c,v 1.209 2006/06/06 11:45:55 drh Exp $ +** $Id: where.c,v 1.210 2006/06/11 23:41:56 drh Exp $ */ #include "sqliteInt.h" @@ -1601,7 +1601,7 @@ WhereInfo *sqlite3WhereBegin( pTabItem = &pTabList->a[pLevel->iFrom]; pTab = pTabItem->pTab; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - if( pTab->isTransient || pTab->pSelect ) continue; + if( pTab->isEphem || pTab->pSelect ) continue; if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){ sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, OP_OpenRead); if( pTab->nCol<(sizeof(Bitmask)*8) ){ @@ -2087,7 +2087,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom]; Table *pTab = pTabItem->pTab; assert( pTab!=0 ); - if( pTab->isTransient || pTab->pSelect ) continue; + if( pTab->isEphem || pTab->pSelect ) continue; if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){ sqlite3VdbeAddOp(v, OP_Close, pTabItem->iCursor, 0); } |