Added test code to check for file descriptor leaks.  All regression tests pass
now on both win2k and linux. (CVS 868)

FossilOrigin-Name: 75ba78280f7ab6b6acce5878859312f3223ee898
diff --git a/src/main.c b/src/main.c
index c17c2f1..8fa81d8 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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.113 2003/02/12 14:09:44 drh Exp $
+** $Id: main.c,v 1.114 2003/02/16 22:21:32 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -457,7 +457,11 @@
 */
 void sqlite_close(sqlite *db){
   HashElem *i;
-  if( sqliteSafetyCheck(db) || sqliteSafetyOn(db) ){ return; }
+  db->want_to_close = 1;
+  if( sqliteSafetyCheck(db) || sqliteSafetyOn(db) ){
+    /* printf("DID NOT CLOSE\n"); fflush(stdout); */
+    return;
+  }
   db->magic = SQLITE_MAGIC_CLOSED;
   sqliteBtreeClose(db->pBe);
   sqliteResetInternalSchema(db);
diff --git a/src/os.c b/src/os.c
index a071679..d0b50dc 100644
--- a/src/os.c
+++ b/src/os.c
@@ -225,6 +225,16 @@
 #define SimulateIOError(A)
 #endif
 
+/*
+** When testing, keep a count of the number of open files.
+*/
+#ifdef SQLITE_TEST
+int sqlite_open_file_count = 0;
+#define OpenCounter(X)  sqlite_open_file_count+=(X)
+#else
+#define OpenCounter(X)
+#endif
+
 
 /*
 ** Delete the named file
@@ -296,6 +306,7 @@
   }
   id->locked = 0;
   TRACE3("OPEN    %-3d %s\n", id->fd, zFilename);
+  OpenCounter(+1);
   return SQLITE_OK;
 #endif
 #if OS_WIN
@@ -325,6 +336,7 @@
   }
   id->h = h;
   id->locked = 0;
+  OpenCounter(+1);
   return SQLITE_OK;
 #endif
 #if OS_MAC
@@ -374,6 +386,7 @@
   }
   id->locked = 0;
   id->delOnClose = 0;
+  OpenCounter(+1);
   return SQLITE_OK;
 #endif
 }
@@ -415,6 +428,7 @@
     unlink(zFilename);
   }
   TRACE3("OPEN-EX %-3d %s\n", id->fd, zFilename);
+  OpenCounter(+1);
   return SQLITE_OK;
 #endif
 #if OS_WIN
@@ -439,6 +453,7 @@
   }
   id->h = h;
   id->locked = 0;
+  OpenCounter(+1);
   return SQLITE_OK;
 #endif
 #if OS_MAC
@@ -467,6 +482,7 @@
   id->delOnClose = delFlag;
   if (delFlag)
     id->pathToDel = sqliteOsFullPathname(zFilename);
+  OpenCounter(+1);
   return SQLITE_OK;
 #endif
 }
@@ -493,6 +509,7 @@
   }
   id->locked = 0;
   TRACE3("OPEN-RO %-3d %s\n", id->fd, zFilename);
+  OpenCounter(+1);
   return SQLITE_OK;
 #endif
 #if OS_WIN
@@ -509,6 +526,7 @@
   }
   id->h = h;
   id->locked = 0;
+  OpenCounter(+1);
   return SQLITE_OK;
 #endif
 #if OS_MAC
@@ -534,6 +552,7 @@
   }
   id->locked = 0;
   id->delOnClose = 0;
+  OpenCounter(+1);
   return SQLITE_OK;
 #endif
 }
@@ -651,10 +670,12 @@
   releaseLockInfo(id->pLock);
   sqliteOsLeaveMutex();
   TRACE2("CLOSE   %-3d\n", id->fd);
+  OpenCounter(-1);
   return SQLITE_OK;
 #endif
 #if OS_WIN
   CloseHandle(id->h);
+  OpenCounter(-1);
   return SQLITE_OK;
 #endif
 #if OS_MAC
@@ -669,6 +690,8 @@
     unlink(id->pathToDel);
     sqliteFree(id->pathToDel);
   }
+  OpenCounter(-1);
+  return SQLITE_OK;
 #endif
 }
 
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index e434543..e8f1682 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.161 2003/02/12 14:09:44 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.162 2003/02/16 22:21:32 drh Exp $
 */
 #include "config.h"
 #include "sqlite.h"
@@ -209,6 +209,7 @@
   int flags;                    /* Miscellanous flags. See below */
   u8 file_format;               /* What file format version is this database? */
   u8 safety_level;              /* How aggressive at synching data to disk */
+  u8 want_to_close;             /* Close after all VDBEs are deallocated */
   int schema_cookie;            /* Magic number that changes with the schema */
   int next_cookie;              /* Value of schema_cookie after commit */
   int cache_size;               /* Number of pages to use in the cache */
diff --git a/src/test1.c b/src/test1.c
index 232259f..402b2c2 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -13,18 +13,25 @@
 ** is not included in the SQLite library.  It is used for automated
 ** testing of the SQLite library.
 **
-** $Id: test1.c,v 1.21 2003/02/16 19:13:37 drh Exp $
+** $Id: test1.c,v 1.22 2003/02/16 22:21:32 drh Exp $
 */
 #include "sqliteInt.h"
 #include "tcl.h"
+#include "os.h"
 #include <stdlib.h>
 #include <string.h>
 
+#if OS_WIN
+# define PTR_FMT "%x"
+#else
+# define PTR_FMT "%p"
+#endif
+
 /*
 ** Decode a pointer to an sqlite object.
 */
 static int getDbPointer(Tcl_Interp *interp, const char *zArg, sqlite **ppDb){
-  if( sscanf(zArg, "%p", (void**)ppDb)!=1 ){
+  if( sscanf(zArg, PTR_FMT, (void**)ppDb)!=1 ){
     Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
     return TCL_ERROR;
   }
@@ -35,7 +42,7 @@
 ** Decode a pointer to an sqlite_vm object.
 */
 static int getVmPointer(Tcl_Interp *interp, const char *zArg, sqlite_vm **ppVm){
-  if( sscanf(zArg, "%p", (void**)ppVm)!=1 ){
+  if( sscanf(zArg, PTR_FMT, (void**)ppVm)!=1 ){
     Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
     return TCL_ERROR;
   }
@@ -67,7 +74,7 @@
     free(zErr);
     return TCL_ERROR;
   }
-  sprintf(zBuf,"%p", db);
+  sprintf(zBuf,PTR_FMT, db);
   Tcl_AppendResult(interp, zBuf, 0);
   return TCL_OK;
 }
@@ -735,7 +742,7 @@
     return TCL_ERROR;
   }
   if( vm ){
-    sprintf(zBuf, "%p", vm);
+    sprintf(zBuf, PTR_FMT, vm);
     Tcl_AppendResult(interp, zBuf, 0);
   }
   return TCL_OK;
@@ -853,6 +860,7 @@
 */
 int Sqlitetest1_Init(Tcl_Interp *interp){
   extern int sqlite_search_count;
+  extern int sqlite_open_file_count;
   static struct {
      char *zName;
      Tcl_CmdProc *xProc;
@@ -889,5 +897,7 @@
   }
   Tcl_LinkVar(interp, "sqlite_search_count", 
       (char*)&sqlite_search_count, TCL_LINK_INT);
+  Tcl_LinkVar(interp, "sqlite_open_file_count", 
+      (char*)&sqlite_open_file_count, TCL_LINK_INT);
   return TCL_OK;
 }
diff --git a/src/util.c b/src/util.c
index 26e7afc..8231e98 100644
--- a/src/util.c
+++ b/src/util.c
@@ -14,7 +14,7 @@
 ** This file contains functions for allocating memory, comparing
 ** strings, and stuff like that.
 **
-** $Id: util.c,v 1.57 2003/01/29 14:06:09 drh Exp $
+** $Id: util.c,v 1.58 2003/02/16 22:21:32 drh Exp $
 */
 #include "sqliteInt.h"
 #include <stdarg.h>
@@ -1163,7 +1163,8 @@
   if( db->magic==SQLITE_MAGIC_OPEN ){
     db->magic = SQLITE_MAGIC_BUSY;
     return 0;
-  }else if( db->magic==SQLITE_MAGIC_BUSY || db->magic==SQLITE_MAGIC_ERROR ){
+  }else if( db->magic==SQLITE_MAGIC_BUSY || db->magic==SQLITE_MAGIC_ERROR
+             || db->want_to_close ){
     db->magic = SQLITE_MAGIC_ERROR;
     db->flags |= SQLITE_Interrupt;
   }
@@ -1179,7 +1180,8 @@
   if( db->magic==SQLITE_MAGIC_BUSY ){
     db->magic = SQLITE_MAGIC_OPEN;
     return 0;
-  }else if( db->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_ERROR ){
+  }else if( db->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_ERROR
+             || db->want_to_close ){
     db->magic = SQLITE_MAGIC_ERROR;
     db->flags |= SQLITE_Interrupt;
   }
diff --git a/src/vdbe.c b/src/vdbe.c
index 67c7fdb..07819c1 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -36,7 +36,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.203 2003/01/29 22:58:26 drh Exp $
+** $Id: vdbe.c,v 1.204 2003/02/16 22:21:32 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -5741,5 +5741,8 @@
 #endif
   rc = p->rc;
   sqliteVdbeDelete(p);
+  if( db->want_to_close && db->pVdbe==0 ){
+    sqlite_close(db);
+  }
   return rc;
 }