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:
parent
badf7a7a2f
commit
4cbdda9e27
28
manifest
28
manifest
@ -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
|
||||
|
@ -1 +1 @@
|
||||
0d369ff071d296501cc33d4622144b22946ac555
|
||||
32c97b884b104d120db3c0a87f5eab28f36851f8
|
@ -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);
|
||||
}
|
||||
|
29
src/delete.c
29
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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
32
src/insert.c
32
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++){
|
||||
|
@ -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.
|
||||
**
|
||||
|
@ -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;
|
||||
|
48
src/update.c
48
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);
|
||||
|
58
src/vdbe.c
58
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.
|
||||
**
|
||||
** 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 */
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user