From: danielk1977 Date: Wed, 14 Jun 2006 06:31:28 +0000 (+0000) Subject: Add tests for error conditions surrounding the creation/connection of virtual tables... X-Git-Tag: version-3.6.10~2932 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a4e763671d9a9d29fc5f7cab047a930929628547;p=thirdparty%2Fsqlite.git Add tests for error conditions surrounding the creation/connection of virtual tables. (CVS 3235) FossilOrigin-Name: 5e592c422b86deb5802c6536e91661717ee9bbe1 --- diff --git a/manifest b/manifest index 40645736e7..630170c89b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C The\secho\smodule\stest\sis\snow\srunning.\s\sAdded\sthe\stclvar\smodule\stest\sbut\shave\nnot\syet\sdone\sanything\swith\sit.\s(CVS\s3234) -D 2006-06-13T23:51:34 +C Add\stests\sfor\serror\sconditions\ssurrounding\sthe\screation/connection\sof\svirtual\stables.\s(CVS\s3235) +D 2006-06-14T06:31:28 F Makefile.in 200f6dc376ecfd9b01e5359c4e0c10c02f649b34 F Makefile.linux-gcc 74ba0eadf88748a9ce3fd03d2a3ede2e6715baec F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -84,7 +84,7 @@ F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25 F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f F src/test6.c 60a02961ceb7b3edc25f5dc5c1ac2556622a76de F src/test7.c 03fa8d787f6aebc6d1f72504d52f33013ad2c8e3 -F src/test8.c d21b301afbc35a5c4ded0ecc784d59bc8f795c75 +F src/test8.c f91c78d8ad3aecf3e670e66c087a79ff806b21b2 F src/test_async.c e3deaedd4d86a56391b81808fde9e44fbd92f1d3 F src/test_md5.c 6c42bc0a3c0b54be34623ff77a0eec32b2fa96e3 F src/test_server.c a6460daed0b92ecbc2531b6dc73717470e7a648c @@ -102,7 +102,7 @@ F src/vdbeapi.c af663689ef57e5506f190bbd1068d28936b0fb34 F src/vdbeaux.c c9474fd27f1735170feb4f6a46885d282cf22d52 F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5 F src/vdbemem.c 5f0afe3b92bb2c037f8d5d697f7c151fa50783a3 -F src/vtab.c 7de1347022248edfb260c54f259148f413320cb7 +F src/vtab.c 6af0aa0ef2ebca743a4647eb22fd5d5d3813d83e F src/where.c 299c385e32a7b98d42864c7c83cdc6a778fae562 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -288,7 +288,7 @@ F test/vacuum.test 37f998b841cb335397c26d9bbc3457182af2565f F test/vacuum2.test 5aea8c88a65cb29f7d175296e7c819c6158d838c F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102 F test/view.test 16e2774fe35e47a07ac4471b7f0bcc948b1aa6d5 -F test/vtab1.test 86e4c90c96cbf7f2c3b31069ed8c2d5dfd3bf378 +F test/vtab1.test e445b10cb9662f180c96f2af4f82841656c35373 F test/where.test ee7c9a6659b07e1ee61177f6e7ff71565ee2c9df F test/where2.test a16476a5913e75cf65b38f2daa6157a6b7791394 F test/where3.test 3b5ad2c58069e12be2bd86bc5e211a82810521aa @@ -364,7 +364,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P 9372481f233e1563b5ee137535f0fbf19851ffad -R e6ce8e5a9dba6e782016ada2d5443cc3 -U drh -Z 6f9bc9c4a49544af7a028d3a571bcd52 +P 29199eeea4c46168ccaa7535d4941bd740479dee +R dc5e6094d3fe7373d35dfb54c78f916b +U danielk1977 +Z 267156075d7b55f7a94e810698d71dbc diff --git a/manifest.uuid b/manifest.uuid index f77be546a1..2a5b436431 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -29199eeea4c46168ccaa7535d4941bd740479dee \ No newline at end of file +5e592c422b86deb5802c6536e91661717ee9bbe1 \ No newline at end of file diff --git a/src/test8.c b/src/test8.c index 24067b95a6..903ec3c7b4 100644 --- a/src/test8.c +++ b/src/test8.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test8.c,v 1.11 2006/06/13 23:51:35 drh Exp $ +** $Id: test8.c,v 1.12 2006/06/14 06:31:28 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -35,12 +35,11 @@ struct echo_vtab { sqlite3_vtab base; Tcl_Interp *interp; sqlite3 *db; - char *zTableName; /* Name of the real table */ - char *zStmt; /* "SELECT rowid, * FROM " */ - int *aIndex; - int nCol; - char **aCol; + char *zTableName; /* Name of the real table */ + int nCol; /* Number of columns in the real table */ + int *aIndex; /* Array of size nCol. True if column has an index */ + char **aCol; /* Array of size nCol. Column names */ }; /* An echo cursor object */ @@ -198,7 +197,6 @@ static int echoDeclareVtab( rc = SQLITE_ERROR; } sqlite3_finalize(pStmt); - pVtab->zStmt = sqlite3MPrintf("SELECT rowid, * FROM %s ", argv[1]); if( rc==SQLITE_OK ){ rc = getIndexArray(db, argv[1], &pVtab->aIndex); } @@ -210,6 +208,19 @@ static int echoDeclareVtab( return rc; } +static int echoDestructor(sqlite3_vtab *pVtab){ + int ii; + echo_vtab *p = (echo_vtab*)pVtab; + sqliteFree(p->aIndex); + for(ii=0; iinCol; ii++){ + sqliteFree(p->aCol[ii]); + } + sqliteFree(p->aCol); + sqliteFree(p->zTableName); + sqliteFree(p); + return 0; +} + static int echoConstructor( sqlite3 *db, const sqlite3_module *pModule, @@ -220,8 +231,6 @@ static int echoConstructor( echo_vtab *pVtab; pVtab = sqliteMalloc( sizeof(*pVtab) ); - - *ppVtab = &pVtab->base; pVtab->base.pModule = pModule; pVtab->interp = pModule->pAux; pVtab->db = db; @@ -230,8 +239,13 @@ static int echoConstructor( appendToEchoModule(pVtab->interp, argv[i]); } - echoDeclareVtab(pVtab, db, argc, argv); - return 0; + if( echoDeclareVtab(pVtab, db, argc, argv) ){ + echoDestructor((sqlite3_vtab *)pVtab); + return SQLITE_ERROR; + } + + *ppVtab = &pVtab->base; + return SQLITE_OK; } /* Methods for the echo module */ @@ -254,20 +268,6 @@ static int echoConnect( return echoConstructor(db, pModule, argc, argv, ppVtab); } -static int echoDestructor(sqlite3_vtab *pVtab){ - int ii; - echo_vtab *p = (echo_vtab*)pVtab; - sqliteFree(p->zStmt); - sqliteFree(p->aIndex); - for(ii=0; iinCol; ii++){ - sqliteFree(p->aCol[ii]); - } - sqliteFree(p->aCol); - sqliteFree(p->zTableName); - sqliteFree(p); - return 0; -} - static int echoDisconnect(sqlite3_vtab *pVtab){ appendToEchoModule(((echo_vtab *)pVtab)->interp, "xDisconnect"); return echoDestructor(pVtab); diff --git a/src/vtab.c b/src/vtab.c index 30bff32674..6f94e2ce1e 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code used to help implement virtual tables. ** -** $Id: vtab.c,v 1.8 2006/06/13 23:51:35 drh Exp $ +** $Id: vtab.c,v 1.9 2006/06/14 06:31:28 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_VIRTUALTABLE #include "sqliteInt.h" @@ -144,7 +144,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ int iDb; Vdbe *v; if( pTab->pModule==0 ){ - sqlite3ErrorMsg(pParse, "unknown module: %s", zModule); + sqlite3ErrorMsg(pParse, "no such module: %s", zModule); } /* Compute the complete text of the CREATE VIRTUAL TABLE statement */ @@ -254,7 +254,7 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ zModule = pTab->azModuleArg[0]; if( !pModule || !pModule->xConnect ){ const char *zModule = pTab->azModuleArg[0]; - sqlite3ErrorMsg(pParse, "unknown module: %s", zModule); + sqlite3ErrorMsg(pParse, "no such module: %s", zModule); rc = SQLITE_ERROR; } else { char **azArg = pTab->azModuleArg; @@ -349,22 +349,31 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){ ** error. Otherwise, do nothing. */ if( !pModule ){ - *pzErr = sqlite3MPrintf("unknown module: %s", zModule); + *pzErr = sqlite3MPrintf("no such module: %s", zModule); rc = SQLITE_ERROR; - }else if( pModule->xCreate ){ + }else{ + int rc2; char **azArg = pTab->azModuleArg; int nArg = pTab->nModuleArg; + assert( !db->pVTab ); + assert( pModule->xCreate ); db->pVTab = pTab; rc = sqlite3SafetyOff(db); assert( rc==SQLITE_OK ); rc = pModule->xCreate(db, pModule, nArg, azArg, &pTab->pVtab); + rc2 = sqlite3SafetyOn(db); + + if( SQLITE_OK!=rc ){ + *pzErr = sqlite3MPrintf("vtable constructor failed: %s", zTab); + } else if( db->pVTab ){ + const char *zFormat = "vtable constructor did not declare schema: %s"; + *pzErr = sqlite3MPrintf(zFormat, zTab); + rc = SQLITE_ERROR; + } db->pVTab = 0; - if( rc ){ - *pzErr = sqlite3MPrintf("module create failed: %s", zModule); - sqlite3SafetyOn(db); - } else { - rc = sqlite3SafetyOn(db); + if( rc==SQLITE_OK ){ + rc = rc2; } } diff --git a/test/vtab1.test b/test/vtab1.test index a48435ac20..38575ac401 100644 --- a/test/vtab1.test +++ b/test/vtab1.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is creating and dropping virtual tables. # -# $Id: vtab1.test,v 1.11 2006/06/13 23:51:35 drh Exp $ +# $Id: vtab1.test,v 1.12 2006/06/14 06:31:28 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -21,37 +21,107 @@ ifcapable !vtab { return } -# We cannot create a virtual table if the module has not -# been registered. +#---------------------------------------------------------------------- +# Organization of tests in this file: +# +# vtab1-1.*: Error conditions and other issues surrounding creation/connection +# of a virtual module. +# vtab1-2.*: Test sqlite3_declare_vtab() and the xConnect/xDisconnect methods. +# vtab1-3.*: Table scans and WHERE clauses. +# vtab1-4.*: Table scans and ORDER BY clauses. +# vtab1-5.*: Test queries that include joins. This brings the +# sqlite3_index_info.estimatedCost variable into play. +# +# This file uses the "echo" module (see src/test8.c). Refer to comments +# in that file for the special behaviour of the Tcl $echo_module variable. +# +# TODO: +# +# * How to test the sqlite3_index_constraint_usage.omit field? Or +# sqlite3_index_info.orderByConsumed? +# + + +#---------------------------------------------------------------------- +# Test cases vtab1.1.* +# + +# We cannot create a virtual table if the module has not been registered. # do_test vtab1-1.1 { catchsql { CREATE VIRTUAL TABLE t1 USING echo; } -} {1 {unknown module: echo}} +} {1 {no such module: echo}} do_test vtab1-1.2 { execsql { SELECT name FROM sqlite_master ORDER BY 1 } } {} -# After we register the echo module, we are allowed to create -# virtual tables using that module. +# Register the module +register_echo_module [sqlite3_connection_pointer db] + +# Once a module has been registered, virtual tables using that module +# may be created. However if a module xCreate() fails to call +# sqlite3_declare_vtab() an error will be raised and the table not created. +# +# The "echo" module does not invoke sqlite3_declare_vtab() if it is +# passed zero arguments. # do_test vtab1-1.3 { - register_echo_module [sqlite3_connection_pointer db] catchsql { CREATE VIRTUAL TABLE t1 USING echo; } -} {0 {}} +} {1 {vtable constructor did not declare schema: t1}} do_test vtab1-1.4 { - set echo_module -} {xCreate echo} + execsql { + SELECT name FROM sqlite_master ORDER BY 1 + } +} {} + +# The "echo" module xCreate method returns an error and does not create +# the virtual table if it is passed an argument that does not correspond +# to an existing real table in the same database. +# do_test vtab1-1.5 { + catchsql { + CREATE VIRTUAL TABLE t1 USING echo(no_such_table); + } +} {1 {vtable constructor failed: t1}} +do_test vtab1-1.6 { execsql { - SELECT name, sql FROM sqlite_master ORDER BY 1 + SELECT name FROM sqlite_master ORDER BY 1 } -} {t1 {CREATE VIRTUAL TABLE t1 USING echo}} +} {} + +# Test to make sure nothing goes wrong and no memory is leaked if we +# select an illegal table-name (i.e a reserved name or the name of a +# table that already exists). +# +do_test vtab1-1.7 { + catchsql { + CREATE VIRTUAL TABLE sqlite_master USING echo; + } +} {1 {object name reserved for internal use: sqlite_master}} +do_test vtab1-1.8 { + catchsql { + CREATE TABLE treal(a, b, c); + CREATE VIRTUAL TABLE treal USING echo(treal); + } +} {1 {table treal already exists}} +do_test vtab1-1.9 { + execsql { + DROP TABLE treal; + SELECT name FROM sqlite_master ORDER BY 1 + } +} {} + +#---------------------------------------------------------------------- +# Test cases vtab1.2.* +# +# At this point, the database is completely empty. The echo module +# has already been registered. # If a single argument is passed to the echo module during table # creation, it is assumed to be the name of a table in the same @@ -70,77 +140,92 @@ do_test vtab1-2.1 { ] do_test vtab1-2.2 { execsql { - CREATE VIRTUAL TABLE t2 USING echo(template); + CREATE VIRTUAL TABLE t1 USING echo(template); } - execsql { PRAGMA table_info(t2); } + execsql { PRAGMA table_info(t1); } } [list \ 0 a {} 0 {} 0 \ 1 b {} 0 {} 0 \ 2 c {} 0 {} 0 \ ] -# Test that the database can be unloaded. This should invoke -# the xDisconnect() callback each of the two virtual tables - t1 and t2. +# Test that the database can be unloaded. This should invoke the xDisconnect() +# callback for the successfully create virtual table (t1). +# do_test vtab1-2.3 { -breakpoint set echo_module [list] db close set echo_module -} [list xDisconnect xDisconnect] +} [list xDisconnect] - set echo_module [list] -# Re-open the database. Check that the schema of the virtual -# table is still correct. +# Re-open the database. This should not cause any virtual methods to +# be called. The invocation of xConnect() is delayed until the virtual +# table schema is first required by the compiler. +# do_test vtab1-2.4 { + set echo_module [list] sqlite3 db test.db db cache size 0 - register_echo_module [sqlite3_connection_pointer db] - execsql { PRAGMA table_info(t2); } + set echo_module +} {} + +# Try to query the virtual table schema. This should fail, as the +# echo module has not been registered with this database connection. +# +do_test vtab1.2.6 { +breakpoint + catchsql { PRAGMA table_info(t1); } +} {1 {no such module: echo}} + +# Register the module +register_echo_module [sqlite3_connection_pointer db] + +# Try to query the virtual table schema again. This time it should +# invoke the xConnect method and succeed. +# +do_test vtab1.2.7 { + execsql { PRAGMA table_info(t1); } } [list \ 0 a {} 0 {} 0 \ 1 b {} 0 {} 0 \ 2 c {} 0 {} 0 \ ] +do_test vtab1.2.8 { + set echo_module +} {xConnect echo template} -# Drop the table t2. This should cause the xDestroy (but not xDisconnect) -# method to be invoked. +# Drop table t1. This should cause the xDestroy (but not xDisconnect) method +# to be invoked. do_test vtab1-2.5 { - set echo_module [list] + set echo_module "" execsql { - DROP TABLE t2; + DROP TABLE t1; } set echo_module -} [list xDestroy] - +} {xDestroy} do_test vtab1-2.6 { execsql { - PRAGMA table_info(t2); + PRAGMA table_info(t1); } } {} do_test vtab1-2.7 { execsql { SELECT sql FROM sqlite_master; } -} [list {CREATE VIRTUAL TABLE t1 USING echo} \ - {CREATE TABLE template(a, b, c)} \ -] +} [list {CREATE TABLE template(a, b, c)}] + +# Clean up other test artifacts: do_test vtab1-2.8 { - set echo_module [list] execsql { - DROP TABLE t1; DROP TABLE template; - } - set echo_module -} [list] -do_test vtab1-2.9 { - execsql { SELECT sql FROM sqlite_master; } } [list] #---------------------------------------------------------------------- -# Test case vtab1-3 tests simple linear scans (no filter conditions) of -# virtual table modules. +# Test case vtab1-3 test table scans and the echo module's +# xBestIndex/xFilter handling of WHERE conditions. + do_test vtab1-3.1 { set echo_module "" execsql { @@ -150,15 +235,20 @@ do_test vtab1-3.1 { } set echo_module } [list xCreate echo treal] + +# Test that a SELECT on t1 doesn't crash. No rows are returned +# because the underlying real table is currently empty. +# 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; } } {} + +# Put some data into the table treal. Then try a few simple SELECT +# statements on 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); @@ -175,7 +265,6 @@ do_test vtab1-3.5 { SELECT rowid FROM t1; } } {1 2} - do_test vtab1-3.6 { set echo_module "" execsql { @@ -183,17 +272,34 @@ do_test vtab1-3.6 { } } {1 2 3 4 5 6} do_test vtab1-3.7 { - set echo_module -} {xBestIndex {SELECT rowid, * FROM 'treal'} xFilter {SELECT rowid, * FROM 'treal'}} + execsql { + SELECT rowid, * FROM t1; + } +} {1 1 2 3 2 4 5 6} + +# Execute some SELECT statements with WHERE clauses on the t1 table. +# Then check the echo_module variable (written to by the module methods +# in test8.c) to make sure the xBestIndex() and xFilter() methods were +# called correctly. +# do_test vtab1-3.8 { + set echo_module "" + execsql { + SELECT * FROM t1; + } + set echo_module +} [list xBestIndex {SELECT rowid, * FROM 'treal'} \ + xFilter {SELECT rowid, * FROM 'treal'} ] +do_test vtab1-3.9 { set echo_module "" execsql { SELECT * FROM t1 WHERE b = 5; } } {4 5 6} -do_test vtab1-3.9 { +do_test vtab1-3.10 { set echo_module -} {xBestIndex {SELECT rowid, * FROM 'treal' WHERE b = ?} xFilter {SELECT rowid, * FROM 'treal' WHERE b = ?} 5} +} [list xBestIndex {SELECT rowid, * FROM 'treal' WHERE b = ?} \ + xFilter {SELECT rowid, * FROM 'treal' WHERE b = ?} 5 ] do_test vtab1-3.10 { set echo_module "" execsql { @@ -202,7 +308,8 @@ do_test vtab1-3.10 { } {4 5 6} do_test vtab1-3.11 { set echo_module -} {xBestIndex {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} xFilter {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} 5 10} +} [list xBestIndex {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} \ + xFilter {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} 5 10 ] do_test vtab1-3.12 { set echo_module "" execsql { @@ -211,6 +318,8 @@ do_test vtab1-3.12 { } {1 2 3 4 5 6} do_test vtab1-3.13 { set echo_module -} {xBestIndex {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} xFilter {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} 2 10} +} [list xBestIndex {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} \ + xFilter {SELECT rowid, * FROM 'treal' WHERE b >= ? AND b <= ?} 2 10 ] finish_test +