]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix an assertion failure when the disk fills up. Add tests for a full
authordrh <drh@noemail.net>
Fri, 12 Oct 2001 17:30:04 +0000 (17:30 +0000)
committerdrh <drh@noemail.net>
Fri, 12 Oct 2001 17:30:04 +0000 (17:30 +0000)
disk situation. (CVS 285)

FossilOrigin-Name: 0a7848b6190981cb7eb673bbe68cb217694daf2e

16 files changed:
Makefile.in
Makefile.template
manifest
manifest.uuid
src/build.c
src/hash.c
src/main.c
src/os.c
src/pager.c
src/parse.y
src/sqliteInt.h
src/test2.c
src/vdbe.h
test/ioerr.test [new file with mode: 0644]
www/c_interface.tcl
www/changes.tcl

index 8c3f9a41f3e9b7d9d203771481a0448a9766dd05..3840766f800fb27f53a56e3d951a1140b49b15f6 100644 (file)
@@ -99,6 +99,7 @@ SRC = \
 #
 TESTSRC = \
   $(TOP)/src/btree.c \
+  $(TOP)/src/os.c \
   $(TOP)/src/pager.c \
   $(TOP)/src/test1.c \
   $(TOP)/src/test2.c \
index 14a30b63d1375a40ebf8556a1d1937516e14b768..7e45f4464eee2e7d23cd280f67bccdfedd35fcad 100644 (file)
@@ -146,6 +146,7 @@ SRC = \
 #
 TESTSRC = \
   $(TOP)/src/btree.c \
+  $(TOP)/src/os.c \
   $(TOP)/src/pager.c \
   $(TOP)/src/test1.c \
   $(TOP)/src/test2.c \
index 747fa3aa35aa099931f315b6df7e242c157f2937..ba3fb942c6284ebc9df00021e1e8c353b30ec900 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,7 +1,7 @@
-C Version\s2.0.2\s(CVS\s468)
-D 2001-10-09T14:00:00
-F Makefile.in 98d4627cb364537e4c3a29ee806171f3abf5211a
-F Makefile.template 1e54087c0390c4ce0bb5be43e14ba028283751e6
+C Fix\san\sassertion\sfailure\swhen\sthe\sdisk\sfills\sup.\s\sAdd\stests\sfor\sa\sfull\ndisk\ssituation.\s(CVS\s285)
+D 2001-10-12T17:30:04
+F Makefile.in 6801df952cb1df64aa32e4de85fed24511d28efd
+F Makefile.template 582916b263aa40a70521dfb3d99d574028abd47b
 F README 93d2977cc5c6595c448de16bdefc312b9d401533
 F VERSION 73e5f5e088b67ed1629b08ca531b81c778ab8695
 F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d
@@ -21,36 +21,36 @@ F publish.sh badcd69b8e3a8bc69b162c4c9d7c209b2a0b119e
 F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
 F src/btree.c 7e9c33a714ed1630562f89ad19847f5f28bd6d4d
 F src/btree.h 57d653ef5137b91f2a068aaf71a2905468dd2cb7
-F src/build.c 707f6ef58dcdd50ead9ead914d673b08e7121bc5
+F src/build.c cb3607c86f20dd3c18dccbe21f1b9bcd33ef9a36
 F src/delete.c 93c9d5e160395020a25d59371625db74c97c7c4d
 F src/expr.c 2f68829d983ec3f92eeb8b89ce4b9e5704169a80
-F src/hash.c bf36fb4cba114015123b0050f137d2c4553778a1
+F src/hash.c b7ced0735287c142a3b2db46c3cae3e6826afb75
 F src/hash.h a5f5b3ce2d086a172c5879b0b06a27a82eac9fac
 F src/insert.c a48ba850461b203fb8dbc7add83fc6b6a9cf47f3
-F src/main.c ece73e5a44fab98144c4a93084d68b4fc413ba66
+F src/main.c 9a18e97290d41844e8c12e021fb7c42948a19dc9
 F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
-F src/os.c a83f4cb85e4d3b98c1659a799f9e318fcaf1c76c
+F src/os.c cece4ac6cabc9d377ef0a4ab4c16f6f0f6c84377
 F src/os.h bed702c9e3b768bc3cb1b12c90b83d099c1546be
-F src/pager.c 3445bd7c18cbfdffd8d6d1077f0b2bdf788da4fe
+F src/pager.c e2e189a15e230c60e811f5e2ab25e68ae41c90be
 F src/pager.h a0d4c5ae271914aa07b62aee0707997d6932b6ca
