aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2006-06-11 23:41:55 +0000
committerdrh <drh@noemail.net>2006-06-11 23:41:55 +0000
commitb9bb7c187e5cc9cce7d4e6fac38533339e865f33 (patch)
tree3d12b363c1d5496178d24a45ff90913049986880 /src
parente09daa90ac013c75806e582d7a073bf4d98783c2 (diff)
downloadsqlite-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.c23
-rw-r--r--src/delete.c4
-rw-r--r--src/expr.c14
-rw-r--r--src/insert.c4
-rw-r--r--src/main.c8
-rw-r--r--src/parse.y19
-rw-r--r--src/select.c96
-rw-r--r--src/sqlite.h.in8
-rw-r--r--src/sqliteInt.h53
-rw-r--r--src/tclsqlite.c4
-rw-r--r--src/test1.c8
-rw-r--r--src/test8.c136
-rw-r--r--src/tokenize.c5
-rw-r--r--src/update.c4
-rw-r--r--src/vdbe.c38
-rw-r--r--src/vdbe.h4
-rw-r--r--src/vtab.c211
-rw-r--r--src/where.c6
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);
}