1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

Improvements to the SQLITE_MISUSE detection logic. Also added test cases

for this logic, including the new test file "misuse.test". (CVS 559)

FossilOrigin-Name: f42907ce457e012592f8c043dc6c915e87258b35
This commit is contained in:
drh
2002-05-10 13:14:07 +00:00
parent 247be43d60
commit c22bd47d55
16 changed files with 437 additions and 111 deletions

View File

@ -1 +1 @@
2.4.11 2.4.12

View File

@ -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) 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-10T05:44:56 D 2002-05-10T13:14:07
F Makefile.in 50f1b3351df109b5774771350d8c1b8d3640130d F Makefile.in 50f1b3351df109b5774771350d8c1b8d3640130d
F Makefile.template 89e373b2dad0321df00400fa968dc14b61a03296 F Makefile.template 89e373b2dad0321df00400fa968dc14b61a03296
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
F VERSION fad4e0bf37e1af179693612ee7dd3e21591578a4 F VERSION 45e2ae5cf63867a750b544c539f79a076d53a9a0
F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d
F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588 F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588
F config.sub f14b07d544ca26b5d698259045136b783e18fc7f F config.sub f14b07d544ca26b5d698259045136b783e18fc7f
@ -28,7 +28,7 @@ F src/func.c a31dcba85bc2ecb9b752980289cf7e6cd0cafbce
F src/hash.c cc259475e358baaf299b00a2c7370f2b03dda892 F src/hash.c cc259475e358baaf299b00a2c7370f2b03dda892
F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9 F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9
F src/insert.c 31233f44fc79edbb43523a830e54736a8e222ff4 F src/insert.c 31233f44fc79edbb43523a830e54736a8e222ff4
F src/main.c a7041c9a32515a33dea8150dd33f748ce6e57861 F src/main.c 0a4643660b2a3dee3427a10fcea336756526c27c
F src/md5.c b2b1a34fce66ceca97f4e0dabc20be8be7933c92 F src/md5.c b2b1a34fce66ceca97f4e0dabc20be8be7933c92
F src/os.c 5ab8b6b4590d0c1ab8e96c67996c170e4462e0fc F src/os.c 5ab8b6b4590d0c1ab8e96c67996c170e4462e0fc
F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10 F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10
@ -41,20 +41,20 @@ F src/select.c 1b623a7d826ec7c245bc542b665d61724da2a62d
F src/shell.c 5acbe59e137d60d8efd975c683dbea74ab626530 F src/shell.c 5acbe59e137d60d8efd975c683dbea74ab626530
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in 0038faa6d642de06b91143ee65a131bd831d020b F src/sqlite.h.in 0038faa6d642de06b91143ee65a131bd831d020b
F src/sqliteInt.h b850d1013577be1aa34ca3b7985fa8aca733709b F src/sqliteInt.h b37d2d28e4ca3dcf67772bf937aa12b171d9610b
F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63 F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
F src/tclsqlite.c c9e9039762d9866eae70bf782237d0206a13f57e F src/tclsqlite.c 9300c9606a38bc0c75d6c0bc8a6197ab979353d1
F src/test1.c d46ab7a82a9c16a3b1ee363cb4c0f98c5ff65743 F src/test1.c 09d95048b66ce6dcd2bae90f443589043d7d631e
F src/test2.c 669cc22781c6461a273416ec1a7414d25c081730 F src/test2.c 669cc22781c6461a273416ec1a7414d25c081730
F src/test3.c 4e52fff8b01f08bd202f7633feda5639b7ba2b5e F src/test3.c 4e52fff8b01f08bd202f7633feda5639b7ba2b5e
F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f
F src/tokenize.c 5624d342601f616157ba266abccc1368a5afee70 F src/tokenize.c 5624d342601f616157ba266abccc1368a5afee70
F src/update.c 7dd714a6a7fa47f849ebb36b6d915974d6c6accb F src/update.c 7dd714a6a7fa47f849ebb36b6d915974d6c6accb
F src/util.c 79bcc175e48662faa523d4d00d34bfa246ae219f F src/util.c 707c30f8c13cddace7c08556ac450c0b786660b3
F src/vdbe.c aa5d5f76f2d7f76b1f63d81c5fd2dc91e66c49a4 F src/vdbe.c c957417fa83b5fb717dcd81204c253125b3e7e0c
F src/vdbe.h 67840a462e1daedb958cca0ccc97db140d3d9152 F src/vdbe.h 67840a462e1daedb958cca0ccc97db140d3d9152
F src/where.c 5e3e97adfa5800378f2ed45bb9312dd3a70e239c F src/where.c 5e3e97adfa5800378f2ed45bb9312dd3a70e239c
F test/all.test 6aa106eee4d7127afa5cee97c51a783a79694ead F test/all.test e4d3821eeba751829b419cd47814bd20af4286d1
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578 F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
F test/btree.test bf326f546a666617367a7033fa2c07451bd4f8e1 F test/btree.test bf326f546a666617367a7033fa2c07451bd4f8e1
F test/btree2.test e3b81ec33dc2f89b3e6087436dfe605b870c9080 F test/btree2.test e3b81ec33dc2f89b3e6087436dfe605b870c9080
@ -71,11 +71,12 @@ F test/insert2.test eb8481878a7f52ccb4e3346f87550f5afdd77f76
F test/intpkey.test 31b5f28b2c44273e6695cf36ab2e4133aee7753c F test/intpkey.test 31b5f28b2c44273e6695cf36ab2e4133aee7753c
F test/ioerr.test 57d9bffaca18b34f9e976f786eadc2591d6efc6a F test/ioerr.test 57d9bffaca18b34f9e976f786eadc2591d6efc6a
F test/limit.test a930f3eba2a7691c8397ccab33710b931589566a F test/limit.test a930f3eba2a7691c8397ccab33710b931589566a
F test/lock.test 19593689260c419efe7ced55b1418653a4b7bcd1 F test/lock.test 3fcfd46a73119f6a18094673328a32c7b3047a8f
F test/main.test 1626345b5f630c5398eede500d9354813b76b0fd F test/main.test e121fed34ebf67f595290776162e322b08470127
F test/malloc.test 70fdd0812e2a57eb746aaf015350f58bb8eee0b1 F test/malloc.test 70fdd0812e2a57eb746aaf015350f58bb8eee0b1
F test/minmax.test fb6ab400271ae1f5bc88617c2882f2f081ea8e6d F test/minmax.test fb6ab400271ae1f5bc88617c2882f2f081ea8e6d
F test/misc1.test a03214118429b40ca5548bc1fae0ebd5c34dabe6 F test/misc1.test a03214118429b40ca5548bc1fae0ebd5c34dabe6
F test/misuse.test 3ef43523b24cf1a7f56c2d344ec3025f60c6fce4
F test/notnull.test b1f3e42fc475b0b5827b27b2e9b562081995ff30 F test/notnull.test b1f3e42fc475b0b5827b27b2e9b562081995ff30
F test/pager.test b0c0d00cd5dce0ce21f16926956b195c0ab5044c F test/pager.test b0c0d00cd5dce0ce21f16926956b195c0ab5044c
F test/pragma.test 0b9675ef1f5ba5b43abfa337744445fc5b01a34a F test/pragma.test 0b9675ef1f5ba5b43abfa337744445fc5b01a34a
@ -94,7 +95,7 @@ F test/subselect.test 335d3dad8d585726c447dfee8d9c4f7383c76b78
F test/table.test 17b0b6eafa3faaee5545b7a94e6c1ff73f0880f3 F test/table.test 17b0b6eafa3faaee5545b7a94e6c1ff73f0880f3
F test/tableapi.test 3c80421a889e1d106df16e5800fa787f0d2914a6 F test/tableapi.test 3c80421a889e1d106df16e5800fa787f0d2914a6
F test/tclsqlite.test 79deeffd7cd637ca0f06c5dbbf2f44d272079533 F test/tclsqlite.test 79deeffd7cd637ca0f06c5dbbf2f44d272079533
F test/temptable.test 0e9934283259a5e637eec756a7eefd6964c0f79b F test/temptable.test daa83489eea2e9aaeeece09675c28be84c72cb67
F test/tester.tcl dc1b56bd628b487e4d75bfd1e7480b5ed8810ac6 F test/tester.tcl dc1b56bd628b487e4d75bfd1e7480b5ed8810ac6
F test/trans.test ae0b9a82d5d34122c3a3108781eb8d078091ccee F test/trans.test ae0b9a82d5d34122c3a3108781eb8d078091ccee
F test/unique.test 07776624b82221a80c8b4138ce0dd8b0853bb3ea F test/unique.test 07776624b82221a80c8b4138ce0dd8b0853bb3ea
@ -114,8 +115,8 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4 F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
F www/c_interface.tcl fbaddacc3fed376d4aebfddceb31a1fac00cf158 F www/c_interface.tcl d8c0cdd533a80fc6af480ad50a952c46423c1786
F www/changes.tcl 2178c2f6a259885904f6406864006a1602d5d498 F www/changes.tcl d1057bb733c574d9dca73578daf78a3128a61426
F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2 F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2
F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060 F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
F www/download.tcl 29aa6679ca29621d10613f60ebbbda18f4b91c49 F www/download.tcl 29aa6679ca29621d10613f60ebbbda18f4b91c49
@ -130,7 +131,7 @@ F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279 F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
P 1b0ee944c9af10078aba628e85d79f8682afa2b6 P a05fabd2df1cb38c555a7b2f31b0ca687db500c2
R af1468ce6a17da4c94780c1e8568bbbf R b30599eb63bdfc63e05ba22c1fe53652
U drh U drh
Z 8cea50e279e02e056a890661e5730afa Z b94dda4b81c12e0efb3453e43d29b6de