-F src/parse.y e88f1efe096a1a01c9076099fe1d81deedfa11de
+F src/parse.y 2275a832b544e8b57c422880a0d9badd4976d042
 F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9
 F src/random.c 2a9cc2c9716d14815fd4c2accf89d87a1143e46b
 F src/select.c 0ef8ca1b7de2467fe082bcb35a5ab3b5be56153c
 F src/shell.c cb8c41f1b2173efd212dab3f35f1fc6bf32ead76
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
 F src/sqlite.h.in b95c161abf1d58bceb05290fa3f657d8f388fc11
-F src/sqliteInt.h 603566f58dff0e0295e57792e9313fe5d253f1a2
+F src/sqliteInt.h 141b57b9eee7e8c937ac603f6cb7ecca77c1dd77
 F src/table.c abd0adbe0fee39d995287b3bcccd908d174dfcac
 F src/tclsqlite.c 765599686c19ed777ac379928d732c8bfc63ebac
 F src/test1.c e4b31f62ea71963cbae44338acf477a04fc8fc49
-F src/test2.c 0168b39225b768cfdadd534406f9dec58c27879e
+F src/test2.c e9f99aa5ee73872819259d6612c11e55e1644321
 F src/test3.c 4a0d7b882fdae731dbb759f512ad867122452f96
 F src/tokenize.c 15d349b68d9dc5722956bd7549752ace62034787
 F src/update.c 49a1edb1a3e44dfff3f799e00f2a3319f2393cd8
 F src/util.c 4da3be37d0fd3c640d2d3033503768afdc8e5387
 F src/vdbe.c 594050d9a8dc51b97320c52d4665de313b842c27
-F src/vdbe.h 7eb7e9e6c58fe9430efab35e168f96cb4bd6cb45
+F src/vdbe.h adecb0f37d2c1aa34f2cbd359b63b8c922e72c1f
 F src/where.c b676765ad0360769173b09f46265ddec8d48367a
 F test/all.test a2320eb40b462f25bd3e33115b1cabf3791450dd
 F test/bigrow.test a35f2de9948b24e427fb292c35947795efe182d0
@@ -64,6 +64,7 @@ F test/in.test 9323681388be301dc73f370b4cd62c5a33f79d1e
 F test/index.test 6076f29d09a4f26a2efa38b03b8cc338b8662f0e
 F test/insert.test a5c122aa726f1cef6f07d6767e8fd6f220994c11
 F test/insert2.test 252d7130d8cc20f649b31a4f503cd87e660abda8
+F test/ioerr.test 57d9bffaca18b34f9e976f786eadc2591d6efc6a
 F test/lock.test 19593689260c419efe7ced55b1418653a4b7bcd1
 F test/main.test 085ece17913a487caacbc0a392638c958c83a75d
 F test/malloc.test f1400a8d002eb96f1ca0a34abe56d2ab3e324740
@@ -100,8 +101,8 @@ F tool/report1.txt 9eae07f26a8fc53889b45fc833a66a33daa22816
 F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
 F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
 F www/arch.tcl 03b521d252575f93b9c52f7c8b0007011512fcfb
-F www/c_interface.tcl 8e8d9e66e8467c5751116c3427296bde77f474a6
-F www/changes.tcl 2b416b49a136312678317f509821cf9359e421b5
+F www/c_interface.tcl a59ee0835d1b33fcddab7d4fd65cf9e50f7d2dc7
+F www/changes.tcl 4c722e1271b9c25477f2483dad1a96681ce73380
 F www/crosscompile.tcl c99efacb3aefaa550c6e80d91b240f55eb9fd33e
 F www/download.tcl 3e51c9ff1326b0a182846134987301310dff7d60
 F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
@@ -113,7 +114,7 @@ F www/speed.tcl ab7d6d3bc898472bd94320a5d3c63de928d4804b
 F www/sqlite.tcl 6a21242a272e9c0939a04419a51c3d50cae33e3e
 F www/tclsqlite.tcl 13d50723f583888fc80ae1a38247c0ab415066fa
 F www/vdbe.tcl bb7d620995f0a987293e9d4fb6185a3b077e9b44
-P abe5a25b9dcf1e47f3cb37fd419f620db03bd4da
-R 811a44282886ed3bd9485148120cee71
+P 44d00a6f58c71ca11423df12530177baaa054a01
+R 8b125f0466bafcf592b4cb611703e2d3
 U drh
