/ Check-in [4fe8e51c]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:added the sqlite_busy_handler() interface (CVS 109)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 4fe8e51c248369572637a5351bd193f07e059fa2
User & Date: drh 2000-07-28 14:32:48
Context
2000-07-28
14:32
added the sqlite_busy_handler() interface (CVS 1700) check-in: 2d57b02f user: drh tags: trunk
14:32
added the sqlite_busy_handler() interface (CVS 109) check-in: 4fe8e51c user: drh tags: trunk
2000-06-26
12:02
:-) (CVS 108) check-in: 937c27b7 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Makefile.in.

160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
gdbmdump:	$(TOP)/tool/gdbmdump.c
	$(TCC) $(GDBM_FLAGS) -o gdbmdump $(TOP)/tool/gdbmdump.c $(LIBGDBM)

tclsqlite:	$(TOP)/src/tclsqlite.c libsqlite.a
	$(TCC) $(TCL_FLAGS) -DTCLSH=1 -o tclsqlite \
		$(TOP)/src/tclsqlite.c libsqlite.a $(LIBGDBM) $(LIBTCL)

test:	tclsqlite
	./tclsqlite $(TOP)/test/all.test

sqlite.tar.gz:	
	pwd=`pwd`; cd $(TOP)/..; tar czf $$pwd/sqlite.tar.gz sqlite

index.html:	$(TOP)/www/index.tcl sqlite.tar.gz last_change
	tclsh $(TOP)/www/index.tcl >index.html







|







160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
gdbmdump:	$(TOP)/tool/gdbmdump.c
	$(TCC) $(GDBM_FLAGS) -o gdbmdump $(TOP)/tool/gdbmdump.c $(LIBGDBM)

tclsqlite:	$(TOP)/src/tclsqlite.c libsqlite.a
	$(TCC) $(TCL_FLAGS) -DTCLSH=1 -o tclsqlite \
		$(TOP)/src/tclsqlite.c libsqlite.a $(LIBGDBM) $(LIBTCL)

test:	tclsqlite sqlite
	./tclsqlite $(TOP)/test/all.test

sqlite.tar.gz:	
	pwd=`pwd`; cd $(TOP)/..; tar czf $$pwd/sqlite.tar.gz sqlite

index.html:	$(TOP)/www/index.tcl sqlite.tar.gz last_change
	tclsh $(TOP)/www/index.tcl >index.html

Changes to configure.

521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
....
1722
1723
1724
1725
1726
1727
1728




















































1729
1730
1731
1732
1733
1734
1735
else
  ac_n= ac_c='\c' ac_t=
fi



# The following RCS revision string applies to configure.in
# $Revision: 1.3 $

#########
# Make sure we are not building in a subdirectory of the source tree.
#

temp=`echo $srcdir | grep '[^./]'`

................................................................................
if test "$found" = "yes"; then
  TARGET_HAVE_READLINE=1
else
  TARGET_HAVE_READLINE=0
fi























































#########
# Generate the output files.
#
trap '' 1 2 15
cat > confcache <<\EOF
# This file is a shell script that caches the results of configure







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
....
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
else
  ac_n= ac_c='\c' ac_t=
fi



# The following RCS revision string applies to configure.in
# $Revision: 1.4 $

#########
# Make sure we are not building in a subdirectory of the source tree.
#

temp=`echo $srcdir | grep '[^./]'`

................................................................................
if test "$found" = "yes"; then
  TARGET_HAVE_READLINE=1
else
  TARGET_HAVE_READLINE=0
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.
#
trap '' 1 2 15
cat > confcache <<\EOF
# This file is a shell script that caches the results of configure

Changes to configure.in.

147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
...
505
506
507
508
509
510
511





512
513
514
515
# the corresponding code.
#
AC_INIT(src/sqlite.h)

dnl Put the RCS revision string after AC_INIT so that it will also
dnl show in in configure.
# The following RCS revision string applies to configure.in
# $Revision: 1.3 $

#########
# Make sure we are not building in a subdirectory of the source tree.
#
changequote(<<<,>>>)
temp=`echo $srcdir | grep '[^./]'`
changequote([,])
................................................................................
  TARGET_HAVE_READLINE=1
else
  TARGET_HAVE_READLINE=0
fi
AC_SUBST(TARGET_READLINE_INC)
AC_SUBST(TARGET_HAVE_READLINE)






#########
# Generate the output files.
#
AC_OUTPUT(Makefile)







|







 







>
>
>
>
>




147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
...
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
# the corresponding code.
#
AC_INIT(src/sqlite.h)

dnl Put the RCS revision string after AC_INIT so that it will also
dnl show in in configure.
# The following RCS revision string applies to configure.in
# $Revision: 1.4 $

