diff --git a/manifest b/manifest index e464d4b5bc..83d21a64c6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Clarify\sdocumentation\sof\sDEFAULT\sCURRENT_TIME\setc.\s(version\s3.1.0\sand\sgreater\sonly).\s(CVS\s2274) -D 2005-01-24T23:27:32 +C Prevent\scollation\ssequences\sand\suser\sfunctions\sfrom\sbeing\sdeleted\sor\schanged\swhile\sSQL\sstatements\sare\sexecuting.\s(CVS\s2275) +D 2005-01-25T04:27:55 F Makefile.in ffd81f5e926d40b457071b4de8d7c1fa18f39b5a F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1 @@ -42,7 +42,7 @@ F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 F src/insert.c 037eb46630f027d0f93584db180d08ce163f3dbb F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b -F src/main.c 1fe0216dc01e1929e7e009cdedfb3e6e2391d717 +F src/main.c 302e21bdaa015f590fdb7e69d50f45788da0fb0b F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070 F src/os.h ae44064dc118b20d39450cb331409a775e8bb1c6 F src/os_common.h 0e7f428ba0a6c40a61bc56c4e96f493231301b73 @@ -63,8 +63,8 @@ F src/shell.c 1f0da77ef0520afd6df71f4781076021874310f3 F src/sqlite.h.in 7d7c28344e2bd770491b56ed9169be20859c707d F src/sqliteInt.h be6fa5e31c65e2b8e10112ee47a6e63ec7de37b5 F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9 -F src/tclsqlite.c 47ecdb00e9bc135b37ad5bed84fefe20d7c19611 -F src/test1.c 0a71a150659dd261be775c5eb60ae6c0c856c8a5 +F src/tclsqlite.c 101994a2c4c0eaa69f1de9bfe4a02167f6049e7d +F src/test1.c 8c320f043b869c08fca86c4f01de027774eb85a8 F src/test2.c bbc2ecc58ceeab12d1e40970f831b1017524e40d F src/test3.c 683e1e3819152ffd35da2f201e507228921148d0 F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df @@ -174,9 +174,9 @@ F test/reindex.test 3552c6b944a3fab28cfd3049c04c65cb79419757 F test/rollback.test 94cd981ee3a627d9f6466f69dcf1f7dbfe695d7a F test/rowid.test 040a3bef06f970c45f5fcd14b2355f7f4d62f0cf F test/safety.test 907b64fee719554a3622853812af3886fddbbb4f -F test/schema.test 8725b41e19dec6c2d060b134417fe3da83c22d70 +F test/schema.test 3787768619706fc6f47c53cbe23472e782302e1e F test/select1.test ad700a2a1c325a23a7206ad4d189e33917de526f -F test/select2.test 04103fbd55fca9558fd79d637fb7819d9d0b2f52 +F test/select2.test 01b9cbc06e5ed662ce0289aa5f47314d54541e82 F test/select3.test 9de435aa84fc406708cd8dc1b1d60e7f27cea685 F test/select4.test c239f516aa31f42f2ef7c6d7cd01105f08f934ca F test/select5.test 94db800bbeff2e426c0175e07f7a71d4617853b5 @@ -272,7 +272,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl 3e522a06ad41992023c80ca29a048ae2331ca5bd -P b243681a0e328ee0bbf1140abfb60d65d2102ad5 -R ccb6447e7156933de8fc182a220c72ff +P 557eb2ec9d825c0a2830d3355d0d27b4b5937de2 +R ccc679b6d9c5516b3defef2b60c271aa U danielk1977 -Z dad25937f9866029c7d3ceaad1989791 +Z 95e1deb222b350d5a7b99118f5214f27 diff --git a/manifest.uuid b/manifest.uuid index 2ad32a7ff3..fbe7a2cf5a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -557eb2ec9d825c0a2830d3355d0d27b4b5937de2 \ No newline at end of file +cabab62bc10568d435806a7059fad7274f0dd4c8 \ No newline at end of file diff --git a/src/main.c b/src/main.c index 9ab3d75628..e993b81617 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.274 2005/01/24 10:25:59 danielk1977 Exp $ +** $Id: main.c,v 1.275 2005/01/25 04:27:55 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -736,6 +736,22 @@ int sqlite3_create_function( #else enc = SQLITE_UTF8; #endif + + /* Check if an existing function is being overridden or deleted. If so, + ** and there are active VMs, then return SQLITE_BUSY. If a function + ** is being overridden/deleted but there are no active VMs, allow the + ** operation to continue but invalidate all precompiled statements. + */ + p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 0); + if( p && p->iPrefEnc==enc && p->nArg==nArg ){ + if( db->activeVdbeCnt ){ + sqlite3Error(db, SQLITE_BUSY, + "Unable to delete/modify user-function due to active statements"); + return SQLITE_BUSY; + }else{ + sqlite3ExpirePreparedStatements(db); + } + } p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 1); if( p==0 ) return SQLITE_NOMEM; @@ -1288,10 +1304,17 @@ int sqlite3_create_collation( return SQLITE_ERROR; } - /* If removing a collation sequence, then set the expired flag for - ** all precompiled statements. + /* Check if this call is removing or replacing an existing collation + ** sequence. If so, and there are active VMs, return busy. If there + ** are no active VMs, invalidate any pre-compiled statements. */ - if( !xCompare ){ + pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 0); + if( pColl && pColl->xCmp ){ + if( db->activeVdbeCnt ){ + sqlite3Error(db, SQLITE_BUSY, + "Unable to delete/modify collation sequence due to active statements"); + return SQLITE_BUSY; + } sqlite3ExpirePreparedStatements(db); } diff --git a/src/tclsqlite.c b/src/tclsqlite.c index dc05eab0ad..a5ef6106ce 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -11,7 +11,7 @@ ************************************************************************* ** A TCL Interface to SQLite ** -** $Id: tclsqlite.c,v 1.117 2005/01/24 10:25:59 danielk1977 Exp $ +** $Id: tclsqlite.c,v 1.118 2005/01/25 04:27:55 danielk1977 Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ @@ -696,6 +696,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ strcpy(pCollate->zScript, zScript); if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8, pCollate, tclSqlCollate) ){ + Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); return TCL_ERROR; } break; @@ -1128,7 +1129,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ rc = sqlite3_create_function(pDb->db, zName, -1, SQLITE_UTF8, pFunc, tclSqlFunc, 0, 0); if( rc!=SQLITE_OK ){ - rc = TCL_ERROR; + rc = TCL_ERROR; + Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); }else{ /* Must flush any cached statements */ flushStmtCache( pDb ); diff --git a/src/test1.c b/src/test1.c index c751861a89..0d197f0861 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.127 2005/01/22 03:03:55 drh Exp $ +** $Id: test1.c,v 1.128 2005/01/25 04:27:55 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -2599,6 +2599,58 @@ static int test_sleep( } #endif +/* +** Usage: sqlite_delete_function DB function-name +** +** Delete the user function 'function-name' from database handle DB. It +** is assumed that the user function was created as UTF8, any number of +** arguments (the way the TCL interface does it). +*/ +static int delete_function( + void * clientData, + Tcl_Interp *interp, + int argc, + char **argv +){ + int rc; + sqlite3 *db; + if( argc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " DB function-name", 0); + return TCL_ERROR; + } + if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; + rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0, 0, 0, 0); + Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); + return TCL_OK; +} + +/* +** Usage: sqlite_delete_collation DB collation-name +** +** Delete the collation sequence 'collation-name' from database handle +** DB. It is assumed that the collation sequence was created as UTF8 (the +** way the TCL interface does it). +*/ +static int delete_collation( + void * clientData, + Tcl_Interp *interp, + int argc, + char **argv +){ + int rc; + sqlite3 *db; + if( argc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " DB function-name", 0); + return TCL_ERROR; + } + if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; + rc = sqlite3_create_collation(db, argv[2], SQLITE_UTF8, 0, 0); + Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); + return TCL_OK; +} + /* ** Usage: tcl_variable_type VARIABLENAME ** @@ -2840,6 +2892,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ #if 0 { "sqlite3_sleep", (Tcl_CmdProc*)test_sleep }, #endif + { "sqlite_delete_function", (Tcl_CmdProc*)delete_function }, + { "sqlite_delete_collation", (Tcl_CmdProc*)delete_collation } }; static struct { char *zName; diff --git a/test/schema.test b/test/schema.test index 04f7f13485..262fc4bf5a 100644 --- a/test/schema.test +++ b/test/schema.test @@ -1,4 +1,4 @@ -# 2004 Jan 24 +# 2005 Jan 24 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: @@ -13,7 +13,7 @@ # This file tests the various conditions under which an SQLITE_SCHEMA # error should be returned. # -# $Id: schema.test,v 1.2 2005/01/24 13:03:32 danielk1977 Exp $ +# $Id: schema.test,v 1.3 2005/01/25 04:27:55 danielk1977 Exp $ #--------------------------------------------------------------------- # When any of the following types of SQL statements or actions are @@ -31,6 +31,14 @@ # # Note: Test cases schema-6.* are missing right now. # +# Test cases schema-9.* and schema-10.* test some specific bugs +# that came up during development. +# +# Test cases schema-11.* test that it is impossible to delete or +# change a collation sequence or user-function while SQL statements +# are executing. Adding new collations or functions is allowed. +# +# Note: Test cases schema-11.* are also missing right now. set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -153,6 +161,26 @@ do_test schema-5.4 { sqlite3_finalize $::STMT } {SQLITE_SCHEMA} +#--------------------------------------------------------------------- +# Tests 6.* check that prepared statements are invalidated when +# a user-function is deleted (but not when one is added). +do_test schema-6.1 { + set sql {SELECT * FROM abc;} + set ::STMT [sqlite3_prepare $::DB $sql -1 TAIL] + db function hello_function {} + sqlite3_step $::STMT +} {SQLITE_DONE} +do_test schema-6.2 { + sqlite3_reset $::STMT +} {SQLITE_OK} +do_test schema-6.3 { + sqlite_delete_function $::DB hello_function + sqlite3_step $::STMT +} {SQLITE_ERROR} +do_test schema-6.4 { + sqlite3_finalize $::STMT +} {SQLITE_SCHEMA} + #--------------------------------------------------------------------- # Tests 7.* check that prepared statements are invalidated when # a collation sequence is deleted (but not when one is added). @@ -255,5 +283,49 @@ do_test schema-10.5 { db2 close } {} +#--------------------------------------------------------------------- +# Attempting to delete or replace a user-function or collation sequence +# while there are active statements returns an SQLITE_BUSY error. +# +# schema-11.1 - 11.4: User function. +# schema-11.5 - 11.8: Collation sequence. +# +do_test schema-11.1 { + db function tstfunc {} + set sql {SELECT * FROM abc} + set ::STMT [sqlite3_prepare $::DB $sql -1 TAIL] + sqlite3_step $::STMT +} {SQLITE_ROW} +do_test schema-11.2 { + sqlite_delete_function $::DB tstfunc +} {SQLITE_BUSY} +do_test schema-11.3 { + set rc [catch { + db function tstfunc {} + } msg] + list $rc $msg +} {1 {Unable to delete/modify user-function due to active statements}} +do_test schema-11.4 { + sqlite3_finalize $::STMT +} {SQLITE_OK} +do_test schema-11.5 { + db collate tstcollate {} + set sql {SELECT * FROM abc} + set ::STMT [sqlite3_prepare $::DB $sql -1 TAIL] + sqlite3_step $::STMT +} {SQLITE_ROW} +do_test schema-11.6 { + sqlite_delete_collation $::DB tstcollate +} {SQLITE_BUSY} +do_test schema-11.7 { + set rc [catch { + db collate tstcollate {} + } msg] + list $rc $msg +} {1 {Unable to delete/modify collation sequence due to active statements}} +do_test schema-11.8 { + sqlite3_finalize $::STMT +} {SQLITE_OK} + finish_test diff --git a/test/select2.test b/test/select2.test index 1d9d87bd17..52525a6d5a 100644 --- a/test/select2.test +++ b/test/select2.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the SELECT statement. # -# $Id: select2.test,v 1.23 2005/01/24 12:46:14 drh Exp $ +# $Id: select2.test,v 1.24 2005/01/25 04:27:55 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -71,7 +71,7 @@ ifcapable tclvar { } execsql {COMMIT} }] - set result {} + list } {} puts "time with cache: $::t1" } @@ -86,7 +86,7 @@ do_test select2-2.0.2 { } execsql {COMMIT} }] - set result {} + list } {} puts "time without cache: $t2" ifcapable tclvar {