Index: VERSION
==================================================================
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
-1.0.10
+1.0.11
Index: src/build.c
==================================================================
--- src/build.c
+++ src/build.c
@@ -31,11 +31,11 @@
** DROP INDEX
** creating expressions and ID lists
** COPY
** VACUUM
**
-** $Id: build.c,v 1.23 2000/08/03 15:09:20 drh Exp $
+** $Id: build.c,v 1.24 2000/10/16 22:06:42 drh Exp $
*/
#include "sqliteInt.h"
/*
** This routine is called after a single SQL statement has been
@@ -46,24 +46,26 @@
**
** Note that if an error occurred, it might be the case that
** no VDBE code was generated.
*/
void sqliteExec(Parse *pParse){
+ int rc = SQLITE_OK;
if( pParse->pVdbe ){
if( pParse->explain ){
- sqliteVdbeList(pParse->pVdbe, pParse->xCallback, pParse->pArg,
- &pParse->zErrMsg);
+ rc = 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);
+ rc = sqliteVdbeExec(pParse->pVdbe, pParse->xCallback, pParse->pArg,
+ &pParse->zErrMsg, pParse->db->pBusyArg,
+ pParse->db->xBusyCallback);
}
sqliteVdbeDelete(pParse->pVdbe);
pParse->pVdbe = 0;
pParse->colNamesSet = 0;
+ pParse->rc = rc;
}
}
/*
** Construct a new expression node and return a pointer to it.
Index: src/main.c
==================================================================
--- src/main.c
+++ src/main.c
@@ -24,11 +24,11 @@
** 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.19 2000/10/11 19:28:52 drh Exp $
+** $Id: main.c,v 1.20 2000/10/16 22:06:42 drh Exp $
*/
#include "sqliteInt.h"
/*
** This is the callback routine for the code that initializes the
@@ -152,11 +152,11 @@
};
/* Create a virtual machine to run the initialization program. Run
** the program. The delete the virtual machine.
*/
- vdbe = sqliteVdbeCreate(db->pBe);
+ vdbe = sqliteVdbeCreate(db);
if( vdbe==0 ){
sqliteSetString(pzErrMsg, "out of memory",0);
return 1;
}
sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg);
@@ -225,11 +225,11 @@
/* Attempt to read the schema */
rc = sqliteInit(db, pzErrMsg);
if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
sqlite_close(db);
return 0;
- }else{
+ }else /* if( pzErrMsg ) */{
free(*pzErrMsg);
*pzErrMsg = 0;
}
return db;
}
@@ -309,13 +309,12 @@
}
memset(&sParse, 0, sizeof(sParse));
sParse.db = db;
sParse.xCallback = xCallback;
sParse.pArg = pArg;
- rc = sqliteRunParser(&sParse, zSql, pzErrMsg);
- sqliteStrRealloc(pzErrMsg);
- return rc;
+ sqliteRunParser(&sParse, zSql, pzErrMsg);
+ return sParse.rc;
}
/*
** This routine implements a busy callback that sleeps and tries
** again until a timeout value is reached. The timeout value is
@@ -380,5 +379,12 @@
sqlite_busy_handler(db, sqlite_default_busy_callback, (void*)ms);
}else{
sqlite_busy_handler(db, 0, 0);
}
}
+
+/*
+** Cause any pending operation to stop at its earliest opportunity.
+*/
+void sqlite_interrupt(sqlite *db){
+ db->flags |= SQLITE_Interrupt;
+}
Index: src/select.c
==================================================================
--- src/select.c
+++ src/select.c
@@ -22,11 +22,11 @@
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle SELECT statements.
**
-** $Id: select.c,v 1.26 2000/07/29 13:06:59 drh Exp $
+** $Id: select.c,v 1.27 2000/10/16 22:06:42 drh Exp $
*/
#include "sqliteInt.h"
/*
** Allocate a new Select structure and return a pointer to that
@@ -422,11 +422,11 @@
** If an error occurs, return NULL and leave a message in pParse.
*/
Vdbe *sqliteGetVdbe(Parse *pParse){
Vdbe *v = pParse->pVdbe;
if( v==0 ){
- v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+ v = pParse->pVdbe = sqliteVdbeCreate(pParse->db);
}
if( v==0 ){
sqliteSetString(&pParse->zErrMsg, "out of memory", 0);
pParse->nErr++;
}
@@ -816,11 +816,11 @@
/* Begin generating code.
*/
v = pParse->pVdbe;
if( v==0 ){
- v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+ v = pParse->pVdbe = sqliteVdbeCreate(pParse->db);
}
if( v==0 ){
sqliteSetString(&pParse->zErrMsg, "out of memory", 0);
pParse->nErr++;
return 1;
Index: src/shell.c
==================================================================
--- src/shell.c
+++ src/shell.c
@@ -22,27 +22,37 @@
**
*************************************************************************
** This file contains code to implement the "sqlite" command line
** utility for accessing SQLite databases.
**
-** $Id: shell.c,v 1.26 2000/10/08 22:20:58 drh Exp $
+** $Id: shell.c,v 1.27 2000/10/16 22:06:42 drh Exp $
*/
#include
#include
#include
#include "sqlite.h"
#include
#include
+#ifdef OS_UNIX
+# include
+#endif
#if defined(HAVE_READLINE) && HAVE_READLINE==1
# include
# include
#else
# define readline getline
# define add_history(X)
#endif
+/*
+** The following is the open SQLite database. We make a pointer
+** to this database a static variable so that it can be accessed
+** by the SIGINT handler to interrupt database processing.
+*/
+static sqlite *db = 0;
+
/*
** This routine reads a line of text from standard input, stores
** the text in memory obtained from malloc() and returns a pointer
** to the text. NULL is returned at end of file, or if malloc()
** fails.
@@ -226,10 +236,17 @@
break;
}
z += i + 1;
}
}
+
+/*
+** This routine runs when the user presses Ctrl-C
+*/
+static void interrupt_handler(int NotUsed){
+ if( db ) sqlite_interrupt(db);
+}
/*
** This is the callback routine that the SQLite library
** invokes for each row of a query result.
*/
@@ -445,11 +462,10 @@
/* Process the input line.
*/
if( nArg==0 ) return;
n = strlen(azArg[0]);
c = azArg[0][0];
-
if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
char *zErrMsg = 0;
if( nArg==1 ){
sqlite_exec(db,
"SELECT name, type, sql FROM sqlite_master "
@@ -667,19 +683,21 @@
azArg[0]);
}
}
int main(int argc, char **argv){
- sqlite *db;
char *zErrMsg = 0;
char *argv0 = argv[0];
struct callback_data data;
memset(&data, 0, sizeof(data));
data.mode = MODE_List;
strcpy(data.separator,"|");
data.showHeader = 0;
+#ifdef SIGINT
+ signal(SIGINT, interrupt_handler);
+#endif
while( argc>=2 && argv[1][0]=='-' ){
if( strcmp(argv[1],"-html")==0 ){
data.mode = MODE_Html;
argc--;
argv++;
Index: src/sqlite.h.in
==================================================================
--- src/sqlite.h.in
+++ src/sqlite.h.in
@@ -22,11 +22,11 @@
**
*************************************************************************
** This header file defines the interface that the sqlite library
** presents to client programs.
**
-** @(#) $Id: sqlite.h.in,v 1.5 2000/10/09 12:57:01 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.6 2000/10/16 22:06:42 drh Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
#include /* Needed for the definition of va_list */
@@ -128,17 +128,27 @@
/*
** Return values for sqlite_exec()
*/
#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_ERROR 1 /* SQL error or missing database */
+#define SQLITE_INTERNAL 2 /* An internal logic error in SQLite */
#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 */
+#define SQLITE_INTERRUPT 8 /* Operation terminated by sqlite_interrupt() */
+
+/* This function causes any pending database operation to abort and
+** return at its earliest opportunity. This routine is typically
+** called in response to a user include such as pressing "Cancel"
+** or Ctrl-C where the user wants a long query operation to halt
+** immediately.
+*/
+void sqlite_interrupt(sqlite*);
+
/* 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
Index: src/sqliteInt.h
==================================================================
--- src/sqliteInt.h
+++ src/sqliteInt.h
@@ -21,11 +21,11 @@
** http://www.hwaci.com/drh/
**
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.30 2000/08/28 15:51:44 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.31 2000/10/16 22:06:42 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
#include "vdbe.h"
#include "parse.h"
@@ -133,12 +133,13 @@
};
/*
** Possible values for the sqlite.flags.
*/
-#define SQLITE_VdbeTrace 0x00000001
-#define SQLITE_Initialized 0x00000002
+#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
+#define SQLITE_Initialized 0x00000002 /* True after initialization */
+#define SQLITE_Interrupt 0x00000004 /* Cancel current operation */
/*
** Current file format version
*/
#define SQLITE_FileFormat 2
@@ -323,10 +324,11 @@
/*
** An SQL parser context
*/
struct Parse {
sqlite *db; /* The main database structure */
+ int rc; /* Return code from execution */
sqlite_callback xCallback; /* The callback function */
void *pArg; /* First argument to the callback function */
char *zErrMsg; /* An error message */
Token sErrToken; /* The token at which the error occurred */
Token sFirstToken; /* The first token parsed */
Index: src/tokenize.c
==================================================================
--- src/tokenize.c
+++ src/tokenize.c
@@ -25,11 +25,11 @@
**
** This file contains C code that splits an SQL input string up into
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
-** $Id: tokenize.c,v 1.13 2000/08/09 17:17:25 drh Exp $
+** $Id: tokenize.c,v 1.14 2000/10/16 22:06:42 drh Exp $
*/
#include "sqliteInt.h"
#include
#include
@@ -296,11 +296,11 @@
return 1;
}
/*
** Run the parser on the given SQL string. The parser structure is
-** passed in. Return the number of errors.
+** passed in. An SQLITE_ status code.
*/
int sqliteRunParser(Parse *pParse, char *zSql, char **pzErrMsg){
int nErr = 0;
int i;
void *pEngine;
@@ -309,10 +309,12 @@
extern void *sqliteParserAlloc(void*(*)(int));
extern void sqliteParserFree(void*, void(*)(void*));
extern int sqliteParser(void*, int, ...);
extern void sqliteParserTrace(FILE*, char *);
+ pParse->db->flags &= ~SQLITE_Interrupt;
+ pParse->rc = SQLITE_OK;
i = 0;
sqliteParseInfoReset(pParse);
pEngine = sqliteParserAlloc((void*(*)(int))malloc);
if( pEngine==0 ){
sqliteSetString(pzErrMsg, "out of memory", 0);
@@ -320,10 +322,15 @@
}
sqliteParserTrace(trace, "parser: ");
while( nErr==0 && i>=0 && zSql[i]!=0 ){
int tokenType;
+ if( (pParse->db->flags & SQLITE_Interrupt)!=0 ){
+ pParse->rc = SQLITE_INTERRUPT;
+ sqliteSetString(pzErrMsg, "interrupt", 0);
+ break;
+ }
pParse->sLastToken.z = &zSql[i];
pParse->sLastToken.n = sqliteGetToken(&zSql[i], &tokenType);
i += pParse->sLastToken.n;
if( once ){
pParse->sFirstToken = pParse->sLastToken;
@@ -389,11 +396,11 @@
pParse->zErrMsg = 0;
}
break;
}
}
- if( nErr==0 ){
+ if( nErr==0 && (pParse->db->flags & SQLITE_Interrupt)==0 ){
sqliteParser(pEngine, 0, pParse->sLastToken, pParse);
if( pParse->zErrMsg && pParse->sErrToken.z ){
sqliteSetNString(pzErrMsg, "near \"", -1,
pParse->sErrToken.z, pParse->sErrToken.n,
"\": ", -1,
@@ -421,7 +428,11 @@
if( pParse->pNewTable ){
sqliteDeleteTable(pParse->db, pParse->pNewTable);
pParse->pNewTable = 0;
}
sqliteParseInfoReset(pParse);
+ sqliteStrRealloc(pzErrMsg);
+ if( nErr>0 && pParse->rc==SQLITE_OK ){
+ pParse->rc = SQLITE_ERROR;
+ }
return nErr;
}
Index: src/vdbe.c
==================================================================
--- src/vdbe.c
+++ src/vdbe.c
@@ -39,11 +39,11 @@
** 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.42 2000/10/11 19:28:53 drh Exp $
+** $Id: vdbe.c,v 1.43 2000/10/16 22:06:43 drh Exp $
*/
#include "sqliteInt.h"
#include
#include
@@ -167,10 +167,11 @@
/*
** An instance of the virtual machine
*/
struct Vdbe {
+ sqlite *db; /* The whole database */
Dbbe *pBe; /* Opaque context structure used by DB backend */
FILE *trace; /* Write an execution trace here, if not NULL */
int nOp; /* Number of instructions in the program */
int nOpAlloc; /* Number of slots allocated for aOp[] */
Op *aOp; /* Space to hold the virtual machine's program */
@@ -202,15 +203,16 @@
};
/*
** Create a new virtual database engine.
*/
-Vdbe *sqliteVdbeCreate(Dbbe *pBe){
+Vdbe *sqliteVdbeCreate(sqlite *db){
Vdbe *p;
p = sqliteMalloc( sizeof(Vdbe) );
- p->pBe = pBe;
+ p->pBe = db->pBe;
+ p->db = db;
return p;
}
/*
** Turn tracing on or off
@@ -834,10 +836,16 @@
azValue[3] = zP2;
azValue[5] = 0;
rc = SQLITE_OK;
/* if( pzErrMsg ){ *pzErrMsg = 0; } */
for(i=0; rc==SQLITE_OK && inOp; i++){
+ if( p->db->flags & SQLITE_Interrupt ){
+ p->db->flags &= ~SQLITE_Interrupt;
+ sqliteSetString(pzErrMsg, "interrupted", 0);
+ rc = SQLITE_INTERRUPT;
+ break;
+ }
sprintf(zAddr,"%d",i);
sprintf(zP1,"%d", p->aOp[i].p1);
sprintf(zP2,"%d", p->aOp[i].p2);
azValue[4] = p->aOp[i].p3;
azValue[1] = zOpName[p->aOp[i].opcode];
@@ -926,10 +934,19 @@
}
#endif
/* if( pzErrMsg ){ *pzErrMsg = 0; } */
for(pc=0; rc==SQLITE_OK && pcnOp && pc>=0; pc++){
pOp = &p->aOp[pc];
+
+ /* Interrupt processing if requested.
+ */
+ if( p->db->flags & SQLITE_Interrupt ){
+ p->db->flags &= ~SQLITE_Interrupt;
+ rc = SQLITE_INTERRUPT;
+ sqliteSetString(pzErrMsg, "interrupted", 0);
+ break;
+ }
/* Only allow tracing if NDEBUG is not defined.
*/
#ifndef NDEBUG
if( p->trace ){
Index: src/vdbe.h
==================================================================
--- src/vdbe.h
+++ src/vdbe.h
@@ -25,11 +25,11 @@
**
** 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.13 2000/10/11 19:28:53 drh Exp $
+** $Id: vdbe.h,v 1.14 2000/10/16 22:06:43 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include
@@ -180,11 +180,11 @@
/*
** Prototypes for the VDBE interface. See comments on the implementation
** for a description of what each of these routines does.
*/
-Vdbe *sqliteVdbeCreate(Dbbe*);
+Vdbe *sqliteVdbeCreate(sqlite*);
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*);
Index: test/dbbe.test
==================================================================
--- test/dbbe.test
+++ test/dbbe.test
@@ -21,11 +21,11 @@
#
#***********************************************************************
# This file implements regression tests for SQLite library. The
# focus of this file is exercising the code in dbbe.c.
#
-# $Id: dbbe.test,v 1.3 2000/08/17 09:50:00 drh Exp $
+# $Id: dbbe.test,v 1.4 2000/10/16 22:06:43 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Try to open a database that does not exist.
@@ -128,9 +128,9 @@
execsql {CREATE TABLE t1(x int)}
db close
sqlite db testdb 0444
set v [catch {execsql {INSERT INTO t1 VALUES(1)}} msg]
lappend v $msg
-} {1 {table t1 is readonly}}
+} {7 {table t1 is readonly}}
finish_test
Index: test/lock.test
==================================================================
--- test/lock.test
+++ test/lock.test
@@ -21,11 +21,11 @@
#
#***********************************************************************
# This file implements regression tests for SQLite library. The
# focus of this script is database locks.
#
-# $Id: lock.test,v 1.2 2000/08/04 13:51:11 drh Exp $
+# $Id: lock.test,v 1.3 2000/10/16 22:06:43 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -57,11 +57,11 @@
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}}
+} {5 {table big is locked}}
do_test lock-1.3 {
# Try to update the database in a separate process
#
set f [open update.sql w]
Index: www/c_interface.tcl
==================================================================
--- www/c_interface.tcl
+++ www/c_interface.tcl
@@ -1,9 +1,9 @@
#
# Run this Tcl script to generate the sqlite.html file.
#
-set rcsid {$Id: c_interface.tcl,v 1.10 2000/10/09 12:57:01 drh Exp $}
+set rcsid {$Id: c_interface.tcl,v 1.11 2000/10/16 22:06:43 drh Exp $}
puts {
The C language interface to the SQLite library
@@ -65,10 +65,12 @@
int *ncolumn,
char **errmsg
);
void sqlite_free_table(char**);
+
+void sqlite_interrupt(sqlite*);
int sqlite_complete(const char *sql);
void sqlite_busy_handler(sqlite*, int (*)(void*,const char*,int), void*);
@@ -261,10 +263,14 @@
This return code indicates that an attempt was made to write to
a database file that was originally opened for reading only. This can
happen if the callback from a query attempts to update the table
being queried.
+SQLITE_INTERRUPT
+This value is returned if a call to sqlite_interrupt()
+interrupts a database operation in progress.
+
Querying without using a callback function
@@ -315,10 +321,18 @@
to sqlite_free_table() when the table is no longer needed.
The sqlite_get_table() routine returns the same integer
result code as sqlite_exec().
+Interrupting an SQLite operation
+
+The sqlite_interrupt() function can be called from a
+different thread or from a signal handler to the current database
+operation to exit at its first opportunity. When this happens,
+the sqlite_exec() routine (or the equivalent) that started
+the database operation will return SQLITE_INTERRUPT.
+
Testing for a complete SQL statement
The next interface routine to SQLite is a convenience function used
to test whether or not a string forms a complete SQL statement.
If the sqlite_complete() function returns true when its input
Index: www/changes.tcl
==================================================================
--- www/changes.tcl
+++ www/changes.tcl
@@ -15,11 +15,18 @@
proc chng {date desc} {
puts "
$date"
puts ""
}
-chng {2000 Oct 11 (Not Released)} {
+chng {2000 Oct 16 (1.0.11)
+Added the sqlite_interrupt() interface.
+In the shell, sqlite_interrupt() is invoked when the
+ user presses Control-C
+Fixed bugs in the return value of sqlite_exec().
+}
+
+chng {2000 Oct 11 (1.0.10)
Added notes on how to compile for Windows95/98.
Add Doug Lea's memory allocator to the distribution, for completeness.
Removed a few variables that were not being used. Etc.
}