-C Bugfixes:\sFix\sa\ssegfault\sintroduced\sas\spart\sof\sthe\snew\svtab\scode,\sdeallocate\smemory\sin\sthe\sDestroy()\smethod\sof\sthe\secho\smodule.\s(CVS\s3222)
-D 2006-06-13T04:11:44
+C Add\simplementations\sfor\sopcodes\srequired\sfor\slinear\sscans\sof\svirtual\stables.\s(CVS\s3223)
+D 2006-06-13T10:24:43
F Makefile.in 56fd6261e83f60724e6dcd764e06ab68cbd53909
F Makefile.linux-gcc 74ba0eadf88748a9ce3fd03d2a3ede2e6715baec
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
F src/shell.c 55bf6335dae7146f7a300039f5d6bb35010f1996
F src/sqlite.h.in 6fb7062da7e9c446623fa26b042bcf4b4050d702
F src/sqlite3ext.h 127bd394c8eea481f2ac9b754bf399dbfc818b75
-F src/sqliteInt.h 9562411b336b77123d1f569d4144fe3ba1ecb3bf
+F src/sqliteInt.h 91cc3603fe2e1be18d52490a2fa65ed9640fb338
F src/table.c f64ec4fbfe333f8df925bc6ba494f55e05b0e75e
F src/tclsqlite.c 0b2a04cfc1b4298adfbe90a754cfbbe207aca11a
F src/test1.c 88291fa6674dcd409b1c9d76d3119151d4b81a50
F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f
F src/test6.c 60a02961ceb7b3edc25f5dc5c1ac2556622a76de
F src/test7.c 03fa8d787f6aebc6d1f72504d52f33013ad2c8e3
-F src/test8.c c85eba7e98405e6c3d22ece241ee4e9ea4d154f8
+F src/test8.c d29427a0254f7609b0dd2561e62cf78e21c9d689
F src/test_async.c e3deaedd4d86a56391b81808fde9e44fbd92f1d3
F src/test_md5.c 6c42bc0a3c0b54be34623ff77a0eec32b2fa96e3
F src/test_server.c a6460daed0b92ecbc2531b6dc73717470e7a648c
F src/utf.c ab81ac59084ff1c07d421eb1a0a84ec809603b44
F src/util.c ca6ee72772c0f5dc04d2e0ab1973fd3b6a9bf79d
F src/vacuum.c 5b37d0f436f8e1ffacd17934e44720b38d2247f9
-F src/vdbe.c 59cb0d8cd19f090061f41715c44b3ed2af6bf264
+F src/vdbe.c 1f68000f8690e13535106f1b1bbaedc2da045457
F src/vdbe.h f72e5c00af759b7ed6fd606d508036d732098cc3
F src/vdbeInt.h 6ccb7eaae76ebd761470f6a035501ff33aa92c20
F src/vdbeapi.c 7dc662e7c905ce666bb506dced932e0307115cbf
-F src/vdbeaux.c bcad5264196266118eb4ed0b2db3829fe335a67d
+F src/vdbeaux.c 0168d770d03f9815511780a49cd8360d9a5f1ec5
F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5
F src/vdbemem.c 5f0afe3b92bb2c037f8d5d697f7c151fa50783a3
-F src/vtab.c 4ec6ac7e5e4fccb38401285d0e329d018622859f
+F src/vtab.c 0e39af5822bb17b0007b0df7fad527aa0e3ebd38
F src/where.c c0f3cd3831cd9defb7c7788038d439a5922e7bd6
F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/vacuum2.test 5aea8c88a65cb29f7d175296e7c819c6158d838c
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
F test/view.test 16e2774fe35e47a07ac4471b7f0bcc948b1aa6d5
-F test/vtab1.test b3a93d0b4667bf27adfbb555154086c7e25ee597
+F test/vtab1.test 67fed6f9b91b75d3e1988b47a972b30dd5ed2d97
F test/where.test ee7c9a6659b07e1ee61177f6e7ff71565ee2c9df
F test/where2.test a16476a5913e75cf65b38f2daa6157a6b7791394
F test/where3.test 3b5ad2c58069e12be2bd86bc5e211a82810521aa
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P f9ea9704755eee3fd29af7a47be1d41620be8835
-R b50ded4b4061c3fa2b3bc042599da575
+P 00f3c249bc79556d0cb3999f543887bd4f160347
+R 0931417f268857ba4bba3e3f6b5bc6db
U danielk1977
-Z 42d9f8623c9300c98d0eb90f55c29716
+Z 7ec75a36e0232c7c8167de06e4e6d3ac
-00f3c249bc79556d0cb3999f543887bd4f160347
\ No newline at end of file
+1f20e1832b38c76d2b0dde5fd720670c2ad0438b
\ No newline at end of file
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.502 2006/06/12 21:59:14 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.503 2006/06/13 10:24:43 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
sqlite3_vtab *pVtab; /* Pointer to the module instance */
int nModuleArg; /* Number of arguments to the module */
char **azModuleArg; /* Text of all module args. [0] is module name */
- u8 needCreate; /* Need to call pMod->xCreate() */
u8 isVirtual; /* True if this is a virtual table */
#endif
Schema *pSchema;
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
-** $Id: test8.c,v 1.7 2006/06/13 04:11:44 danielk1977 Exp $
+** $Id: test8.c,v 1.8 2006/06/13 10:24:43 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
+typedef struct echo_vtab echo_vtab;
+typedef struct echo_cursor echo_cursor;
+
+/* An echo vtab object */
+struct echo_vtab {
+ sqlite3_vtab base;
+ Tcl_Interp *interp;
+ sqlite3 *db;
+ char *zStmt;
+};
+
+/* An echo cursor object */
+struct echo_cursor {
+ sqlite3_vtab_cursor base;
+ sqlite3_stmt *pStmt;
+ int errcode; /* Error code */
+};
+
/*
** Global Tcl variable $echo_module is a list. This routine appends
** the string element zArg to that list in interpreter interp.
** Hence, the virtual table should have exactly the same column names and
** types as the real table.
*/
-static int echoDeclareVtab(sqlite3 *db, int argc, char **argv){
+static int echoDeclareVtab(
+ echo_vtab *pVtab,
+ sqlite3 *db,
+ int argc,
+ char **argv
+){
int rc = SQLITE_OK;
if( argc==2 ){
rc = SQLITE_ERROR;
}
sqlite3_finalize(pStmt);
+ pVtab->zStmt = sqlite3MPrintf("SELECT rowid, * FROM %s ", argv[1]);
}
return rc;
}
-/* An echo vtab object */
-typedef struct echo_vtab echo_vtab;
-struct echo_vtab {
- sqlite3_vtab base;
- Tcl_Interp *interp;
-};
-
-/* Methods for the echo module */
-static int echoCreate(
+static int echoConstructor(
sqlite3 *db,
const sqlite3_module *pModule,
int argc, char **argv,
echo_vtab *pVtab;
pVtab = sqliteMalloc( sizeof(*pVtab) );
+
*ppVtab = &pVtab->base;
pVtab->base.pModule = pModule;
pVtab->interp = pModule->pAux;
- appendToEchoModule(pVtab->interp, "xCreate");
+ pVtab->db = db;
for(i=0; i<argc; i++){
appendToEchoModule(pVtab->interp, argv[i]);
}
- echoDeclareVtab(db, argc, argv);
+ echoDeclareVtab(pVtab, db, argc, argv);
return 0;
}
+
+/* Methods for the echo module */
+static int echoCreate(
+ sqlite3 *db,
+ const sqlite3_module *pModule,
+ int argc, char **argv,
+ sqlite3_vtab **ppVtab
+){
+ appendToEchoModule((Tcl_Interp *)(pModule->pAux), "xCreate");
+ return echoConstructor(db, pModule, argc, argv, ppVtab);
+}
static int echoConnect(
sqlite3 *db,
const sqlite3_module *pModule,
int argc, char **argv,
sqlite3_vtab **ppVtab
){
- int i;
- Tcl_Interp *interp = pModule->pAux;
- echo_vtab *pVtab;
-
- pVtab = sqliteMalloc( sizeof(*pVtab) );
- *ppVtab = &pVtab->base;
- pVtab->base.pModule = pModule;
- pVtab->interp = pModule->pAux;
- appendToEchoModule(pVtab->interp, "xConnect");
- for(i=0; i<argc; i++){
- appendToEchoModule(pVtab->interp, argv[i]);
- }
-
- echoDeclareVtab(db, argc, argv);
- return 0;
+ appendToEchoModule((Tcl_Interp *)(pModule->pAux), "xConnect");
+ return echoConstructor(db, pModule, argc, argv, ppVtab);
}
+
static int echoDisconnect(sqlite3_vtab *pVtab){
echo_vtab *p = (echo_vtab*)pVtab;
appendToEchoModule(p->interp, "xDisconnect");
- sqliteFree(pVtab);
+ sqliteFree(p->zStmt);
+ sqliteFree(p);
return 0;
}
static int echoDestroy(sqlite3_vtab *pVtab){
echo_vtab *p = (echo_vtab*)pVtab;
appendToEchoModule(p->interp, "xDestroy");
- sqliteFree(pVtab);
+ sqliteFree(p->zStmt);
+ sqliteFree(p);
return 0;
}
+static int echoOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor)
+{
+ echo_cursor *pCur;
+ pCur = sqliteMalloc(sizeof(echo_cursor));
+ *ppCursor = (sqlite3_vtab_cursor *)pCur;
+ return SQLITE_OK;
+}
+
+static int echoClose(sqlite3_vtab_cursor *cur)
+{
+ echo_cursor *pCur = (echo_cursor *)cur;
+ sqlite3_finalize(pCur->pStmt);
+ sqliteFree(pCur);
+ return SQLITE_OK;
+}
+
+static int echoNext(sqlite3_vtab_cursor *cur)
+{
+ int rc;
+ echo_cursor *pCur = (echo_cursor *)cur;
+
+ rc = sqlite3_step(pCur->pStmt);
+
+ if( rc==SQLITE_ROW ){
+ rc = 1;
+ } else {
+ pCur->errcode = sqlite3_finalize(pCur->pStmt);
+ pCur->pStmt = 0;
+ rc = 0;
+ }
+
+ return rc;
+}
+
+static int echoFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idx,
+ int argc,
+ sqlite3_value **argv
+){
+ int rc;
+
+ echo_cursor *pCur = (echo_cursor *)pVtabCursor;
+ echo_vtab *pVtab = (echo_vtab *)pVtabCursor->pVtab;
+ sqlite3 *db = pVtab->db;
+
+ sqlite3_finalize(pCur->pStmt);
+ pCur->pStmt = 0;
+ rc = sqlite3_prepare(db, pVtab->zStmt, -1, &pCur->pStmt, 0);
+
+ if( rc==SQLITE_OK ){
+ rc = echoNext(pVtabCursor);
+ }
+
+ return rc;
+}
+
+static int echoColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i)
+{
+ int iCol = i + 1;
+ sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt;
+
+ assert( sqlite3_data_count(pStmt)>iCol );
+ switch( sqlite3_column_type(pStmt, iCol) ){
+ case SQLITE_INTEGER:
+ sqlite3_result_int64(ctx, sqlite3_column_int64(pStmt, iCol));
+ break;
+ case SQLITE_FLOAT:
+ sqlite3_result_double(ctx, sqlite3_column_double(pStmt, iCol));
+ break;
+ case SQLITE_TEXT:
+ sqlite3_result_text(ctx,
+ sqlite3_column_text(pStmt, iCol),
+ sqlite3_column_bytes(pStmt, iCol),
+ SQLITE_TRANSIENT
+ );
+ break;
+ case SQLITE_BLOB:
+ sqlite3_result_blob(ctx,
+ sqlite3_column_blob(pStmt, iCol),
+ sqlite3_column_bytes(pStmt, iCol),
+ SQLITE_TRANSIENT
+ );
+ break;
+ }
+ return SQLITE_OK;
+}
+
+static int echoRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid)
+{
+ sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt;
+ *pRowid = sqlite3_column_int64(pStmt, 0);
+ return SQLITE_OK;
+}
+
+
+
/*
** The xBestIndex method for the echo module always returns
** an index of 123.
echoBestIndex,
echoDisconnect,
echoDestroy,
+ echoOpen, /* xOpen - open a cursor */
+ echoClose, /* xClose - close a cursor */
+ echoFilter, /* xFilter - configure scan constraints */
+ echoNext, /* xNext - advance a cursor */
+ echoColumn, /* xColumn - read data */
+ echoRowid /* xRowid - read data */
};
/*
** 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.554 2006/06/12 21:59:14 drh Exp $
+** $Id: vdbe.c,v 1.555 2006/06/13 10:24:43 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
** table and stores that cursor in P1.
*/
case OP_VOpen: {
+ Cursor *pCur = 0;
+ sqlite3_vtab_cursor *pVtabCursor = 0;
+
+ sqlite3_vtab *pVtab = (sqlite3_vtab *)(pOp->p3);
+ sqlite3_module *pModule = (sqlite3_module *)pVtab->pModule;
+
+ assert(pVtab && pModule);
+ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+ rc = pModule->xOpen(pVtab, &pVtabCursor);
+ if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
+ if( SQLITE_OK==rc ){
+ /* Initialise sqlite3_vtab_cursor base class */
+ pVtabCursor->pVtab = pVtab;
+
+ /* Initialise vdbe cursor object */
+ pCur = allocateCursor(p, pOp->p1, -1);
+ pCur->pVtabCursor = pVtabCursor;
+ }
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
** by P1. The index number parameter to xFilter is the top of the stack.
** Next down on the stack is the argc parameter. Beneath the
** next of stack are argc additional parameters which are passed to
-** xFilter as argv. The index number, argc, and all argv stack values
-** are popped from the stack before this instruction completes.
+** xFilter as argv. The topmost parameter (i.e. 3rd element popped from
+** the stack) becomes argv[argc-1] when passed to xFilter.
+**
+** The index number, argc, and all argv stack values are popped from the
+** stack before this instruction completes.
**
** A jump is made to P2 if the result set after filtering would be
** empty.
*/
case OP_VFilter: {
+ int iIndex;
+ int nArg;
+
+ const sqlite3_module *pModule;
+
+ Cursor *pCur = p->apCsr[pOp->p1];
+ assert( pCur->pVtabCursor );
+ pModule = pCur->pVtabCursor->pVtab->pModule;
+
+ /* Grab the index number and argc parameters off the top of the stack. */
+ assert( (&pTos[-1])>=p->aStack );
+ assert( pTos[0].flags==MEM_Int && pTos[-1].flags==MEM_Int );
+ iIndex = pTos[0].i;
+ nArg = pTos[-1].i;
+
+ /* Invoke the xFilter method if one is defined. */
+ if( pModule->xFilter ){
+ int res;
+ Mem *apArg;
+ apArg = &pTos[1-2-nArg];
+
+ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+ res = pModule->xFilter(pCur->pVtabCursor, iIndex, nArg, &apArg);
+ if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
+
+ if( res==0 ){
+ pc = pOp->p2 - 1;
+ }
+ }
+
+ /* Pop the index number, argc value and parameters off the stack */
+ popStack(&pTos, 2+nArg);
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
** the virtual-table that the P1 cursor is pointing to.
*/
case OP_VRowid: {
+ const sqlite3_module *pModule;
+
+ Cursor *pCur = p->apCsr[pOp->p1];
+ assert( pCur->pVtabCursor );
+ pModule = pCur->pVtabCursor->pVtab->pModule;
+ if( pModule->xRowid==0 ){
+ sqlite3SetString(&p->zErrMsg, "Unsupported module operation: xRowid", 0);
+ rc = SQLITE_ERROR;
+ } else {
+ sqlite_int64 iRow;
+
+ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+ rc = pModule->xRowid(pCur->pVtabCursor, &iRow);
+ if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
+
+ pTos++;
+ pTos->flags = MEM_Int;
+ pTos->i = iRow;
+ }
+
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
** the row of the virtual-table that the P1 cursor is pointing to.
*/
case OP_VColumn: {
+ const sqlite3_module *pModule;
+
+ Cursor *pCur = p->apCsr[pOp->p1];
+ assert( pCur->pVtabCursor );
+ pModule = pCur->pVtabCursor->pVtab->pModule;
+ if( pModule->xColumn==0 ){
+ sqlite3SetString(&p->zErrMsg, "Unsupported module operation: xColumn", 0);
+ rc = SQLITE_ERROR;
+ } else {
+ sqlite3_context sContext;
+ memset(&sContext, 0, sizeof(sContext));
+ sContext.s.flags = MEM_Null;
+ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+ rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2);
+
+ /* Copy the result of the function to the top of the stack. We
+ ** do this regardless of whether or not an error occured to ensure any
+ ** dynamic allocation in sContext.s (a Mem struct) is released.
+ */
+ sqlite3VdbeChangeEncoding(&sContext.s, encoding);
+ pTos++;
+ pTos->flags = 0;
+ sqlite3VdbeMemMove(pTos, &sContext.s);
+
+ if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
+ }
+
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
** the end of its result set, then fall through to the next instruction.
*/
case OP_VNext: {
+ const sqlite3_module *pModule;
+ int res = 0;
+
+ Cursor *pCur = p->apCsr[pOp->p1];
+ assert( pCur->pVtabCursor );
+ pModule = pCur->pVtabCursor->pVtab->pModule;
+ if( pModule->xNext==0 ){
+ sqlite3SetString(&p->zErrMsg, "Unsupported module operation: xNext", 0);
+ rc = SQLITE_ERROR;
+ } else {
+ /* Invoke the xNext() method of the module. There is no way for the
+ ** underlying implementation to return an error if one occurs during
+ ** xNext(). Instead, if an error occurs, true is returned (indicating that
+ ** data is available) and the error code returned when xColumn or
+ ** some other method is next invoked on the save virtual table cursor.
+ */
+ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+ res = pModule->xNext(pCur->pVtabCursor);
+ if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
+
+ if( res ){
+ /* If there is data (or an error), jump to P2 */
+ pc = pOp->p2 - 1;
+ }
+ }
+
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
if( pCx->pVtabCursor ){
sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
sqlite3_vtab *pVtab = pVtabCursor->pVtab;
- sqlite3_module *pModule = pVtab->pModule;
+ const sqlite3_module *pModule = pVtab->pModule;
pModule->xClose(pVtabCursor);
}
#endif
*************************************************************************
** This file contains code used to help implement virtual tables.
**
-** $Id: vtab.c,v 1.5 2006/06/12 16:01:22 danielk1977 Exp $
+** $Id: vtab.c,v 1.6 2006/06/13 10:24:43 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h"
}
}
- if( SQLITE_OK==rc ){
- pTab->needCreate = 0;
- }
return rc;
}
# This file implements regression tests for SQLite library. The
# focus of this file is creating and dropping virtual tables.
#
-# $Id: vtab1.test,v 1.7 2006/06/13 04:11:44 danielk1977 Exp $
+# $Id: vtab1.test,v 1.8 2006/06/13 10:24:44 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set echo_module
} [list xDestroy]
-finish_test
-
do_test vtab1-2.6 {
execsql {
PRAGMA table_info(t2);
}
} [list]
+#----------------------------------------------------------------------
+# Test case vtab1-3 tests simple linear scans (no filter conditions) of
+# virtual table modules.
+do_test vtab1-3.1 {
+ set echo_module ""
+ execsql {
+ CREATE TABLE treal(a INTEGER, b VARCHAR(32), c);
+ CREATE VIRTUAL TABLE t1 USING echo(treal);
+ }
+ set echo_module
+} [list xCreate echo treal]
+do_test vtab1-3.2 {
+ # Test that a SELECT on t2 doesn't crash. No rows are returned
+ # because the underlying real table, is currently empty.
+ execsql {
+ SELECT a, b, c FROM t1;
+ }
+} {}
+do_test vtab1-3.3 {
+ # Put some data into the table treal. Then try a select on t1.
+ execsql {
+ INSERT INTO treal VALUES(1, 2, 3);
+ INSERT INTO treal VALUES(4, 5, 6);
+ SELECT * FROM t1;
+ }
+} {1 2 3 4 5 6}
+do_test vtab1-3.4 {
+ execsql {
+ SELECT a FROM t1;
+ }
+} {1 4}
+do_test vtab1-3.5 {
+ execsql {
+ SELECT rowid FROM t1;
+ }
+} {1 2}
+
finish_test
+