diff --git a/VERSION b/VERSION index 11e3212692..cf95c0186a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.11 +2.4.12 diff --git a/manifest b/manifest index 461db2f61e..7aaed6f2e4 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Attempt\sto\sdetect\swhen\stwo\sor\smore\sthreads\stry\sto\suse\sthe\ssame\sdatabase\sat\nthe\ssame\stime\sand\sreturn\san\sSQLITE_MISUSE\serror.\s\sAlso\sreturn\sthis\serror\nif\san\sattempt\sis\smade\sto\suse\sa\sclosed\sdatabase.\s(CVS\s558) -D 2002-05-10T05:44:56 +C Improvements\sto\sthe\sSQLITE_MISUSE\sdetection\slogic.\s\sAlso\sadded\stest\scases\nfor\sthis\slogic,\sincluding\sthe\snew\stest\sfile\s"misuse.test".\s(CVS\s559) +D 2002-05-10T13:14:07 F Makefile.in 50f1b3351df109b5774771350d8c1b8d3640130d F Makefile.template 89e373b2dad0321df00400fa968dc14b61a03296 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0 -F VERSION fad4e0bf37e1af179693612ee7dd3e21591578a4 +F VERSION 45e2ae5cf63867a750b544c539f79a076d53a9a0 F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588 F config.sub f14b07d544ca26b5d698259045136b783e18fc7f @@ -28,7 +28,7 @@ F src/func.c a31dcba85bc2ecb9b752980289cf7e6cd0cafbce F src/hash.c cc259475e358baaf299b00a2c7370f2b03dda892 F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9 F src/insert.c 31233f44fc79edbb43523a830e54736a8e222ff4 -F src/main.c a7041c9a32515a33dea8150dd33f748ce6e57861 +F src/main.c 0a4643660b2a3dee3427a10fcea336756526c27c F src/md5.c b2b1a34fce66ceca97f4e0dabc20be8be7933c92 F src/os.c 5ab8b6b4590d0c1ab8e96c67996c170e4462e0fc F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10 @@ -41,20 +41,20 @@ F src/select.c 1b623a7d826ec7c245bc542b665d61724da2a62d F src/shell.c 5acbe59e137d60d8efd975c683dbea74ab626530 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/sqlite.h.in 0038faa6d642de06b91143ee65a131bd831d020b -F src/sqliteInt.h b850d1013577be1aa34ca3b7985fa8aca733709b +F src/sqliteInt.h b37d2d28e4ca3dcf67772bf937aa12b171d9610b F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63 -F src/tclsqlite.c c9e9039762d9866eae70bf782237d0206a13f57e -F src/test1.c d46ab7a82a9c16a3b1ee363cb4c0f98c5ff65743 +F src/tclsqlite.c 9300c9606a38bc0c75d6c0bc8a6197ab979353d1 +F src/test1.c 09d95048b66ce6dcd2bae90f443589043d7d631e F src/test2.c 669cc22781c6461a273416ec1a7414d25c081730 F src/test3.c 4e52fff8b01f08bd202f7633feda5639b7ba2b5e F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f F src/tokenize.c 5624d342601f616157ba266abccc1368a5afee70 F src/update.c 7dd714a6a7fa47f849ebb36b6d915974d6c6accb -F src/util.c 79bcc175e48662faa523d4d00d34bfa246ae219f -F src/vdbe.c aa5d5f76f2d7f76b1f63d81c5fd2dc91e66c49a4 +F src/util.c 707c30f8c13cddace7c08556ac450c0b786660b3 +F src/vdbe.c c957417fa83b5fb717dcd81204c253125b3e7e0c F src/vdbe.h 67840a462e1daedb958cca0ccc97db140d3d9152 F src/where.c 5e3e97adfa5800378f2ed45bb9312dd3a70e239c -F test/all.test 6aa106eee4d7127afa5cee97c51a783a79694ead +F test/all.test e4d3821eeba751829b419cd47814bd20af4286d1 F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578 F test/btree.test bf326f546a666617367a7033fa2c07451bd4f8e1 F test/btree2.test e3b81ec33dc2f89b3e6087436dfe605b870c9080 @@ -71,11 +71,12 @@ F test/insert2.test eb8481878a7f52ccb4e3346f87550f5afdd77f76 F test/intpkey.test 31b5f28b2c44273e6695cf36ab2e4133aee7753c F test/ioerr.test 57d9bffaca18b34f9e976f786eadc2591d6efc6a F test/limit.test a930f3eba2a7691c8397ccab33710b931589566a -F test/lock.test 19593689260c419efe7ced55b1418653a4b7bcd1 -F test/main.test 1626345b5f630c5398eede500d9354813b76b0fd +F test/lock.test 3fcfd46a73119f6a18094673328a32c7b3047a8f +F test/main.test e121fed34ebf67f595290776162e322b08470127 F test/malloc.test 70fdd0812e2a57eb746aaf015350f58bb8eee0b1 F test/minmax.test fb6ab400271ae1f5bc88617c2882f2f081ea8e6d F test/misc1.test a03214118429b40ca5548bc1fae0ebd5c34dabe6 +F test/misuse.test 3ef43523b24cf1a7f56c2d344ec3025f60c6fce4 F test/notnull.test b1f3e42fc475b0b5827b27b2e9b562081995ff30 F test/pager.test b0c0d00cd5dce0ce21f16926956b195c0ab5044c F test/pragma.test 0b9675ef1f5ba5b43abfa337744445fc5b01a34a @@ -94,7 +95,7 @@ F test/subselect.test 335d3dad8d585726c447dfee8d9c4f7383c76b78 F test/table.test 17b0b6eafa3faaee5545b7a94e6c1ff73f0880f3 F test/tableapi.test 3c80421a889e1d106df16e5800fa787f0d2914a6 F test/tclsqlite.test 79deeffd7cd637ca0f06c5dbbf2f44d272079533 -F test/temptable.test 0e9934283259a5e637eec756a7eefd6964c0f79b +F test/temptable.test daa83489eea2e9aaeeece09675c28be84c72cb67 F test/tester.tcl dc1b56bd628b487e4d75bfd1e7480b5ed8810ac6 F test/trans.test ae0b9a82d5d34122c3a3108781eb8d078091ccee F test/unique.test 07776624b82221a80c8b4138ce0dd8b0853bb3ea @@ -114,8 +115,8 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4 F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b -F www/c_interface.tcl fbaddacc3fed376d4aebfddceb31a1fac00cf158 -F www/changes.tcl 2178c2f6a259885904f6406864006a1602d5d498 +F www/c_interface.tcl d8c0cdd533a80fc6af480ad50a952c46423c1786 +F www/changes.tcl d1057bb733c574d9dca73578daf78a3128a61426 F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2 F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060 F www/download.tcl 29aa6679ca29621d10613f60ebbbda18f4b91c49 @@ -130,7 +131,7 @@ F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P 1b0ee944c9af10078aba628e85d79f8682afa2b6 -R af1468ce6a17da4c94780c1e8568bbbf +P a05fabd2df1cb38c555a7b2f31b0ca687db500c2 +R b30599eb63bdfc63e05ba22c1fe53652 U drh -Z 8cea50e279e02e056a890661e5730afa +Z b94dda4b81c12e0efb3453e43d29b6de diff --git a/manifest.uuid b/manifest.uuid index 61cabf279d..7d307aa5ca 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a05fabd2df1cb38c555a7b2f31b0ca687db500c2 \ No newline at end of file +f42907ce457e012592f8c043dc6c915e87258b35 \ No newline at end of file diff --git a/src/main.c b/src/main.c index c66f0e8c82..56865f13c8 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.70 2002/05/10 05:44:56 drh Exp $ +** $Id: main.c,v 1.71 2002/05/10 13:14:07 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -435,7 +435,7 @@ int sqlite_changes(sqlite *db){ */ void sqlite_close(sqlite *db){ HashElem *i; - if( sqliteSafetyOn(db) ){ return; } + if( sqliteSafetyCheck(db) || sqliteSafetyOn(db) ){ return; } db->magic = SQLITE_MAGIC_CLOSED; sqliteBtreeClose(db->pBe); clearHashTable(db, 0); @@ -530,7 +530,7 @@ int sqlite_exec( Parse sParse; if( pzErrMsg ) *pzErrMsg = 0; - if( sqliteSafetyOn(db) ){ return SQLITE_MISUSE; } + if( sqliteSafetyOn(db) ) goto exec_misuse; if( (db->flags & SQLITE_Initialized)==0 ){ int rc = sqliteInit(db, pzErrMsg); if( rc!=SQLITE_OK ){ @@ -560,47 +560,50 @@ int sqlite_exec( clearHashTable(db, 1); } db->recursionDepth--; - if( sqliteSafetyOff(db) ){ sParse.rc = SQLITE_MISUSE; } + if( sqliteSafetyOff(db) ) goto exec_misuse; return sParse.rc; + +exec_misuse: + if( pzErrMsg ){ + *pzErrMsg = 0; + sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), 0); + sqliteStrRealloc(pzErrMsg); + } + return SQLITE_MISUSE; } /* -** Change the magic from SQLITE_MAGIC_OPEN to SQLITE_MAGIC_BUSY. -** Return an error (non-zero) if the magic was not SQLITE_MAGIC_OPEN -** when this routine is called. -** -** This routine is a attempt to detect if two threads attempt -** to use the same sqlite* pointer at the same time. There is a -** race condition so it is possible that the error is not detected. -** But usually the problem will be seen. The result will be an -** error which can be used to debugging the application that is -** using SQLite incorrectly. +** Return a static string that describes the kind of error specified in the +** argument. */ -int sqliteSafetyOn(sqlite *db){ - if( db->magic==SQLITE_MAGIC_OPEN ){ - db->magic = SQLITE_MAGIC_BUSY; - return 0; - }else{ - db->magic = SQLITE_MAGIC_ERROR; - db->flags |= SQLITE_Interrupt; - return 1; - } -} - -/* -** Change the magic from SQLITE_MAGIC_BUSY to SQLITE_MAGIC_OPEN. -** Return an error (non-zero) if the magic was not SQLITE_MAGIC_BUSY -** when this routine is called. -*/ -int sqliteSafetyOff(sqlite *db){ - if( db->magic==SQLITE_MAGIC_BUSY ){ - db->magic = SQLITE_MAGIC_OPEN; - return 0; - }else{ - db->magic = SQLITE_MAGIC_ERROR; - db->flags |= SQLITE_Interrupt; - return 1; +const char *sqlite_error_string(int rc){ + const char *z; + switch( rc ){ + case SQLITE_OK: z = "not an error"; break; + case SQLITE_ERROR: z = "SQL logic error or missing database"; break; + case SQLITE_INTERNAL: z = "internal SQLite implementation flaw"; break; + case SQLITE_PERM: z = "access permission denied"; break; + case SQLITE_ABORT: z = "callback requested query abort"; break; + case SQLITE_BUSY: z = "database is locked"; break; + case SQLITE_LOCKED: z = "database table is locked"; break; + case SQLITE_NOMEM: z = "out of memory"; break; + case SQLITE_READONLY: z = "attempt to write a readonly database"; break; + case SQLITE_INTERRUPT: z = "interrupted"; break; + case SQLITE_IOERR: z = "disk I/O error"; break; + case SQLITE_CORRUPT: z = "database disk image is malformed"; break; + case SQLITE_NOTFOUND: z = "table or record not found"; break; + case SQLITE_FULL: z = "database is full"; break; + case SQLITE_CANTOPEN: z = "unable to open database file"; break; + case SQLITE_PROTOCOL: z = "database locking protocol failure"; break; + case SQLITE_EMPTY: z = "table contains no data"; break; + case SQLITE_SCHEMA: z = "database schema has changed"; break; + case SQLITE_TOOBIG: z = "too much data for one table row"; break; + case SQLITE_CONSTRAINT: z = "constraint failed"; break; + case SQLITE_MISMATCH: z = "datatype mismatch"; break; + case SQLITE_MISUSE: z = "library routine called out of sequence";break; + default: z = "unknown error"; break; } + return z; } /* @@ -718,7 +721,7 @@ int sqlite_create_function( void *pUserData /* User data */ ){ FuncDef *p; - if( db==0 || zName==0 ) return 1; + if( db==0 || zName==0 || sqliteSafetyCheck(db) ) return 1; p = sqliteFindFunction(db, zName, strlen(zName), nArg, 1); if( p==0 ) return 1; p->xFunc = xFunc; @@ -736,7 +739,7 @@ int sqlite_create_aggregate( void *pUserData /* User data */ ){ FuncDef *p; - if( db==0 || zName==0 ) return 1; + if( db==0 || zName==0 || sqliteSafetyCheck(db) ) return 1; p = sqliteFindFunction(db, zName, strlen(zName), nArg, 1); if( p==0 ) return 1; p->xFunc = 0; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index fbdb47dc99..f8251bbd14 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.106 2002/05/10 05:44:56 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.107 2002/05/10 13:14:07 drh Exp $ */ #include "sqlite.h" #include "hash.h" @@ -661,3 +661,4 @@ FuncDef *sqliteFindFunction(sqlite*,const char*,int,int,int); void sqliteRegisterBuildinFunctions(sqlite*); int sqliteSafetyOn(sqlite*); int sqliteSafetyOff(sqlite*); +int sqliteSafetyCheck(sqlite*); diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 045c18d788..7df3f77419 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -11,7 +11,7 @@ ************************************************************************* ** A TCL Interface to SQLite ** -** $Id: tclsqlite.c,v 1.31 2002/04/12 10:08:59 drh Exp $ +** $Id: tclsqlite.c,v 1.32 2002/05/10 13:14:07 drh Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ @@ -552,10 +552,18 @@ static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){ return TCL_ERROR; } Tcl_CreateObjCommand(interp, argv[1], DbObjCmd, (char*)p, DbDeleteCmd); + + /* If compiled with SQLITE_TEST turned on, then register the "md5sum" + ** SQL function and return an integer which is the memory address of + ** the underlying sqlite* pointer. + */ #ifdef SQLITE_TEST { - extern void Md5_Register(sqlite*); - Md5_Register(p->db); + char zBuf[40]; + extern void Md5_Register(sqlite*); + Md5_Register(p->db); + sprintf(zBuf, "%d", (int)p->db); + Tcl_AppendResult(interp, zBuf, 0); } #endif return TCL_OK; diff --git a/src/test1.c b/src/test1.c index 217d1f9d92..852824b52c 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.7 2002/03/11 02:06:13 drh Exp $ +** $Id: test1.c,v 1.8 2002/05/10 13:14:07 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -197,6 +197,117 @@ static int sqlite_test_close( return TCL_OK; } +/* +** Implementation of the x_coalesce() function. +** Return the first argument non-NULL argument. +*/ +static void ifnullFunc(sqlite_func *context, int argc, const char **argv){ + int i; + for(i=0; in++; + } +} +static void countFinalize(sqlite_func *context){ + CountCtx *p; + p = sqlite_aggregate_context(context, sizeof(*p)); + sqlite_set_result_int(context, p ? p->n : 0); +} + +/* +** Usage: sqlite_test_create_aggregate DB +** +** Call the sqlite_create_function API on the given database in order +** to create a function named "x_count". This function does the same thing +** as the "md5sum" function. +** +** The original motivation for this routine was to be able to call the +** sqlite_create_aggregate function while a query is in progress in order +** to test the SQLITE_MISUSE detection logic. +*/ +static int sqlite_test_create_aggregate( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + char **argv /* Text of each argument */ +){ + sqlite *db; + if( argc!=2 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " FILENAME\"", 0); + return TCL_ERROR; + } + db = (sqlite*)atoi(argv[1]); + sqlite_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0); + sqlite_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0); + return TCL_OK; +} + + + /* ** Usage: sqlite_mprintf_int FORMAT INTEGER INTEGER INTEGER ** @@ -355,6 +466,10 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ Tcl_CreateCommand(interp, "sqlite_get_table_printf", test_get_table_printf, 0, 0); Tcl_CreateCommand(interp, "sqlite_close", sqlite_test_close, 0, 0); + Tcl_CreateCommand(interp, "sqlite_create_function", + sqlite_test_create_function, 0, 0); + Tcl_CreateCommand(interp, "sqlite_create_aggregate", + sqlite_test_create_aggregate, 0, 0); Tcl_LinkVar(interp, "sqlite_search_count", (char*)&sqlite_search_count, TCL_LINK_INT); #ifdef MEMORY_DEBUG diff --git a/src/util.c b/src/util.c index 50cd8cfd21..a13b92af59 100644 --- a/src/util.c +++ b/src/util.c @@ -14,7 +14,7 @@ ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** -** $Id: util.c,v 1.42 2002/05/10 05:44:56 drh Exp $ +** $Id: util.c,v 1.43 2002/05/10 13:14:07 drh Exp $ */ #include "sqliteInt.h" #include @@ -1069,35 +1069,57 @@ sqliteLikeCompare(const unsigned char *zPattern, const unsigned char *zString){ } /* -** Return a static string that describes the kind of error specified in the -** argument. +** Change the sqlite.magic from SQLITE_MAGIC_OPEN to SQLITE_MAGIC_BUSY. +** Return an error (non-zero) if the magic was not SQLITE_MAGIC_OPEN +** when this routine is called. +** +** This routine is a attempt to detect if two threads use the +** same sqlite* pointer at the same time. There is a race +** condition so it is possible that the error is not detected. +** But usually the problem will be seen. The result will be an +** error which can be used to debugging the application that is +** using SQLite incorrectly. */ -const char *sqlite_error_string(int rc){ - const char *z; - switch( rc ){ - case SQLITE_OK: z = "not an error"; break; - case SQLITE_ERROR: z = "SQL logic error or missing database"; break; - case SQLITE_INTERNAL: z = "internal SQLite implementation flaw"; break; - case SQLITE_PERM: z = "access permission denied"; break; - case SQLITE_ABORT: z = "callback requested query abort"; break; - case SQLITE_BUSY: z = "database is locked"; break; - case SQLITE_LOCKED: z = "database table is locked"; break; - case SQLITE_NOMEM: z = "out of memory"; break; - case SQLITE_READONLY: z = "attempt to write a readonly database"; break; - case SQLITE_INTERRUPT: z = "interrupted"; break; - case SQLITE_IOERR: z = "disk I/O error"; break; - case SQLITE_CORRUPT: z = "database disk image is malformed"; break; - case SQLITE_NOTFOUND: z = "table or record not found"; break; - case SQLITE_FULL: z = "database is full"; break; - case SQLITE_CANTOPEN: z = "unable to open database file"; break; - case SQLITE_PROTOCOL: z = "database locking protocol failure"; break; - case SQLITE_EMPTY: z = "table contains no data"; break; - case SQLITE_SCHEMA: z = "database schema has changed"; break; - case SQLITE_TOOBIG: z = "too much data for one table row"; break; - case SQLITE_CONSTRAINT: z = "constraint failed"; break; - case SQLITE_MISMATCH: z = "datatype mismatch"; break; - case SQLITE_MISUSE: z = "SQLite library used incorrectly"; break; - default: z = "unknown error"; break; +int sqliteSafetyOn(sqlite *db){ + if( db->magic==SQLITE_MAGIC_OPEN ){ + db->magic = SQLITE_MAGIC_BUSY; + return 0; + }else{ + db->magic = SQLITE_MAGIC_ERROR; + db->flags |= SQLITE_Interrupt; + return 1; } - return z; +} + +/* +** Change the magic from SQLITE_MAGIC_BUSY to SQLITE_MAGIC_OPEN. +** Return an error (non-zero) if the magic was not SQLITE_MAGIC_BUSY +** when this routine is called. +*/ +int sqliteSafetyOff(sqlite *db){ + if( db->magic==SQLITE_MAGIC_BUSY ){ + db->magic = SQLITE_MAGIC_OPEN; + return 0; + }else{ + db->magic = SQLITE_MAGIC_ERROR; + db->flags |= SQLITE_Interrupt; + return 1; + } +} + +/* +** Check to make sure we are not currently executing an sqlite_exec(). +** If we are currently in an sqlite_exec(), return true and set +** sqlite.magic to SQLITE_MAGIC_ERROR. This will cause a complete +** shutdown of the database. +** +** This routine is used to try to detect when API routines are called +** at the wrong time or in the wrong sequence. +*/ +int sqliteSafetyCheck(sqlite *db){ + if( db->recursionDepth ){ + db->magic = SQLITE_MAGIC_ERROR; + return 1; + } + return 0; } diff --git a/src/vdbe.c b/src/vdbe.c index 22b625c541..6d577f844a 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -30,7 +30,7 @@ ** But other routines are also provided to help in building up ** a program instruction by instruction. ** -** $Id: vdbe.c,v 1.140 2002/05/10 05:44:56 drh Exp $ +** $Id: vdbe.c,v 1.141 2002/05/10 13:14:07 drh Exp $ */ #include "sqliteInt.h" #include @@ -1112,8 +1112,12 @@ int sqliteVdbeList( for(i=0; rc==SQLITE_OK && inOp; i++){ if( db->flags & SQLITE_Interrupt ){ db->flags &= ~SQLITE_Interrupt; - sqliteSetString(pzErrMsg, "interrupted", 0); - rc = SQLITE_INTERRUPT; + if( db->magic!=SQLITE_MAGIC_BUSY ){ + rc = SQLITE_MISUSE; + }else{ + rc = SQLITE_INTERRUPT; + } + sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0); break; } sprintf(zAddr,"%d",i); @@ -1299,8 +1303,12 @@ int sqliteVdbeExec( */ if( db->flags & SQLITE_Interrupt ){ db->flags &= ~SQLITE_Interrupt; - rc = SQLITE_INTERRUPT; - sqliteSetString(pzErrMsg, "interrupted", 0); + if( db->magic!=SQLITE_MAGIC_BUSY ){ + rc = SQLITE_MISUSE; + }else{ + rc = SQLITE_INTERRUPT; + } + sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0); break; } diff --git a/test/all.test b/test/all.test index ff5c4fbc77..85d9a80be5 100644 --- a/test/all.test +++ b/test/all.test @@ -10,7 +10,7 @@ #*********************************************************************** # This file runs all tests. # -# $Id: all.test,v 1.13 2002/03/06 22:01:36 drh Exp $ +# $Id: all.test,v 1.14 2002/05/10 13:14:08 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -33,6 +33,7 @@ set EXCLUDE { all.test quick.test malloc.test + misuse.test btree2.test } @@ -71,9 +72,10 @@ if {$LeakList!=""} { puts " Ok" } -# Run the malloc tests after memory leak detection. We do leak -# some if malloc fails. +# Run the malloc tests and the misuse test after memory leak detection. +# Both tests leak memory. # +catch {source $testdir/misuse.test} catch {source $testdir/malloc.test} really_finish_test diff --git a/test/lock.test b/test/lock.test index df18506301..685d02f0f9 100644 --- a/test/lock.test +++ b/test/lock.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script is database locks. # -# $Id: lock.test,v 1.13 2001/10/09 04:19:47 drh Exp $ +# $Id: lock.test,v 1.14 2002/05/10 13:14:08 drh Exp $ set testdir [file dirname $argv0] @@ -21,6 +21,7 @@ source $testdir/tester.tcl # do_test lock-1.0 { sqlite db2 ./test.db + set dummy {} } {} do_test lock-1.1 { execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} diff --git a/test/main.test b/test/main.test index daee82c9fc..4eceab0811 100644 --- a/test/main.test +++ b/test/main.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is exercising the code in main.c. # -# $Id: main.test,v 1.9 2001/10/13 02:59:09 drh Exp $ +# $Id: main.test,v 1.10 2002/05/10 13:14:08 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -80,7 +80,7 @@ do_test main-2.0 { puts $fd hi! close $fd set v [catch {sqlite db test.db} msg] - lappend v $msg + if {$v} {lappend v $msg} {lappend v {}} } {0 {}} # Here are some tests for tokenize.c. diff --git a/test/misuse.test b/test/misuse.test new file mode 100644 index 0000000000..2437fc3be5 --- /dev/null +++ b/test/misuse.test @@ -0,0 +1,161 @@ +# 2002 May 10 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# +# This file implements tests for the SQLITE_MISUSE detection logic. +# This test file leaks memory and file descriptors. +# +# $Id: misuse.test,v 1.1 2002/05/10 13:14:08 drh Exp $ + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# Make sure the test logic works +# +do_test misuse-1.1 { + db close + set ::DB [sqlite db test.db] + execsql { + CREATE TABLE t1(a,b); + INSERT INTO t1 VALUES(1,2); + } + sqlite_exec_printf $::DB {SELECT * FROM t1} {} +} {0 {a b 1 2}} +do_test misuse-1.2 { + sqlite_exec_printf $::DB {SELECT x_coalesce(NULL,a) AS 'xyz' FROM t1} {} +} {1 {no such function: x_coalesce}} +do_test misuse-1.3 { + sqlite_create_function $::DB + sqlite_exec_printf $::DB {SELECT x_coalesce(NULL,a) AS 'xyz' FROM t1} {} +} {0 {xyz 1}} + +# Use the x_sqlite_exec() SQL function to simulate the effect of two +# threads trying to use the same database at the same time. +# +do_test misuse-1.4 { + sqlite_exec_printf $::DB { + SELECT x_sqlite_exec('SELECT * FROM t1'); + } {} +} {21 {library routine called out of sequence}} +do_test misuse-1.5 { + sqlite_exec_printf $::DB {SELECT * FROM t1} {} +} {21 {library routine called out of sequence}} +do_test misuse-1.6 { + catchsql { + SELECT * FROM t1 + } +} {1 {library routine called out of sequence}} + +# Attempt to register a new SQL function while an sqlite_exec() is active. +# +do_test misuse-2.1 { + db close + set ::DB [sqlite db test.db] + execsql { + SELECT * FROM t1 + } +} {1 2} +do_test misuse-2.2 { + sqlite_exec_printf $::DB {SELECT * FROM t1} {} +} {0 {a b 1 2}} +do_test misuse-2.3 { + set v [catch { + db eval {SELECT * FROM t1} {} { + sqlite_create_function $::DB + } + } msg] + lappend v $msg +} {1 {library routine called out of sequence}} +do_test misuse-2.4 { + sqlite_exec_printf $::DB {SELECT * FROM t1} {} +} {21 {library routine called out of sequence}} +do_test misuse-2.5 { + catchsql { + SELECT * FROM t1 + } +} {1 {library routine called out of sequence}} + +# Attempt to register a new SQL aggregate while an sqlite_exec() is active. +# +do_test misuse-3.1 { + db close + set ::DB [sqlite db test.db] + execsql { + SELECT * FROM t1 + } +} {1 2} +do_test misuse-3.2 { + sqlite_exec_printf $::DB {SELECT * FROM t1} {} +} {0 {a b 1 2}} +do_test misuse-3.3 { + set v [catch { + db eval {SELECT * FROM t1} {} { + sqlite_create_aggregate $::DB + } + } msg] + lappend v $msg +} {1 {library routine called out of sequence}} +do_test misuse-3.4 { + sqlite_exec_printf $::DB {SELECT * FROM t1} {} +} {21 {library routine called out of sequence}} +do_test misuse-3.5 { + catchsql { + SELECT * FROM t1 + } +} {1 {library routine called out of sequence}} + +# Attempt to close the database from an sqlite_exec callback. +# +do_test misuse-4.1 { + db close + set ::DB [sqlite db test.db] + execsql { + SELECT * FROM t1 + } +} {1 2} +do_test misuse-4.2 { + sqlite_exec_printf $::DB {SELECT * FROM t1} {} +} {0 {a b 1 2}} +do_test misuse-4.3 { + set v [catch { + db eval {SELECT * FROM t1} {} { + sqlite_close $::DB + } + } msg] + lappend v $msg +} {1 {library routine called out of sequence}} +do_test misuse-4.4 { + sqlite_exec_printf $::DB {SELECT * FROM t1} {} +} {21 {library routine called out of sequence}} +do_test misuse-4.5 { + catchsql { + SELECT * FROM t1 + } +} {1 {library routine called out of sequence}} + +# Attempt to use a database after it has been closed. +# +do_test misuse-5.1 { + db close + set ::DB [sqlite db test.db] + execsql { + SELECT * FROM t1 + } +} {1 2} +do_test misuse-5.2 { + sqlite_exec_printf $::DB {SELECT * FROM t1} {} +} {0 {a b 1 2}} +do_test misuse-5.3 { + db close + sqlite_exec_printf $::DB {SELECT * FROM t1} {} +} {21 {library routine called out of sequence}} + +finish_test diff --git a/test/temptable.test b/test/temptable.test index 213ba81d49..01d66dc812 100644 --- a/test/temptable.test +++ b/test/temptable.test @@ -12,7 +12,7 @@ # # This file implements tests for temporary tables and indices. # -# $Id: temptable.test,v 1.4 2002/01/10 14:31:49 drh Exp $ +# $Id: temptable.test,v 1.5 2002/05/10 13:14:08 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -21,6 +21,7 @@ source $testdir/tester.tcl # do_test temptable-1.0 { sqlite db2 ./test.db + set dummy {} } {} # Create a permanent table. diff --git a/www/c_interface.tcl b/www/c_interface.tcl index 93d27b8bde..8c5ee91882 100644 --- a/www/c_interface.tcl +++ b/www/c_interface.tcl @@ -1,7 +1,7 @@ # # Run this Tcl script to generate the sqlite.html file. # -set rcsid {$Id: c_interface.tcl,v 1.27 2002/05/10 05:44:57 drh Exp $} +set rcsid {$Id: c_interface.tcl,v 1.28 2002/05/10 13:14:08 drh Exp $} puts { @@ -300,9 +300,7 @@ an INTEGER PRIMARY KEY column is only allowed to store integer data. is used incorrectly. Examples of incorrect usage include calling sqlite_exec() after the database has been closed using sqlite_close() or calling sqlite_exec() with the same -database pointer simultaneously from two separate threads. The -library makes an effort to detect these sorts of problems, but it -cannot detect them with 100% accuracy. +database pointer simultaneously from two separate threads.

diff --git a/www/changes.tcl b/www/changes.tcl index 9a8331a2f7..d435549bff 100644 --- a/www/changes.tcl +++ b/www/changes.tcl @@ -25,6 +25,11 @@ proc chng {date desc} { puts "

    $desc

" } +chng {2002 May 09 (2.4.12)} { +
  • Added logic to detect when the library API routines are called out + of sequence.
  • +} + chng {2002 May 08 (2.4.11)} {
  • Bug fix: Column names in the result set were not being generated correctly for some (rather complex) VIEWs. This could cause a