diff --git a/Makefile.in b/Makefile.in
index 37c7dab7a6..08bf85c7ba 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -48,7 +48,7 @@ LIBREADLINE = @TARGET_READLINE_LIBS@
# Object files for the SQLite library.
#
LIBOBJ = build.o dbbe.o delete.o expr.o insert.o \
- main.o parse.o select.o table.o tokenize.o update.o \
+ main.o parse.o printf.o select.o table.o tokenize.o update.o \
util.o vdbe.o where.o tclsqlite.o
# All of the source code files.
@@ -62,6 +62,7 @@ SRC = \
$(TOP)/src/insert.c \
$(TOP)/src/main.c \
$(TOP)/src/parse.y \
+ $(TOP)/src/printf.c \
$(TOP)/src/select.c \
$(TOP)/src/shell.c \
$(TOP)/src/sqlite.h.in \
@@ -164,6 +165,9 @@ update.o: $(TOP)/src/update.c $(HDR)
tclsqlite.o: $(TOP)/src/tclsqlite.c $(HDR)
$(TCC) $(GDBM_FLAGS) $(TCL_FLAGS) -c $(TOP)/src/tclsqlite.c
+printf.o: $(TOP)/src/printf.c $(HDR)
+ $(TCC) $(GDBM_FLAGS) $(TCL_FLAGS) -c $(TOP)/src/printf.c
+
gdbmdump: $(TOP)/tool/gdbmdump.c
$(TCC) $(GDBM_FLAGS) -o gdbmdump $(TOP)/tool/gdbmdump.c $(LIBGDBM)
diff --git a/VERSION b/VERSION
index b0f3d96f87..66c4c2263e 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.8
+1.0.9
diff --git a/manifest b/manifest
index e51b544bb5..1c703f59aa 100644
--- a/manifest
+++ b/manifest
@@ -1,9 +1,9 @@
-C Version\s1.0.8\s(CVS\s494)
-D 2000-09-30T23:00:00
+C Added\sthe\s_printf()\sinterface.\s(CVS\s150)
+D 2000-10-08T22:20:57
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
-F Makefile.in 2fe404a488607712e569d69974d7929bae06ad1e
+F Makefile.in f0b70aaa6717f9454c787dc74e5504c98ae7ea18
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
-F VERSION c2e64b60cb74d152b5b5a0822f0e8cb673c928da
+F VERSION 1fe894c9b80001e9dbc3b40ef1f4f984c9b624f3
F configure 3dc1edb9dcf60215e31ff72b447935ab62211442 x
F configure.in d892ca33db7e88a055519ce2f36dcb11020e8fff
F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
@@ -15,10 +15,11 @@ F src/expr.c e8e350d7baa33bd9ed8701c159eaba5e912e0adb
F src/insert.c f146f149ad2422a1dc3bfa7a1651a25940f98958
F src/main.c 9a89579b40e498920f86e89878f52185457b9c2c
F src/parse.y 5d199034de5d29ebedb42c1c51f34db4df40cbe5
+F src/printf.c 534954b942046761e0860c30a9031fa9d803ca3c
F src/select.c d382e96c2221d08367cc87976f2b574537c9de97
-F src/shell.c 3d25f6709c2794cd910733a48a14f105eed6d7f3
+F src/shell.c ef5d12129c824cb98238763e9e86ca1847e0c7bd
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
-F src/sqlite.h.in 1e0e4495172f752935ad534871ff726ae509d2f0
+F src/sqlite.h.in 8d87c93de1b43c3cce984a4204d8de84e0a626b6
F src/sqliteInt.h b65fdecac7281aafb4c9ff3e79ea1b5546478385
F src/table.c 12f0165b47178b54a675d25ed373ee7e798d6ff0
F src/tclsqlite.c 7ccccae67fb36ed60ec98282953bf5dad0f9c16f
@@ -62,8 +63,8 @@ F tool/renumberOps.awk 6d067177ad5f8d711b79577b462da9b3634bd0a9
F www/arch.fig 4f246003b7da23bd63b8b0af0618afb4ee3055c8
F www/arch.png 8dae0766d42ed3de9ed013c1341a5792bcf633e6
F www/arch.tcl a40380c1fe0080c43e6cc5c20ed70731511b06be
-F www/c_interface.tcl 73b5c1354e250a12ceaaccc376611351c867146a
-F www/changes.tcl d62039b5387cc0871ec1bd3b15065a7c7d421cb1
+F www/c_interface.tcl 47d6b9b66510be10d3b482ce978a317a183477e5
+F www/changes.tcl c4f4584325dd55f7f4146bb9f5c5f9f7ce385302
F www/crosscompile.tcl 19734ce7f18b16ff2ed8479412abf8aca56e1dcc
F www/fileformat.tcl cfb7fba80b7275555281ba2f256c00734bcdd1c9
F www/index.tcl b19418d506f90968deef972bf1b427d98bdf13e0
@@ -71,9 +72,9 @@ F www/lang.tcl 9192e114b19987e630a41e879585b87006eb84a1
F www/mingw.tcl fc5f4ba9d336b6e8c97347cc6496d6162461ef60
F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
-F www/tclsqlite.tcl 21ecd82eaea3ce3d08593a9a2d2bfdb3c1f7b547
+F www/tclsqlite.tcl ae101d5f7c07dcc59770e2a84aae09025fab2dad
F www/vdbe.tcl bcbfc33bcdd0ebad95eab31286adb9e1bc289520
-P 7e0bacedf928095b29e7166eacd2356e8169d6dd
-R 3e751dc5aea8f130e00211562c95fd7d
+P 384909e50f4ae2e84534f9a6505cfb5cc9f4d6ca
+R 20b739a1a421bb63bda38b88ca775180
U drh
-Z 96e782ab6ce077a32cb4132dcba512bf
+Z 26c391a6fcfb2f70f6b3966c96a404f9
diff --git a/manifest.uuid b/manifest.uuid
index 4313275861..52b6b1b042 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-384909e50f4ae2e84534f9a6505cfb5cc9f4d6ca
\ No newline at end of file
+f9372072a6d6caa15fa14ec722523944470fe155
\ No newline at end of file
diff --git a/src/printf.c b/src/printf.c
new file mode 100644
index 0000000000..ed3854e44f
--- /dev/null
+++ b/src/printf.c
@@ -0,0 +1,788 @@
+/*
+** The "printf" code that follows dates from the 1980's. It is in
+** the public domain. The original comments are included here for
+** completeness. They are slightly out-of-date.
+**
+** The following modules is an enhanced replacement for the "printf" programs
+** found in the standard library. The following enhancements are
+** supported:
+**
+** + Additional functions. The standard set of "printf" functions
+** includes printf, fprintf, sprintf, vprintf, vfprintf, and
+** vsprintf. This module adds the following:
+**
+** * snprintf -- Works like sprintf, but has an extra argument
+** which is the size of the buffer written to.
+**
+** * mprintf -- Similar to sprintf. Writes output to memory
+** obtained from malloc.
+**
+** * xprintf -- Calls a function to dispose of output.
+**
+** * nprintf -- No output, but returns the number of characters
+** that would have been output by printf.
+**
+** * A v- version (ex: vsnprintf) of every function is also
+** supplied.
+**
+** + A few extensions to the formatting notation are supported:
+**
+** * The "=" flag (similar to "-") causes the output to be
+** be centered in the appropriately sized field.
+**
+** * The %b field outputs an integer in binary notation.
+**
+** * The %c field now accepts a precision. The character output
+** is repeated by the number of times the precision specifies.
+**
+** * The %' field works like %c, but takes as its character the
+** next character of the format string, instead of the next
+** argument. For example, printf("%.78'-") prints 78 minus
+** signs, the same as printf("%.78c",'-').
+**
+** + When compiled using GCC on a SPARC, this version of printf is
+** faster than the library printf for SUN OS 4.1.
+**
+** + All functions are fully reentrant.
+**
+*/
+#include "sqliteInt.h"
+/*
+** Undefine COMPATIBILITY to make some slight changes in the way things
+** work. I think the changes are an improvement, but they are not
+** backwards compatible.
+*/
+/* #define COMPATIBILITY / * Compatible with SUN OS 4.1 */
+
+/*
+** Conversion types fall into various categories as defined by the
+** following enumeration.
+*/
+enum et_type { /* The type of the format field */
+ etRADIX, /* Integer types. %d, %x, %o, and so forth */
+ etFLOAT, /* Floating point. %f */
+ etEXP, /* Exponentional notation. %e and %E */
+ etGENERIC, /* Floating or exponential, depending on exponent. %g */
+ etSIZE, /* Return number of characters processed so far. %n */
+ etSTRING, /* Strings. %s */
+ etPERCENT, /* Percent symbol. %% */
+ etCHARX, /* Characters. %c */
+ etERROR, /* Used to indicate no such conversion type */
+/* The rest are extensions, not normally found in printf() */
+ etCHARLIT, /* Literal characters. %' */
+ etSQLESCAPE, /* Strings with '\'' doubled. %q */
+ etORDINAL /* 1st, 2nd, 3rd and so forth */
+};
+
+/*
+** Each builtin conversion character (ex: the 'd' in "%d") is described
+** by an instance of the following structure
+*/
+typedef struct et_info { /* Information about each format field */
+ int fmttype; /* The format field code letter */
+ int base; /* The base for radix conversion */
+ char *charset; /* The character set for conversion */
+ int flag_signed; /* Is the quantity signed? */
+ char *prefix; /* Prefix on non-zero values in alt format */
+ enum et_type type; /* Conversion paradigm */
+} et_info;
+
+/*
+** The following table is searched linearly, so it is good to put the
+** most frequently used conversion types first.
+*/
+static et_info fmtinfo[] = {
+ { 'd', 10, "0123456789", 1, 0, etRADIX, },
+ { 's', 0, 0, 0, 0, etSTRING, },
+ { 'q', 0, 0, 0, 0, etSQLESCAPE, },
+ { 'c', 0, 0, 0, 0, etCHARX, },
+ { 'o', 8, "01234567", 0, "0", etRADIX, },
+ { 'u', 10, "0123456789", 0, 0, etRADIX, },
+ { 'x', 16, "0123456789abcdef", 0, "x0", etRADIX, },
+ { 'X', 16, "0123456789ABCDEF", 0, "X0", etRADIX, },
+ { 'r', 10, "0123456789", 0, 0, etORDINAL, },
+ { 'f', 0, 0, 1, 0, etFLOAT, },
+ { 'e', 0, "e", 1, 0, etEXP, },
+ { 'E', 0, "E", 1, 0, etEXP, },
+ { 'g', 0, "e", 1, 0, etGENERIC, },
+ { 'G', 0, "E", 1, 0, etGENERIC, },
+ { 'i', 10, "0123456789", 1, 0, etRADIX, },
+ { 'n', 0, 0, 0, 0, etSIZE, },
+ { '%', 0, 0, 0, 0, etPERCENT, },
+ { 'b', 2, "01", 0, "b0", etRADIX, }, /* Binary */
+ { 'p', 10, "0123456789", 0, 0, etRADIX, }, /* Pointers */
+ { '\'', 0, 0, 0, 0, etCHARLIT, }, /* Literal char */
+};
+#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
+
+/*
+** If NOFLOATINGPOINT is defined, then none of the floating point
+** conversions will work.
+*/
+#ifndef etNOFLOATINGPOINT
+/*
+** "*val" is a double such that 0.1 <= *val < 10.0
+** Return the ascii code for the leading digit of *val, then
+** multiply "*val" by 10.0 to renormalize.
+**
+** Example:
+** input: *val = 3.14159
+** output: *val = 1.4159 function return = '3'
+**
+** The counter *cnt is incremented each time. After counter exceeds
+** 16 (the number of significant digits in a 64-bit float) '0' is
+** always returned.
+*/
+static int et_getdigit(double *val, int *cnt){
+ int digit;
+ double d;
+ if( (*cnt)++ >= 16 ) return '0';
+ digit = (int)*val;
+ d = digit;
+ digit += '0';
+ *val = (*val - d)*10.0;
+ return digit;
+}
+#endif
+
+#define etBUFSIZE 1000 /* Size of the output buffer */
+
+/*
+** The root program. All variations call this core.
+**
+** INPUTS:
+** func This is a pointer to a function taking three arguments
+** 1. A pointer to anything. Same as the "arg" parameter.
+** 2. A pointer to the list of characters to be output
+** (Note, this list is NOT null terminated.)
+** 3. An integer number of characters to be output.
+** (Note: This number might be zero.)
+**
+** arg This is the pointer to anything which will be passed as the
+** first argument to "func". Use it for whatever you like.
+**
+** fmt This is the format string, as in the usual print.
+**
+** ap This is a pointer to a list of arguments. Same as in
+** vfprint.
+**
+** OUTPUTS:
+** The return value is the total number of characters sent to
+** the function "func". Returns -1 on a error.
+**
+** Note that the order in which automatic variables are declared below
+** seems to make a big difference in determining how fast this beast
+** will run.
+*/
+static int vxprintf(
+ void (*func)(void*,char*,int),
+ void *arg,
+ const char *format,
+ va_list ap
+){
+ register const char *fmt; /* The format string. */
+ register int c; /* Next character in the format string */
+ register char *bufpt; /* Pointer to the conversion buffer */
+ register int precision; /* Precision of the current field */
+ register int length; /* Length of the field */
+ register int idx; /* A general purpose loop counter */
+ int count; /* Total number of characters output */
+ int width; /* Width of the current field */
+ int flag_leftjustify; /* True if "-" flag is present */
+ int flag_plussign; /* True if "+" flag is present */
+ int flag_blanksign; /* True if " " flag is present */
+ int flag_alternateform; /* True if "#" flag is present */
+ int flag_zeropad; /* True if field width constant starts with zero */
+ int flag_long; /* True if "l" flag is present */
+ int flag_center; /* True if "=" flag is present */
+ unsigned long longvalue; /* Value for integer types */
+ double realvalue; /* Value for real types */
+ et_info *infop; /* Pointer to the appropriate info structure */
+ char buf[etBUFSIZE]; /* Conversion buffer */
+ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
+ int errorflag = 0; /* True if an error is encountered */
+ enum et_type xtype; /* Conversion paradigm */
+ char *zMem; /* String to be freed */
+ char *zExtra; /* Extra memory used for etTCLESCAPE conversions */
+ static char spaces[] = " "
+ " ";
+#define etSPACESIZE (sizeof(spaces)-1)
+#ifndef etNOFLOATINGPOINT
+ int exp; /* exponent of real numbers */
+ double rounder; /* Used for rounding floating point values */
+ int flag_dp; /* True if decimal point should be shown */
+ int flag_rtz; /* True if trailing zeros should be removed */
+ int flag_exp; /* True to force display of the exponent */
+ int nsd; /* Number of significant digits returned */
+#endif
+
+ fmt = format; /* Put in a register for speed */
+ count = length = 0;
+ bufpt = 0;
+ for(; (c=(*fmt))!=0; ++fmt){
+ if( c!='%' ){
+ register int amt;
+ bufpt = (char *)fmt;
+ amt = 1;
+ while( (c=(*++fmt))!='%' && c!=0 ) amt++;
+ (*func)(arg,bufpt,amt);
+ count += amt;
+ if( c==0 ) break;
+ }
+ if( (c=(*++fmt))==0 ){
+ errorflag = 1;
+ (*func)(arg,"%",1);
+ count++;
+ break;
+ }
+ /* Find out what flags are present */
+ flag_leftjustify = flag_plussign = flag_blanksign =
+ flag_alternateform = flag_zeropad = flag_center = 0;
+ do{
+ switch( c ){
+ case '-': flag_leftjustify = 1; c = 0; break;
+ case '+': flag_plussign = 1; c = 0; break;
+ case ' ': flag_blanksign = 1; c = 0; break;
+ case '#': flag_alternateform = 1; c = 0; break;
+ case '0': flag_zeropad = 1; c = 0; break;
+ case '=': flag_center = 1; c = 0; break;
+ default: break;
+ }
+ }while( c==0 && (c=(*++fmt))!=0 );
+ if( flag_center ) flag_leftjustify = 0;
+ /* Get the field width */
+ width = 0;
+ if( c=='*' ){
+ width = va_arg(ap,int);
+ if( width<0 ){
+ flag_leftjustify = 1;
+ width = -width;
+ }
+ c = *++fmt;
+ }else{
+ while( isdigit(c) ){
+ width = width*10 + c - '0';
+ c = *++fmt;
+ }
+ }
+ if( width > etBUFSIZE-10 ){
+ width = etBUFSIZE-10;
+ }
+ /* Get the precision */
+ if( c=='.' ){
+ precision = 0;
+ c = *++fmt;
+ if( c=='*' ){
+ precision = va_arg(ap,int);
+#ifndef etCOMPATIBILITY
+ /* This is sensible, but SUN OS 4.1 doesn't do it. */
+ if( precision<0 ) precision = -precision;
+#endif
+ c = *++fmt;
+ }else{
+ while( isdigit(c) ){
+ precision = precision*10 + c - '0';
+ c = *++fmt;
+ }
+ }
+ /* Limit the precision to prevent overflowing buf[] during conversion */
+ if( precision>etBUFSIZE-40 ) precision = etBUFSIZE-40;
+ }else{
+ precision = -1;
+ }
+ /* Get the conversion type modifier */
+ if( c=='l' ){
+ flag_long = 1;
+ c = *++fmt;
+ }else{
+ flag_long = 0;
+ }
+ /* Fetch the info entry for the field */
+ infop = 0;
+ for(idx=0; idx
The interface to the SQLite library consists of eight functions -(only the first three of which are required), -one opaque data structure, and some constants used as return -values from sqlite_exec():
+The interface to the SQLite library consists of three core functions, +one opaque data structure, and some constants used as return values. +The core interface is as follows:
+ +typedef struct sqlite sqlite; @@ -42,6 +41,22 @@ int sqlite_exec( char **errmsg ); +#define SQLITE_OK 0 /* Successful result */ +#define SQLITE_INTERNAL 1 /* An internal logic error in SQLite */ +#define SQLITE_ERROR 2 /* SQL error or missing database */ +#define SQLITE_PERM 3 /* Access permission denied */ +#define SQLITE_ABORT 4 /* Callback routine requested an abort */ +#define SQLITE_BUSY 5 /* One or more database files are locked */ +#define SQLITE_NOMEM 6 /* A malloc() failed */ +#define SQLITE_READONLY 7 /* Attempt to write a readonly database */ +
Only the three core routines shown above are required to use +SQLite. But there are many other functions that provide +useful interfaces. These extended routines are as follows: +
+ +int sqlite_get_table( sqlite*, char *sql, @@ -61,14 +76,44 @@ void sqlite_busy_timeout(sqlite*, int ms); const char sqlite_version[]; -#define SQLITE_OK 0 /* Successful result */ -#define SQLITE_INTERNAL 1 /* An internal logic error in SQLite */ -#define SQLITE_ERROR 2 /* SQL error or missing database */ -#define SQLITE_PERM 3 /* Access permission denied */ -#define SQLITE_ABORT 4 /* Callback routine requested an abort */ -#define SQLITE_BUSY 5 /* One or more database files are locked */ -#define SQLITE_NOMEM 6 /* A malloc() failed */ -#define SQLITE_READONLY 7 /* Attempt to write a readonly database */ +int sqlite_exec_printf( + sqlite*, + char *sql, + int (*)(void*,int,char**,char**), + void*, + char **errmsg, + ... +); + +int sqlite_exec_vprintf( + sqlite*, + char *sql, + int (*)(void*,int,char**,char**), + void*, + char **errmsg, + va_list +); + +int sqlite_get_table_printf( + sqlite*, + char *sql, + char ***result, + int *nrow, + int *ncolumn, + char **errmsg, + ... +); + +int sqlite_get_table_vprintf( + sqlite*, + char *sql, + char ***result, + int *nrow, + int *ncolumn, + char **errmsg, + va_list +); +
All of the above definitions are included in the "sqlite.h" @@ -304,7 +349,7 @@ the SQLITE_VERSION macro against the sqlite_version string constant to verify that the version number of the header file and the library match.
-The GDBM library supports database locks at the file level. If a GDBM database file is opened for reading, then that same @@ -345,6 +390,85 @@ 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.
+The four utility functions
+ ++
implement the same query functionality as sqlite_exec() +and sqlite_get_table(). But instead of taking a complete +SQL statement as their second argument, the four _printf +routines take a printf-style format string. The SQL statement to +be executed is generated from this format string and from whatever +additional arguments are attached to the end of the function call.
+ +There are two advantages to using the SQLite printf +functions instead of sprintf(). First of all, with the +SQLite printf routines, there is never a danger of overflowing a +static buffer as there is with sprintf(). The SQLite +printf routines automatically allocate (and later free) +as much memory as is +necessary to hold the SQL statements generated.
+ +The second advantage the SQLite printf routines have over +sprintf() is a new formatting option specifically designed +to support string literals in SQL. Within the format string, +the %q formatting option works very much like %s in that it +reads a null-terminated string from the argument list and inserts +it into the result. But %q translates the inserted string by +making two copies of every single-quote (') character in the +substituted string. This has the effect of escaping the end-of-string +meaning of single-quote within a string literal. +
+ +Consider an example. Suppose you are trying to insert a string +values into a database table where the string value was obtained from +user input. Suppose the string to be inserted is stored in a variable +named zString. The code to insert this string might look like this:
+ +
+sqlite_exec_printf(db,
+ "INSERT INTO table1 VALUES('%s')",
+ 0, 0, 0, zString);
+
+
+If the zString variable holds text like "Hello", then this statement +will work just fine. But suppose the user enters a string like +"Hi y'all!". The SQL statement generated reads as follows: + +
+INSERT INTO table1 VALUES('Hi y'all')
+
+
+This is not valid SQL because of the apostrophy in the word "y'all". +But if the %q formatting option is used instead of %s, like this:
+ +
+sqlite_exec_printf(db,
+ "INSERT INTO table1 VALUES('%q')",
+ 0, 0, 0, zString);
+
+
+Then the generated SQL will look like the following:
+ +
+INSERT INTO table1 VALUES('Hi y''all')
+
+
+Here the apostrophy has been escaped and the SQL statement is well-formed. +When generating SQL on-the-fly from data that might contain a +single-quote character ('), it is always a good idea to use the +SQLite printf routines and the %q formatting option instead of sprintf. +
+For examples of how the SQLite C/C++ interface can be used, diff --git a/www/changes.tcl b/www/changes.tcl index f2028309e9..bd1b0860d7 100644 --- a/www/changes.tcl +++ b/www/changes.tcl @@ -17,6 +17,14 @@ proc chng {date desc} { puts "
The above code creates a new table named t1 with columns -a and b. What could be simplier?
+a and b. What could be simpler?Query results are returned as a list of column values. If a query requests 2 columns and there are 3 rows matching the query, @@ -186,14 +186,58 @@ a=3 b=howdy!
+The "complete" method takes a string of supposed SQL as its only argument. +It returns TRUE if the string is a complete statement of SQL and FALSE if +there is more to be entered.
+ +The "complete" method is useful when building interactive applications +in order to know when the user has finished entering a line of SQL code. +This is really just an interface to the sqlite_complete() C +function. Refer to the C/C++ interface +specification for additional information.
The "timeout" method is used to control how long the SQLite library +will wait for locks to clear before giving up on a database transaction. +The default timeout is 0 millisecond. (In other words, the default behavior +is not to wait at all.)
+ +The GDBM library the underlies SQLite allows multiple simultaneous +readers or a single writer but not both. If any process is writing to +the database no other process is allows to read or write. If any process +is reading the database other processes are allowed to read but not write. +Each GDBM file is locked separately. Because each SQL table is stored as +a separate file, it is possible for different processes to write to different +database tables at the same time, just not the same table.
+ +When SQLite tries to open a GDBM file and finds that it is locked, it +can optionally delay for a short while and try to open the file again. +This process repeats until the query times out and SQLite returns a +failure. The timeout is adjustable. It is set to 0 by default so that +if a GDBM file is locked, the SQL statement fails immediately. But you +can use the "timeout" method to change the timeout value to a positive +number. For example:
+ +db1 timeout 2000+ +
The argument to the timeout method is the maximum number of milliseconds +to wait for the lock to clear. So in the example above, the maximum delay +would be 2 seconds.
The "busy" method, like "timeout", only comes into play when a GDBM +file is locked. But the "busy" method gives the programmer much more +control over what action to take. The "busy" method specifies a callback +Tcl procedure that is invoked whenever SQLite tries to open a locked +GDBM file. This callback can do whatever is desired. Presumably, the +callback will do some other useful work for a short while then return +so that the lock can be tried again. The callback procedure should +return "0" if it wants SQLite to try again to open the GDBM file and +should return "1" if it wants SQLite to abandon the current operation. }