-Z bb72d0236472bbdc7b77722d8537d4bf
+Z c3df09919ca8934d0890578a526b0048
index 54ee600512ecb1f6e6784957a2b11dac91727e85..5bdf7867e28062fddf47aaa0deeb28d3c181454f 100644 (file)
@@ -1 +1 @@
-44d00a6f58c71ca11423df12530177baaa054a01
\ No newline at end of file
+0a7848b6190981cb7eb673bbe68cb217694daf2e
\ No newline at end of file
index 656eca7c0d9132925d59800ecb6c0de74d675087..59b993b471ea4f051b89c9d0c0154fe1b3e26d30 100644 (file)
@@ -25,7 +25,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.46 2001/10/09 04:19:47 drh Exp $
+** $Id: build.c,v 1.47 2001/10/12 17:30:05 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -1477,6 +1477,36 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
     }
   }else
 
+  if( sqliteStrICmp(zLeft, "index_list")==0 ){
+    Index *pIdx;
+    Table *pTab;
+    Vdbe *v;
+    pTab = sqliteFindTable(db, zRight);
+    if( pTab ){
+      v = sqliteGetVdbe(pParse);
+      pIdx = pTab->pIndex;
+    }
+    if( pTab && pIdx && v ){
+      int i = 0; 
+      static VdbeOp indexListPreface[] = {
+        { OP_ColumnCount, 3, 0,       0},
+        { OP_ColumnName,  0, 0,       "seq"},
+        { OP_ColumnName,  1, 0,       "name"},
+        { OP_ColumnName,  2, 0,       "unique"},
+      };
+
+      sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
+      while(pIdx){
+        sqliteVdbeAddOp(v, OP_Integer, i, 0, 0, 0);
+        sqliteVdbeAddOp(v, OP_String, 0, 0, pIdx->zName, 0);
+        sqliteVdbeAddOp(v, OP_Integer, pIdx->isUnique, 0, 0, 0);
+        sqliteVdbeAddOp(v, OP_Callback, 3, 0, 0, 0);
+       ++i;
+       pIdx = pIdx->pNext;
+      }
+    }
+  }else
+
 #ifndef NDEBUG
   if( sqliteStrICmp(zLeft, "parser_trace")==0 ){
     extern void sqliteParserTrace(FILE*, char *);
index db854d7390d7083bf1320a2c86b1bb713c7dbcd8..945a919ed85354d4295707958d2d120c24a1e5c7 100644 (file)
@@ -12,7 +12,7 @@
 ** This is the implementation of generic hash-tables
 ** used in SQLite.
 **
-** $Id: hash.c,v 1.1 2001/09/22 18:12:10 drh Exp $
+** $Id: hash.c,v 1.2 2001/10/12 17:30:05 drh Exp $
 */
 #include "sqliteInt.h"
 #include <assert.h>
@@ -197,7 +197,7 @@ static HashElem *findElementGivenHash(
   return 0;
 }
 
-/* Remove a single entry from the pH given a pointer to that
+/* Remove a single entry from the hash table given a pointer to that
 ** element and a hash on the element's key.
 */
 static void removeElementGivenHash(
@@ -228,7 +228,7 @@ static void removeElementGivenHash(
 }
 
 /* Attempt to locate an element of the associative pH with a key
-** that matches "key".  Return the data for this element if it is
+** that matches pKey,nKey.  Return the data for this element if it is
 ** found, or NULL if no match is found.
 */
 void *sqliteHashFind(const Hash *pH, const void *pKey, int nKey){
@@ -245,19 +245,19 @@ void *sqliteHashFind(const Hash *pH, const void *pKey, int nKey){
   return elem ? elem->data : 0;
 }
 
-/* Insert an element into the pH.  The key will be "key" and
-** the data will be "data".
+/* Insert an element into the hash table pH.  The key is pKey,nKey
+** and the data is "data".
 **
-** If no pH element exists with a matching key, then a new
-** pH element is created.  The key is copied (using the copy
-** function of the key class) into the new element.  NULL is returned.
+** If no element exists with a matching key, then a new
+** element is created.  A copy of the key is made if the copyKey
+** flag is set.  NULL is returned.
 **
 ** If another element already exists with the same key, then the
 ** new data replaces the old data and the old data is returned.
 ** The key is not copied in this instance.
 **
 ** If the "data" parameter to this function is NULL, then the
-** element corresponding to "key" is removed from the pH.
+** element corresponding to "key" is removed from the hash table.
 */
 void *sqliteHashInsert(Hash *pH, void *pKey, int nKey, void *data){
   int hraw;             /* Raw hash value of the key */
index e3d1695d16d58a8eae9e3a5aff24d6018baaf9c7..b9b44c1504b5e25d615a30cc8bce997e90787470 100644 (file)
@@ -14,7 +14,7 @@
 ** other files are for internal use by SQLite and should not be
 ** accessed by users of the library.
 **
-** $Id: main.c,v 1.45 2001/10/09 13:46:01 drh Exp $
+** $Id: main.c,v 1.46 2001/10/12 17:30:05 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
index 3aaf8fae7e54c8691a1a7447412edb413675f854..f09aacc6305723698a0500185b6bd3e573ab82a0 100644 (file)
--- a/src/os.c
+++ b/src/os.c
@@ -11,7 +11,7 @@
 ******************************************************************************
 **
 ** This file contains code that is specific to particular operating
-** systems.  The purpose of this file is to provide a uniform abstract
+** systems.  The purpose of this file is to provide a uniform abstraction
 ** on which the rest of SQLite can operate.
 */
 #include "sqliteInt.h"
@@ -158,6 +158,23 @@ static void releaseLockInfo(struct lockInfo *pInfo){
 }
 #endif  /** POSIX advisory lock work-around **/
 
+/*
+** If we compile with the SQLITE_TEST macro set, then the following block
+** of code will give us the ability to simulate a disk I/O error.  This
+** is used for testing the I/O recovery logic.
+*/
+#ifdef SQLITE_TEST
+int sqlite_io_error_pending = 0;
+#define SimulateIOError(A)  \
+   if( sqlite_io_error_pending ) \
+     if( sqlite_io_error_pending-- == 1 ){ local_ioerr(); return A; }
+static void local_ioerr(){
+  sqlite_io_error_pending = 0;  /* Really just a place to set a breakpoint */
+}
+#else
+#define SimulateIOError(A)
+#endif
+
 
 /*
 ** Delete the named file
@@ -248,7 +265,7 @@ int sqliteOsOpenReadWrite(
      NULL
   );
   if( h==INVALID_HANDLE_VALUE ){
-    HANDLE h = CreateFile(zFilename,
+    h = CreateFile(zFilename,
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
@@ -443,12 +460,14 @@ int sqliteOsClose(OsFile id){
 int sqliteOsRead(OsFile id, void *pBuf, int amt){
 #if OS_UNIX
   int got;
+  SimulateIOError(SQLITE_IOERR);
   got = read(id.fd, pBuf, amt);
   if( got<0 ) got = 0;
   return got==amt ? SQLITE_OK : SQLITE_IOERR;
 #endif
 #if OS_WIN
   DWORD got;
+  SimulateIOError(SQLITE_IOERR);
   if( !ReadFile(id, pBuf, amt, &got, 0) ){
     got = 0;
   }
@@ -463,12 +482,14 @@ int sqliteOsRead(OsFile id, void *pBuf, int amt){
 int sqliteOsWrite(OsFile id, const void *pBuf, int amt){
 #if OS_UNIX
   int wrote;
+  SimulateIOError(SQLITE_IOERR);
   wrote = write(id.fd, pBuf, amt);
   if( wrote<amt ) return SQLITE_FULL;
   return SQLITE_OK;
 #endif
 #if OS_WIN
   DWORD wrote;
+  SimulateIOError(SQLITE_IOERR);
   if( !WriteFile(id, pBuf, amt, &wrote, 0) || wrote<amt ){
     return SQLITE_FULL;
   }
@@ -494,6 +515,7 @@ int sqliteOsSeek(OsFile id, int offset){
 ** Make sure all writes to a particular file are committed to disk.
 */
 int sqliteOsSync(OsFile id){
+  SimulateIOError(SQLITE_IOERR);
 #if OS_UNIX
   return fsync(id.fd)==0 ? SQLITE_OK : SQLITE_IOERR;
 #endif
@@ -506,6 +528,7 @@ int sqliteOsSync(OsFile id){
 ** Truncate an open file to a specified size
 */
 int sqliteOsTruncate(OsFile id, int nByte){
+  SimulateIOError(SQLITE_IOERR);
 #if OS_UNIX
   return ftruncate(id.fd, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;
 #endif
@@ -522,6 +545,7 @@ int sqliteOsTruncate(OsFile id, int nByte){
 int sqliteOsFileSize(OsFile id, int *pSize){
 #if OS_UNIX
   struct stat buf;
+  SimulateIOError(SQLITE_IOERR);
   if( fstat(id.fd, &buf)!=0 ){
     return SQLITE_IOERR;
   }
@@ -529,6 +553,7 @@ int sqliteOsFileSize(OsFile id, int *pSize){
   return SQLITE_OK;
 #endif
 #if OS_WIN
+  SimulateIOError(SQLITE_IOERR);
   *pSize = GetFileSize(id, 0);
   return SQLITE_OK;
 #endif
index 4584ffdb227a5465c5fc4fc1fadad6d29541690c..7134744e69083dc64f53570c1fd79aeff1a9cc2c 100644 (file)
@@ -18,7 +18,7 @@
 ** file simultaneously, or one process from reading the database while
 ** another is writing.
 **
-** @(#) $Id: pager.c,v 1.26 2001/10/08 13:22:33 drh Exp $
+** @(#) $Id: pager.c,v 1.27 2001/10/12 17:30:05 drh Exp $
 */
 #include "sqliteInt.h"
 #include "pager.h"
@@ -128,6 +128,7 @@ struct Pager {
 #define PAGER_ERR_MEM      0x02  /* malloc() failed */
 #define PAGER_ERR_LOCK     0x04  /* error in the locking protocol */
 #define PAGER_ERR_CORRUPT  0x08  /* database or journal corruption */
+#define PAGER_ERR_DISK     0x10  /* general disk I/O error - bad hard drive? */
 
 /*
 ** The journal file contains page records in the following
@@ -178,6 +179,7 @@ static const unsigned char aJournalMagic[] = {
 static int pager_errcode(Pager *pPager){
   int rc = SQLITE_OK;
   if( pPager->errMask & PAGER_ERR_LOCK )    rc = SQLITE_PROTOCOL;
+  if( pPager->errMask & PAGER_ERR_DISK )    rc = SQLITE_IOERR;
   if( pPager->errMask & PAGER_ERR_FULL )    rc = SQLITE_FULL;
   if( pPager->errMask & PAGER_ERR_MEM )     rc = SQLITE_NOMEM;
   if( pPager->errMask & PAGER_ERR_CORRUPT ) rc = SQLITE_CORRUPT;
@@ -305,20 +307,25 @@ static int pager_playback(Pager *pPager){
   sqliteOsSeek(pPager->jfd, 0);
   rc = sqliteOsRead(pPager->jfd, aMagic, sizeof(aMagic));
   if( rc!=SQLITE_OK || memcmp(aMagic,aJournalMagic,sizeof(aMagic))!=0 ){
-    return SQLITE_PROTOCOL;
+    rc = SQLITE_PROTOCOL;
+    goto end_playback;
   }
   rc = sqliteOsRead(pPager->jfd, &mxPg, sizeof(mxPg));
   if( rc!=SQLITE_OK ){
-    return SQLITE_PROTOCOL;
+    goto end_playback;
+  }
+  rc = sqliteOsTruncate(pPager->fd, mxPg*SQLITE_PAGE_SIZE);
+  if( rc!=SQLITE_OK ){
+    goto end_playback;
   }
-  sqliteOsTruncate(pPager->fd, mxPg*SQLITE_PAGE_SIZE);
   pPager->dbSize = mxPg;
   
   /* Begin reading the journal beginning at the end and moving
   ** toward the beginning.
   */
-  if( sqliteOsFileSize(pPager->jfd, &nRec)!=SQLITE_OK ){
-    return SQLITE_OK;
+  rc = sqliteOsFileSize(pPager->jfd, &nRec);
+  if( rc!=SQLITE_OK ){
+    goto end_playback;
   }
   nRec = (nRec - (sizeof(aMagic)+sizeof(Pgno))) / sizeof(PageRecord);
 
@@ -353,6 +360,8 @@ static int pager_playback(Pager *pPager){
     rc = sqliteOsWrite(pPager->fd, pgRec.aData, SQLITE_PAGE_SIZE);
     if( rc!=SQLITE_OK ) break;
   }
+
+end_playback:
   if( rc!=SQLITE_OK ){
     pager_unwritelock(pPager);
     pPager->errMask |= PAGER_ERR_CORRUPT;
@@ -470,6 +479,7 @@ int sqlitepager_pagecount(Pager *pPager){
     return pPager->dbSize;
   }
   if( sqliteOsFileSize(pPager->fd, &n)!=SQLITE_OK ){
+    pPager->errMask |= PAGER_ERR_DISK;
     return 0;
   }
   n /= SQLITE_PAGE_SIZE;
@@ -589,7 +599,7 @@ static int syncAllPages(Pager *pPager){
       pPg->dirty = 0;
     }
   }
-  return SQLITE_OK;
+  return rc;
 }
 
 /*
@@ -790,8 +800,12 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){
     if( pPager->dbSize<pgno ){
       memset(PGHDR_TO_DATA(pPg), 0, SQLITE_PAGE_SIZE);
     }else{
+      int rc;
       sqliteOsSeek(pPager->fd, (pgno-1)*SQLITE_PAGE_SIZE);
-      sqliteOsRead(pPager->fd, PGHDR_TO_DATA(pPg), SQLITE_PAGE_SIZE);
+      rc = sqliteOsRead(pPager->fd, PGHDR_TO_DATA(pPg), SQLITE_PAGE_SIZE);
+      if( rc!=SQLITE_OK ){
+        return rc;
+      }
     }
     if( pPager->nExtra>0 ){
       memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra);
index a190751e08d1502975c73b050ee7bd2e864eb241..065cdfb4c80de80e6afe5ea5e467363ce619e6e0 100644 (file)
@@ -14,7 +14,7 @@
 ** the parser.  Lemon will also generate a header file containing
 ** numeric codes for all of the tokens.
 **
-** @(#) $Id: parse.y,v 1.35 2001/10/08 13:22:33 drh Exp $
+** @(#) $Id: parse.y,v 1.36 2001/10/12 17:30:05 drh Exp $
 */
 %token_prefix TK_
 %token_type {Token}
@@ -329,10 +329,11 @@ inscollist(A) ::= ids(Y).                     {A = sqliteIdListAppend(0,&Y);}
 %right NOT.
 %left EQ NE ISNULL NOTNULL IS LIKE GLOB BETWEEN IN.
 %left GT GE LT LE.
+%left BITAND BITOR LSHIFT RSHIFT.
 %left PLUS MINUS.
-%left STAR SLASH.
+%left STAR SLASH MOD.
 %left CONCAT.
-%right UMINUS.
+%right UMINUS BITNOT.
 
 %type expr {Expr*}
 %destructor expr {sqliteExprDelete($$);}
@@ -364,7 +365,11 @@ expr(A) ::= expr(X) LE expr(Y).    {A = sqliteExpr(TK_LE, X, Y, 0);}
 expr(A) ::= expr(X) GE expr(Y).    {A = sqliteExpr(TK_GE, X, Y, 0);}
 expr(A) ::= expr(X) NE expr(Y).    {A = sqliteExpr(TK_NE, X, Y, 0);}
 expr(A) ::= expr(X) EQ expr(Y).    {A = sqliteExpr(TK_EQ, X, Y, 0);}
-expr(A) ::= expr(X) LIKE expr(Y).  {A = sqliteExpr(TK_LIKE, X, Y, 0);}
+expr(A) ::= expr(X) BITAND expr(Y). {A = sqliteExpr(TK_BITAND, X, Y, 0);}
+expr(A) ::= expr(X) BITOR expr(Y).  {A = sqliteExpr(TK_BITOR, X, Y, 0);}
+expr(A) ::= expr(X) LSHIFT expr(Y). {A = sqliteExpr(TK_LSHIFT, X, Y, 0);}
+expr(A) ::= expr(X) RSHIFT expr(Y). {A = sqliteExpr(TK_RSHIFT, X, Y, 0);}
+expr(A) ::= expr(X) LIKE expr(Y).   {A = sqliteExpr(TK_LIKE, X, Y, 0);}
 expr(A) ::= expr(X) NOT LIKE expr(Y).  {
   A = sqliteExpr(TK_LIKE, X, Y, 0);
   A = sqliteExpr(TK_NOT, A, 0, 0);
@@ -380,6 +385,7 @@ expr(A) ::= expr(X) PLUS expr(Y).  {A = sqliteExpr(TK_PLUS, X, Y, 0);}
 expr(A) ::= expr(X) MINUS expr(Y). {A = sqliteExpr(TK_MINUS, X, Y, 0);}
 expr(A) ::= expr(X) STAR expr(Y).  {A = sqliteExpr(TK_STAR, X, Y, 0);}
 expr(A) ::= expr(X) SLASH expr(Y). {A = sqliteExpr(TK_SLASH, X, Y, 0);}
+expr(A) ::= expr(X) MOD expr(Y).   {A = sqliteExpr(TK_MOD, X, Y, 0);}
 expr(A) ::= expr(X) CONCAT expr(Y). {A = sqliteExpr(TK_CONCAT, X, Y, 0);}
 expr(A) ::= expr(X) ISNULL(E). {
   A = sqliteExpr(TK_ISNULL, X, 0, 0);
@@ -397,10 +403,18 @@ expr(A) ::= expr(X) NOT NULL(E). {
   A = sqliteExpr(TK_NOTNULL, X, 0, 0);
   sqliteExprSpan(A,&X->span,&E);
 }
+expr(A) ::= expr(X) IS NOT NULL(E). {
+  A = sqliteExpr(TK_NOTNULL, X, 0, 0);
+  sqliteExprSpan(A,&X->span,&E);
+}
 expr(A) ::= NOT(B) expr(X). {
   A = sqliteExpr(TK_NOT, X, 0, 0);
   sqliteExprSpan(A,&B,&X->span);
 }
+expr(A) ::= BITNOT(B) expr(X). {
+  A = sqliteExpr(TK_BITNOT, X, 0, 0);
+  sqliteExprSpan(A,&B,&X->span);
+}
 expr(A) ::= MINUS(B) expr(X). [UMINUS] {
   A = sqliteExpr(TK_UMINUS, X, 0, 0);
   sqliteExprSpan(A,&B,&X->span);
index 7a65cdcd9d8000794f65ac6d28a4848b2fde02ad..781b415edad2ee6f03ce910380402b4c40a20612 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.59 2001/10/09 04:19:47 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.60 2001/10/12 17:30:05 drh Exp $
 */
 #include "sqlite.h"
 #include "hash.h"
@@ -117,6 +117,21 @@ extern int sqlite_iMallocFail;   /* Fail sqliteMalloc() after this many calls */
 #define FN_Fcnt       6
 #define FN_Length     7
 #define FN_Substr     8
+#if 0
+#define FN_Abs        9
+#define FN_Ceil       10
+#define FN_Floor      11
+#define FN_Frac       12
+#define FN_Sin        13
+#define FN_Cos        14
+#define FN_Tan        15
+#define FN_Asin       16
+#define FN_Acos       17
+#define FN_Atan       18
+#define FN_Exp        19
+#define FN_Ln         20
+#define FN_Pow        21
+#endif
 
 /*
 ** Forward references to structures
index e08c189e272a84354579eebf28e2f9352ebad179..12b81e8ea7e76ee9f7dc7ec55c886d8f07bf9548 100644 (file)
@@ -13,7 +13,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** testing of the SQLite library.
 **
-** $Id: test2.c,v 1.5 2001/09/16 00:13:27 drh Exp $
+** $Id: test2.c,v 1.6 2001/10/12 17:30:05 drh Exp $
 */
 #include "sqliteInt.h"
 #include "pager.h"
@@ -388,6 +388,7 @@ static int page_write(
 ** Register commands with the TCL interpreter.
 */
 int Sqlitetest2_Init(Tcl_Interp *interp){
+  extern int sqlite_io_error_pending;
   Tcl_CreateCommand(interp, "pager_open", pager_open, 0, 0);
   Tcl_CreateCommand(interp, "pager_close", pager_close, 0, 0);
   Tcl_CreateCommand(interp, "pager_commit", pager_commit, 0, 0);
@@ -400,5 +401,7 @@ int Sqlitetest2_Init(Tcl_Interp *interp){
   Tcl_CreateCommand(interp, "page_read", page_read, 0, 0);
   Tcl_CreateCommand(interp, "page_write", page_write, 0, 0);
   Tcl_CreateCommand(interp, "page_number", page_number, 0, 0);
+  Tcl_LinkVar(interp, "sqlite_io_error_pending",
+     (char*)&sqlite_io_error_pending, TCL_LINK_INT);
   return TCL_OK;
 }
index b1fde29cb2345fa8d07d4aa883de9d49f39cec87..b70c5c6b9c99b2ac75665cbdd8b628c6d7c8ec4c 100644 (file)
@@ -15,7 +15,7 @@
 ** 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.26 2001/10/08 13:22:33 drh Exp $
+** $Id: vdbe.h,v 1.27 2001/10/12 17:30:05 drh Exp $
 */
 #ifndef _SQLITE_VDBE_H_
 #define _SQLITE_VDBE_H_
@@ -160,6 +160,15 @@ typedef struct VdbeOp VdbeOp;
 #define OP_Subtract           83
 #define OP_Multiply           84
 #define OP_Divide             85
+#define OP_Remainder
+#define OP_BitAnd
+#define OP_BitOr
+#define OP_BitNot
+#define OP_ShiftLeft
+#define OP_ShiftRight
+#define OP_Power
+#define OP_Exp
+#define OP_Log
 #define OP_Min                86
 #define OP_Max                87
 #define OP_Like               88
diff --git a/test/ioerr.test b/test/ioerr.test
new file mode 100644 (file)
index 0000000..be47b6b
--- /dev/null
@@ -0,0 +1,59 @@
+# 2001 October 12
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.  The
+# focus of this file is testing for correct handling of I/O errors
+# such as writes failing because the disk is full.
+# 
+# The tests in this file use special facilities that are only
+# available in the SQLite test fixture.
+#
+# $Id: ioerr.test,v 1.1 2001/10/12 17:30:05 drh Exp $
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+set ::go 1
+for {set n 1} {$go} {incr n} {
+  do_test ioerr-1.$n.1 {
+    set ::sqlite_io_error_pending 0
+    db close
+    catch {file delete -force test.db}
+    sqlite db test.db
+    execsql {SELECT * FROM sqlite_master}
+  } {}
+  do_test ioerr-1.$n.2 [subst {
+    set ::sqlite_io_error_pending $n
+  }] $n
+  do_test ioerr-1.$n.3 {
+    set r [catch {db eval {
+      CREATE TABLE t1(a,b,c);
+      SELECT * FROM sqlite_master;
+      BEGIN TRANSACTION;
+      INSERT INTO t1 VALUES(1,2,3);
+      INSERT INTO t1 VALUES(4,5,6);
+      ROLLBACK;
+      SELECT * FROM t1;
+      BEGIN TRANSACTION;
+      INSERT INTO t1 VALUES(1,2,3);
+      INSERT INTO t1 VALUES(4,5,6);
+      COMMIT;
+      SELECT * FROM t1;
+      DELETE FROM t1 WHERE a<100;
+    }} msg]
+    # if {$r} {puts $msg}
+    set ::go [expr {$::sqlite_io_error_pending<=0}]
+    expr {$::sqlite_io_error_pending>0 || $r!=0}
+  } {1}
+}
+set ::sqlite_io_error_pending 0
+
+
+finish_test
index c65f5891883d96ee2f8c47c09b299b4dbcb845b1..30d0a7d772495f8da63f68d16424f32dc51537ac 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Run this Tcl script to generate the sqlite.html file.
 #
-set rcsid {$Id: c_interface.tcl,v 1.16 2001/09/28 23:11:24 drh Exp $}
+set rcsid {$Id: c_interface.tcl,v 1.17 2001/10/12 17:30:05 drh Exp $}
 
 puts {<html>
 <head>
@@ -292,7 +292,10 @@ that there is no more space left on the disk.
 <dd><p>This value is returned if SQLite detects that the database it is
 working on has become corrupted.  Corruption might occur due to a rogue
 process writing to the database file or it might happen due to an 
-perviously undetected logic error in of SQLite. 
+perviously undetected logic error in of SQLite. This value is also
+returned if a disk I/O error occurs in such a way that SQLite is forced
+to leave the database file in a corrupted state.  The latter should only
+happen due to a hardware or operating system malfunction.
 </p></dd>
 <dt>SQLITE_FULL</dt>
 <dd><p>This value is returned if an insertion failed because there is
index ac06b1bf9e8539eb5e0380b43c32eb40ff48aca7..47fdcc3831ec7280596fe1cbac5a8d3092d65847 100644 (file)
@@ -17,6 +17,14 @@ proc chng {date desc} {
   puts "<DD><P><UL>$desc</UL></P></DD>"
 }
 
+chng {2001 Oct ? (2.0.3)} {
+<li>Bug fix: the <b>sqlite_busy_timeout()</b> function was delaying 1000
+    times too long before failing.</li>
+<li>Bug fix: an assertion was failing if the disk holding the database
+    file became full or stopped accepting writes for some other reason.
+    New tests were added to detect similar problems in the future.</li>
+}
+
 chng {2001 Oct 9 (2.0.2)} {
 <li>Fix two bugs in the locking protocol.  (One was masking the other.)</li>
 <li>Removed some unused "#include <unistd.h>" that were causing problems