diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 8 | ||||
-rw-r--r-- | src/delete.c | 29 | ||||
-rw-r--r-- | src/expr.c | 6 | ||||
-rw-r--r-- | src/insert.c | 32 | ||||
-rw-r--r-- | src/sqliteInt.h | 15 | ||||
-rw-r--r-- | src/trigger.c | 7 | ||||
-rw-r--r-- | src/update.c | 48 | ||||
-rw-r--r-- | src/vdbe.c | 60 | ||||
-rw-r--r-- | src/where.c | 4 |
9 files changed, 162 insertions, 47 deletions
diff --git a/src/build.c b/src/build.c index 535ccca8d..cd6f290c4 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.399 2006/06/12 16:01:22 danielk1977 Exp $ +** $Id: build.c,v 1.400 2006/06/14 19:00:21 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -1655,7 +1655,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ if( sqlite3VtabCallConnect(pParse, pTable) ){ return SQLITE_ERROR; } - if( pTable->isVirtual ) return 0; + if( IsVirtual(pTable) ) return 0; #endif #ifndef SQLITE_OMIT_VIEW @@ -1981,11 +1981,9 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ /* Remove the table entry from SQLite's internal schema and modify ** the schema cookie. */ -#ifndef SQLITE_OMIT_VIRTUALTABLE - if( pTab->isVirtual ){ + if( IsVirtual(pTab) ){ sqlite3VdbeOp3(v, OP_VDestroy, iDb, 0, pTab->zName, 0); } -#endif sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0); sqlite3ChangeCookie(db, v, iDb); } diff --git a/src/delete.c b/src/delete.c index e16597d8a..37b8577d8 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.123 2006/06/11 23:41:55 drh Exp $ +** $Id: delete.c,v 1.124 2006/06/14 19:00:21 drh Exp $ */ #include "sqliteInt.h" @@ -42,8 +42,12 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ ** writable return 0; */ int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){ - if( pTab->readOnly && (pParse->db->flags & SQLITE_WriteSchema)==0 - && pParse->nested==0 ){ + if( (pTab->readOnly && (pParse->db->flags & SQLITE_WriteSchema)==0 + && pParse->nested==0) +#ifndef SQLITE_OMIT_VIRTUALTABLE + || (pTab->pModule && pTab->pModule->xUpdate==0) +#endif + ){ sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName); return 1; } @@ -66,7 +70,9 @@ void sqlite3OpenTable( Table *pTab, /* The table to be opened */ int opcode /* OP_OpenRead or OP_OpenWrite */ ){ - Vdbe *v = sqlite3GetVdbe(p); + Vdbe *v; + if( IsVirtual(pTab) ) return; + v = sqlite3GetVdbe(p); assert( opcode==OP_OpenWrite || opcode==OP_OpenRead ); sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite), pTab->zName); sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); @@ -205,7 +211,7 @@ void sqlite3DeleteFrom( ** It is easier just to erase the whole table. Note, however, that ** this means that the row change count will be incorrect. */ - if( pWhere==0 && !triggers_exist ){ + if( pWhere==0 && !triggers_exist && !IsVirtual(pTab) ){ if( db->flags & SQLITE_CountRows ){ /* If counting rows deleted, just count the total number of ** entries in the table. */ @@ -243,7 +249,7 @@ void sqlite3DeleteFrom( /* Remember the rowid of every item to be deleted. */ - sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); + sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0); sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0); if( db->flags & SQLITE_CountRows ){ sqlite3VdbeAddOp(v, OP_AddImm, 1, 0); @@ -304,7 +310,14 @@ void sqlite3DeleteFrom( } /* Delete the row */ - sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0); +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( IsVirtual(pTab) ){ + sqlite3VdbeOp3(v, OP_VUpdate, 0, 1, (const char*)pTab->pVtab, P3_VTAB); + }else +#endif + { + sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0); + } } /* If there are row triggers, close all cursors then invoke @@ -327,7 +340,7 @@ void sqlite3DeleteFrom( sqlite3VdbeResolveLabel(v, end); /* Close the cursors after the loop if there are no row triggers */ - if( !triggers_exist ){ + if( !triggers_exist && !IsVirtual(pTab) ){ for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum); } diff --git a/src/expr.c b/src/expr.c index d9f24c37b..43e1c715e 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.261 2006/06/13 04:11:44 danielk1977 Exp $ +** $Id: expr.c,v 1.262 2006/06/14 19:00:21 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -1489,7 +1489,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ }else if( pExpr->iColumn>=0 ){ Table *pTab = pExpr->pTab; int iCol = pExpr->iColumn; - int op = (pTab && pTab->isVirtual) ? OP_VColumn : OP_Column; + int op = (pTab && IsVirtual(pTab)) ? OP_VColumn : OP_Column; sqlite3VdbeAddOp(v, op, pExpr->iTable, iCol); sqlite3ColumnDefault(v, pTab, iCol); #ifndef SQLITE_OMIT_FLOATING_POINT @@ -1499,7 +1499,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ #endif }else{ Table *pTab = pExpr->pTab; - int op = (pTab && pTab->isVirtual) ? OP_VRowid : OP_Rowid; + int op = (pTab && IsVirtual(pTab)) ? OP_VRowid : OP_Rowid; sqlite3VdbeAddOp(v, op, pExpr->iTable, 0); } break; diff --git a/src/insert.c b/src/insert.c index 295d753d3..3d34feda9 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.165 2006/06/11 23:41:55 drh Exp $ +** $Id: insert.c,v 1.166 2006/06/14 19:00:21 drh Exp $ */ #include "sqliteInt.h" @@ -567,6 +567,10 @@ void sqlite3Insert( ** case the record number is the same as that column. */ if( !isView ){ + if( IsVirtual(pTab) ){ + /* The row that the VUpdate opcode will delete: none */ + sqlite3VdbeAddOp(v, OP_Null, 0, 0); + } if( keyColumn>=0 ){ if( useTempTable ){ sqlite3VdbeAddOp(v, OP_Column, srcTab, keyColumn); @@ -582,6 +586,8 @@ void sqlite3Insert( sqlite3VdbeAddOp(v, OP_Pop, 1, 0); sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem); sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); + }else if( IsVirtual(pTab) ){ + sqlite3VdbeAddOp(v, OP_Null, 0, 0); }else{ sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem); } @@ -624,10 +630,18 @@ void sqlite3Insert( /* Generate code to check constraints and generate index keys and ** do the insertion. */ - sqlite3GenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0, - 0, onError, endOfLoop); - sqlite3CompleteInsertion(pParse, pTab, base, 0,0,0, +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( IsVirtual(pTab) ){ + sqlite3VdbeOp3(v, OP_VUpdate, 0, pTab->nCol+1, + (const char*)pTab->pVtab, P3_VTAB); + }else +#endif + { + sqlite3GenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0, + 0, onError, endOfLoop); + sqlite3CompleteInsertion(pParse, pTab, base, 0,0,0, (triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1); + } } /* Update the count of rows that are inserted @@ -665,7 +679,7 @@ void sqlite3Insert( sqlite3VdbeResolveLabel(v, iCleanup); } - if( !triggers_exist ){ + if( !triggers_exist && !IsVirtual(pTab) ){ /* Close all tables opened */ sqlite3VdbeAddOp(v, OP_Close, base, 0); for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ @@ -1105,9 +1119,13 @@ void sqlite3OpenTableAndIndices( int op /* OP_OpenRead or OP_OpenWrite */ ){ int i; - int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + int iDb; Index *pIdx; - Vdbe *v = sqlite3GetVdbe(pParse); + Vdbe *v; + + if( IsVirtual(pTab) ) return; + iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + v = sqlite3GetVdbe(pParse); assert( v!=0 ); sqlite3OpenTable(pParse, base, iDb, pTab, op); for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 28ea1f73f..fcc147adf 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.504 2006/06/13 15:36:07 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.505 2006/06/14 19:00:21 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -694,7 +694,6 @@ struct Table { 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 */ - u8 isVirtual; /* True if this is a virtual table */ int nRef; /* Number of pointers to this Table */ Trigger *pTrigger; /* List of SQL triggers on this table */ FKey *pFKey; /* Linked list of all foreign keys in this table */ @@ -708,6 +707,7 @@ struct Table { #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3_module *pModule; /* Pointer to the implementation of the module */ sqlite3_vtab *pVtab; /* Pointer to the module instance */ + u8 isVirtual; /* True if this is a virtual table */ int nModuleArg; /* Number of arguments to the module */ char **azModuleArg; /* Text of all module args. [0] is module name */ #endif @@ -715,6 +715,17 @@ struct Table { }; /* +** Test to see whether or not a table is a virtual table. This is +** done as a macro so that it will be optimized out when virtual +** table support is omitted from the build. +*/ +#ifndef SQLITE_OMIT_VIRTUALTABLE +# define IsVirtual(X) ((X)->isVirtual) +#else +# define IsVirtual(X) 0 +#endif + +/* ** Each foreign key constraint is an instance of the following structure. ** ** A foreign key is associated with two tables. The "from" table is diff --git a/src/trigger.c b/src/trigger.c index d670e527c..15992df38 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -103,6 +103,10 @@ void sqlite3BeginTrigger( /* The table does not exist. */ goto trigger_cleanup; } + if( IsVirtual(pTab) ){ + sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables"); + goto trigger_cleanup; + } /* Check that the trigger name is not reserved and that no trigger of the ** specified name exists */ @@ -594,9 +598,10 @@ int sqlite3TriggersExist( int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */ ExprList *pChanges /* Columns that change in an UPDATE statement */ ){ - Trigger *pTrigger = pTab->pTrigger; + Trigger *pTrigger; int mask = 0; + pTrigger = IsVirtual(pTab) ? 0 : pTab->pTrigger; while( pTrigger ){ if( pTrigger->op==op && checkColumnOverLap(pTrigger->pColumns, pChanges) ){ mask |= pTrigger->tr_tm; diff --git a/src/update.c b/src/update.c index f1662eb1a..bc2a27150 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.124 2006/06/11 23:41:56 drh Exp $ +** $Id: update.c,v 1.125 2006/06/14 19:00:22 drh Exp $ */ #include "sqliteInt.h" @@ -277,9 +277,9 @@ void sqlite3Update( pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0); if( pWInfo==0 ) goto update_cleanup; - /* Remember the index of every item to be updated. + /* Remember the rowid of every item to be updated. */ - sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); + sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0); sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0); /* End the database scan loop. @@ -358,7 +358,7 @@ void sqlite3Update( } } - if( !isView ){ + if( !isView && !IsVirtual(pTab) ){ /* ** Open every index that needs updating. Note that if any ** index could potentially invoke a REPLACE conflict resolution @@ -390,7 +390,7 @@ void sqlite3Update( /* Loop over every record that needs updating. We have to load ** the old data for each record to be updated because some columns ** might not change and we will need to copy the old value. - ** Also, the old data is needed to delete the old index entires. + ** Also, the old data is needed to delete the old index entries. ** So make the cursor point at the old record. */ if( !triggers_exist ){ @@ -444,6 +444,42 @@ void sqlite3Update( sqlite3CompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRowid, 1, -1); } +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( !isView && IsVirtual(pTab) ){ + addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0); + + /* If the record number will change, push the record number as it + ** will be after the update. (The old record number is currently + ** on top of the stack.) + */ + if( chngRowid ){ + sqlite3ExprCode(pParse, pRowidExpr); + sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); + }else{ + sqlite3VdbeAddOp(v, OP_Dup, 0, 0); + } + + /* Compute new data for this record. + */ + for(i=0; i<pTab->nCol; i++){ + if( i==pTab->iPKey ){ + sqlite3VdbeAddOp(v, OP_Null, 0, 0); + continue; + } + j = aXRef[i]; + if( j<0 ){ + sqlite3VdbeAddOp(v, OP_VNoChange, 0, 0); + }else{ + sqlite3ExprCode(pParse, pChanges->a[j].pExpr); + } + } + + /* Make the update */ + sqlite3VdbeOp3(v, OP_VUpdate, 0, pTab->nCol+2, + (const char*)pTab->pVtab, P3_VTAB); + } +#endif /* SQLITE_OMIT_VIRTUAL */ + /* Increment the row counter */ if( db->flags & SQLITE_CountRows && !pParse->trigStack){ @@ -474,7 +510,7 @@ void sqlite3Update( sqlite3VdbeJumpHere(v, addr); /* Close all tables if there were no FOR EACH ROW triggers */ - if( !triggers_exist ){ + if( !triggers_exist && !IsVirtual(pTab) ){ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( openAll || aIdxUsed[i] ){ sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0); diff --git a/src/vdbe.c b/src/vdbe.c index 5757cdc8a..050ab337b 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.559 2006/06/14 13:03:24 danielk1977 Exp $ +** $Id: vdbe.c,v 1.560 2006/06/14 19:00:22 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -4539,7 +4539,7 @@ case OP_TableLock: { /* no-push */ ** P3 is the name of a virtual table in database P1. Call the xCreate method ** for that table. */ -case OP_VCreate: { +case OP_VCreate: { /* no-push */ rc = sqlite3VtabCallCreate(db, pOp->p1, pOp->p3, &p->zErrMsg); break; } @@ -4551,7 +4551,7 @@ case OP_VCreate: { ** P3 is the name of a virtual table in database P1. Call the xDestroy method ** of that table. */ -case OP_VDestroy: { +case OP_VDestroy: { /* no-push */ rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p3); break; } @@ -4564,7 +4564,7 @@ case OP_VDestroy: { ** P1 is a cursor number. This opcode opens a cursor to the virtual ** table and stores that cursor in P1. */ -case OP_VOpen: { +case OP_VOpen: { /* no-push */ Cursor *pCur = 0; sqlite3_vtab_cursor *pVtabCursor = 0; @@ -4610,7 +4610,7 @@ case OP_VOpen: { ** A jump is made to P2 if the result set after filtering would be ** empty. */ -case OP_VFilter: { +case OP_VFilter: { /* no-push */ int nArg; const sqlite3_module *pModule; @@ -4725,7 +4725,7 @@ case OP_VColumn: { ** jump to instruction P2. Or, if the virtual table has reached ** the end of its result set, then fall through to the next instruction. */ -case OP_VNext: { +case OP_VNext: { /* no-push */ const sqlite3_module *pModule; int res = 0; @@ -4756,6 +4756,22 @@ case OP_VNext: { } #endif /* SQLITE_OMIT_VIRTUALTABLE */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* Opcode: VNoChange * * * +** +** Push an entry onto the stack which says to the VUpdate command +** that the corresponding column of the row should not be modified. +*/ +case OP_VNoChange: { + pTos++; + pTos->flags = 0; + pTos->n = 0; + break; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + + #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VUpdate * P2 P3 ** @@ -4764,23 +4780,41 @@ case OP_VNext: { ** are taken from the stack to pass to the xUpdate invocation. The ** value on the top of the stack corresponds to the p2th element ** of the argv array passed to xUpdate. -*/ -case OP_VUpdate: { +** +** The xUpdate method will do a DELETE or an INSERT or both. +** The argv[0] element (which corresponds to the P2-th element down +** on the stack) is the rowid of a row to delete. If argv[0] is +** NULL then no deletion occurs. The argv[1] element is the rowid +** of the new row. This can be NULL to have the virtual table +** select the new rowid for itself. The higher elements in the +** stack are the values of columns in the new row. if any argv[i] +** where i>=2 is a NULL pointer (that is to say if argv[i]==NULL +** which is different from if sqlite3_value_type(argv[i])==SQLITE_NULL) +** that means to preserve a copy of that element. In other words, +** copy the corresponding value from the argv[0] row into the new row. +** +** If P2==1 then no insert is performed. argv[0] is the rowid of +** a row to delete. +*/ +case OP_VUpdate: { /* no-push */ sqlite3_vtab *pVtab = (sqlite3_vtab *)(pOp->p3); sqlite3_module *pModule = (sqlite3_module *)pVtab->pModule; + int nArg = pOp->p2; + assert( pOp->p3type==P3_VTAB ); if( pModule->xUpdate==0 ){ - sqlite3SetString(&p->zErrMsg, "Unsupported module operation: xUpdate", 0); + sqlite3SetString(&p->zErrMsg, "read-only table", 0); rc = SQLITE_ERROR; }else{ int i; Mem **apArg = p->apArg; - int nArg = pOp->p1; - for(i = 0; i<nArg; i++){ - apArg[i] = &pTos[i+1-nArg]; - storeTypeInfo(apArg[i], 0); + Mem *pX = &pTos[1-nArg]; + for(i = 0; i<nArg; i++, pX++){ + apArg[i] = pX->flags ? storeTypeInfo(pX,0), pX : 0; } rc = pModule->xUpdate(pVtab, nArg, apArg); } + popStack(&pTos, nArg); + break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ diff --git a/src/where.c b/src/where.c index d137d740f..3928c488a 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.216 2006/06/13 23:51:35 drh Exp $ +** $Id: where.c,v 1.217 2006/06/14 19:00:22 drh Exp $ */ #include "sqliteInt.h" @@ -1790,7 +1790,7 @@ WhereInfo *sqlite3WhereBegin( } assert( pTabItem->pTab ); #ifndef SQLITE_OMIT_VIRTUALTABLE - if( pTabItem->pTab->isVirtual ){ + if( IsVirtual(pTabItem->pTab) ){ cost = bestVirtualIndex(pParse, &wc, pTabItem, notReady, ppOrderBy ? *ppOrderBy : 0, i==0, &pLevel->pIdxInfo); |