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:
37
manifest
37
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)
|
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
|
||||||
|
@ -1 +1 @@
|
|||||||
a05fabd2df1cb38c555a7b2f31b0ca687db500c2
|
f42907ce457e012592f8c043dc6c915e87258b35
|
83
src/main.c
83
src/main.c
@ -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;
|
||||||
|
@ -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*);
|
||||||
|
@ -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;
|
||||||
|
117
src/test1.c
117
src/test1.c
@ -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
|
||||||
|
82
src/util.c
82
src/util.c
@ -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;
|
||||||
}
|
}
|
||||||
|
18
src/vdbe.c
18
src/vdbe.c
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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}
|
||||||
|
@ -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
161
test/misuse.test
Normal 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
|
@ -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.
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user