#########
# Make sure we are not building in a subdirectory of the source tree.
#
changequote(<<<,>>>)
temp=`echo $srcdir | grep '[^./]'`
changequote([,])
................................................................................
  TARGET_HAVE_READLINE=1
else
  TARGET_HAVE_READLINE=0
fi
AC_SUBST(TARGET_READLINE_INC)
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.
#
AC_OUTPUT(Makefile)

Changes to src/build.c.

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
..
52
53
54
55
56
57
58
59

60
61
62
63
64
65
66
**     DROP TABLE
**     CREATE INDEX
**     DROP INDEX
**     creating expressions and ID lists
**     COPY
**     VACUUM
**
** $Id: build.c,v 1.19 2000/06/21 13:59:11 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine is called after a single SQL statement has been
** parsed and we want to execute the VDBE code to implement 
** that statement.  Prior action routines should have already
................................................................................
    if( pParse->explain ){
      sqliteVdbeList(pParse->pVdbe, pParse->xCallback, pParse->pArg, 
                     &pParse->zErrMsg);
    }else{
      FILE *trace = (pParse->db->flags & SQLITE_VdbeTrace)!=0 ? stderr : 0;
      sqliteVdbeTrace(pParse->pVdbe, trace);
      sqliteVdbeExec(pParse->pVdbe, pParse->xCallback, pParse->pArg, 
                     &pParse->zErrMsg);

    }
    sqliteVdbeDelete(pParse->pVdbe);
    pParse->pVdbe = 0;
    pParse->colNamesSet = 0;
  }
}








|







 







|
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
..
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
**     DROP TABLE
**     CREATE INDEX
**     DROP INDEX
**     creating expressions and ID lists
**     COPY
**     VACUUM
**
** $Id: build.c,v 1.20 2000/07/28 14:32:49 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine is called after a single SQL statement has been
** parsed and we want to execute the VDBE code to implement 
** that statement.  Prior action routines should have already
................................................................................
    if( pParse->explain ){
      sqliteVdbeList(pParse->pVdbe, pParse->xCallback, pParse->pArg, 
                     &pParse->zErrMsg);
    }else{
      FILE *trace = (pParse->db->flags & SQLITE_VdbeTrace)!=0 ? stderr : 0;
      sqliteVdbeTrace(pParse->pVdbe, trace);
      sqliteVdbeExec(pParse->pVdbe, pParse->xCallback, pParse->pArg, 
                     &pParse->zErrMsg, pParse->db->pBusyArg,
                     pParse->db->xBusyCallback);
    }
    sqliteVdbeDelete(pParse->pVdbe);
    pParse->pVdbe = 0;
    pParse->colNamesSet = 0;
  }
}

Changes to src/dbbe.c.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
...
378
379
380
381
382
383
384




385

386
387
388
389
390
391
392
** sqlite and the code that does the actually reading and writing
** of information to the disk.
**
** This file uses GDBM as the database backend.  It should be
** relatively simple to convert to a different database such
** as NDBM, SDBM, or BerkeleyDB.
**
** $Id: dbbe.c,v 1.15 2000/06/21 13:59:11 drh Exp $
*/
#include "sqliteInt.h"
#include <gdbm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>
................................................................................
      rc = SQLITE_READONLY;
    }
  }
  pCursr->pBe = pBe;
  pCursr->pFile = pFile;
  pCursr->readPending = 0;
  pCursr->needRewind = 1;




  *ppCursr = pCursr;

  return rc;
}

/*
** Drop a table from the database.  The file on the disk that corresponds
** to this table is deleted.
*/







|







 







>
>
>
>
|
>







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
...
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
** sqlite and the code that does the actually reading and writing
** of information to the disk.
**
** This file uses GDBM as the database backend.  It should be
** relatively simple to convert to a different database such
** as NDBM, SDBM, or BerkeleyDB.
**
** $Id: dbbe.c,v 1.16 2000/07/28 14:32:49 drh Exp $
*/
#include "sqliteInt.h"
#include <gdbm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>
................................................................................
      rc = SQLITE_READONLY;
    }
  }
  pCursr->pBe = pBe;
  pCursr->pFile = pFile;
  pCursr->readPending = 0;
  pCursr->needRewind = 1;
  if( rc!=SQLITE_OK ){
    sqliteDbbeCloseCursor(pCursr);
    *ppCursr = 0;
  }else{
    *ppCursr = pCursr;
  }
  return rc;
}

/*
** Drop a table from the database.  The file on the disk that corresponds
** to this table is deleted.
*/

Changes to src/main.c.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
...
130
131
132
133
134
135
136
137

138
139
140
141
142
143
144
...
272
273
274
275
276
277
278




































































**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.13 2000/06/21 13:59:12 drh Exp $
*/
#include "sqliteInt.h"

