mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
added the sqlite_busy_handler() interface (CVS 109)
FossilOrigin-Name: 4fe8e51c248369572637a5351bd193f07e059fa2
This commit is contained in:
@@ -164,7 +164,7 @@ tclsqlite: $(TOP)/src/tclsqlite.c libsqlite.a
|
|||||||
$(TCC) $(TCL_FLAGS) -DTCLSH=1 -o tclsqlite \
|
$(TCC) $(TCL_FLAGS) -DTCLSH=1 -o tclsqlite \
|
||||||
$(TOP)/src/tclsqlite.c libsqlite.a $(LIBGDBM) $(LIBTCL)
|
$(TOP)/src/tclsqlite.c libsqlite.a $(LIBGDBM) $(LIBTCL)
|
||||||
|
|
||||||
test: tclsqlite
|
test: tclsqlite sqlite
|
||||||
./tclsqlite $(TOP)/test/all.test
|
./tclsqlite $(TOP)/test/all.test
|
||||||
|
|
||||||
sqlite.tar.gz:
|
sqlite.tar.gz:
|
||||||
|
54
configure
vendored
54
configure
vendored
@@ -525,7 +525,7 @@ fi
|
|||||||
|
|
||||||
|
|
||||||
# The following RCS revision string applies to configure.in
|
# The following RCS revision string applies to configure.in
|
||||||
# $Revision: 1.3 $
|
# $Revision: 1.4 $
|
||||||
|
|
||||||
#########
|
#########
|
||||||
# Make sure we are not building in a subdirectory of the source tree.
|
# Make sure we are not building in a subdirectory of the source tree.
|
||||||
@@ -1727,6 +1727,58 @@ fi
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#########
|
||||||
|
# Figure out whether or not we have a "usleep()" function.
|
||||||
|
#
|
||||||
|
echo $ac_n "checking for usleep""... $ac_c" 1>&6
|
||||||
|
echo "configure:1735: checking for usleep" >&5
|
||||||
|
if eval "test \"`echo '$''{'ac_cv_func_usleep'+set}'`\" = set"; then
|
||||||
|
echo $ac_n "(cached) $ac_c" 1>&6
|
||||||
|
else
|
||||||
|
cat > conftest.$ac_ext <<EOF
|
||||||
|
#line 1740 "configure"
|
||||||
|
#include "confdefs.h"
|
||||||
|
/* System header to define __stub macros and hopefully few prototypes,
|
||||||
|
which can conflict with char usleep(); below. */
|
||||||
|
#include <assert.h>
|
||||||
|
/* Override any gcc2 internal prototype to avoid an error. */
|
||||||
|
/* We use char because int might match the return type of a gcc2
|
||||||
|
builtin and then its argument prototype would still apply. */
|
||||||
|
char usleep();
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
/* The GNU C library defines this for functions which it implements
|
||||||
|
to always fail with ENOSYS. Some functions are actually named
|
||||||
|
something starting with __ and the normal name is an alias. */
|
||||||
|
#if defined (__stub_usleep) || defined (__stub___usleep)
|
||||||
|
choke me
|
||||||
|
#else
|
||||||
|
usleep();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
; return 0; }
|
||||||
|
EOF
|
||||||
|
if { (eval echo configure:1763: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||||
|
rm -rf conftest*
|
||||||
|
eval "ac_cv_func_usleep=yes"
|
||||||
|
else
|
||||||
|
echo "configure: failed program was:" >&5
|
||||||
|
cat conftest.$ac_ext >&5
|
||||||
|
rm -rf conftest*
|
||||||
|
eval "ac_cv_func_usleep=no"
|
||||||
|
fi
|
||||||
|
rm -f conftest*
|
||||||
|
fi
|
||||||
|
|
||||||
|
if eval "test \"`echo '$ac_cv_func_'usleep`\" = yes"; then
|
||||||
|
echo "$ac_t""yes" 1>&6
|
||||||
|
TARGET_CFLAGS="$TARGET_CFLAGS -DHAVE_USLEEP=1"
|
||||||
|
else
|
||||||
|
echo "$ac_t""no" 1>&6
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
#########
|
#########
|
||||||
# Generate the output files.
|
# Generate the output files.
|
||||||
#
|
#
|
||||||
|
@@ -151,7 +151,7 @@ AC_INIT(src/sqlite.h)
|
|||||||
dnl Put the RCS revision string after AC_INIT so that it will also
|
dnl Put the RCS revision string after AC_INIT so that it will also
|
||||||
dnl show in in configure.
|
dnl show in in configure.
|
||||||
# The following RCS revision string applies to configure.in
|
# The following RCS revision string applies to configure.in
|
||||||
# $Revision: 1.3 $
|
# $Revision: 1.4 $
|
||||||
|
|
||||||
#########
|
#########
|
||||||
# Make sure we are not building in a subdirectory of the source tree.
|
# Make sure we are not building in a subdirectory of the source tree.
|
||||||
@@ -509,6 +509,11 @@ fi
|
|||||||
AC_SUBST(TARGET_READLINE_INC)
|
AC_SUBST(TARGET_READLINE_INC)
|
||||||
AC_SUBST(TARGET_HAVE_READLINE)
|
AC_SUBST(TARGET_HAVE_READLINE)
|
||||||
|
|
||||||
|
#########
|
||||||
|
# Figure out whether or not we have a "usleep()" function.
|
||||||
|
#
|
||||||
|
AC_CHECK_FUNC(usleep, [TARGET_CFLAGS="$TARGET_CFLAGS -DHAVE_USLEEP=1"])
|
||||||
|
|
||||||
#########
|
#########
|
||||||
# Generate the output files.
|
# Generate the output files.
|
||||||
#
|
#
|
||||||
|
43
manifest
43
manifest
@@ -1,29 +1,29 @@
|
|||||||
C :-)\s(CVS\s108)
|
C added\sthe\ssqlite_busy_handler()\sinterface\s(CVS\s109)
|
||||||
D 2000-06-26T12:02:51
|
D 2000-07-28T14:32:48
|
||||||
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
|
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
|
||||||
F Makefile.in 02ecb0cd0de7ddf7b4623d480061870798787556
|
F Makefile.in 9e6dcd232e594fb599a5e9ba8bcf45e6c6e2fe72
|
||||||
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
|
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
|
||||||
F configure c366a0402bce79ef11fe1bf703ad6ce4ff6afbb0 x
|
F configure 1354f60305c781609c94cd4b677ab4ff4d830b85 x
|
||||||
F configure.in 1085ff994a334b131325de906ed318e926673588
|
F configure.in 77732d0a7d3ec66b7fc2303ae823fa5419ca7e6c
|
||||||
F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
|
F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
|
||||||
F src/build.c 55edb404bbf4476c73c81604ddb9738281a689a4
|
F src/build.c ac2e238356008411c3aa09c96823529d4103afcc
|
||||||
F src/dbbe.c 99aa6daca9a039eebb284dd459bef712ea3843f9
|
F src/dbbe.c 3604cf7dec6856a4963ab8f2220449f3d02e759a
|
||||||
F src/dbbe.h 8718b718b36d37584e9bbdfccec10588fa91271f
|
F src/dbbe.h 8718b718b36d37584e9bbdfccec10588fa91271f
|
||||||
F src/delete.c 4d491eaf61b515516749c7ed68fa3b2ee8a09065
|
F src/delete.c 4d491eaf61b515516749c7ed68fa3b2ee8a09065
|
||||||
F src/expr.c 2fa63f086707176d09092e71832f9bbdc6a8ac85
|
F src/expr.c 2fa63f086707176d09092e71832f9bbdc6a8ac85
|
||||||
F src/insert.c f146f149ad2422a1dc3bfa7a1651a25940f98958
|
F src/insert.c f146f149ad2422a1dc3bfa7a1651a25940f98958
|
||||||
F src/main.c 30b33b6e0cdd5ae1c0af9f626e78a1dc7b835e26
|
F src/main.c 82dba47063cb9837910c3bcefacb47de7486fb47
|
||||||
F src/parse.y 86e268c29a0f00ffc062bbe934d95ea0d6308b0a
|
F src/parse.y 86e268c29a0f00ffc062bbe934d95ea0d6308b0a
|
||||||
F src/select.c aaf23d4a6ef44e4378840ec94b6aa64641c01b5c
|
F src/select.c aaf23d4a6ef44e4378840ec94b6aa64641c01b5c
|
||||||
F src/shell.c 8387580e44878022c88c02b189bf23bff1862bda
|
F src/shell.c ffcb11569f6f1756148b389ac0f1fc480859698e
|
||||||
F src/sqlite.h 58da0a8590133777b741f9836beaef3d58f40268
|
F src/sqlite.h 82ae53028e27919250f886ff9d7c4927de81978a
|
||||||
F src/sqliteInt.h ddc6f8081ef469ede272cf6a382773dac5758dfc
|
F src/sqliteInt.h cf4b8f3c7fbb50adf3d879770defe72502a39022
|
||||||
F src/tclsqlite.c 9f358618ae803bedf4fb96da5154fd45023bc1f7
|
F src/tclsqlite.c 9f358618ae803bedf4fb96da5154fd45023bc1f7
|
||||||
F src/tokenize.c 77ff8164a8751994bc9926ce282847f653ac0c16
|
F src/tokenize.c 77ff8164a8751994bc9926ce282847f653ac0c16
|
||||||
F src/update.c 51b9ef7434b15e31096155da920302e9db0d27fc
|
F src/update.c 51b9ef7434b15e31096155da920302e9db0d27fc
|
||||||
F src/util.c fcd7ac9d2be8353f746e52f665e6c4f5d6b3b805
|
F src/util.c fcd7ac9d2be8353f746e52f665e6c4f5d6b3b805
|
||||||
F src/vdbe.c 38cec3e88db70b7689018377c1594ac18f746b19
|
F src/vdbe.c 72b533a452953aca618a935b5155d1d4eed3193c
|
||||||
F src/vdbe.h 5f58611b19799de2dbcdefa4eef33a255cfa8d0d
|
F src/vdbe.h 6c5653241633c583549c2d8097394ab52550eb63
|
||||||
F src/where.c 420f666a38b405cd58bd7af832ed99f1dbc7d336
|
F src/where.c 420f666a38b405cd58bd7af832ed99f1dbc7d336
|
||||||
F test/all.test 0950c135cab7e60c07bd745ccfad1476211e5bd7
|
F test/all.test 0950c135cab7e60c07bd745ccfad1476211e5bd7
|
||||||
F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb
|
F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb
|
||||||
@@ -34,6 +34,7 @@ F test/in.test 2c560c0f55fb777029fd9bb5378f2997582aa603
|
|||||||
F test/index.test 620ceab7165dd078d1266bdc2cac6147f04534ac
|
F test/index.test 620ceab7165dd078d1266bdc2cac6147f04534ac
|
||||||
F test/insert.test 66f4c3bd600fec8eb1e733b928cbe6fa885eff0c
|
F test/insert.test 66f4c3bd600fec8eb1e733b928cbe6fa885eff0c
|
||||||
F test/insert2.test 732405e30331635af8d159fccabe835eea5cd0c6
|
F test/insert2.test 732405e30331635af8d159fccabe835eea5cd0c6
|
||||||
|
F test/lock.test 42a2d171eba1078cf3fd58ab64241eb8f1b08d69
|
||||||
F test/main.test b7366cc6f3690915a11834bc1090deeff08acaf9
|
F test/main.test b7366cc6f3690915a11834bc1090deeff08acaf9
|
||||||
F test/select1.test 4e57b0b5eae0c991d9cc51d1288be0476110e6f6
|
F test/select1.test 4e57b0b5eae0c991d9cc51d1288be0476110e6f6
|
||||||
F test/select2.test ed6e7fc3437079686d7ae4390a00347bbd5f7bf8
|
F test/select2.test ed6e7fc3437079686d7ae4390a00347bbd5f7bf8
|
||||||
@@ -57,15 +58,15 @@ F tool/renumberOps.awk 6d067177ad5f8d711b79577b462da9b3634bd0a9
|
|||||||
F www/arch.fig 4e26e9dca3c49724fc8f554c695ddea9f2413156
|
F www/arch.fig 4e26e9dca3c49724fc8f554c695ddea9f2413156
|
||||||
F www/arch.png c4d908b79065a72e7dcf19317f36d1324c550e87
|
F www/arch.png c4d908b79065a72e7dcf19317f36d1324c550e87
|
||||||
F www/arch.tcl 4f6a9afecc099a27bba17b4f8cc9561abc15dc40
|
F www/arch.tcl 4f6a9afecc099a27bba17b4f8cc9561abc15dc40
|
||||||
F www/c_interface.tcl 8eb800f67e6896b1894d666b81c0b418cea09fc7
|
F www/c_interface.tcl 29593cf77025bab137b7ba64b9459eb5eb6b4873
|
||||||
F www/changes.tcl dc7ae83bf05845c043c6d2315413f2dae989658d
|
F www/changes.tcl 6c14cc0f1c1a8929aa0b44304b0e2450d801b5b5
|
||||||
F www/fileformat.tcl f3a70650e942262f8285d53097d48f0b3aa59862
|
F www/fileformat.tcl f3a70650e942262f8285d53097d48f0b3aa59862
|
||||||
F www/index.tcl 4116afce6a8c63d68882d2b00aa10b079e0129cd
|
F www/index.tcl 58c9a33ceba12f5efee446c6b10b4f6523a214e1
|
||||||
F www/lang.tcl 1645e9107d75709be4c6099b643db235bbe0a151
|
F www/lang.tcl 1645e9107d75709be4c6099b643db235bbe0a151
|
||||||
F www/opcode.tcl 401bdc639509c2f17d3bb97cbbdfdc22a61faa07
|
F www/opcode.tcl 401bdc639509c2f17d3bb97cbbdfdc22a61faa07
|
||||||
F www/sqlite.tcl b685dc3ce345a6db0441e6d5716ed29abb96dd29
|
F www/sqlite.tcl 69781eaffb02e17aa4af28b76a2bedb19baa8e9f
|
||||||
F www/vdbe.tcl 3ea62769f7a09ee0ee803c8de000182909a31e4e
|
F www/vdbe.tcl 3330c700ef9c212a169f568a595361e4cce749ed
|
||||||
P 79ce59cf79df3da2c9dcb944dba15c64c99fbad1
|
P 937c27b7e18505d0f8b85d2040db8d6a8b7cd441
|
||||||
R 7f9d7add7ab2d3c72acbddbd24bcb674
|
R c695a62141a00b7f6ab88cfdecb913c6
|
||||||
U drh
|
U drh
|
||||||
Z 7a87be763e4ccb46d3ff76e2d3d669ce
|
Z 65d7af2246a10e3639543f77b1956b6b
|
||||||
|
@@ -1 +1 @@
|
|||||||
937c27b7e18505d0f8b85d2040db8d6a8b7cd441
|
4fe8e51c248369572637a5351bd193f07e059fa2
|
@@ -33,7 +33,7 @@
|
|||||||
** COPY
|
** COPY
|
||||||
** VACUUM
|
** VACUUM
|
||||||
**
|
**
|
||||||
** $Id: build.c,v 1.19 2000/06/21 13:59:11 drh Exp $
|
** $Id: build.c,v 1.20 2000/07/28 14:32:49 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -56,7 +56,8 @@ void sqliteExec(Parse *pParse){
|
|||||||
FILE *trace = (pParse->db->flags & SQLITE_VdbeTrace)!=0 ? stderr : 0;
|
FILE *trace = (pParse->db->flags & SQLITE_VdbeTrace)!=0 ? stderr : 0;
|
||||||
sqliteVdbeTrace(pParse->pVdbe, trace);
|
sqliteVdbeTrace(pParse->pVdbe, trace);
|
||||||
sqliteVdbeExec(pParse->pVdbe, pParse->xCallback, pParse->pArg,
|
sqliteVdbeExec(pParse->pVdbe, pParse->xCallback, pParse->pArg,
|
||||||
&pParse->zErrMsg);
|
&pParse->zErrMsg, pParse->db->pBusyArg,
|
||||||
|
pParse->db->xBusyCallback);
|
||||||
}
|
}
|
||||||
sqliteVdbeDelete(pParse->pVdbe);
|
sqliteVdbeDelete(pParse->pVdbe);
|
||||||
pParse->pVdbe = 0;
|
pParse->pVdbe = 0;
|
||||||
|
@@ -30,7 +30,7 @@
|
|||||||
** relatively simple to convert to a different database such
|
** relatively simple to convert to a different database such
|
||||||
** as NDBM, SDBM, or BerkeleyDB.
|
** as NDBM, SDBM, or BerkeleyDB.
|
||||||
**
|
**
|
||||||
** $Id: dbbe.c,v 1.15 2000/06/21 13:59:11 drh Exp $
|
** $Id: dbbe.c,v 1.16 2000/07/28 14:32:49 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <gdbm.h>
|
#include <gdbm.h>
|
||||||
@@ -382,7 +382,12 @@ int sqliteDbbeOpenCursor(
|
|||||||
pCursr->pFile = pFile;
|
pCursr->pFile = pFile;
|
||||||
pCursr->readPending = 0;
|
pCursr->readPending = 0;
|
||||||
pCursr->needRewind = 1;
|
pCursr->needRewind = 1;
|
||||||
*ppCursr = pCursr;
|
if( rc!=SQLITE_OK ){
|
||||||
|
sqliteDbbeCloseCursor(pCursr);
|
||||||
|
*ppCursr = 0;
|
||||||
|
}else{
|
||||||
|
*ppCursr = pCursr;
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
73
src/main.c
73
src/main.c
@@ -26,7 +26,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.13 2000/06/21 13:59:12 drh Exp $
|
** $Id: main.c,v 1.14 2000/07/28 14:32:49 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -134,7 +134,8 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg);
|
sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg);
|
||||||
rc = sqliteVdbeExec(vdbe, sqliteOpenCb, db, pzErrMsg);
|
rc = sqliteVdbeExec(vdbe, sqliteOpenCb, db, pzErrMsg,
|
||||||
|
db->pBusyArg, db->xBusyCallback);
|
||||||
sqliteVdbeDelete(vdbe);
|
sqliteVdbeDelete(vdbe);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
Table *pTab;
|
Table *pTab;
|
||||||
@@ -276,3 +277,71 @@ int sqlite_exec(
|
|||||||
sqliteStrRealloc(pzErrMsg);
|
sqliteStrRealloc(pzErrMsg);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This routine implements a busy callback that sleeps and tries
|
||||||
|
** again until a timeout value is reached. The timeout value is
|
||||||
|
** an integer number of milliseconds passed in as the first
|
||||||
|
** argument.
|
||||||
|
*/
|
||||||
|
static int sqlite_default_busy_callback(
|
||||||
|
void *Timeout, /* Maximum amount of time to wait */
|
||||||
|
const char *NotUsed, /* The name of the table that is busy */
|
||||||
|
int count /* Number of times table has been busy */
|
||||||
|
){
|
||||||
|
int rc;
|
||||||
|
#ifdef HAVE_USLEEP
|
||||||
|
int delay = 10000;
|
||||||
|
int prior_delay = 0;
|
||||||
|
int timeout = (int)Timeout;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=1; i<count; i++){
|
||||||
|
prior_delay += delay;
|
||||||
|
delay = delay*2;
|
||||||
|
if( delay>=1000000 ){
|
||||||
|
delay = 1000000;
|
||||||
|
prior_delay += 1000000*(count - i - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( prior_delay + delay > timeout*1000 ){
|
||||||
|
delay = timeout*1000 - prior_delay;
|
||||||
|
if( delay<=0 ) return 0;
|
||||||
|
}
|
||||||
|
usleep(delay);
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
|
int timeout = (int)Timeout;
|
||||||
|
if( (count+1)*1000 > timeout ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
sleep(1);
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This routine sets the busy callback for an Sqlite database to the
|
||||||
|
** given callback function with the given argument.
|
||||||
|
*/
|
||||||
|
void sqlite_busy_handler(
|
||||||
|
sqlite *db,
|
||||||
|
int (*xBusy)(void*,const char*,int),
|
||||||
|
void *pArg
|
||||||
|
){
|
||||||
|
db->xBusyCallback = xBusy;
|
||||||
|
db->pBusyArg = pArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This routine installs a default busy handler that waits for the
|
||||||
|
** specified number of milliseconds before returning 0.
|
||||||
|
*/
|
||||||
|
void sqlite_busy_timeout(sqlite *db, int ms){
|
||||||
|
if( ms>0 ){
|
||||||
|
sqlite_busy_handler(db, sqlite_default_busy_callback, (void*)ms);
|
||||||
|
}else{
|
||||||
|
sqlite_busy_handler(db, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
11
src/shell.c
11
src/shell.c
@@ -24,7 +24,7 @@
|
|||||||
** This file contains code to implement the "sqlite" command line
|
** This file contains code to implement the "sqlite" command line
|
||||||
** utility for accessing SQLite databases.
|
** utility for accessing SQLite databases.
|
||||||
**
|
**
|
||||||
** $Id: shell.c,v 1.15 2000/06/21 13:59:12 drh Exp $
|
** $Id: shell.c,v 1.16 2000/07/28 14:32:49 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -112,7 +112,7 @@ static char *one_input_line(const char *zPrior, int isatty){
|
|||||||
zPrompt = "sqlite> ";
|
zPrompt = "sqlite> ";
|
||||||
}
|
}
|
||||||
zResult = readline(zPrompt);
|
zResult = readline(zPrompt);
|
||||||
add_history(zResult);
|
if( zResult ) add_history(zResult);
|
||||||
return zResult;
|
return zResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,6 +382,7 @@ static char zHelp[] =
|
|||||||
".schema ?TABLE? Show the CREATE statements\n"
|
".schema ?TABLE? Show the CREATE statements\n"
|
||||||
".separator STRING Change separator string for \"list\" mode\n"
|
".separator STRING Change separator string for \"list\" mode\n"
|
||||||
".tables List names all tables in the database\n"
|
".tables List names all tables in the database\n"
|
||||||
|
".timeout MS Try opening locked tables for MS milliseconds\n"
|
||||||
".width NUM NUM ... Set column widths for \"column\" mode\n"
|
".width NUM NUM ... Set column widths for \"column\" mode\n"
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -554,7 +555,7 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
|
|||||||
sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
|
sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
|
||||||
}else
|
}else
|
||||||
|
|
||||||
if( c=='t' && strncmp(azArg[0], "tables", n)==0 ){
|
if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
|
||||||
struct callback_data data;
|
struct callback_data data;
|
||||||
char *zErrMsg = 0;
|
char *zErrMsg = 0;
|
||||||
static char zSql[] =
|
static char zSql[] =
|
||||||
@@ -569,6 +570,10 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
|
|||||||
}
|
}
|
||||||
}else
|
}else
|
||||||
|
|
||||||
|
if( c=='t' && n>1 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){
|
||||||
|
sqlite_busy_timeout(db, atoi(azArg[1]));
|
||||||
|
}else
|
||||||
|
|
||||||
if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
|
if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
|
||||||
int j;
|
int j;
|
||||||
for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
|
for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
|
||||||
|
52
src/sqlite.h
52
src/sqlite.h
@@ -24,7 +24,7 @@
|
|||||||
** This header file defines the interface that the sqlite library
|
** This header file defines the interface that the sqlite library
|
||||||
** presents to client programs.
|
** presents to client programs.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqlite.h,v 1.3 2000/06/02 01:51:20 drh Exp $
|
** @(#) $Id: sqlite.h,v 1.4 2000/07/28 14:32:50 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITE_H_
|
#ifndef _SQLITE_H_
|
||||||
#define _SQLITE_H_
|
#define _SQLITE_H_
|
||||||
@@ -94,12 +94,16 @@ typedef int (*sqlite_callback)(void*,int,char**, char**);
|
|||||||
** message is written into memory obtained from malloc() and
|
** message is written into memory obtained from malloc() and
|
||||||
** *errmsg is made to point to that message. If errmsg==NULL,
|
** *errmsg is made to point to that message. If errmsg==NULL,
|
||||||
** then no error message is ever written. The return value is
|
** then no error message is ever written. The return value is
|
||||||
** SQLITE_ERROR if an error occurs.
|
** SQLITE_ERROR if an error occurs. The calling function is
|
||||||
|
** responsible for freeing the memory that holds the error
|
||||||
|
** message.
|
||||||
**
|
**
|
||||||
** If the query could not be executed because a database file is
|
** If the query could not be executed because a database file is
|
||||||
** locked or busy, then this function returns SQLITE_BUSY. If
|
** locked or busy, then this function returns SQLITE_BUSY. (This
|
||||||
** the query could not be executed because a file is missing or
|
** behavior can be modified somewhat using the sqlite_busy_handler()
|
||||||
** has incorrect permissions, this function returns SQLITE_ERROR.
|
** and sqlite_busy_timeout() functions below.) If the query could
|
||||||
|
** not be executed because a file is missing or has incorrect
|
||||||
|
** permissions, this function returns SQLITE_ERROR.
|
||||||
*/
|
*/
|
||||||
int sqlite_exec(
|
int sqlite_exec(
|
||||||
sqlite*, /* An open database */
|
sqlite*, /* An open database */
|
||||||
@@ -121,8 +125,6 @@ int sqlite_exec(
|
|||||||
#define SQLITE_NOMEM 6 /* A malloc() failed */
|
#define SQLITE_NOMEM 6 /* A malloc() failed */
|
||||||
#define SQLITE_READONLY 7 /* Attempt to write a readonly database */
|
#define SQLITE_READONLY 7 /* Attempt to write a readonly database */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* This function returns true if the given input string comprises
|
/* This function returns true if the given input string comprises
|
||||||
** one or more complete SQL statements.
|
** one or more complete SQL statements.
|
||||||
**
|
**
|
||||||
@@ -132,4 +134,40 @@ int sqlite_exec(
|
|||||||
*/
|
*/
|
||||||
int sqlite_complete(const char *sql);
|
int sqlite_complete(const char *sql);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This routine identifies a callback function that is invoked
|
||||||
|
** whenever an attempt is made to open a database table that is
|
||||||
|
** currently locked by another process or thread. If the busy callback
|
||||||
|
** is NULL, then sqlite_exec() returns SQLITE_BUSY immediately if
|
||||||
|
** it finds a locked table. If the busy callback is not NULL, then
|
||||||
|
** sqlite_exec() invokes the callback with three arguments. The
|
||||||
|
** second argument is the name of the locked table and the third
|
||||||
|
** argument is the number of times the table has been busy. If the
|
||||||
|
** busy callback returns 0, then sqlite_exec() immediately returns
|
||||||
|
** SQLITE_BUSY. If the callback returns non-zero, then sqlite_exec()
|
||||||
|
** tries to open the table again and the cycle repeats.
|
||||||
|
**
|
||||||
|
** The default busy callback is NULL.
|
||||||
|
**
|
||||||
|
** Sqlite is re-entrant, so the busy handler may start a new query.
|
||||||
|
** (It is not clear why anyone would every want to do this, but it
|
||||||
|
** is allowed, in theory.) But the busy handler may not close the
|
||||||
|
** database. Closing the database from a busy handler will delete
|
||||||
|
** data structures out from under the executing query and will
|
||||||
|
** probably result in a coredump.
|
||||||
|
*/
|
||||||
|
void sqlite_busy_handler(sqlite*, int(*)(void*,const char*,int), void*);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This routine sets a busy handler that sleeps for a while when a
|
||||||
|
** table is locked. The handler will sleep multiple times until
|
||||||
|
** at least "ms" milleseconds of sleeping have been done. After
|
||||||
|
** "ms" milleseconds of sleeping, the handler returns 0 which
|
||||||
|
** causes sqlite_exec() to return SQLITE_BUSY.
|
||||||
|
**
|
||||||
|
** Calling this routine with an argument less than or equal to zero
|
||||||
|
** turns off all busy handlers.
|
||||||
|
*/
|
||||||
|
void sqlite_busy_timeout(sqlite*, int ms);
|
||||||
|
|
||||||
#endif /* _SQLITE_H_ */
|
#endif /* _SQLITE_H_ */
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.25 2000/06/21 13:59:12 drh Exp $
|
** @(#) $Id: sqliteInt.h,v 1.26 2000/07/28 14:32:50 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqlite.h"
|
#include "sqlite.h"
|
||||||
#include "dbbe.h"
|
#include "dbbe.h"
|
||||||
@@ -122,6 +122,8 @@ typedef struct AggExpr AggExpr;
|
|||||||
struct sqlite {
|
struct sqlite {
|
||||||
Dbbe *pBe; /* The backend driver */
|
Dbbe *pBe; /* The backend driver */
|
||||||
int flags; /* Miscellanous flags */
|
int flags; /* Miscellanous flags */
|
||||||
|
void *pBusyArg; /* 1st Argument to the busy callback */
|
||||||
|
int (*xBusyCallback)(void *,const char*,int);
|
||||||
Table *apTblHash[N_HASH]; /* All tables of the database */
|
Table *apTblHash[N_HASH]; /* All tables of the database */
|
||||||
Index *apIdxHash[N_HASH]; /* All indices of the database */
|
Index *apIdxHash[N_HASH]; /* All indices of the database */
|
||||||
};
|
};
|
||||||
|
63
src/vdbe.c
63
src/vdbe.c
@@ -41,7 +41,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.34 2000/06/21 13:59:13 drh Exp $
|
** $Id: vdbe.c,v 1.35 2000/07/28 14:32:50 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -868,13 +868,22 @@ static Sorter *Merge(Sorter *pLeft, Sorter *pRight){
|
|||||||
** Other fatal errors return SQLITE_ERROR.
|
** Other fatal errors return SQLITE_ERROR.
|
||||||
**
|
**
|
||||||
** If a database file could not be opened because it is locked by
|
** If a database file could not be opened because it is locked by
|
||||||
** another database instance, then this routine returns SQLITE_BUSY.
|
** another database instance, then the xBusy() callback is invoked
|
||||||
|
** with pBusyArg as its first argument, the name of the table as the
|
||||||
|
** second argument, and the number of times the open has been attempted
|
||||||
|
** as the third argument. The xBusy() callback will typically wait
|
||||||
|
** for the database file to be openable, then return. If xBusy()
|
||||||
|
** returns non-zero, another attempt is made to open the file. If
|
||||||
|
** xBusy() returns zero, or if xBusy is NULL, then execution halts
|
||||||
|
** and this routine returns SQLITE_BUSY.
|
||||||
*/
|
*/
|
||||||
int sqliteVdbeExec(
|
int sqliteVdbeExec(
|
||||||
Vdbe *p, /* The VDBE */
|
Vdbe *p, /* The VDBE */
|
||||||
sqlite_callback xCallback, /* The callback */
|
sqlite_callback xCallback, /* The callback */
|
||||||
void *pArg, /* 1st argument to callback */
|
void *pArg, /* 1st argument to callback */
|
||||||
char **pzErrMsg /* Error msg written here */
|
char **pzErrMsg, /* Error msg written here */
|
||||||
|
void *pBusyArg, /* 1st argument to the busy callback */
|
||||||
|
int (*xBusy)(void*,const char*,int) /* Called when a file is busy */
|
||||||
){
|
){
|
||||||
int pc; /* The program counter */
|
int pc; /* The program counter */
|
||||||
Op *pOp; /* Current operation */
|
Op *pOp; /* Current operation */
|
||||||
@@ -1698,6 +1707,7 @@ int sqliteVdbeExec(
|
|||||||
** deleted when the cursor is closed.
|
** deleted when the cursor is closed.
|
||||||
*/
|
*/
|
||||||
case OP_Open: {
|
case OP_Open: {
|
||||||
|
int busy = 0;
|
||||||
int i = pOp->p1;
|
int i = pOp->p1;
|
||||||
if( i<0 ) goto bad_instruction;
|
if( i<0 ) goto bad_instruction;
|
||||||
if( i>=p->nCursor ){
|
if( i>=p->nCursor ){
|
||||||
@@ -1709,26 +1719,35 @@ int sqliteVdbeExec(
|
|||||||
}else if( p->aCsr[i].pCursor ){
|
}else if( p->aCsr[i].pCursor ){
|
||||||
sqliteDbbeCloseCursor(p->aCsr[i].pCursor);
|
sqliteDbbeCloseCursor(p->aCsr[i].pCursor);
|
||||||
}
|
}
|
||||||
rc = sqliteDbbeOpenCursor(p->pBe, pOp->p3, pOp->p2,&p->aCsr[i].pCursor);
|
do {
|
||||||
switch( rc ){
|
rc = sqliteDbbeOpenCursor(p->pBe,pOp->p3,pOp->p2,&p->aCsr[i].pCursor);
|
||||||
case SQLITE_BUSY: {
|
switch( rc ){
|
||||||
sqliteSetString(pzErrMsg,"table ", pOp->p3, " is locked", 0);
|
case SQLITE_BUSY: {
|
||||||
break;
|
if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){
|
||||||
|
sqliteSetString(pzErrMsg,"table ", pOp->p3, " is locked", 0);
|
||||||
|
busy = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SQLITE_PERM: {
|
||||||
|
sqliteSetString(pzErrMsg, pOp->p2 ? "write" : "read",
|
||||||
|
" permission denied for table ", pOp->p3, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SQLITE_READONLY: {
|
||||||
|
sqliteSetString(pzErrMsg,"table ", pOp->p3,
|
||||||
|
" is readonly", 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SQLITE_NOMEM: {
|
||||||
|
goto no_mem;
|
||||||
|
}
|
||||||
|
case SQLITE_OK: {
|
||||||
|
busy = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case SQLITE_PERM: {
|
}while( busy );
|
||||||
sqliteSetString(pzErrMsg, pOp->p2 ? "write" : "read",
|
|
||||||
" permission denied for table ", pOp->p3, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SQLITE_READONLY: {
|
|
||||||
sqliteSetString(pzErrMsg,"table ", pOp->p3,
|
|
||||||
" is readonly", 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SQLITE_NOMEM: {
|
|
||||||
goto no_mem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p->aCsr[i].index = 0;
|
p->aCsr[i].index = 0;
|
||||||
p->aCsr[i].keyAsData = 0;
|
p->aCsr[i].keyAsData = 0;
|
||||||
break;
|
break;
|
||||||
|
@@ -27,7 +27,7 @@
|
|||||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||||
** simple program to access and modify the underlying database.
|
** simple program to access and modify the underlying database.
|
||||||
**
|
**
|
||||||
** $Id: vdbe.h,v 1.10 2000/06/11 23:50:13 drh Exp $
|
** $Id: vdbe.h,v 1.11 2000/07/28 14:32:50 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITE_VDBE_H_
|
#ifndef _SQLITE_VDBE_H_
|
||||||
#define _SQLITE_VDBE_H_
|
#define _SQLITE_VDBE_H_
|
||||||
@@ -187,7 +187,8 @@ void sqliteVdbeDequoteP3(Vdbe*, int addr);
|
|||||||
int sqliteVdbeMakeLabel(Vdbe*);
|
int sqliteVdbeMakeLabel(Vdbe*);
|
||||||
void sqliteVdbeDelete(Vdbe*);
|
void sqliteVdbeDelete(Vdbe*);
|
||||||
int sqliteVdbeOpcode(const char *zName);
|
int sqliteVdbeOpcode(const char *zName);
|
||||||
int sqliteVdbeExec(Vdbe*,sqlite_callback,void*,char**);
|
int sqliteVdbeExec(Vdbe*,sqlite_callback,void*,char**,void*,
|
||||||
|
int(*)(void*,const char*,int));
|
||||||
int sqliteVdbeList(Vdbe*,sqlite_callback,void*,char**);
|
int sqliteVdbeList(Vdbe*,sqlite_callback,void*,char**);
|
||||||
void sqliteVdbeResolveLabel(Vdbe*, int);
|
void sqliteVdbeResolveLabel(Vdbe*, int);
|
||||||
int sqliteVdbeCurrentAddr(Vdbe*);
|
int sqliteVdbeCurrentAddr(Vdbe*);
|
||||||
|
101
test/lock.test
Normal file
101
test/lock.test
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
# Copyright (c) 1999, 2000 D. Richard Hipp
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public
|
||||||
|
# License along with this library; if not, write to the
|
||||||
|
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
# Boston, MA 02111-1307, USA.
|
||||||
|
#
|
||||||
|
# Author contact information:
|
||||||
|
# drh@hwaci.com
|
||||||
|
# http://www.hwaci.com/drh/
|
||||||
|
#
|
||||||
|
#***********************************************************************
|
||||||
|
# This file implements regression tests for SQLite library. The
|
||||||
|
# focus of this script is database locks.
|
||||||
|
#
|
||||||
|
# $Id: lock.test,v 1.1 2000/07/28 14:32:50 drh Exp $
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
|
||||||
|
|
||||||
|
# Create a largish table
|
||||||
|
#
|
||||||
|
do_test lock-1.0 {
|
||||||
|
execsql {CREATE TABLE big(f1 int, f2 int, f3 int)}
|
||||||
|
set f [open ./testdata1.txt w]
|
||||||
|
for {set i 1} {$i<=500} {incr i} {
|
||||||
|
puts $f "$i\t[expr {$i*2}]\t[expr {$i*3}]"
|
||||||
|
}
|
||||||
|
close $f
|
||||||
|
execsql {COPY big FROM './testdata1.txt'}
|
||||||
|
file delete -force ./testdata1.txt
|
||||||
|
} {}
|
||||||
|
|
||||||
|
do_test lock-1.1 {
|
||||||
|
# Create a background query that gives us a read lock on the big table
|
||||||
|
#
|
||||||
|
set f [open slow.sql w]
|
||||||
|
puts $f "SELECT a.f1, b.f1 FROM big AS a, big AS B"
|
||||||
|
puts $f "WHERE a.f1+b.f1==0.5;"
|
||||||
|
close $f
|
||||||
|
set ::lock_pid [exec ./sqlite testdb <slow.sql &]
|
||||||
|
after 10
|
||||||
|
set v {}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
do_test lock-1.2 {
|
||||||
|
# Now try to update the database
|
||||||
|
#
|
||||||
|
set v [catch {execsql {UPDATE big SET f2='xyz' WHERE f1=11}} msg]
|
||||||
|
lappend v $msg
|
||||||
|
} {1 {table big is locked}}
|
||||||
|
|
||||||
|
do_test lock-1.3 {
|
||||||
|
# Try to update the database in a separate process
|
||||||
|
#
|
||||||
|
set f [open update.sql w]
|
||||||
|
puts $f ".timeout 0"
|
||||||
|
puts $f "UPDATE big SET f2='xyz' WHERE f1=11;"
|
||||||
|
puts $f "SELECT f2 FROM big WHERE f1=11;"
|
||||||
|
close $f
|
||||||
|
exec ./sqlite testdb <update.sql
|
||||||
|
} "SQL error: table big is locked\n22"
|
||||||
|
|
||||||
|
do_test lock-1.4 {
|
||||||
|
# Try to update the database using a timeout
|
||||||
|
#
|
||||||
|
set f [open update.sql w]
|
||||||
|
puts $f ".timeout 1000"
|
||||||
|
puts $f "UPDATE big SET f2='xyz' WHERE f1=11;"
|
||||||
|
puts $f "SELECT f2 FROM big WHERE f1=11;"
|
||||||
|
close $f
|
||||||
|
exec ./sqlite testdb <update.sql
|
||||||
|
} "SQL error: table big is locked\n22"
|
||||||
|
|
||||||
|
do_test lock-1.5 {
|
||||||
|
# Try to update the database using a timeout
|
||||||
|
#
|
||||||
|
set f [open update.sql w]
|
||||||
|
puts $f ".timeout 10000"
|
||||||
|
puts $f "UPDATE big SET f2='xyz' WHERE f1=11;"
|
||||||
|
puts $f "SELECT f2 FROM big WHERE f1=11;"
|
||||||
|
close $f
|
||||||
|
exec ./sqlite testdb <update.sql
|
||||||
|
} {xyz}
|
||||||
|
|
||||||
|
catch {exec ps -uax | grep $::lock_pid}
|
||||||
|
catch {exec kill -HUP $::lock_pid}
|
||||||
|
catch {exec kill -9 $::lock_pid}
|
||||||
|
|
||||||
|
finish_test
|
@@ -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.5 2000/06/21 13:59:14 drh Exp $}
|
set rcsid {$Id: c_interface.tcl,v 1.6 2000/07/28 14:32:51 drh Exp $}
|
||||||
|
|
||||||
puts {<html>
|
puts {<html>
|
||||||
<head>
|
<head>
|
||||||
@@ -22,7 +22,8 @@ programming interface.</p>
|
|||||||
|
|
||||||
<h2>The API</h2>
|
<h2>The API</h2>
|
||||||
|
|
||||||
<p>The interface to the SQLite library consists of 4 functions,
|
<p>The interface to the SQLite library consists of six functions
|
||||||
|
(only three of which are required),
|
||||||
one opaque data structure, and some constants used as return
|
one opaque data structure, and some constants used as return
|
||||||
values from sqlite_exec():</p>
|
values from sqlite_exec():</p>
|
||||||
|
|
||||||
@@ -43,6 +44,10 @@ int sqlite_exec(
|
|||||||
|
|
||||||
int sqlite_complete(const char *sql);
|
int sqlite_complete(const char *sql);
|
||||||
|
|
||||||
|
void sqlite_busy_handler(sqlite*, int (*)(void*,const char*,int), void*);
|
||||||
|
|
||||||
|
void sqlite_busy_timeout(sqlite*, int ms);
|
||||||
|
|
||||||
#define SQLITE_OK 0 /* Successful result */
|
#define SQLITE_OK 0 /* Successful result */
|
||||||
#define SQLITE_INTERNAL 1 /* An internal logic error in SQLite */
|
#define SQLITE_INTERNAL 1 /* An internal logic error in SQLite */
|
||||||
#define SQLITE_ERROR 2 /* SQL error or missing database */
|
#define SQLITE_ERROR 2 /* SQL error or missing database */
|
||||||
@@ -225,6 +230,47 @@ then <b>sqlite_exec()</b> is called and the input buffer is reset. If
|
|||||||
the continuation prompt and another line of text is read and added to
|
the continuation prompt and another line of text is read and added to
|
||||||
the input buffer.</p>
|
the input buffer.</p>
|
||||||
|
|
||||||
|
<h2>Changing the libraries reponse to locked files</h2>
|
||||||
|
|
||||||
|
<p>The GDBM library supports database locks at the file level.
|
||||||
|
If a GDBM database file is opened for reading, then that same
|
||||||
|
file cannot be reopened for writing until all readers have closed
|
||||||
|
the file. If a GDBM file is open for writing, then the file cannot
|
||||||
|
be reopened for reading or writing until it is closed.</p>
|
||||||
|
|
||||||
|
<p>If the SQLite library attempts to open a GDBM file and finds that
|
||||||
|
the file is locked, the default action is to abort the current
|
||||||
|
operation and return SQLITE_BUSY. But this is not always the most
|
||||||
|
convenient behavior, so a mechanism exists to change it.</p>
|
||||||
|
|
||||||
|
<p>The <b>sqlite_busy_handler()</b> procedure can be used to register
|
||||||
|
a busy callback with an open SQLite database. The busy callback will
|
||||||
|
be invoked whenever SQLite tries to open a GDBM file that is locked.
|
||||||
|
The callback will typically do some other useful work, or perhaps sleep,
|
||||||
|
in order to give the lock a chance to clear. If the callback returns
|
||||||
|
non-zero, then SQLite tries again to open the GDBM file and the cycle
|
||||||
|
repeats. If the callback returns zero, then SQLite aborts the current
|
||||||
|
operation and returns SQLITE_BUSY.</p>
|
||||||
|
|
||||||
|
<p>The arguments to <b>sqlite_busy_handler()</b> are the opaque
|
||||||
|
structure returned from <b>sqlite_open()</b>, a pointer to the busy
|
||||||
|
callback function, and a generic pointer that will be passed as
|
||||||
|
the first argument to the busy callback. When SQLite invokes the
|
||||||
|
busy callback, it sends it three arguments: the generic pointer
|
||||||
|
that was passed in as the third argument to <b>sqlite_busy_handler</b>,
|
||||||
|
the name of the database table or index that the library is trying
|
||||||
|
to open, and the number of times that the library has attempted to
|
||||||
|
open the database table or index.</p>
|
||||||
|
|
||||||
|
<p>For the common case where we want the busy callback to sleep,
|
||||||
|
the SQLite library provides a convenience routine <b>sqlite_busy_timeout()</b>.
|
||||||
|
The first argument to <b>sqlite_busy_timeout()</b> is a pointer to
|
||||||
|
an open SQLite database and the second argument is a number of milliseconds.
|
||||||
|
After <b>sqlite_busy_timeout()</b> has been executed, the SQLite library
|
||||||
|
will wait for the lock to clear for at least the number of milliseconds
|
||||||
|
specified before it returns SQLITE_BUSY. Specifying zero milliseconds for
|
||||||
|
the timeout restores the default behavior.</p>
|
||||||
|
|
||||||
<h2>Usage Examples</h2>
|
<h2>Usage Examples</h2>
|
||||||
|
|
||||||
<p>For examples of how the SQLite C/C++ interface can be used,
|
<p>For examples of how the SQLite C/C++ interface can be used,
|
||||||
|
@@ -17,6 +17,11 @@ proc chng {date desc} {
|
|||||||
puts "<DD><P><UL>$desc</UL></P></DD>"
|
puts "<DD><P><UL>$desc</UL></P></DD>"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chng {2000 July 28} {
|
||||||
|
<li>Added the <b>sqlite_busy_handler()</b>
|
||||||
|
and <b>sqlite_busy_timeout()</b> interface.</li>
|
||||||
|
}
|
||||||
|
|
||||||
chng {2000 June 23} {
|
chng {2000 June 23} {
|
||||||
<li>Begin writing the <a href="vdbe.html">VDBE tutorial</a>.</li>
|
<li>Begin writing the <a href="vdbe.html">VDBE tutorial</a>.</li>
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Run this TCL script to generate HTML for the index.html file.
|
# Run this TCL script to generate HTML for the index.html file.
|
||||||
#
|
#
|
||||||
set rcsid {$Id: index.tcl,v 1.18 2000/06/09 14:14:34 drh Exp $}
|
set rcsid {$Id: index.tcl,v 1.19 2000/07/28 14:32:51 drh Exp $}
|
||||||
|
|
||||||
puts {<html>
|
puts {<html>
|
||||||
<head><title>SQLite: An SQL Database Engine Built Atop GDBM</title></head>
|
<head><title>SQLite: An SQL Database Engine Built Atop GDBM</title></head>
|
||||||
@@ -50,8 +50,8 @@ an separate RDBMS.</p>
|
|||||||
<li>Import and export data from
|
<li>Import and export data from
|
||||||
<a href="http://www.postgresql.org/">PostgreSQL</a>.</li>
|
<a href="http://www.postgresql.org/">PostgreSQL</a>.</li>
|
||||||
<li>Very simple
|
<li>Very simple
|
||||||
<a href="c_interface.html">C/C++ interface</a> uses only
|
<a href="c_interface.html">C/C++ interface</a> requires the use of only
|
||||||
four functions and one opaque structure.</li>
|
three functions and one opaque structure.</li>
|
||||||
<li>A <a href="http://dev.scriptics.com/">Tcl</a> interface is
|
<li>A <a href="http://dev.scriptics.com/">Tcl</a> interface is
|
||||||
included.</li>
|
included.</li>
|
||||||
<li>Command-line access program <a href="sqlite.html">sqlite</a> uses
|
<li>Command-line access program <a href="sqlite.html">sqlite</a> uses
|
||||||
|
@@ -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: sqlite.tcl,v 1.10 2000/06/23 17:02:09 drh Exp $}
|
set rcsid {$Id: sqlite.tcl,v 1.11 2000/07/28 14:32:51 drh Exp $}
|
||||||
|
|
||||||
puts {<html>
|
puts {<html>
|
||||||
<head>
|
<head>
|
||||||
@@ -156,6 +156,7 @@ sqlite> (((.help)))
|
|||||||
.schema ?TABLE? Show the CREATE statements
|
.schema ?TABLE? Show the CREATE statements
|
||||||
.separator STRING Change separator string for "list" mode
|
.separator STRING Change separator string for "list" mode
|
||||||
.tables List names all tables in the database
|
.tables List names all tables in the database
|
||||||
|
.timeout MS Try opening locked tables for MS milliseconds
|
||||||
.width NUM NUM ... Set column widths for "column" mode
|
.width NUM NUM ... Set column widths for "column" mode
|
||||||
sqlite>
|
sqlite>
|
||||||
}
|
}
|
||||||
@@ -467,6 +468,13 @@ addr opcode p1 p2 p3
|
|||||||
}
|
}
|
||||||
|
|
||||||
puts {
|
puts {
|
||||||
|
|
||||||
|
<p>The ".timeout" command sets the amount of time that the <b>sqlite</b>
|
||||||
|
program will wait for locks to clear on files it is trying to access
|
||||||
|
before returning an error. The default value of the timeout is zero so
|
||||||
|
that an error is returned immediately if any needed database table or
|
||||||
|
index is locked.</p>
|
||||||
|
|
||||||
<p>And finally, we mention the ".exit" command which causes the
|
<p>And finally, we mention the ".exit" command which causes the
|
||||||
sqlite program to exit.</p>
|
sqlite program to exit.</p>
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Run this Tcl script to generate the vdbe.html file.
|
# Run this Tcl script to generate the vdbe.html file.
|
||||||
#
|
#
|
||||||
set rcsid {$Id: vdbe.tcl,v 1.3 2000/06/26 12:02:51 drh Exp $}
|
set rcsid {$Id: vdbe.tcl,v 1.4 2000/07/28 14:32:51 drh Exp $}
|
||||||
|
|
||||||
puts {<html>
|
puts {<html>
|
||||||
<head>
|
<head>
|
||||||
@@ -728,7 +728,7 @@ created for every SQLite database. It looks like this:</p>
|
|||||||
<blockquote><pre>
|
<blockquote><pre>
|
||||||
CREATE TABLE sqlite_master (
|
CREATE TABLE sqlite_master (
|
||||||
type TEXT, -- either "table" or "index"
|
type TEXT, -- either "table" or "index"
|
||||||
name TEXT, -- name of the table or index
|
name TEXT, -- name of this table or index
|
||||||
tbl_name TEXT, -- for indices: name of associated table
|
tbl_name TEXT, -- for indices: name of associated table
|
||||||
sql TEXT -- SQL text of the original CREATE statement
|
sql TEXT -- SQL text of the original CREATE statement
|
||||||
)
|
)
|
||||||
@@ -751,7 +751,7 @@ the first thing it does is a SELECT to read the "sql"
|
|||||||
columns from all entries of the sqlite_master table.
|
columns from all entries of the sqlite_master table.
|
||||||
The "sql" column contains the complete SQL text of the
|
The "sql" column contains the complete SQL text of the
|
||||||
CREATE statement that originally generated the index or
|
CREATE statement that originally generated the index or
|
||||||
table. This text is fed back into the SQLite parse
|
table. This text is fed back into the SQLite parser
|
||||||
and used to reconstruct the
|
and used to reconstruct the
|
||||||
internal data structures describing the index or table.</p>
|
internal data structures describing the index or table.</p>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user