Added code to INSERT, DELETE and UPDATE virtual tables. The new code is

mostly untested. (CVS 3248)

FossilOrigin-Name: 32c97b884b104d120db3c0a87f5eab28f36851f8
This commit is contained in:
drh 2006-06-14 19:00:20 +00:00
parent badf7a7a2f
commit 4cbdda9e27
11 changed files with 176 additions and 61 deletions

View File

@ -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

View File

@ -1 +1 @@
0d369ff071d296501cc33d4622144b22946ac555
32c97b884b104d120db3c0a87f5eab28f36851f8

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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++){

View File

@ -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,12 +707,24 @@ 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
Schema *pSchema;
};
/*
** 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.
**

View File

@ -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;

View File

@ -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);

View File

@ -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.
**
** 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: {
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 */

View File

@ -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);