/*
** This is the callback routine for the code that initializes the
** database.  Each callback contains text of a CREATE TABLE or
** CREATE INDEX statement that must be parsed to yield the internal
................................................................................
  */
  vdbe = sqliteVdbeCreate(db->pBe);
  if( vdbe==0 ){
    sqliteSetString(pzErrMsg, "out of memory",0); 
    return 1;
  }
  sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg);
  rc = sqliteVdbeExec(vdbe, sqliteOpenCb, db, pzErrMsg);

  sqliteVdbeDelete(vdbe);
  if( rc==SQLITE_OK ){
    Table *pTab;
    char *azArg[2];
    azArg[0] = master_schema;
    azArg[1] = 0;
    sqliteOpenCb(db, 1, azArg, 0);
................................................................................
  sParse.db = db;
  sParse.xCallback = xCallback;
  sParse.pArg = pArg;
  rc = sqliteRunParser(&sParse, zSql, pzErrMsg);
  sqliteStrRealloc(pzErrMsg);
  return rc;
}











































































|







 







|
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.14 2000/07/28 14:32:49 drh Exp $
*/
#include "sqliteInt.h"

/*
** This is the callback routine for the code that initializes the
** database.  Each callback contains text of a CREATE TABLE or
** CREATE INDEX statement that must be parsed to yield the internal
................................................................................
  */
  vdbe = sqliteVdbeCreate(db->pBe);
  if( vdbe==0 ){
    sqliteSetString(pzErrMsg, "out of memory",0); 
    return 1;
  }
  sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg);
  rc = sqliteVdbeExec(vdbe, sqliteOpenCb, db, pzErrMsg, 
                      db->pBusyArg, db->xBusyCallback);
  sqliteVdbeDelete(vdbe);
  if( rc==SQLITE_OK ){
    Table *pTab;
    char *azArg[2];
    azArg[0] = master_schema;
    azArg[1] = 0;
    sqliteOpenCb(db, 1, azArg, 0);
................................................................................
  sParse.db = db;
  sParse.xCallback = xCallback;
  sParse.pArg = pArg;
  rc = sqliteRunParser(&sParse, zSql, pzErrMsg);
  sqliteStrRealloc(pzErrMsg);
  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);
  }
}

Changes to src/shell.c.

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
...
378
379
380
381
382
383
384

385
386
387
388
389
390
391
...
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570




571
572
573
574
575
576
577
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains code to implement the "sqlite" command line
** utility for accessing SQLite databases.
**
** $Id: shell.c,v 1.15 2000/06/21 13:59:12 drh Exp $
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "sqlite.h"
#include <unistd.h>
#include <ctype.h>
................................................................................
  }
  if( zPrior && zPrior[0] ){
    zPrompt = "   ...> ";
  }else{
    zPrompt = "sqlite> ";
  }
  zResult = readline(zPrompt);
  add_history(zResult);
  return zResult;
}

/*
** An pointer to an instance of this structure is passed from
** the main program to the callback.  This is used to communicate
** state and mode information.
................................................................................
                                      "\"list\", or \"html\"\n"
  ".mode insert TABLE     Generate SQL insert statements for TABLE\n"
  ".output FILENAME       Send output to FILENAME\n"
  ".output stdout         Send output to the screen\n"
  ".schema ?TABLE?        Show the CREATE statements\n"
  ".separator STRING      Change separator string for \"list\" mode\n"
  ".tables                List names all tables in the database\n"

  ".width NUM NUM ...     Set column widths for \"column\" mode\n"
;

/*
** If an input line begins with "." then invoke this routine to
** process that line.
*/
................................................................................
    }
  }else

  if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
    sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
  }else

  if( c=='t' && strncmp(azArg[0], "tables", n)==0 ){
    struct callback_data data;
    char *zErrMsg = 0;
    static char zSql[] = 
      "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name";
    memcpy(&data, p, sizeof(data));
    data.showHeader = 0;
    data.mode = MODE_List;
    sqlite_exec(db, zSql, callback, &data, &zErrMsg);
    if( zErrMsg ){
      fprintf(stderr,"Error: %s\n", zErrMsg);
      free(zErrMsg);
    }
  }else





  if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
    int j;
    for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
      p->colWidth[j-1] = atoi(azArg[j]);
    }
  }else







|







 







|







 







>







 







|













>
>
>
>







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
...
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
...
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains code to implement the "sqlite" command line
** utility for accessing SQLite databases.
**
** $Id: shell.c,v 1.16 2000/07/28 14:32:49 drh Exp $
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "sqlite.h"
#include <unistd.h>
#include <ctype.h>
................................................................................
  }
  if( zPrior && zPrior[0] ){
    zPrompt = "   ...> ";
  }else{
    zPrompt = "sqlite> ";
  }
  zResult = readline(zPrompt);
  if( zResult ) add_history(zResult);
  return zResult;
}