View File

@ -1 +1 @@
a05fabd2df1cb38c555a7b2f31b0ca687db500c2 f42907ce457e012592f8c043dc6c915e87258b35

View File

@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be ** other files are for internal use by SQLite and should not be
** accessed by users of the library. ** 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 "sqliteInt.h"
#include "os.h" #include "os.h"
@ -435,7 +435,7 @@ int sqlite_changes(sqlite *db){
*/ */
void sqlite_close(sqlite *db){ void sqlite_close(sqlite *db){
HashElem *i; HashElem *i;
if( sqliteSafetyOn(db) ){ return; } if( sqliteSafetyCheck(db) || sqliteSafetyOn(db) ){ return; }
db->magic = SQLITE_MAGIC_CLOSED; db->magic = SQLITE_MAGIC_CLOSED;
sqliteBtreeClose(db->pBe); sqliteBtreeClose(db->pBe);
clearHashTable(db, 0); clearHashTable(db, 0);
@ -530,7 +530,7 @@ int sqlite_exec(
Parse sParse; Parse sParse;
if( pzErrMsg ) *pzErrMsg = 0; if( pzErrMsg ) *pzErrMsg = 0;
if( sqliteSafetyOn(db) ){ return SQLITE_MISUSE; } if( sqliteSafetyOn(db) ) goto exec_misuse;
if( (db->flags & SQLITE_Initialized)==0 ){ if( (db->flags & SQLITE_Initialized)==0 ){
int rc = sqliteInit(db, pzErrMsg); int rc = sqliteInit(db, pzErrMsg);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@ -560,47 +560,50 @@ int sqlite_exec(
clearHashTable(db, 1); clearHashTable(db, 1);
} }
db->recursionDepth--; db->recursionDepth--;
if( sqliteSafetyOff(db) ){ sParse.rc = SQLITE_MISUSE; } if( sqliteSafetyOff(db) ) goto exec_misuse;
return sParse.rc; 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 a static string that describes the kind of error specified in the
** Return an error (non-zero) if the magic was not SQLITE_MAGIC_OPEN ** argument.
** 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.
*/ */
int sqliteSafetyOn(sqlite *db){ const char *sqlite_error_string(int rc){
if( db->magic==SQLITE_MAGIC_OPEN ){ const char *z;
db->magic = SQLITE_MAGIC_BUSY; switch( rc ){
return 0; case SQLITE_OK: z = "not an error"; break;
}else{ case SQLITE_ERROR: z = "SQL logic error or missing database"; break;
db->magic = SQLITE_MAGIC_ERROR; case SQLITE_INTERNAL: z = "internal SQLite implementation flaw"; break;
db->flags |= SQLITE_Interrupt; case SQLITE_PERM: z = "access permission denied"; break;
return 1; 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;
** Change the magic from SQLITE_MAGIC_BUSY to SQLITE_MAGIC_OPEN. case SQLITE_INTERRUPT: z = "interrupted"; break;
** Return an error (non-zero) if the magic was not SQLITE_MAGIC_BUSY case SQLITE_IOERR: z = "disk I/O error"; break;
** when this routine is called. case SQLITE_CORRUPT: z = "database disk image is malformed"; break;
*/ case SQLITE_NOTFOUND: z = "table or record not found"; break;
int sqliteSafetyOff(sqlite *db){ case SQLITE_FULL: z = "database is full"; break;
if( db->magic==SQLITE_MAGIC_BUSY ){ case SQLITE_CANTOPEN: z = "unable to open database file"; break;
db->magic = SQLITE_MAGIC_OPEN; case SQLITE_PROTOCOL: z = "database locking protocol failure"; break;
return 0; case SQLITE_EMPTY: z = "table contains no data"; break;
}else{ case SQLITE_SCHEMA: z = "database schema has changed"; break;
db->magic = SQLITE_MAGIC_ERROR; case SQLITE_TOOBIG: z = "too much data for one table row"; break;
db->flags |= SQLITE_Interrupt; case SQLITE_CONSTRAINT: z = "constraint failed"; break;
return 1; 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 */ void *pUserData /* User data */
){ ){
FuncDef *p; 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); p = sqliteFindFunction(db, zName, strlen(zName), nArg, 1);
if( p==0 ) return 1; if( p==0 ) return 1;
p->xFunc = xFunc; p->xFunc = xFunc;
@ -736,7 +739,7 @@ int sqlite_create_aggregate(
void *pUserData /* User data */ void *pUserData /* User data */
){ ){
FuncDef *p; 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); p = sqliteFindFunction(db, zName, strlen(zName), nArg, 1);
if( p==0 ) return 1; if( p==0 ) return 1;
p->xFunc = 0; p->xFunc = 0;

View File

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** 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 "sqlite.h"
#include "hash.h" #include "hash.h"
@ -661,3 +661,4 @@ FuncDef *sqliteFindFunction(sqlite*,const char*,int,int,int);
void sqliteRegisterBuildinFunctions(sqlite*); void sqliteRegisterBuildinFunctions(sqlite*);
int sqliteSafetyOn(sqlite*); int sqliteSafetyOn(sqlite*);
int sqliteSafetyOff(sqlite*); int sqliteSafetyOff(sqlite*);
int sqliteSafetyCheck(sqlite*);

View File

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** A TCL Interface to SQLite ** 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 */ #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; return TCL_ERROR;
} }
Tcl_CreateObjCommand(interp, argv[1], DbObjCmd, (char*)p, DbDeleteCmd); 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 #ifdef SQLITE_TEST
{ {
extern void Md5_Register(sqlite*); char zBuf[40];
Md5_Register(p->db); extern void Md5_Register(sqlite*);
Md5_Register(p->db);
sprintf(zBuf, "%d", (int)p->db);
Tcl_AppendResult(interp, zBuf, 0);
} }
#endif #endif
return TCL_OK; return TCL_OK;

View File

@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated ** is not included in the SQLite library. It is used for automated
** testing of the SQLite library. ** 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 "sqliteInt.h"
#include "tcl.h" #include "tcl.h"
@ -197,6 +197,117 @@ static int sqlite_test_close(
return TCL_OK; 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; i<argc; i++){
if( argv[i] ){
sqlite_set_result_string(context, argv[i], -1);
break;
}
}
}
/*
** Implementation of the x_sqlite_exec() function. This function takes
** a single argument and attempts to execute that argument as SQL code.
** This is illegal and shut set the SQLITE_MISUSE flag on the database.
**
** This routine simulates the effect of having two threads attempt to
** use the same database at the same time.
*/
static void sqliteExecFunc(sqlite_func *context, int argc, const char **argv){
sqlite_exec((sqlite*)sqlite_user_data(context), argv[0], 0, 0, 0);
}
/*
** Usage: sqlite_test_create_function DB
**
** Call the sqlite_create_function API on the given database in order
** to create a function named "x_coalesce". This function does the same thing
** as the "coalesce" function. This function also registers an SQL function
** named "x_sqlite_exec" that invokes sqlite_exec(). Invoking sqlite_exec()
** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
** The effect is similar to trying to use the same database connection from
** two threads at the same time.
**
** The original motivation for this routine was to be able to call the
** sqlite_create_function function while a query is in progress in order
** to test the SQLITE_MISUSE detection logic.
*/
static int sqlite_test_create_function(
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;
extern void Md5_Register(sqlite*);
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" FILENAME\"", 0);
return TCL_ERROR;
}
db = (sqlite*)atoi(argv[1]);
sqlite_create_function(db, "x_coalesce", -1, ifnullFunc, 0);
sqlite_create_function(db, "x_sqlite_exec", 1, sqliteExecFunc, db);
return TCL_OK;
}
/*
** Routines to implement the x_count() aggregate function.
*/
typedef struct CountCtx CountCtx;
struct CountCtx {
int n;
};
static void countStep(sqlite_func *context, int argc, const char **argv){
CountCtx *p;
p = sqlite_aggregate_context(context, sizeof(*p));
if( (argc==0 || argv[0]) && p ){
p->n++;
}
}
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 ** 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, Tcl_CreateCommand(interp, "sqlite_get_table_printf", test_get_table_printf,
0, 0); 0, 0);
Tcl_CreateCommand(interp, "sqlite_close", sqlite_test_close, 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", Tcl_LinkVar(interp, "sqlite_search_count",
(char*)&sqlite_search_count, TCL_LINK_INT); (char*)&sqlite_search_count, TCL_LINK_INT);
#ifdef MEMORY_DEBUG #ifdef MEMORY_DEBUG

View File

@ -14,7 +14,7 @@
** This file contains functions for allocating memory, comparing ** This file contains functions for allocating memory, comparing
** strings, and stuff like that. ** 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 "sqliteInt.h"
#include <stdarg.h> #include <stdarg.h>
@ -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 ** Change the sqlite.magic from SQLITE_MAGIC_OPEN to SQLITE_MAGIC_BUSY.
** argument. ** 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){ int sqliteSafetyOn(sqlite *db){
const char *z; if( db->magic==SQLITE_MAGIC_OPEN ){
switch( rc ){ db->magic = SQLITE_MAGIC_BUSY;
case SQLITE_OK: z = "not an error"; break; return 0;
case SQLITE_ERROR: z = "SQL logic error or missing database"; break; }else{
case SQLITE_INTERNAL: z = "internal SQLite implementation flaw"; break; db->magic = SQLITE_MAGIC_ERROR;
case SQLITE_PERM: z = "access permission denied"; break; db->flags |= SQLITE_Interrupt;
case SQLITE_ABORT: z = "callback requested query abort"; break; return 1;
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;
} }
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;
} }

View File

@ -30,7 +30,7 @@
** But other routines are also provided to help in building up ** But other routines are also provided to help in building up
** a program instruction by instruction. ** 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 "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -1112,8 +1112,12 @@ int sqliteVdbeList(
for(i=0; rc==SQLITE_OK && i<p->nOp; i++){ for(i=0; rc==SQLITE_OK && i<p->nOp; i++){
if( db->flags & SQLITE_Interrupt ){ if( db->flags & SQLITE_Interrupt ){
db->flags &= ~SQLITE_Interrupt; db->flags &= ~SQLITE_Interrupt;
sqliteSetString(pzErrMsg, "interrupted", 0); if( db->magic!=SQLITE_MAGIC_BUSY ){
rc = SQLITE_INTERRUPT; rc = SQLITE_MISUSE;
}else{
rc = SQLITE_INTERRUPT;
}
sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0);
break; break;
} }
sprintf(zAddr,"%d",i); sprintf(zAddr,"%d",i);
@ -1299,8 +1303,12 @@ int sqliteVdbeExec(
*/ */
if( db->flags & SQLITE_Interrupt ){ if( db->flags & SQLITE_Interrupt ){
db->flags &= ~SQLITE_Interrupt; db->flags &= ~SQLITE_Interrupt;
rc = SQLITE_INTERRUPT; if( db->magic!=SQLITE_MAGIC_BUSY ){
sqliteSetString(pzErrMsg, "interrupted", 0); rc = SQLITE_MISUSE;
}else{
rc = SQLITE_INTERRUPT;
}
sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0);
break; break;
} }

View File

@ -10,7 +10,7 @@
#*********************************************************************** #***********************************************************************
# This file runs all tests. # 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] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -33,6 +33,7 @@ set EXCLUDE {
all.test all.test
quick.test quick.test
malloc.test malloc.test
misuse.test
btree2.test btree2.test
} }
@ -71,9 +72,10 @@ if {$LeakList!=""} {
puts " Ok" puts " Ok"
} }
# Run the malloc tests after memory leak detection. We do leak # Run the malloc tests and the misuse test after memory leak detection.
# some if malloc fails. # Both tests leak memory.
# #
catch {source $testdir/misuse.test}
catch {source $testdir/malloc.test} catch {source $testdir/malloc.test}
really_finish_test really_finish_test

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this script is database locks. # 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] set testdir [file dirname $argv0]
@ -21,6 +21,7 @@ source $testdir/tester.tcl
# #
do_test lock-1.0 { do_test lock-1.0 {
sqlite db2 ./test.db sqlite db2 ./test.db
set dummy {}
} {} } {}
do_test lock-1.1 { do_test lock-1.1 {
execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this file is exercising the code in main.c. # 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] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -80,7 +80,7 @@ do_test main-2.0 {
puts $fd hi! puts $fd hi!
close $fd close $fd
set v [catch {sqlite db test.db} msg] set v [catch {sqlite db test.db} msg]
lappend v $msg if {$v} {lappend v $msg} {lappend v {}}
} {0 {}} } {0 {}}
# Here are some tests for tokenize.c. # Here are some tests for tokenize.c.

