diff options
author | drh <drh@noemail.net> | 2006-06-14 19:00:20 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2006-06-14 19:00:20 +0000 |
commit | 4cbdda9e273d030228bc58128d59e84009baefeb (patch) | |
tree | 8da8bb9cb7812dbe99a7e58929aab1b73c630095 | |
parent | badf7a7a2fa7af2e78341999a3de812d04d1eaeb (diff) | |
download | sqlite-4cbdda9e273d030228bc58128d59e84009baefeb.tar.gz sqlite-4cbdda9e273d030228bc58128d59e84009baefeb.zip |
Added code to INSERT, DELETE and UPDATE virtual tables. The new code is
mostly untested. (CVS 3248)
FossilOrigin-Name: 32c97b884b104d120db3c0a87f5eab28f36851f8
-rw-r--r-- | manifest | 28 | ||||
-rw-r--r-- | manifest.uuid | 2 | ||||
-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 |
11 files changed, 177 insertions, 62 deletions
@@ -1,5 +1,5 @@ -C Better\sdocumentation\son\sthe\slimits\sof\suser-defined\sfunctions.\s\sAnd\sa\nmarginally\sbetter\serror\smessage\swhen\sthose\slimits\sare\sexceeded.\nTicket\s#1847.\s(CVS\s3247) -D 2006-06-14T15:35:37 +C Added\scode\sto\sINSERT,\sDELETE\sand\sUPDATE\svirtual\stables.\s\sThe\snew\scode\sis\nmostly\suntested.\s(CVS\s3248) +D 2006-06-14T19:00:21 F Makefile.in 200f6dc376ecfd9b01e5359c4e0c10c02f649b34 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -36,17 +36,17 @@ F src/attach.c 27a31d3b89d7ebb5b358847607b1ec795384123c F src/auth.c 9ae84d2d94eb96195e04515715e08e85963e96c2 F src/btree.c ed343b3dbcbc7da9ac481ef2b98c4239fe6d9629 F src/btree.h 40055cfc09defd1146bc5b922399c035f969e56d -F src/build.c 133a046cef19c8bc80dafb38bb82229caefd6fff +F src/build.c 076619b2a5cbdbdabf5201fc45dda488d7f3cbe6 F src/callback.c fd9bb39f7ff6b52bad8365617abc61c720640429 F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675 F src/date.c cd2bd5d1ebc6fa12d6312f69789ae5b0a2766f2e -F src/delete.c f9a8c7837adb4bb4810a698a041a88d5ec7bfa9a +F src/delete.c d529fe3e20d87af628c0078fc33a3e717bb511cf F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b -F src/expr.c 8c873e05436ca8ee0ac4c7825d35ff898abb9c89 +F src/expr.c 78b521337d628b1fd9d87b12dbbe771247aab585 F src/func.c 01e559893b5e43bea85135ad3e481d86c447942a F src/hash.c 449f3d6620193aa557f5d86cbc5cc6b87702b185 F src/hash.h 1b3f7e2609141fd571f62199fc38687d262e9564 -F src/insert.c 2c3eeb4bcde13c1006824ef14953c2fdad31cf36 +F src/insert.c bda00a0e4be8bf4e591186e710075662781293d0 F src/legacy.c fa15d505dd4e45044177ee4d1c6aeaf8c836d390 F src/loadext.c d8c7bd14e6ebc4e9f1ff269475bf63e131919449 F src/main.c 4e48472d06ac3fc0250023e2eb406fc7d8d0a27c @@ -74,7 +74,7 @@ F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c ad73192b30a338a58fe81183d4a5d5a1d4e51d36 F src/sqlite.h.in b1ecebd3154cf49ba189193f7bdc10a78a9394a2 F src/sqlite3ext.h 127bd394c8eea481f2ac9b754bf399dbfc818b75 -F src/sqliteInt.h e8710fd5c10c03ca4a2fb49802b8aae6689f27a0 +F src/sqliteInt.h 5a806625f0e9400419d60f74dccef44569dd7871 F src/table.c f64ec4fbfe333f8df925bc6ba494f55e05b0e75e F src/tclsqlite.c 4ad22f354b6e4e137889000e9f585a0590ca39c5 F src/test1.c 40f20775903bc76d3be3e7c026dddcbc221c1cb0 @@ -91,12 +91,12 @@ F src/test_md5.c 6c42bc0a3c0b54be34623ff77a0eec32b2fa96e3 F src/test_server.c a6460daed0b92ecbc2531b6dc73717470e7a648c F src/test_tclvar.c d434037c1730cfffbf007ac82f1c405d7155a92a F src/tokenize.c 6ebcafa6622839968dda4418a7b6945f277a128f -F src/trigger.c 48bbb94c11954c8e132efcc04478efe8304c4196 -F src/update.c 0186f09414a6578156d40666becc964f85c2a616 +F src/trigger.c 0fc40125820409a6274834a6e04ad804d96e2793 +F src/update.c 5e638a61102776c0f0333994e18361b40598b44f F src/utf.c ab81ac59084ff1c07d421eb1a0a84ec809603b44 F src/util.c ca6ee72772c0f5dc04d2e0ab1973fd3b6a9bf79d F src/vacuum.c 5b37d0f436f8e1ffacd17934e44720b38d2247f9 -F src/vdbe.c 337ef4045ade927fa77192d0d040001b2386fba3 +F src/vdbe.c 64427e4b088ee26e9a8710724ef0a8ab5b9fd1e6 F src/vdbe.h 258b5d1c0aaa72192f09ff0568ce42b383f156fa F src/vdbeInt.h 6ccb7eaae76ebd761470f6a035501ff33aa92c20 F src/vdbeapi.c 6af0e7160af260052a7a4500464221a03dada75f @@ -104,7 +104,7 @@ F src/vdbeaux.c de49c1943146ad97538bc2bb0bce7f2c5e5db4f2 F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5 F src/vdbemem.c 5f0afe3b92bb2c037f8d5d697f7c151fa50783a3 F src/vtab.c 507cbb4e2101900339ce88e57144cc01dafa374e -F src/where.c 299c385e32a7b98d42864c7c83cdc6a778fae562 +F src/where.c 393022cb4ac77d1f00d9c27540ce13ca5486c5b0 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/all.test 5df90d015ca63fcef2a4b62c24f7316b66c4bfd4 @@ -366,7 +366,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P 676de55b28f0b22cf78f5e71f4a960f3d76c2d72 -R a8a1cc8c95b40bc320a675a33fc7e864 +P 0d369ff071d296501cc33d4622144b22946ac555 +R 0b4c2c0c45eeadd2de545aaca4dfef08 U drh -Z a5cbc134908c784d2a3323e83c952926 +Z 2664815c8d0942e02de99ff6b38443c3 diff --git a/manifest.uuid b/manifest.uuid index c5f3627f5..3975ebc30 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0d369ff071d296501cc33d4622144b22946ac555
\ No newline at end of file +32c97b884b104d120db3c0a87f5eab28f36851f8
\ No newline at end of file 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); |