/*
** An pointer to an instance of this structure is passed from
** the main program to the callback.  This is used to communicate
** state and mode information.
................................................................................
                                      "\"list\", or \"html\"\n"
  ".mode insert TABLE     Generate SQL insert statements for TABLE\n"
  ".output FILENAME       Send output to FILENAME\n"
  ".output stdout         Send output to the screen\n"
  ".schema ?TABLE?        Show the CREATE statements\n"
  ".separator STRING      Change separator string for \"list\" mode\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"
;

/*
** If an input line begins with "." then invoke this routine to
** process that line.
*/
................................................................................
    }
  }else

  if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
    sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
  }else

  if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
    struct callback_data data;
    char *zErrMsg = 0;
    static char zSql[] = 
      "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name";
    memcpy(&data, p, sizeof(data));
    data.showHeader = 0;
    data.mode = MODE_List;
    sqlite_exec(db, zSql, callback, &data, &zErrMsg);
    if( zErrMsg ){
      fprintf(stderr,"Error: %s\n", zErrMsg);
      free(zErrMsg);
    }
  }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 ){
    int j;
    for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
      p->colWidth[j-1] = atoi(azArg[j]);
    }
  }else

Changes to src/sqlite.h.

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
..
90
91
92
93
94
95
96
97


98
99
100


101
102
103
104
105
106
107
108
109
...
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134




































