From 960e8c6317c3550faa1dab181a473d611f2fe378 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 3 Apr 2001 16:53:21 +0000 Subject: [PATCH] Bug fixes from Oleg Oleinick (CVS 195) FossilOrigin-Name: 1f0197d504fa2bde15b287ac6c0102cacdb1e482 --- Makefile.in | 3 +- VERSION | 2 +- manifest | 37 +++++++++++---------- manifest.uuid | 2 +- src/dbbe.h | 18 +++++----- src/dbbegdbm.c | 7 ++-- src/dbbemem.c | 6 ++-- src/pager.h | 56 +++++++++++++++++++++++++++++++ src/sqlite.h.in | 4 ++- src/tclsqlite.c | 15 +++++++-- src/test.file | 1 - test/dbbe.test | 4 +-- test/lock.test | 4 +-- test/tclsqlite.test | 80 +++++++++++++++++++++++++++++++++++++++++++++ tool/lemon.c | 57 +++++++++++++++++++++++++------- tool/lempar.c | 32 ++++++++++-------- www/changes.tcl | 6 ++++ 17 files changed, 266 insertions(+), 68 deletions(-) create mode 100644 src/pager.h delete mode 100644 src/test.file create mode 100644 test/tclsqlite.test diff --git a/Makefile.in b/Makefile.in index b8d5f839c4..113efaa354 100644 --- a/Makefile.in +++ b/Makefile.in @@ -56,9 +56,8 @@ LIBOBJ = build.o dbbe.o dbbegdbm.o dbbemem.o delete.o expr.o insert.o \ SRC = \ $(TOP)/src/build.c \ $(TOP)/src/dbbe.c \ - $(TOP)/src/dbbegdbm.c \ - $(TOP)/src/dbbemem.c \ $(TOP)/src/dbbe.h \ + $(TOP)/src/dbbegdbm.c \ $(TOP)/src/dbbemem.c \ $(TOP)/src/delete.c \ $(TOP)/src/expr.c \ diff --git a/VERSION b/VERSION index adb7b04cb2..8b54409523 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.27 +1.0.28 diff --git a/manifest b/manifest index c48e1a771f..5d1dd7e794 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Version\s1.0.27\s(CVS\s476) -D 2001-03-20T22:15:00 +C Bug\sfixes\sfrom\sOleg\sOleinick\s(CVS\s195) +D 2001-04-03T16:53:22 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4 -F Makefile.in 7efa81e2985b45ba73db27d55b70cc927f5abfd7 +F Makefile.in fd8815aa01a7181f60f786158b7737a35413189e F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958 -F VERSION dee81fa1259d8cbb43230e982a9392f11f89859d +F VERSION 010a68e4026cf015511e2c5acc54815fa374d11b F configure 3dc1edb9dcf60215e31ff72b447935ab62211442 x F configure.in d892ca33db7e88a055519ce2f36dcb11020e8fff F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47 @@ -11,9 +11,9 @@ F doc/report1.txt 734cbae63b1310cc643fe5e9e3da1ab55a79b99e F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4 F src/build.c 7aa5879bf58ea6bbff22c26c59d1130021fa6ca4 F src/dbbe.c b178f0959f6bac5ef8a109484c1571053f31abe5 -F src/dbbe.h 57d6debb99f6d7a91364b73cf3f0b129058ebbb3 -F src/dbbegdbm.c 84b2bf31d220f1de1cb0507ea051d30128fd681b -F src/dbbemem.c d0fb86f1e8a52cdb195dc91d07f43765cf48bb95 +F src/dbbe.h 4b33f0cf884dfab49e39a422b2dcaf7a2a0e626c +F src/dbbegdbm.c c4b2857e242ff8b4e8a5ac2d95e2e35f462ce8eb +F src/dbbemem.c f0007eff4a00f28126c093f37f8e7dd2fcaa123b F src/delete.c 7aa9dcb86d5e98c3eb9dee00a459e0ef9b73fbe3 F src/ex/README b745b00acce2d892f60c40111dacdfc48e0c1c7a F src/ex/db.c f1419ae6c93e40b5ac6e39fe7efd95d868e6f9d7 @@ -26,17 +26,17 @@ F src/ex/sizes.tcl f54bad4a2ac567624be59131a6ee42d71b41a3d7 F src/expr.c 49bc261fdc4f4fb91c74cd668a9a952c00e85931 F src/insert.c 4bc1cab84f7805d560a1417734a532843e30b762 F src/main.c 5afe29c425b875acede20f609485866eb5b276f6 +F src/pager.h 889c5cf517ad30704e295540793c893ac843fd5f F src/parse.y 25ee4d8efccc4b247c32fe4ab194e3dd8fd5a4ee F src/printf.c af0dc65c293427272e1949c7807b1d88f10004fd F src/random.c b36c3f57dc80c8f354e6bfbf39cf1e1de021d54a F src/select.c faac634ef0c717bc82ca112a4531a257886f2c7a F src/shell.c 441e20913cde0bb71281f4027623c623530241cd F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e -F src/sqlite.h.in 7c1a53f020418d89d13ed2fe9c477ff54540755d +F src/sqlite.h.in 3b446fcbed6005f0ab89632f3356c4708b349e88 F src/sqliteInt.h 9887d207b98362392668410a11c59b3e334f51a1 F src/table.c 5be76051a8ed6f6bfa641f4adc52529efa34fbf9 -F src/tclsqlite.c 2a925e1835c348f07dd17c87d95ae9a577833407 -F src/test.file 55ca6286e3e4f4fba5d0448333fa99fc5a404a73 +F src/tclsqlite.c f654b0399ea8a29262637dbe71fdfe7c26bd9032 F src/tokenize.c c7ad428f38e56342eb2025320480b5ae9ece1b90 F src/update.c 8365b3922ea098330d1e20862d6e64911e4e03d0 F src/util.c f4573201fc2b581dbf601c53787349310b7da150 @@ -45,7 +45,7 @@ F src/vdbe.h 031b7dd7d6f94c51dc37cdf26efe43d1619bb672 F src/where.c 478fde7c930969ca428de2d80b137959d25ee2fb F test/all.test 15cac2f6b2d4c55bf896212aff3cc9d6597b0490 F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb -F test/dbbe.test 03a6940807f8a1e7538897b4c802a7937677e053 +F test/dbbe.test a022fe2d983848f786e17ef1fc6809cfd37fb02c F test/delete.test 50b9b1f06c843d591741dba7869433a105360dbf F test/expr.test 48273bf48a15d226c35829f702af4254c0ff6795 F test/func.test 02aed8845b98bde1043dda97455de1d37238ebb3 @@ -53,7 +53,7 @@ F test/in.test 2c560c0f55fb777029fd9bb5378f2997582aa603 F test/index.test ee060ef8912be47ba616e50cce7985259a68d58a F test/insert.test 66f4c3bd600fec8eb1e733b928cbe6fa885eff0c F test/insert2.test 732405e30331635af8d159fccabe835eea5cd0c6 -F test/lock.test d8f0fc54f2a88969368c15490ea82811e2d7dd37 +F test/lock.test bca7d53de73138b1f670a2fbdb1f481ff7eaa45a F test/main.test 5b0ed3d586c15b9136b9fd4916dcc95086639387 F test/select1.test 68ff778c24fc8982e63dda37acb5b0396913adf7 F test/select2.test 04ac3bd69298f58c7d0883159bab42ab9ad6021c @@ -63,14 +63,15 @@ F test/select5.test e2b9d51d88cbd6c307c2c05b0ef55fe7ba811ac2 F test/sort.test d582086c4bb7df3fbf50aa72e69d7e235e9f8e31 F test/subselect.test bf8b251a92fb091973c1c469ce499dc9648a41d5 F test/table.test eaa25951c0f18615763cd3dc248ea4bc38739c05 +F test/tclsqlite.test d2aa55926874783b2401f0146e839f773c6796e1 F test/tester.tcl 01f881142be3bd8713abcea06747652067dafb78 F test/update.test 72c0c93310483b86dc904a992220c5b84c7ce100 F test/vacuum.test b95d8119a0a83dc6c4ac63888f8872f06199e065 F test/where.test bbab5a308055fb6087dc23d600b4ad2b72797397 F tool/gdbmdump.c 529e67c78d920606ba196326ea55b57b75fcc82b F tool/gdbmstat.c 56a9033531e5f5a48413f6ec436d5fb0341632c1 -F tool/lemon.c b13a31798574af881753d38f4da7d505929259c3 -F tool/lempar.c a1eec94d6eacc12332368660ec65f3b248853833 +F tool/lemon.c e007bfdbc79a51a4cd7c8a5f81f517cebd121150 +F tool/lempar.c 943b476d44b319eed525e46bb29e15f2c5986b37 F tool/memleak.awk a0a11dd84bf4582acc81c3c61271021ae49b3f15 F tool/opNames.awk 2bd9071a138e4e2be13dc98fe066398a61219e1e F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c @@ -80,7 +81,7 @@ F www/arch.fig 4f246003b7da23bd63b8b0af0618afb4ee3055c8 F www/arch.png 8dae0766d42ed3de9ed013c1341a5792bcf633e6 F www/arch.tcl a40380c1fe0080c43e6cc5c20ed70731511b06be F www/c_interface.tcl 11be2d5826eb7d6efd629751d3b483c1ed78ba14 -F www/changes.tcl e01a5257038fafe0302b629d1b278789409029d2 +F www/changes.tcl 1be73dbd1d45471fdef05f627e8332206768f179 F www/crosscompile.tcl c99efacb3aefaa550c6e80d91b240f55eb9fd33e F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c F www/fileformat.tcl cfb7fba80b7275555281ba2f256c00734bcdd1c9 @@ -91,7 +92,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2 F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad -P daea156e2430762e683ff5460f9f8bb3204ae168 -R e053fcd301655951022cbe2ddba947b1 +P 833291c22734b2ac2342da84710320eb28f5d8cc +R b3979afeb1b2a68085466c778c74b02f U drh -Z ad447a72b5a7a06ad29b2399f5aa6480 +Z ceda48d7a4b9b3c738f23f47b38664dd diff --git a/manifest.uuid b/manifest.uuid index c719651356..d89cf8b8eb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -833291c22734b2ac2342da84710320eb28f5d8cc \ No newline at end of file +1f0197d504fa2bde15b287ac6c0102cacdb1e482 \ No newline at end of file diff --git a/src/dbbe.h b/src/dbbe.h index 6a386adf9a..31c6252f5c 100644 --- a/src/dbbe.h +++ b/src/dbbe.h @@ -28,7 +28,7 @@ ** This library was originally designed to support the following ** backends: GDBM, NDBM, SDBM, Berkeley DB. ** -** $Id: dbbe.h,v 1.11 2001/03/20 22:05:00 drh Exp $ +** $Id: dbbe.h,v 1.12 2001/04/03 16:53:22 drh Exp $ */ #ifndef _SQLITE_DBBE_H_ #define _SQLITE_DBBE_H_ @@ -75,18 +75,19 @@ struct DbbeMethods { /* Close the whole database. */ void (*Close)(Dbbe*); - /* Open a cursor into particular file of a previously opened database. - ** Create the file if it doesn't already exist and writeable!=0. zName - ** is the base name of the file to be opened. This routine will add - ** an appropriate path and extension to the filename to locate the + /* Open a cursor into a particular table of a previously opened database. + ** Create the table if it doesn't already exist and writeable!=0. zName + ** is the base name of the table to be opened. If the database is + ** implement as one file per table, then this routine will add an + ** appropriate path and extension to the table name to locate the ** actual file. ** - ** The keyType parameter is TRUE if this table will only be accessed + ** The intKeyOnly parameter is TRUE if this table will only be accessed ** using integer keys. This parameter allows the database backend to ** use a faster algorithm for the special case of integer keys, if it ** wants to. ** - ** If zName is 0 or "", then a temporary file is created that + ** If zName is 0 or "", then a temporary table is created that ** will be deleted when closed. */ int (*OpenCursor)(Dbbe*, const char *zName, int writeable, @@ -165,7 +166,8 @@ struct DbbeMethods { struct Dbbe { struct DbbeMethods *x; /* Backend-specific methods for database access */ /* There used to be other information here, but it has since - ** been removed. */ + ** been removed. We'll keep the same design, though, in case we + ** ever want to add some new fields in the future. */ }; #endif /* defined(_SQLITE_DBBE_H_) */ diff --git a/src/dbbegdbm.c b/src/dbbegdbm.c index 777c7dacef..8aba06b32f 100644 --- a/src/dbbegdbm.c +++ b/src/dbbegdbm.c @@ -30,7 +30,7 @@ ** relatively simple to convert to a different database such ** as NDBM, SDBM, or BerkeleyDB. ** -** $Id: dbbegdbm.c,v 1.4 2001/03/20 22:05:00 drh Exp $ +** $Id: dbbegdbm.c,v 1.5 2001/04/03 16:53:22 drh Exp $ */ #include "sqliteInt.h" #include @@ -46,6 +46,9 @@ ** for a self-join, for example) then two DbbeCursor structures are ** created but there is only a single BeFile structure with an ** nRef of 2. +** +** This backend uses a separate disk file for each database table +** and index. */ typedef struct BeFile BeFile; struct BeFile { @@ -545,7 +548,7 @@ static int sqliteGdbmDelete(DbbeCursor *pCursr, int nKey, char *pKey){ ** used to implement the GDBM backend. */ static struct DbbeMethods gdbmMethods = { - /* n Close */ sqliteGdbmClose, + /* Close */ sqliteGdbmClose, /* OpenCursor */ sqliteGdbmOpenCursor, /* DropTable */ sqliteGdbmDropTable, /* ReorganizeTable */ sqliteGdbmReorganizeTable, diff --git a/src/dbbemem.c b/src/dbbemem.c index 6bf1cc0f2f..86ddcf5706 100644 --- a/src/dbbemem.c +++ b/src/dbbemem.c @@ -27,8 +27,10 @@ ** of information to the disk. ** ** This file uses an in-memory hash table as the database backend. +** Nothing is ever written to disk using this backend. All information +** is forgotten when the program exits. ** -** $Id: dbbemem.c,v 1.11 2001/03/20 22:05:00 drh Exp $ +** $Id: dbbemem.c,v 1.12 2001/04/03 16:53:22 drh Exp $ */ #include "sqliteInt.h" #include @@ -720,7 +722,7 @@ static int sqliteMemDelete(DbbeCursor *pCursr, int nKey, char *pKey){ ** used to implement the MEMORY backend. */ static struct DbbeMethods memoryMethods = { - /* n Close */ sqliteMemClose, + /* Close */ sqliteMemClose, /* OpenCursor */ sqliteMemOpenCursor, /* DropTable */ sqliteMemDropTable, /* ReorganizeTable */ sqliteMemReorganizeTable, diff --git a/src/pager.h b/src/pager.h new file mode 100644 index 0000000000..cec8f4ea70 --- /dev/null +++ b/src/pager.h @@ -0,0 +1,56 @@ +/* +** Copyright (c) 2001 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 header file defines the interface that the sqlite page cache +** subsystem. The page cache subsystem reads and writes a file a page +** at a time and provides a journal for rollback. +** +** @(#) $Id: pager.h,v 1.1 2001/04/03 16:53:22 drh Exp $ +*/ +#include "sqliteInt.h" + +/* +** The size of one page +*/ +#define SQLITE_PAGE_SIZE 1024 + +/* +** The type used to represent a page number. The first page in a file +** is called page 1. 0 is used to represent "not a page". +*/ +typedef unsigned int Pgno; + +/* +** Each open file is managed by a separate instance of the "Pager" structure. +*/ +typedef struct Pager Pager; + +int sqlite_pager_open(Pager **ppPager, const char *zFilename); +int sqlite_pager_close(Pager *pPager); +int sqlite_pager_get(Pager *pPager, Pgno pgno, void **ppPage); +int sqlite_pager_unref(void*); +Pgno sqlite_pager_pagenumber(void*); +int sqlite_pager_write(void*); +int sqlite_pager_pagecount(Pager*); +int sqlite_pager_commit(Pager*); +int sqlite_pager_rollback(Pager*); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 1f1980dc1d..59332dcf92 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -24,7 +24,7 @@ ** This header file defines the interface that the sqlite library ** presents to client programs. ** -** @(#) $Id: sqlite.h.in,v 1.9 2001/01/20 19:52:49 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.10 2001/04/03 16:53:22 drh Exp $ */ #ifndef _SQLITE_H_ #define _SQLITE_H_ @@ -142,6 +142,8 @@ int sqlite_exec( #define SQLITE_CORRUPT 10 /* The database disk image is malformed */ #define SQLITE_NOTFOUND 11 /* Table or record not found */ #define SQLITE_FULL 12 /* Insertion failed because database is full */ +#define SQLITE_CANTOPEN 13 /* Unable to open the database file */ +#define SQLITE_PROTOCOL 14 /* Database lock protocol error */ /* This function causes any pending database operation to abort and ** return at its earliest opportunity. This routine is typically diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 81c9ddb7e2..c880524220 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -23,7 +23,7 @@ ************************************************************************* ** A TCL Interface to SQLite ** -** $Id: tclsqlite.c,v 1.13 2001/01/31 13:28:09 drh Exp $ +** $Id: tclsqlite.c,v 1.14 2001/04/03 16:53:22 drh Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ @@ -53,6 +53,7 @@ struct CallbackData { char *zArray; /* The array into which data is written */ Tcl_Obj *pCode; /* The code to execute for each row */ int once; /* Set only for the first invocation of callback */ + int tcl_rc; /* Return code from TCL script */ }; /* @@ -88,7 +89,9 @@ static int DbEvalCallback( } cbData->once = 0; rc = Tcl_EvalObj(cbData->interp, cbData->pCode); - return rc!=TCL_OK && rc!=TCL_CONTINUE; + if( rc==TCL_CONTINUE ) rc = TCL_OK; + cbData->tcl_rc = rc; + return rc!=TCL_OK; } /* @@ -171,7 +174,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ SqliteDb *pDb = (SqliteDb*)cd; int choice; static char *DB_optStrs[] = { - "busy", "close", "complete", "eval", "timeout" + "busy", "close", "complete", "eval", "timeout", 0 }; enum DB_opts { DB_BUSY, DB_CLOSE, DB_COMPLETE, DB_EVAL, DB_TIMEOUT @@ -278,20 +281,26 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ cbData.once = 1; cbData.zArray = Tcl_GetStringFromObj(objv[3], 0); cbData.pCode = objv[4]; + cbData.tcl_rc = TCL_OK; zErrMsg = 0; Tcl_IncrRefCount(objv[3]); Tcl_IncrRefCount(objv[4]); rc = sqlite_exec(pDb->db, zSql, DbEvalCallback, &cbData, &zErrMsg); Tcl_DecrRefCount(objv[4]); Tcl_DecrRefCount(objv[3]); + if( cbData.tcl_rc==TCL_BREAK ){ cbData.tcl_rc = TCL_OK; } }else{ Tcl_Obj *pList = Tcl_NewObj(); + cbData.tcl_rc = TCL_OK; rc = sqlite_exec(pDb->db, zSql, DbEvalCallback2, pList, &zErrMsg); Tcl_SetObjResult(interp, pList); } if( zErrMsg ){ Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE); free(zErrMsg); + rc = TCL_ERROR; + }else{ + rc = cbData.tcl_rc; } Tcl_DecrRefCount(objv[2]); return rc; diff --git a/src/test.file b/src/test.file deleted file mode 100644 index 45b983be36..0000000000 --- a/src/test.file +++ /dev/null @@ -1 +0,0 @@ -hi diff --git a/test/dbbe.test b/test/dbbe.test index d30047bc15..c9cd2148c3 100644 --- a/test/dbbe.test +++ b/test/dbbe.test @@ -23,7 +23,7 @@ # 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.6 2001/03/20 12:55:14 drh Exp $ +# $Id: dbbe.test,v 1.7 2001/04/03 16:53:22 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -134,7 +134,7 @@ do_test dbbe-3.1 { sqlite db testdb 0444 set v [catch {execsql {INSERT INTO t1 VALUES(1)}} msg] lappend v $msg -} {7 {table t1 is readonly}} +} {1 {table t1 is readonly}} finish_test diff --git a/test/lock.test b/test/lock.test index bae3864e25..ce93b0e776 100644 --- a/test/lock.test +++ b/test/lock.test @@ -23,7 +23,7 @@ # This file implements regression tests for SQLite library. The # focus of this script is database locks. # -# $Id: lock.test,v 1.7 2001/03/20 12:55:14 drh Exp $ +# $Id: lock.test,v 1.8 2001/04/03 16:53:22 drh Exp $ if {$dbprefix=="gdbm:" && $::tcl_platform(platform)!="windows"} { @@ -60,7 +60,7 @@ do_probtest lock-1.2 { # set v [catch {execsql {UPDATE big SET f2='xyz' WHERE f1=11}} msg] lappend v $msg -} {5 {table big is locked}} +} {1 {table big is locked}} do_probtest lock-1.3 { # Try to update the database in a separate process diff --git a/test/tclsqlite.test b/test/tclsqlite.test new file mode 100644 index 0000000000..fd1f37af0e --- /dev/null +++ b/test/tclsqlite.test @@ -0,0 +1,80 @@ +# 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 TCL interface to the +# SQLite library. +# +# Actually, all tests are based on the TCL interface, so the main +# interface is pretty well tested. This file contains some addition +# tests for fringe issues that the main test suite does not cover. +# +# $Id: tclsqlite.test,v 1.1 2001/04/03 16:53:22 drh Exp $ + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# Check the error messages generated by tclsqlite +# +do_test tcl-1.1 { + set v [catch {sqlite bogus} msg] + lappend v $msg +} {1 {wrong # args: should be "sqlite HANDLE FILENAME ?MODE?"}} +do_test tcl-1.2 { + set v [catch {db bogus} msg] + lappend v $msg +} {1 {bad option "bogus": must be busy, close, complete, eval, or timeout}} +do_test tcl-1.3 { + execsql {CREATE TABLE t1(a int, b int)} + execsql {INSERT INTO t1 VALUES(10,20)} + set v [catch { + db eval {SELECT * FROM t1} data { + error "The error message" + } + } msg] + lappend v $msg +} {1 {The error message}} +do_test tcl-1.4 { + set v [catch { + db eval {SELECT * FROM t2} data { + error "The error message" + } + } msg] + lappend v $msg +} {1 {no such table: t2}} +do_test tcl-1.5 { + set v [catch { + db eval {SELECT * FROM t1} data { + break + } + } msg] + lappend v $msg +} {0 {}} +do_test tcl-1.6 { + set v [catch { + db eval {SELECT * FROM t1} data { + expr x* + } + } msg] + lappend v $msg +} {1 {syntax error in expression "x*"}} + +finish_test diff --git a/tool/lemon.c b/tool/lemon.c index e0ea780439..41426caa97 100644 --- a/tool/lemon.c +++ b/tool/lemon.c @@ -3,8 +3,8 @@ ** ** This file contains all sources (including headers) to the LEMON ** LALR(1) parser generator. The sources have been combined into a -** single file to make it easy to include LEMON as part of another -** program. +** single file to make it easy to include LEMON in the source tree +** and Makefile of another program. ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public @@ -263,6 +263,7 @@ struct lemon { char *name; /* Name of the generated parser */ char *arg; /* Declaration of the 3th argument to parser */ char *tokentype; /* Type of terminal symbols in the parser stack */ + char *vartype; /* The default type of non-terminal symbols */ char *start; /* Name of the start symbol for the grammar */ char *stacksize; /* Size of the parser stack */ char *include; /* Code to put at the start of the C file */ @@ -279,6 +280,8 @@ struct lemon { int extracodeln; /* Line number for the start of the extra code */ char *tokendest; /* Code to execute to destroy token data */ int tokendestln; /* Line number for token destroyer code */ + char *vardest; /* Code for the default non-terminal destructor */ + int vardestln; /* Line number for default non-term destructor code*/ char *filename; /* Name of the input file */ char *outname; /* Name of the current output file */ char *tokenprefix; /* A prefix added to token names in the .h file */ @@ -1216,9 +1219,11 @@ char **argv; lem.basisflag = basisflag; lem.nconflict = 0; lem.name = lem.include = lem.arg = lem.tokentype = lem.start = 0; + lem.vartype = 0; lem.stacksize = 0; lem.error = lem.overflow = lem.failure = lem.accept = lem.tokendest = lem.tokenprefix = lem.outname = lem.extracode = 0; + lem.vardest = 0; lem.tablesize = 0; Symbol_new("$"); lem.errsym = Symbol_new("error"); @@ -1967,6 +1972,9 @@ to follow the previous rule."); }else if( strcmp(x,"token_destructor")==0 ){ psp->declargslot = &psp->gp->tokendest; psp->decllnslot = &psp->gp->tokendestln; + }else if( strcmp(x,"default_destructor")==0 ){ + psp->declargslot = &psp->gp->vardest; + psp->decllnslot = &psp->gp->vardestln; }else if( strcmp(x,"token_prefix")==0 ){ psp->declargslot = &psp->gp->tokenprefix; }else if( strcmp(x,"syntax_error")==0 ){ @@ -1985,6 +1993,8 @@ to follow the previous rule."); psp->declargslot = &(psp->gp->arg); }else if( strcmp(x,"token_type")==0 ){ psp->declargslot = &(psp->gp->tokentype); + }else if( strcmp(x,"default_type")==0 ){ + psp->declargslot = &(psp->gp->vartype); }else if( strcmp(x,"stack_size")==0 ){ psp->declargslot = &(psp->gp->stacksize); }else if( strcmp(x,"start_symbol")==0 ){ @@ -2210,7 +2220,7 @@ struct lemon *gp; } } if( c==0 ){ - ErrorMsg(ps.filename,startline, + ErrorMsg(ps.filename,ps.tokenlineno, "C code starting on this line is not terminated before the end of the file."); ps.errorcnt++; nextcp = cp; @@ -2643,6 +2653,8 @@ struct lemon *lemp; } if( access(buf,004)==0 ){ tpltname = buf; + }else if( access(templatename,004)==0 ){ + tpltname = templatename; }else{ tpltname = pathsearch(lemp->argv0,templatename,0); } @@ -2697,10 +2709,13 @@ int *lineno; cp = lemp->tokendest; if( cp==0 ) return; fprintf(out,"#line %d \"%s\"\n{",lemp->tokendestln,lemp->filename); - }else{ + }else if( sp->destructor ){ cp = sp->destructor; - if( cp==0 ) return; fprintf(out,"#line %d \"%s\"\n{",sp->destructorln,lemp->filename); + }else if( lemp->vardest ){ + cp = lemp->vardest; + if( cp==0 ) return; + fprintf(out,"#line %d \"%s\"\n{",lemp->vardestln,lemp->filename); } for(; *cp; cp++){ if( *cp=='$' && cp[1]=='$' ){ @@ -2717,7 +2732,7 @@ int *lineno; } /* -** Return TRUE (non-zero) if the given symbol has a distructor. +** Return TRUE (non-zero) if the given symbol has a destructor. */ int has_destructor(sp, lemp) struct symbol *sp; @@ -2727,7 +2742,7 @@ struct lemon *lemp; if( sp->type==TERMINAL ){ ret = lemp->tokendest!=0; }else{ - ret = sp->destructor!=0; + ret = lemp->vardest!=0 || sp->destructor!=0; } return ret; } @@ -2796,7 +2811,7 @@ int *lineno; for(i=0; inrhs; i++){ if( rp->rhsalias[i] && !used[i] ){ ErrorMsg(lemp->filename,rp->ruleline, - "Label $%s$ for \"%s(%s)\" is never used.", + "Label %s for \"%s(%s)\" is never used.", rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]); lemp->errorcnt++; }else if( rp->rhsalias[i]==0 ){ @@ -2840,6 +2855,9 @@ int mhflag; /* True if generating makeheaders output */ types = (char**)malloc( arraysize * sizeof(char*) ); for(i=0; ivartype ){ + maxdtlength = strlen(lemp->vartype); + } for(i=0; insymbol; i++){ int len; struct symbol *sp = lemp->symbols[i]; @@ -2855,8 +2873,10 @@ int mhflag; /* True if generating makeheaders output */ /* Build a hash table of datatypes. The ".dtnum" field of each symbol ** is filled in with the hash index plus 1. A ".dtnum" value of 0 is - ** used for terminal symbols and for nonterminals which don't specify - ** a datatype using the %type directive. */ + ** used for terminal symbols. If there is no %default_type defined then + ** 0 is also used as the .dtnum value for nonterminals which do not specify + ** a datatype using the %type directive. + */ for(i=0; insymbol; i++){ struct symbol *sp = lemp->symbols[i]; char *cp; @@ -2864,11 +2884,12 @@ int mhflag; /* True if generating makeheaders output */ sp->dtnum = arraysize+1; continue; } - if( sp->type!=NONTERMINAL || sp->datatype==0 ){ + if( sp->type!=NONTERMINAL || (sp->datatype==0 && lemp->vartype==0) ){ sp->dtnum = 0; continue; } cp = sp->datatype; + if( cp==0 ) cp = lemp->vartype; j = 0; while( isspace(*cp) ) cp++; while( *cp ) stddt[j++] = *cp++; @@ -3159,6 +3180,20 @@ int mhflag; /* Output in makeheaders format if true */ emit_destructor_code(out,lemp->symbols[i],lemp,&lineno); fprintf(out," break;\n"); lineno++; } + if( lemp->vardest ){ + struct symbol *dflt_sp = 0; + for(i=0; insymbol; i++){ + struct symbol *sp = lemp->symbols[i]; + if( sp==0 || sp->type==TERMINAL || + sp->index<=0 || sp->destructor!=0 ) continue; + fprintf(out," case %d:\n",sp->index); lineno++; + dflt_sp = sp; + } + if( dflt_sp!=0 ){ + emit_destructor_code(out,dflt_sp,lemp,&lineno); + fprintf(out," break;\n"); lineno++; + } + } tplt_xfer(lemp->name,in,out,&lineno); /* Generate code which executes whenever the parser stack overflows */ diff --git a/tool/lempar.c b/tool/lempar.c index e5293b1de2..8b35e86bf8 100644 --- a/tool/lempar.c +++ b/tool/lempar.c @@ -1,9 +1,5 @@ /* Driver template for the LEMON parser generator. ** Copyright 1991-1995 by D. Richard Hipp. -* -* This version is specially modified for use with sqlite. -* @(#) $Id: lempar.c,v 1.1 2000/05/29 14:26:02 drh Exp $ -* ** ** This library is free software; you can redistribute it and/or ** modify it under the terms of the GNU Library General Public @@ -177,7 +173,6 @@ static char *yyTracePrompt = 0; ** Outputs: ** None. */ -/* SQLITE MODIFICATION: Give the function file scope */ void ParseTrace(FILE *TraceFILE, char *zTracePrompt){ yyTraceFILE = TraceFILE; yyTracePrompt = zTracePrompt; @@ -195,6 +190,18 @@ static char *yyTokenName[] = { #define YYTRACE(X) #endif +/* +** This function returns the symbolic name associated with a token +** value. +*/ +const char *ParseTokenName(int tokenType){ + if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){ + return yyTokenName[tokenType]; + }else{ + return "Unknown"; + } +} + /* ** This function allocates a new parser. ** The only argument is a pointer to a function which works like @@ -207,10 +214,9 @@ static char *yyTokenName[] = { ** A pointer to a parser. This pointer is used in subsequent calls ** to Parse and ParseFree. */ -/* SQLITE MODIFICATION: Give the function file scope */ -void *ParseAlloc(void *(*mallocProc)()){ +void *ParseAlloc(void *(*mallocProc)(int)){ yyParser *pParser; - pParser = (yyParser*)(*mallocProc)( sizeof(yyParser), __FILE__, __LINE__ ); + pParser = (yyParser*)(*mallocProc)( (int)sizeof(yyParser) ); if( pParser ){ pParser->idx = -1; } @@ -277,15 +283,14 @@ static int yy_pop_parser_stack(yyParser *pParser){ ** from malloc. ** */ -/* SQLITE MODIFICATION: Give the function file scope */ void ParseFree( - void *p, /* The parser to be deleted */ - void (*freeProc)() /* Function used to reclaim memory */ + void *p, /* The parser to be deleted */ + void (*freeProc)(void*) /* Function used to reclaim memory */ ){ yyParser *pParser = (yyParser*)p; if( pParser==0 ) return; while( pParser->idx>=0 ) yy_pop_parser_stack(pParser); - (*freeProc)(pParser, __FILE__, __LINE__); + (*freeProc)((void*)pParser); } /* @@ -366,7 +371,7 @@ static struct { %% }; -static void yy_accept(); /* Forward declaration */ +static void yy_accept(yyParser * ParseANSIARGDECL); /* Forward Declaration */ /* ** Perform a reduce action and the shift that must immediately @@ -475,7 +480,6 @@ static void yy_accept( ** Outputs: ** None. */ -/* SQLITE MODIFICATION: Give the function file scope */ void Parse( void *yyp, /* The parser */ int yymajor, /* The major token code number */ diff --git a/www/changes.tcl b/www/changes.tcl index 111276c81a..ac8dd670e0 100644 --- a/www/changes.tcl +++ b/www/changes.tcl @@ -17,6 +17,12 @@ proc chng {date desc} { puts "

    $desc

" } +chng {2001 Apr 3 (1.0.28)} { +
  • Changes to the "lemon" parser generator to help it work better when + compiled using MSVC.
  • +
  • Bug fixes in the TCL interface identified by Oleg Oleinick.
  • +} + chng {2001 Mar 20 (1.0.27)} {
  • When doing DELETE and UPDATE, the library used to write the record numbers of records to be deleted or updated into a temporary file.