aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build.c8
-rw-r--r--src/delete.c29
-rw-r--r--src/expr.c6
-rw-r--r--src/insert.c32
-rw-r--r--src/sqliteInt.h15
-rw-r--r--src/trigger.c7
-rw-r--r--src/update.c48
-rw-r--r--src/vdbe.c60
-rw-r--r--src/where.c4
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);