135
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This header file defines the interface that the sqlite library
** presents to client programs.
**
** @(#) $Id: sqlite.h,v 1.3 2000/06/02 01:51:20 drh Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_

/*
** Each open sqlite database is represented by an instance of the
** following opaque structure.
................................................................................
** will be invoked.
**
** If an error occurs while parsing or evaluating the SQL (but
** not while executing the callback) then an appropriate error
** message is written into memory obtained from malloc() and
** *errmsg is made to point to that message.  If errmsg==NULL,
** then no error message is ever written.  The return value is
** SQLITE_ERROR if an error occurs.


**
** If the query could not be executed because a database file is
** locked or busy, then this function returns SQLITE_BUSY.  If


** the query could not be executed because a file is missing or
** has incorrect permissions, this function returns SQLITE_ERROR.
*/
int sqlite_exec(
  sqlite*,                      /* An open database */
  char *sql,                    /* SQL to be executed */
  sqlite_callback,              /* Callback function */
  void *,                       /* 1st argument to callback function */
  char **errmsg                 /* Error msg written here */
................................................................................
#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 */



/* This function returns true if the given input string comprises
** one or more complete SQL statements.
**
** The algorithm is simple.  If the last token other than spaces
** and comments is a semicolon, then return true.  otherwise return
** false.
*/
int sqlite_complete(const char *sql);





































#endif /* _SQLITE_H_ */







|







 







|
>
>


|
>
>
|
|







 







<
<









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
..
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
...
121
122
123
124
125
126
127


128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This header file defines the interface that the sqlite library
** presents to client programs.
**
** @(#) $Id: sqlite.h,v 1.4 2000/07/28 14:32:50 drh Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_

/*
** Each open sqlite database is represented by an instance of the
** following opaque structure.
................................................................................
** will be invoked.
**
** If an error occurs while parsing or evaluating the SQL (but
** not while executing the callback) then an appropriate error
** message is written into memory obtained from malloc() and
** *errmsg is made to point to that message.  If errmsg==NULL,
** then no error message is ever written.  The return value is
** 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
** locked or busy, then this function returns SQLITE_BUSY.  (This
** behavior can be modified somewhat using the sqlite_busy_handler()
** 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(
  sqlite*,                      /* An open database */
  char *sql,                    /* SQL to be executed */
  sqlite_callback,              /* Callback function */
  void *,                       /* 1st argument to callback function */
  char **errmsg                 /* Error msg written here */
................................................................................
#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 */



/* This function returns true if the given input string comprises
** one or more complete SQL statements.
**
** The algorithm is simple.  If the last token other than spaces
** and comments is a semicolon, then return true.  otherwise return
** false.
*/
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_ */

Changes to src/sqliteInt.h.

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
...
118
119
120
121
122
123
124


125
126
127
128
129
130
131
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.25 2000/06/21 13:59:12 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
#include "vdbe.h"
#include "parse.h"
#include <gdbm.h>
#include <stdio.h>
................................................................................

/*
** Each database is an instance of the following structure
*/
struct sqlite {
  Dbbe *pBe;                 /* The backend driver */
  int flags;                 /* Miscellanous flags */


  Table *apTblHash[N_HASH];  /* All tables of the database */
  Index *apIdxHash[N_HASH];  /* All indices of the database */
};

/*
** Possible values for the sqlite.flags.
*/







|







 







>
>







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.26 2000/07/28 14:32:50 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
#include "vdbe.h"
#include "parse.h"
#include <gdbm.h>
#include <stdio.h>
................................................................................

/*
** Each database is an instance of the following structure
*/
struct sqlite {
  Dbbe *pBe;                 /* The backend driver */
  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 */
  Index *apIdxHash[N_HASH];  /* All indices of the database */
};

/*
** Possible values for the sqlite.flags.
*/

Changes to src/vdbe.c.

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
...
864
865
866
867
868
869
870







871
872
873
874
875
876
877


878
879
880
881
882
883
884
....
1694
1695
1696
1697
1698
1699
1700

1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711

1712
1713
1714

1715


1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730



1731


1732
1733
1734
1735
1736
1737
1738
** inplicit conversion from one type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.34 2000/06/21 13:59:13 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>

/*
** SQL is translated into a sequence of instructions to be
** executed by a virtual machine.  Each instruction is an instance
................................................................................
**
** A memory allocation error causes this routine to return SQLITE_NOMEM
** and abandon furture processing.
**
** Other fatal errors return SQLITE_ERROR.
**
** If a database file could not be opened because it is locked by







** another database instance, then this routine returns SQLITE_BUSY.
*/
int sqliteVdbeExec(
  Vdbe *p,                   /* The VDBE */
  sqlite_callback xCallback, /* The callback */
  void *pArg,                /* 1st argument to callback */
  char **pzErrMsg            /* Error msg written here */


){
  int pc;                    /* The program counter */
  Op *pOp;                   /* Current operation */
  int rc;                    /* Value to return */
  char zBuf[100];            /* Space to sprintf() and integer */

  p->tos = -1;
................................................................................
      ** automatically closed when the VDBE finishes execution.
      **
      ** If P3 is null or an empty string, a temporary database file
      ** is created.  This temporary database file is automatically 
      ** deleted when the cursor is closed.
      */
      case OP_Open: {

        int i = pOp->p1;
        if( i<0 ) goto bad_instruction;
        if( i>=p->nCursor ){
          int j;
          p->aCsr = sqliteRealloc( p->aCsr, (i+1)*sizeof(Cursor) );
          if( p->aCsr==0 ){ p->nCursor = 0; goto no_mem; }
          for(j=p->nCursor; j<=i; j++) p->aCsr[j].pCursor = 0;
          p->nCursor = i+1;
        }else if( p->aCsr[i].pCursor ){
          sqliteDbbeCloseCursor(p->aCsr[i].pCursor);
        }

        rc = sqliteDbbeOpenCursor(p->pBe, pOp->p3, pOp->p2,&p->aCsr[i].pCursor);
        switch( rc ){
          case SQLITE_BUSY: {

            sqliteSetString(pzErrMsg,"table ", pOp->p3, " is locked", 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;
          }



        }


        p->aCsr[i].index = 0;
        p->aCsr[i].keyAsData = 0;
        break;
      }

      /* Opcode: Close P1 * *
      **







|







 







>
>
>
>
>
>
>
|





|
>
>







 







>











>
|
|
|
>
|
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
|
>
>







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
...
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
....
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
** inplicit conversion from one type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.35 2000/07/28 14:32:50 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>

/*
** SQL is translated into a sequence of instructions to be
** executed by a virtual machine.  Each instruction is an instance
................................................................................
**
** A memory allocation error causes this routine to return SQLITE_NOMEM
** and abandon furture processing.
**
** Other fatal errors return SQLITE_ERROR.
**
** If a database file could not be opened because it is locked by
** 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(
  Vdbe *p,                   /* The VDBE */
  sqlite_callback xCallback, /* The callback */
  void *pArg,                /* 1st argument to callback */
  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 */
  Op *pOp;                   /* Current operation */
  int rc;                    /* Value to return */
  char zBuf[100];            /* Space to sprintf() and integer */

  p->tos = -1;
................................................................................
      ** automatically closed when the VDBE finishes execution.
      **
      ** If P3 is null or an empty string, a temporary database file
      ** is created.  This temporary database file is automatically 
      ** deleted when the cursor is closed.
      */
      case OP_Open: {
        int busy = 0;
        int i = pOp->p1;
        if( i<0 ) goto bad_instruction;
        if( i>=p->nCursor ){
          int j;
          p->aCsr = sqliteRealloc( p->aCsr, (i+1)*sizeof(Cursor) );
          if( p->aCsr==0 ){ p->nCursor = 0; goto no_mem; }
          for(j=p->nCursor; j<=i; j++) p->aCsr[j].pCursor = 0;
          p->nCursor = i+1;
        }else if( p->aCsr[i].pCursor ){
          sqliteDbbeCloseCursor(p->aCsr[i].pCursor);
        }
        do {
          rc = sqliteDbbeOpenCursor(p->pBe,pOp->p3,pOp->p2,&p->aCsr[i].pCursor);
          switch( rc ){
            case SQLITE_BUSY: {
              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;
            }
          }
        }while( busy );
        p->aCsr[i].index = 0;
        p->aCsr[i].keyAsData = 0;
        break;
      }

      /* Opcode: Close P1 * *
      **

Changes to src/vdbe.h.

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
...
183
184
185
186
187
188
189
190

191
192
193
194
195
196
197
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** or VDBE.  The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.10 2000/06/11 23:50:13 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines
................................................................................
int sqliteVdbeAddOp(Vdbe*,int,int,int,const char*,int);
int sqliteVdbeAddOpList(Vdbe*, int nOp, VdbeOp const *aOp);
void sqliteVdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
void sqliteVdbeDequoteP3(Vdbe*, int addr);
int sqliteVdbeMakeLabel(Vdbe*);
void sqliteVdbeDelete(Vdbe*);
int sqliteVdbeOpcode(const char *zName);
int sqliteVdbeExec(Vdbe*,sqlite_callback,void*,char**);

int sqliteVdbeList(Vdbe*,sqlite_callback,void*,char**);
void sqliteVdbeResolveLabel(Vdbe*, int);
int sqliteVdbeCurrentAddr(Vdbe*);
void sqliteVdbeTrace(Vdbe*,FILE*);


#endif







|







 







|
>







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** or VDBE.  The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.11 2000/07/28 14:32:50 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines
................................................................................
int sqliteVdbeAddOp(Vdbe*,int,int,int,const char*,int);
int sqliteVdbeAddOpList(Vdbe*, int nOp, VdbeOp const *aOp);
void sqliteVdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
void sqliteVdbeDequoteP3(Vdbe*, int addr);
int sqliteVdbeMakeLabel(Vdbe*);
void sqliteVdbeDelete(Vdbe*);
int sqliteVdbeOpcode(const char *zName);
int sqliteVdbeExec(Vdbe*,sqlite_callback,void*,char**,void*,
                   int(*)(void*,const char*,int));
int sqliteVdbeList(Vdbe*,sqlite_callback,void*,char**);
void sqliteVdbeResolveLabel(Vdbe*, int);
int sqliteVdbeCurrentAddr(Vdbe*);
void sqliteVdbeTrace(Vdbe*,FILE*);


#endif

Added test/lock.test.











































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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

Changes to www/c_interface.tcl.

1
2
3
4
5
6
7
8
9
10
11
..
18
19
20
21
22
23
24
25

26
27
28
29
30
31
32
..
38
39
40
41
42
43
44




45
46
47
48
49
50
51
...
220
221
222
223
224
225
226









































227
228
229
230
231
232
233
#
# 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 $}

puts {<html>
<head>
  <title>The C language interface to the SQLite library</title>
</head>
<body bgcolor=white>
<h1 align=center>
................................................................................
puts {
<p>The SQLite library is designed to be very easy to use from
a C or C++ program.  This document gives an overview of the C/C++
programming interface.</p>

<h2>The API</h2>

<p>The interface to the SQLite library consists of 4 functions,

one opaque data structure, and some constants used as return
values from sqlite_exec():</p>

<blockquote><pre>
typedef struct sqlite sqlite;

sqlite *sqlite_open(const char *filename, int mode, char **errmsg);
................................................................................
  char *sql,
  int (*)(void*,int,char**,char**),
  void*,
  char **errmsg
);

int sqlite_complete(const char *sql);





#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 */
................................................................................
function to know when it needs to call <b>sqlite_exec()</b>.  After each
line of input is received, <b>sqlite</b> calls <b>sqlite_complete()</b>
on all input in its buffer.  If <b>sqlite_complete()</b> returns true, 
then <b>sqlite_exec()</b> is called and the input buffer is reset.  If
<b>sqlite_complete()</b> returns false, then the prompt is changed to
the continuation prompt and another line of text is read and added to
the input buffer.</p>










































<h2>Usage Examples</h2>

<p>For examples of how the SQLite C/C++ interface can be used,
refer to the source code for the <b>sqlite</b> program in the
file <b>src/shell.c</b> of the source tree.
Additional information about sqlite is available at



|







 







|
>







 







>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
..
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
..
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
#
# Run this Tcl script to generate the sqlite.html file.
#
set rcsid {$Id: c_interface.tcl,v 1.6 2000/07/28 14:32:51 drh Exp $}

puts {<html>
<head>
  <title>The C language interface to the SQLite library</title>
</head>
<body bgcolor=white>
<h1 align=center>
................................................................................
puts {
<p>The SQLite library is designed to be very easy to use from
a C or C++ program.  This document gives an overview of the C/C++
programming interface.</p>

<h2>The API</h2>

<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
values from sqlite_exec():</p>

<blockquote><pre>
typedef struct sqlite sqlite;

sqlite *sqlite_open(const char *filename, int mode, char **errmsg);
................................................................................
  char *sql,
  int (*)(void*,int,char**,char**),
  void*,
  char **errmsg
);

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_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 */
................................................................................
function to know when it needs to call <b>sqlite_exec()</b>.  After each
line of input is received, <b>sqlite</b> calls <b>sqlite_complete()</b>
on all input in its buffer.  If <b>sqlite_complete()</b> returns true, 
then <b>sqlite_exec()</b> is called and the input buffer is reset.  If
<b>sqlite_complete()</b> returns false, then the prompt is changed to
the continuation prompt and another line of text is read and added to
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>

<p>For examples of how the SQLite C/C++ interface can be used,
refer to the source code for the <b>sqlite</b> program in the
file <b>src/shell.c</b> of the source tree.
Additional information about sqlite is available at

Changes to www/changes.tcl.

12
13
14
15
16
17
18





19
20
21
22
23
24
25
}


proc chng {date desc} {
  puts "<DT><B>$date</B></DT>"
  puts "<DD><P><UL>$desc</UL></P></DD>"
}






chng {2000 June 23} {
<li>Begin writing the <a href="vdbe.html">VDBE tutorial</a>.</li>
}

chng {2000 June 21} {
<li>Clean up comments and variable names.  Changes to documentation.







>
>
>
>
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
}


proc chng {date desc} {
  puts "<DT><B>$date</B></DT>"
  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} {
<li>Begin writing the <a href="vdbe.html">VDBE tutorial</a>.</li>
}

chng {2000 June 21} {
<li>Clean up comments and variable names.  Changes to documentation.

Changes to www/index.tcl.

1
2
3
4
5
6
7
8
9
10
11
..
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#
# 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 $}

puts {<html>
<head><title>SQLite: An SQL Database Engine Built Atop GDBM</title></head>
<body bgcolor=white>
<h1 align=center>SQLite: An SQL Database Engine Built Atop
<a href="http://www.gnu.org/software/gdbm/gdbm.html">GDBM</a></h1>
<p align=center>}
................................................................................
<p><ul>
<li>Implements most of SQL92.</li>
<li>A database is just a directory of GDBM files.</li>
<li>Unlimited length records.</li>
<li>Import and export data from 
<a href="http://www.postgresql.org/">PostgreSQL</a>.</li>
<li>Very simple 
<a href="c_interface.html">C/C++ interface</a> uses only
four functions and one opaque structure.</li>
<li>A <a href="http://dev.scriptics.com/">Tcl</a> interface is
included.</li>
<li>Command-line access program <a href="sqlite.html">sqlite</a> uses
the <a href="http://www.google.com/search?q=gnu+readline+library">GNU
Readline library</a></li>
<li>A Tcl-based test suite provides near 100% code coverage</li>
<li>7500+ lines of C code.  No external dependencies other than GDBM.</li>



|







 







|
|







1
2
3
4
5
6
7
8
9
10
11
..
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#
# Run this TCL script to generate HTML for the index.html file.
#
set rcsid {$Id: index.tcl,v 1.19 2000/07/28 14:32:51 drh Exp $}

puts {<html>
<head><title>SQLite: An SQL Database Engine Built Atop GDBM</title></head>
<body bgcolor=white>
<h1 align=center>SQLite: An SQL Database Engine Built Atop
<a href="http://www.gnu.org/software/gdbm/gdbm.html">GDBM</a></h1>
<p align=center>}
................................................................................
<p><ul>
<li>Implements most of SQL92.</li>
<li>A database is just a directory of GDBM files.</li>
<li>Unlimited length records.</li>
<li>Import and export data from 
<a href="http://www.postgresql.org/">PostgreSQL</a>.</li>
<li>Very simple 
<a href="c_interface.html">C/C++ interface</a> requires the use of only
three functions and one opaque structure.</li>
<li>A <a href="http://dev.scriptics.com/">Tcl</a> interface is
included.</li>
<li>Command-line access program <a href="sqlite.html">sqlite</a> uses
the <a href="http://www.google.com/search?q=gnu+readline+library">GNU
Readline library</a></li>
<li>A Tcl-based test suite provides near 100% code coverage</li>
<li>7500+ lines of C code.  No external dependencies other than GDBM.</li>

Changes to www/sqlite.tcl.

1
2
3
4
5
6
7
8
9
10
11
...
152
153
154
155
156
157
158

159
160
161
162
163
164
165
...
463
464
465
466
467
468
469







470
471
472
473
474
475
476
#
# 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 $}

puts {<html>
<head>
  <title>sqlite: A program of interacting with SQLite databases</title>
</head>
<body bgcolor=white>
<h1 align=center>
................................................................................
.mode MODE             Set mode to one of "line", "column", "list", or "html"
.mode insert TABLE     Generate SQL insert statements for TABLE
.output FILENAME       Send output to FILENAME
.output stdout         Send output to the screen
.schema ?TABLE?        Show the CREATE statements
.separator STRING      Change separator string for "list" mode
.tables                List names all tables in the database

.width NUM NUM ...     Set column widths for "column" mode
sqlite> 
}

puts {
<h2>Changing Output Formats</h2>

................................................................................
11    ListRead      0      14                 
12    Delete        0      0                  
13    Goto          0      11                 
14    ListClose     0      0                  
}

puts {







<p>And finally, we mention the ".exit" command which causes the
sqlite program to exit.</p>

<h2>Using sqlite in a shell script</h2>

<p>
One way to use sqlite in a shell script is to use "echo" or



|







 







>







 







>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
...
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
#
# Run this Tcl script to generate the sqlite.html file.
#
set rcsid {$Id: sqlite.tcl,v 1.11 2000/07/28 14:32:51 drh Exp $}

puts {<html>
<head>
  <title>sqlite: A program of interacting with SQLite databases</title>
</head>
<body bgcolor=white>
<h1 align=center>
................................................................................
.mode MODE             Set mode to one of "line", "column", "list", or "html"
.mode insert TABLE     Generate SQL insert statements for TABLE
.output FILENAME       Send output to FILENAME
.output stdout         Send output to the screen
.schema ?TABLE?        Show the CREATE statements
.separator STRING      Change separator string for "list" mode
.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
sqlite> 
}

puts {
<h2>Changing Output Formats</h2>

................................................................................
11    ListRead      0      14                 
12    Delete        0      0                  
13    Goto          0      11                 
14    ListClose     0      0                  
}

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
sqlite program to exit.</p>

<h2>Using sqlite in a shell script</h2>

<p>
One way to use sqlite in a shell script is to use "echo" or

Changes to www/vdbe.tcl.

1
2
3
4
5
6
7
8
9
10
11
...
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
...
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
#
# 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 $}

puts {<html>
<head>
  <title>The Virtual Database Engine of SQLite</title>
</head>
<body bgcolor=white>
<h1 align=center>
................................................................................
"sqlite_master" table, at least from the point of view of the VDBE.
The sqlite_master table is a special table that is automatically
created for every SQLite database.  It looks like this:</p>

<blockquote><pre>
CREATE TABLE sqlite_master (
  type      TEXT,    -- either "table" or "index"
  name      TEXT,    -- name of the table or index
  tbl_name  TEXT,    -- for indices: name of associated table
  sql       TEXT     -- SQL text of the original CREATE statement
)
</pre></blockquote>

<p>Every table (except the "sqlite_master" table itself)
and every named index in an SQLite database has an entry
................................................................................
<p>But from the point of view of the VDBE, a CREATE works
pretty much like an INSERT and a DROP works like a DELETE.
When the SQLite library opens to an existing database,
the first thing it does is a SELECT to read the "sql"
columns from all entries of the sqlite_master table.
The "sql" column contains the complete SQL text of the
CREATE statement that originally generated the index or
table.  This text is fed back into the SQLite parse
and used to reconstruct the
internal data structures describing the index or table.</p>

<h2>Using Indexes To Speed Searches</h2>
<i>TBD</i>
<h2>Joins</h2>
<i>TBD</i>



|







 







|







 







|







1
2
3
4
5
6
7
8
9
10
11
...
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
...
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
#
# Run this Tcl script to generate the vdbe.html file.
#
set rcsid {$Id: vdbe.tcl,v 1.4 2000/07/28 14:32:51 drh Exp $}

puts {<html>
<head>
  <title>The Virtual Database Engine of SQLite</title>
</head>
<body bgcolor=white>
<h1 align=center>
................................................................................
"sqlite_master" table, at least from the point of view of the VDBE.
The sqlite_master table is a special table that is automatically
created for every SQLite database.  It looks like this:</p>

<blockquote><pre>
CREATE TABLE sqlite_master (
  type      TEXT,    -- either "table" or "index"
  name      TEXT,    -- name of this table or index
  tbl_name  TEXT,    -- for indices: name of associated table
  sql       TEXT     -- SQL text of the original CREATE statement
)
</pre></blockquote>

<p>Every table (except the "sqlite_master" table itself)
and every named index in an SQLite database has an entry
................................................................................
<p>But from the point of view of the VDBE, a CREATE works
pretty much like an INSERT and a DROP works like a DELETE.
When the SQLite library opens to an existing database,
the first thing it does is a SELECT to read the "sql"
columns from all entries of the sqlite_master table.
The "sql" column contains the complete SQL text of the
CREATE statement that originally generated the index or
table.  This text is fed back into the SQLite parser
and used to reconstruct the
internal data structures describing the index or table.</p>

<h2>Using Indexes To Speed Searches</h2>
<i>TBD</i>
<h2>Joins</h2>
<i>TBD</i>