161
test/misuse.test Normal file
View File

@ -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

View File

@ -12,7 +12,7 @@
# #
# This file implements tests for temporary tables and indices. # 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] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -21,6 +21,7 @@ source $testdir/tester.tcl
# #
do_test temptable-1.0 { do_test temptable-1.0 {
sqlite db2 ./test.db sqlite db2 ./test.db
set dummy {}
} {} } {}
# Create a permanent table. # Create a permanent table.

View File

@ -1,7 +1,7 @@
# #
# Run this Tcl script to generate the sqlite.html file. # 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 {<html> puts {<html>
<head> <head>
@ -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 is used incorrectly. Examples of incorrect usage include calling
<b>sqlite_exec()</b> after the database has been closed using <b>sqlite_exec()</b> after the database has been closed using
<b>sqlite_close()</b> or calling <b>sqlite_exec()</b> with the same <b>sqlite_close()</b> or calling <b>sqlite_exec()</b> with the same
database pointer simultaneously from two separate threads. The database pointer simultaneously from two separate threads.
library makes an effort to detect these sorts of problems, but it
cannot detect them with 100% accuracy.
</p></dd> </p></dd>
</dl> </dl>
</blockquote> </blockquote>

View File

@ -25,6 +25,11 @@ proc chng {date desc} {
puts "<DD><P><UL>$desc</UL></P></DD>" puts "<DD><P><UL>$desc</UL></P></DD>"
} }
chng {2002 May 09 (2.4.12)} {
<li>Added logic to detect when the library API routines are called out
of sequence.</li>
}
chng {2002 May 08 (2.4.11)} { chng {2002 May 08 (2.4.11)} {
<li>Bug fix: Column names in the result set were not being generated <li>Bug fix: Column names in the result set were not being generated
correctly for some (rather complex) VIEWs. This could cause a correctly for some (rather complex) VIEWs. This could cause a