diff --git a/contrib/pg_autovacuum/README.pg_autovacuum b/contrib/pg_autovacuum/README.pg_autovacuum
index 2f79ba543e647b212c241ecec75b698f1ebd95af..245783ecf47becdf4001be0aca13198e83c55ef9 100644
--- a/contrib/pg_autovacuum/README.pg_autovacuum
+++ b/contrib/pg_autovacuum/README.pg_autovacuum
@@ -1,80 +1,156 @@
 pg_autovacuum README
+--------------------
 
-pg_autovacuum is a libpq client program that monitors all the databases of a
-postgresql server.  It uses the stats collector to monitor insert, update and
-delete activity.  When an individual table exceeds it's insert or delete
-threshold (more detail on thresholds below) then that table is vacuumed or
-analyzed.  This allows postgresql to keep the fsm and table statistics up to
-date without having to schedule periodic vacuums with cron regardless of need.
+pg_autovacuum is a libpq client program that monitors all the
+databases associated with a postgresql server.  It uses the stats
+collector to monitor insert, update and delete activity.  
 
-The primary benefit of pg_autovacuum is that the FSM and table statistic information
-are updated as needed.  When a table is actively changed pg_autovacuum performs the
-necessary vacuums and analyzes, when a table is inactive, no cycles are wasted
-performing vacuums and analyzes that are not needed.
+When a table exceeds its insert or delete threshold (more detail
+on thresholds below) then that table will be  vacuumed or analyzed.  
+
+This allows postgresql to keep the fsm and table statistics up to
+date, and eliminates the need to schedule periodic vacuums.
+
+The primary benefit of pg_autovacuum is that the FSM and table
+statistic information are updated as needed.  When a table is actively
+changing, pg_autovacuum will perform the necessary vacuums and
+analyzes, whereas if a table remains static, no cycles will be wasted
+performing unnecessary vacuums/analyzes.
+
+A secondary benefit of pg_autovacuum is that it ensures that a
+database wide vacuum is performed prior to xid wraparound.  This is an
+important, if rare, problem, as failing to do so can result in major
+data loss.
+
+
+KNOWN ISSUES:
+-------------
+pg_autovacuum has been tested under Redhat Linux (by me) and Solaris (by
+Christopher B. Browne) and all known bugs have been resolved.  Please report
+any problems to the hackers list.
+
+pg_autovacuum does not get started automatically by either the postmaster or
+by pg_ctl.  Along the sames lines, when the postmaster exits no one tells
+pg_autovacuum.  The result is that at the start of the next loop,
+pg_autovacuum fails to connect to the server and exits.  Any time  it fails
+to connect pg_autovacuum exits.
+
+pg_autovacuum requires that the stats system be enabled and reporting row
+level stats.  The overhead of the stats system has been shown to be
+significant under certain workloads.  For instance a tight loop of queries
+performing "select 1" was nearly 30% slower with stats enabled.  However,
+in practice with more realistic workloads, the stats system overhead is
+usually nominal.
 
-A secondary benefit of pg_autovacuum is that it guarantees that a database wide
-vacuum is performed prior to xid wraparound.  This is important as failing to do
-so can result in major data loss.
 
 INSTALL:
-To use pg_autovacuum, uncompress the tar.gz into the contrib directory and modify the
-contrib/Makefile to include the pg_autovacuum directory.  pg_autovacuum will then be made as
-part of the standard postgresql install.
+--------
+
+As of postgresql v7.4 pg_autovacuum is included in the main source tree
+under contrib.  Therefore you just make && make install (similar to most other
+contrib modules) and it will be installed for you.
+
+If you are using an earlier version of postgresql just uncompress the tar.gz
+into the contrib directory and modify the contrib/Makefile to include the pg_autovacuum
+directory.  pg_autovacuum will then be made as part of the standard
+postgresql install.
 
 make sure that the folowing are set in postgresql.conf
-stats_start_collector = true
-stats_row_level = true
 
-start up the postmaster
-then, just execute the pg_autovacuum executable.
+  stats_start_collector = true
+  stats_row_level = true
+
+start up the postmaster, then execute the pg_autovacuum executable.
 
 
 Command line arguments:
+-----------------------
+
 pg_autovacuum has the following optional arguments:
+
 -d debug: 0 silent, 1 basic info, 2 more debug info,  etc...
+-D dameonize: Detach from tty and run in background.
 -s sleep base value: see "Sleeping" below.
 -S sleep scaling factor: see "Sleeping" below.
--t tuple base threshold: see Vacuuming.
--T tuple scaling factor: see Vacuuming.
--U username: Username pg_autovacuum will use to connect with, if not specified the
-   current username is used
+-v vacuum base threshold: see Vacuum and Analyze.
+-V vacuum scaling factor: see Vacuum and Analyze.
+-a analyze base threshold: see Vacuum and Analyze.
+-A analyze scaling factor: see Vacuum and Analyze.
+-L log file: Name of file to which output is submitted, otherwise STDERR
+-U username: Username pg_autovacuum will use to connect with, if not
+   specified the current username is used.
 -P password: Password pg_autovacuum will use to connect with.
 -H host: host name or IP to connect too.
 -p port: port used for connection.
 -h help: list of command line options.
 
-All arguments have default values defined in pg_autovacuum.h.  At the time of this
-writing they are:
-#define AUTOVACUUM_DEBUG    1
-#define BASETHRESHOLD       100
-#define SCALINGFACTOR       2
-#define SLEEPVALUE          3
-#define SLEEPSCALINGFACTOR  2
-#define UPDATE_INTERVAL     2
+All arguments have default values defined in pg_autovacuum.h.  At the
+time of writing they are:
+
+-d 1
+-v 1000
+-V 2   
+-a 500 (half of -v is not specified)
+-A 1   (half of -v is not specified)
+-s 300 (5 minutes)
+-S 2
 
 
 Vacuum and Analyze:
-pg_autovacuum performes either a vacuums analyze or just analyze depending on the table activity.
-If the number of (inserts + updates) > insertThreshold, then an only an analyze is performed.
-If the number of (deletes + updates ) > deleteThreshold, then a vacuum analyze is performed.
-deleteThreshold is equal to: tuple_base_value + (tuple_scaling_factor * "number of tuples in the table")
-insertThreshold is equal to: 0.5 * tuple_base_value + (tuple_scaling_factor * "number of tuples in the table")
-The insertThreshold is half the deleteThreshold because it's a much lighter operation (approx 5%-10% of vacuum),
-so running it more often costs us little in performance degredation.
+-------------------
+
+pg_autovacuum performs either a vacuum analyze or just analyze depending
+on the quantity and type of table activity (insert, update, or delete):
+
+- If the number of (inserts + updates + deletes) > AnalyzeThreshold, then
+  only an analyze is performed.
+
+- If the number of (deletes + updates ) > VacuumThreshold, then a
+  vacuum analyze is performed.
+
+deleteThreshold is equal to: 
+    vacuum_base_value + (vacuum_scaling_factor * "number of tuples in the table")
+
+insertThreshold is equal to: 
+    analyze_base_value + (analyze_scaling_factor * "number of tuples in the table")
+
+The AnalyzeThreshold defaults to half of the VacuumThreshold since it
+represents a much less expensive operation (approx 5%-10% of vacuum), and
+running it more often should not substantially degrade system performance.
 
 Sleeping:
-pg_autovacuum sleeps after it is done checking all the databases.  It does this so as
-to limit the amount of system resources it consumes.  This also allows the system
-administrator to configure pg_autovacuum to be more or less aggressive.  Reducing the
-sleep time will cause pg_autovacuum to respond more quickly to changes, be they database
-addition / removal, table addition / removal, or just normal table activity.  However,
-setting these values to high can have a negative net effect on the server.  If a table
-gets vacuumed 5 times during the course of a large update, it might take much longer
-than if it was vacuumed only once.
+---------
+
+pg_autovacuum sleeps for a while after it is done checking all the
+databases.  It does this in order to limit the amount of system
+resources it consumes.  This also allows the system administrator to
+configure pg_autovacuum to be more or less aggressive.
+
+Reducing the sleep time will cause pg_autovacuum to respond more
+quickly to changes, whether they be database addition/removal, table
+addition/removal, or just normal table activity.
+
+On the other hand, setting pg_autovaccum to sleep values to agressivly
+(for too short a period of time) can have a negative effect on server
+performance.  If a table gets vacuumed 5 times during the course of a
+large update, this is likely to take much longer than if the table was
+vacuumed only once, at the end.
+
 The total time it sleeps is equal to:
-base_sleep_value + sleep_scaling_factor * "duration of the previous loop"
 
-What it monitors:
-pg_autovacuum dynamically generates a list of databases and tables to monitor, in
-addition it will dynamically add and remove databases and tables that are
-removed from the database server while pg_autovacuum is running.
+  base_sleep_value + sleep_scaling_factor * "duration of the previous
+  loop"
+
+Note that timing measurements are made in seconds; specifying
+"pg_vacuum -s 1" means pg_autovacuum could poll the database upto 60 times
+minute.  In a system with large tables where vacuums may run for several
+minutes, longer times between vacuums are likely to be appropriate.
+
+What pg_autovacuum monitors:
+----------------------------
+
+pg_autovacuum dynamically generates a list of all databases and tables that
+exist on the server.  It will dynamically add and remove databases and
+tables that are removed from the database server while pg_autovacuum is
+running.  Overhead is fairly small per object.  For example: 10 databases
+with 10 tables each appears to less than 10k of memory on my Linux box.
diff --git a/contrib/pg_autovacuum/TODO b/contrib/pg_autovacuum/TODO
index 50e5aaaec5cd92d35758e3018265e7bca2a1ed51..f9d383d9863556466f7d80ba1bd71015ab8eae49 100644
--- a/contrib/pg_autovacuum/TODO
+++ b/contrib/pg_autovacuum/TODO
@@ -1,6 +1,5 @@
 Todo Items for pg_autovacuum client
-
-_Allow it to detach from the tty
+--------------------------------------------------------------------------
 
 _create a FSM export function and see if I can use it for pg_autovacuum
 
@@ -9,6 +8,7 @@ _look into possible benifits of pgstattuple contrib work
 _Continue trying to reduce server load created by polling.
 
 Done:
+--------------------------------------------------------------------------
 _Check if required pg_stats are enables, if not exit with error
 
 _Reduce the number connections and queries to the server
@@ -34,3 +34,10 @@ _change name to pg_autovacuum
 
 _Add proper table and database removal functions so that we can properly
 	clear up before we exit, and make sure we don't leak memory when removing tables and such.
+
+_Decouple insert and delete thresholds
+
+_Fix Vacuum debug routine to include the database name.
+
+_Allow it to detach from the tty
+
diff --git a/contrib/pg_autovacuum/pg_autovacuum.c b/contrib/pg_autovacuum/pg_autovacuum.c
index 804436afbd89f468d4d8529544d1bc2031741ac2..dce065d7b6f13f71a2117468051f62bf0553f55d 100644
--- a/contrib/pg_autovacuum/pg_autovacuum.c
+++ b/contrib/pg_autovacuum/pg_autovacuum.c
@@ -1,206 +1,329 @@
 /* pg_autovacuum.c
  * All the code for the pg_autovacuum program
  * (c) 2003 Matthew T. O'Connor
+ * Revisions by Christopher B. Browne, Liberty RMS
  */
 
 #include "pg_autovacuum.h"
+#define TIMEBUFF 256
+FILE *LOGOUTPUT;
+char timebuffer[TIMEBUFF];
+char logbuffer[4096];
 
-/* Create and return tbl_info struct with initalized to values from row or res */
-tbl_info *init_table_info(PGresult *res, int row)
+void
+log_entry (const char *logentry)
 {
-  tbl_info *new_tbl=(tbl_info *)malloc(sizeof(tbl_info));
+  time_t curtime;
+  struct tm *loctime;
+  curtime = time (NULL);
+  loctime = localtime (&curtime);
+  strftime (timebuffer, TIMEBUFF, "%Y-%m-%d %r", loctime);  /* cbb - %F is not always available */
+  fprintf (LOGOUTPUT, "[%s] %s\n", timebuffer, logentry);
+}
+
+/* Function used to detatch the pg_autovacuum daemon from the tty and go into the background *
+*     This code is mostly ripped directly from pm_dameonize in postmaster.c               *
+*     with unneeded code removed.                                                         */
+void daemonize ()
+{
+  pid_t pid;
 
-  if(!new_tbl)
+  pid = fork();
+  if (pid == (pid_t) -1)
   {
-    fprintf(stderr,"init_table_info: Cannot get memory\n");
-    return NULL;
+    log_entry("Error: cannot disassociate from controlling TTY");
+    fflush(LOGOUTPUT);
+    _exit(1);
+  }
+  else if (pid)
+  {  /* parent */
+     /* Parent should just exit, without doing any atexit cleanup */
+    _exit(0);
   }
 
-  if(NULL == res)
-    return NULL;
-
-  new_tbl->schema_name=(char *)malloc(strlen(PQgetvalue(res,row,PQfnumber(res,"schemaname")))+1);
-  if(!new_tbl->schema_name)
+/* GH: If there's no setsid(), we hopefully don't need silent mode.
+ * Until there's a better solution.  */
+#ifdef HAVE_SETSID
+  if (setsid() < 0)
   {
-    fprintf(stderr,"init_table_info: malloc failed on new_tbl->schema_name\n");
-    return NULL;
+    log_entry("Error: cannot disassociate from controlling TTY");
+    fflush(LOGOUTPUT);
+    _exit(1);
   }
-  strcpy(new_tbl->schema_name,PQgetvalue(res,row,PQfnumber(res,"schemaname")));
+#endif
 
-  new_tbl->table_name=(char *)malloc(strlen(PQgetvalue(res,row,PQfnumber(res,"relname"))) + strlen(new_tbl->schema_name)+2);
-  if(!new_tbl->table_name)
-  {
-    fprintf(stderr,"init_table_info: malloc failed on new_tbl->table_name\n");
+}
+
+/* Create and return tbl_info struct with initialized to values from row or res */
+tbl_info *
+init_table_info (PGresult * res, int row, db_info *dbi)
+{
+  tbl_info *new_tbl = (tbl_info *) malloc (sizeof (tbl_info));
+
+  if (!new_tbl) {
+    log_entry ("init_table_info: Cannot get memory");
+    fflush (LOGOUTPUT);
     return NULL;
   }
-  strcpy(new_tbl->table_name,new_tbl->schema_name);
-  strcat(new_tbl->table_name,".");
-  strcat(new_tbl->table_name,PQgetvalue(res,row,PQfnumber(res,"relname")));
 
-  new_tbl->InsertsAtLastAnalyze=(atol(PQgetvalue(res,row,PQfnumber(res,"n_tup_ins"))) + atol(PQgetvalue(res,row,PQfnumber(res,"n_tup_upd"))));
-  new_tbl->DeletesAtLastVacuum =(atol(PQgetvalue(res,row,PQfnumber(res,"n_tup_del"))) + atol(PQgetvalue(res,row,PQfnumber(res,"n_tup_upd"))));
+  if (NULL == res)
+    return NULL;
 
-  new_tbl->relfilenode=atoi(PQgetvalue(res,row,PQfnumber(res,"relfilenode")));
-  new_tbl->reltuples=atoi(PQgetvalue(res,row,PQfnumber(res,"reltuples")));
-  new_tbl->relpages=atoi(PQgetvalue(res,row,PQfnumber(res,"relpages")));
+  new_tbl->dbi = dbi;    /* set pointer to db */
 
-  new_tbl->insertThreshold=args->tuple_base_threshold + args->tuple_scaling_factor*new_tbl->reltuples;
-  new_tbl->deleteThreshold=args->tuple_base_threshold + args->tuple_scaling_factor*new_tbl->reltuples;
+  new_tbl->schema_name = (char *)
+    malloc (strlen (PQgetvalue (res, row, PQfnumber (res, "schemaname"))) + 1);
+  if (!new_tbl->schema_name) {
+    log_entry ("init_table_info: malloc failed on new_tbl->schema_name");
+    fflush (LOGOUTPUT);
+    return NULL;
+  }
+  strcpy (new_tbl->schema_name,
+    PQgetvalue (res, row, PQfnumber (res, "schemaname")));
+
+  new_tbl->table_name = (char *)
+    malloc (strlen (PQgetvalue (res, row, PQfnumber (res, "relname"))) +
+    strlen (new_tbl->schema_name) + 2);
+  if (!new_tbl->table_name) {
+    log_entry ("init_table_info: malloc failed on new_tbl->table_name");
+    fflush (LOGOUTPUT);
+    return NULL;
+  }
+  strcpy (new_tbl->table_name, new_tbl->schema_name);
+  strcat (new_tbl->table_name, ".");
+  strcat (new_tbl->table_name, PQgetvalue (res, row, PQfnumber (res, "relname")));
+
+  new_tbl->CountAtLastAnalyze =
+    (atol (PQgetvalue (res, row, PQfnumber (res, "n_tup_ins"))) +
+     atol (PQgetvalue (res, row, PQfnumber (res, "n_tup_upd"))));
+  new_tbl->curr_analyze_count = new_tbl->CountAtLastAnalyze;
+
+  new_tbl->CountAtLastVacuum =
+    (atol (PQgetvalue (res, row, PQfnumber (res, "n_tup_del"))) +
+     atol (PQgetvalue (res, row, PQfnumber (res, "n_tup_upd"))));
+  new_tbl->curr_vacuum_count = new_tbl->CountAtLastVacuum;
+
+  new_tbl->relfilenode = atoi (PQgetvalue (res, row, PQfnumber (res, "relfilenode")));
+  new_tbl->reltuples =   atoi (PQgetvalue (res, row, PQfnumber (res, "reltuples")));
+  new_tbl->relpages =    atoi (PQgetvalue (res, row, PQfnumber (res, "relpages")));
+
+  new_tbl->analyze_threshold =
+    args->analyze_base_threshold + args->analyze_scaling_factor * new_tbl->reltuples;
+  new_tbl->vacuum_threshold =
+    args->vacuum_base_threshold + args->vacuum_scaling_factor * new_tbl->reltuples;
+
+  if (args->debug >= 2) {
+    print_table_info (new_tbl);
+  }
 
-  if(args->debug >= 2) {print_table_info(new_tbl);}
-  
   return new_tbl;
 }
 
 /* Set thresholds = base_value + scaling_factor * reltuples
-   Should be called after a vacuum since vacuum updates valuesin pg_class */
-void update_table_thresholds(db_info *dbi,tbl_info *tbl)
+   Should be called after a vacuum since vacuum updates values in pg_class */
+void
+update_table_thresholds (db_info * dbi, tbl_info * tbl,int vacuum_type)
 {
-  PGresult *res=NULL;
-  int disconnect=0;
-	char query[128];
+  PGresult *res = NULL;
+  int disconnect = 0;
+  char query[128];
 
-  if(NULL==dbi->conn)
-  { dbi->conn=db_connect(dbi); disconnect=1;}
+  if (NULL == dbi->conn) {
+    dbi->conn = db_connect (dbi);
+    disconnect = 1;
+  }
 
-  if(NULL != dbi->conn)
-  {
-    snprintf(query,sizeof(query),"select relfilenode,reltuples,relpages from pg_class where relfilenode=%i",tbl->relfilenode);
-    res=send_query(query,dbi);
-    if(NULL!=res)
-    {
-    	tbl->reltuples = atoi(PQgetvalue(res,0,PQfnumber(res,"reltuples")));
-    	tbl->relpages = atoi(PQgetvalue(res,0,PQfnumber(res,"relpages")));
-      tbl->deleteThreshold = (args->tuple_base_threshold + args->tuple_scaling_factor*tbl->reltuples);
-      tbl->insertThreshold = (0.5 * tbl->deleteThreshold);
-      PQclear(res);
+  if (NULL != dbi->conn) {
+    snprintf (query, sizeof (query), PAGES_QUERY, tbl->relfilenode);
+    res = send_query (query, dbi);
+    if (NULL != res) {
+      tbl->reltuples =
+        atoi (PQgetvalue (res, 0, PQfnumber (res, "reltuples")));
+      tbl->relpages = atoi (PQgetvalue (res, 0, PQfnumber (res, "relpages")));
+
+      /* update vacuum thresholds only of we just did a vacuum analyze */
+      if(VACUUM_ANALYZE == vacuum_type)
+      {
+        tbl->vacuum_threshold =
+          (args->vacuum_base_threshold + args->vacuum_scaling_factor * tbl->reltuples);
+        tbl->CountAtLastVacuum  = tbl->curr_vacuum_count;
+      }
+
+      /* update analyze thresholds */
+      tbl->analyze_threshold =
+        (args->analyze_base_threshold + args->analyze_scaling_factor * tbl->reltuples);
+      tbl->CountAtLastAnalyze = tbl->curr_analyze_count;
+
+      PQclear (res);
+
+      /* If the stats collector is reporting fewer updates then we have on record
+         then the stats were probably reset, so we need to reset also */
+      if ((tbl->curr_analyze_count < tbl->CountAtLastAnalyze) ||
+          (tbl->curr_vacuum_count < tbl->CountAtLastVacuum))
+      {
+        tbl->CountAtLastAnalyze = tbl->curr_analyze_count;
+        tbl->CountAtLastVacuum = tbl->curr_vacuum_count;
+      }
     }
-	}
-  if(disconnect)	db_disconnect(dbi);
+  }
+  if (disconnect)
+    db_disconnect (dbi);
 }
 
-void update_table_list(db_info *dbi)
+void
+update_table_list (db_info * dbi)
 {
-	int disconnect=0;
-	PGresult *res=NULL;
-	tbl_info *tbl=NULL;
-	Dlelem *tbl_elem=DLGetHead(dbi->table_list);
-	int i=0,t=0,found_match=0;
-	
-  if(NULL==dbi->conn)
-  {	dbi->conn=db_connect(dbi);   disconnect=1;}
-
-  if(NULL != dbi->conn)
-  {
+  int disconnect = 0;
+  PGresult *res = NULL;
+  tbl_info *tbl = NULL;
+  Dlelem *tbl_elem = DLGetHead (dbi->table_list);
+  int i = 0, t = 0, found_match = 0;
+
+  if (NULL == dbi->conn) {
+    dbi->conn = db_connect (dbi);
+    disconnect = 1;
+  }
+
+  if (NULL != dbi->conn) {
     /* Get a result set that has all the information
-    	 we will need to both remove tables from the list
+       we will need to both remove tables from the list
        that no longer exist and add tables to the list
        that are new */
-		res=send_query(query_table_stats(dbi),dbi);
-		t=PQntuples(res);
-   
-		/* First: use the tbl_list as the outer loop and
-				the result set as the inner loop, this will
-				determine what tables should be removed */
-    while(NULL != tbl_elem)
-		{
-			tbl=((tbl_info *)DLE_VAL(tbl_elem));
-			found_match=0;
-			
-			for(i=0;i<t;i++) /* loop through result set looking for a match */
-			{
-				if(tbl->relfilenode==atoi(PQgetvalue(res,i,PQfnumber(res,"relfilenode"))))
-				{
-					found_match=1;
-					break;
-				}
-			}
-			if(0==found_match) /*then we didn't find this tbl_elem in the result set */
-			{
-				Dlelem *elem_to_remove=tbl_elem;
-				tbl_elem=DLGetSucc(tbl_elem);
-				remove_table_from_list(elem_to_remove);
-			}
-			else
-				tbl_elem=DLGetSucc(tbl_elem);
-		} /* Done removing dropped tables from the table_list */
-
-		/* Then loop use result set as outer loop and
-				tbl_list as the inner loop to determine
-				what tables are new */
-		for(i=0;i<t;i++)
-		{
-			tbl_elem=DLGetHead(dbi->table_list);
-			found_match=0;
-			while(NULL != tbl_elem)
-			{
-				tbl=((tbl_info *)DLE_VAL(tbl_elem));
-				if(tbl->relfilenode==atoi(PQgetvalue(res,i,PQfnumber(res,"relfilenode"))))
-				{
-					found_match=1;
-					break;
-				}
-				tbl_elem=DLGetSucc(tbl_elem);
-			}
-			if(0==found_match) /*then we didn't find this result now in the tbl_list */
-			{
-				DLAddTail(dbi->table_list,DLNewElem(init_table_info(res,i)));
-				if(args->debug >= 1) {printf("added table: %s.%s\n",dbi->dbname,((tbl_info *)DLE_VAL(DLGetTail(dbi->table_list)))->table_name);}
-			}
-		} /* end of for loop that adds tables */
-		PQclear(res); res=NULL;
-		if(args->debug >= 3)	{print_table_list(dbi->table_list);}
-		if(disconnect) db_disconnect(dbi);
-	}
+    res = send_query (query_table_stats (dbi), dbi);
+    t = PQntuples (res);
+
+    /* First: use the tbl_list as the outer loop and
+       the result set as the inner loop, this will
+       determine what tables should be removed */
+    while (NULL != tbl_elem) {
+      tbl = ((tbl_info *) DLE_VAL (tbl_elem));
+      found_match = 0;
+
+      for (i = 0; i < t; i++) {	/* loop through result set looking for a match */
+        if (tbl->relfilenode == atoi (PQgetvalue (res, i, PQfnumber (res, "relfilenode")))) {
+          found_match = 1;
+  	    break;
+        }
+      }
+      if (0 == found_match) {	/* then we didn't find this tbl_elem in the result set */
+        Dlelem *elem_to_remove = tbl_elem;
+        tbl_elem = DLGetSucc (tbl_elem);
+        remove_table_from_list (elem_to_remove);
+      }
+      else
+	tbl_elem = DLGetSucc (tbl_elem);
+    }	/* Done removing dropped tables from the table_list */
+
+    /* Then loop use result set as outer loop and
+       tbl_list as the inner loop to determine
+       what tables are new */
+    for (i = 0; i < t; i++)
+    {
+      tbl_elem = DLGetHead (dbi->table_list);
+      found_match = 0;
+      while (NULL != tbl_elem)
+      {
+        tbl = ((tbl_info *) DLE_VAL (tbl_elem));
+        if (tbl->relfilenode == atoi (PQgetvalue (res, i, PQfnumber (res, "relfilenode"))))
+        {
+          found_match = 1;
+	    break;
+	  }
+	  tbl_elem = DLGetSucc (tbl_elem);
+      }
+      if (0 == found_match) 	/*then we didn't find this result now in the tbl_list */
+      {
+        DLAddTail (dbi->table_list, DLNewElem (init_table_info (res, i, dbi)));
+	  if (args->debug >= 1)
+        {
+	    sprintf (logbuffer, "added table: %s.%s", dbi->dbname,
+		   ((tbl_info *) DLE_VAL (DLGetTail (dbi->table_list)))->table_name);
+	    log_entry (logbuffer);
+	  }
+      }
+    }				/* end of for loop that adds tables */
+    fflush (LOGOUTPUT);
+    PQclear (res);
+    res = NULL;
+    if (args->debug >= 3) {
+      print_table_list (dbi->table_list);
+    }
+    if (disconnect)
+      db_disconnect (dbi);
+  }
 }
 
 /* Free memory, and remove the node from the list */
-void remove_table_from_list(Dlelem *tbl_to_remove)
+void
+remove_table_from_list (Dlelem * tbl_to_remove)
 {
-  tbl_info *tbl=((tbl_info *)DLE_VAL(tbl_to_remove));
-
-  if(args->debug >= 1) {printf("Removing table: %s from list.\n",tbl->table_name);}
-  DLRemove(tbl_to_remove);
-
-	if(tbl->schema_name)
-	{	free(tbl->schema_name); tbl->schema_name=NULL;}
-	if(tbl->table_name)
-	{	free(tbl->table_name); tbl->table_name=NULL;}
-	if(tbl)
-	{	free(tbl); tbl=NULL;}
-  DLFreeElem(tbl_to_remove);
+  tbl_info *tbl = ((tbl_info *) DLE_VAL (tbl_to_remove));
+
+  if (args->debug >= 1) {
+    sprintf (logbuffer, "Removing table: %s from list.", tbl->table_name);
+    log_entry (logbuffer);
+    fflush (LOGOUTPUT);
+  }
+  DLRemove (tbl_to_remove);
+
+  if (tbl->schema_name) {
+    free (tbl->schema_name);
+    tbl->schema_name = NULL;
+  }
+  if (tbl->table_name) {
+    free (tbl->table_name);
+    tbl->table_name = NULL;
+  }
+  if (tbl) {
+    free (tbl);
+    tbl = NULL;
+  }
+  DLFreeElem (tbl_to_remove);
 }
 
 /* Free the entire table list */
-void free_tbl_list(Dllist *tbl_list)
+void
+free_tbl_list (Dllist * tbl_list)
 {
-	Dlelem *tbl_elem=DLGetHead(tbl_list);
-	Dlelem *tbl_elem_to_remove=NULL;
-	while(NULL != tbl_elem)
-	{
-		tbl_elem_to_remove=tbl_elem;
-		tbl_elem=DLGetSucc(tbl_elem);
-		remove_table_from_list(tbl_elem_to_remove);
-	}
-	DLFreeList(tbl_list);
+  Dlelem *tbl_elem = DLGetHead (tbl_list);
+  Dlelem *tbl_elem_to_remove = NULL;
+  while (NULL != tbl_elem) {
+    tbl_elem_to_remove = tbl_elem;
+    tbl_elem = DLGetSucc (tbl_elem);
+    remove_table_from_list (tbl_elem_to_remove);
+  }
+  DLFreeList (tbl_list);
 }
 
-void print_table_list(Dllist *table_list)
+void
+print_table_list (Dllist * table_list)
 {
-  Dlelem *table_elem=DLGetHead(table_list);
-  while (NULL != table_elem)
-  {
-    print_table_info(((tbl_info *)DLE_VAL(table_elem)));
-    table_elem=DLGetSucc(table_elem);
+  Dlelem *table_elem = DLGetHead (table_list);
+  while (NULL != table_elem) {
+    print_table_info (((tbl_info *) DLE_VAL (table_elem)));
+    table_elem = DLGetSucc (table_elem);
   }
 }
 
-void print_table_info(tbl_info *tbl)
+void
+print_table_info (tbl_info * tbl)
 {
-  printf("  table name:     %s\n",tbl->table_name);
-  printf("     iThresh: %i; Delete Thresh %i\n",tbl->insertThreshold,tbl->deleteThreshold);
-  printf("     relfilenode: %i; reltuples: %i;  relpages: %i\n",tbl->relfilenode,tbl->reltuples,tbl->relpages);
-  printf("     InsertsAtLastAnalyze: %li; DeletesAtLastVacuum: %li\n",tbl->InsertsAtLastAnalyze,tbl->DeletesAtLastVacuum);
+  sprintf (logbuffer, "  table name:     %s.%s", tbl->dbi->dbname, tbl->table_name);
+  log_entry (logbuffer);
+  sprintf (logbuffer, "     relfilenode: %i",tbl->relfilenode);
+  log_entry (logbuffer);
+  sprintf (logbuffer, "     reltuples: %i;  relpages: %i", tbl->reltuples, tbl->relpages);
+  log_entry (logbuffer);
+  sprintf (logbuffer, "     curr_analyze_count:  %li; cur_delete_count:   %li",
+	   tbl->curr_analyze_count, tbl->curr_vacuum_count);
+  log_entry (logbuffer);
+  sprintf (logbuffer, "     ins_at_last_analyze: %li; del_at_last_vacuum: %li",
+	   tbl->CountAtLastAnalyze, tbl->CountAtLastVacuum);
+  log_entry (logbuffer);
+  sprintf (logbuffer, "     insert_threshold:    %li; delete_threshold    %li",
+	   tbl->analyze_threshold, tbl->vacuum_threshold);
+  log_entry (logbuffer);
+  fflush (LOGOUTPUT);
 }
 
 /* End of table Management Functions */
@@ -208,144 +331,162 @@ void print_table_info(tbl_info *tbl)
 /* Beginning of DB Management Functions */
 
 /* init_db_list() creates the db_list and initalizes template1 */
-Dllist *init_db_list()
+Dllist *
+init_db_list ()
 {
-  Dllist   *db_list=DLNewList();
-  db_info  *dbs=NULL;
-  PGresult *res=NULL;
-
-  DLAddHead(db_list,DLNewElem(init_dbinfo((char *)"template1",0,0)));
-  if(NULL == DLGetHead(db_list)) /* Make sure init_dbinfo was successful */
-  { printf("init_db_list(): Error creating db_list for db: template1.\n"); return NULL; }
+  Dllist *db_list = DLNewList ();
+  db_info *dbs = NULL;
+  PGresult *res = NULL;
+
+  DLAddHead (db_list, DLNewElem (init_dbinfo ((char *) "template1", 0, 0)));
+  if (NULL == DLGetHead (db_list)) {	/* Make sure init_dbinfo was successful */
+    log_entry ("init_db_list(): Error creating db_list for db: template1.");
+    fflush (LOGOUTPUT);
+    return NULL;
+  }
 
   /* We do this just so we can set the proper oid for the template1 database */
-  dbs = ((db_info *)DLE_VAL(DLGetHead(db_list)));
-  dbs->conn=db_connect(dbs);
-
-  if(NULL != dbs->conn)
-  {
-    res=send_query("select oid,age(datfrozenxid) from pg_database where datname = 'template1'",dbs);
-    dbs->oid=atoi(PQgetvalue(res,0,PQfnumber(res,"oid")));
-    dbs->age=atoi(PQgetvalue(res,0,PQfnumber(res,"age")));
-    if(res)
-      PQclear(res);
-
-    if(args->debug >= 2) {print_db_list(db_list,0);}
-	}
+  dbs = ((db_info *) DLE_VAL (DLGetHead (db_list)));
+  dbs->conn = db_connect (dbs);
+
+  if (NULL != dbs->conn) {
+    res = send_query (FROZENOID_QUERY, dbs);
+    dbs->oid = atoi (PQgetvalue (res, 0, PQfnumber (res, "oid")));
+    dbs->age = atoi (PQgetvalue (res, 0, PQfnumber (res, "age")));
+    if (res)
+      PQclear (res);
+
+    if (args->debug >= 2) {
+      print_db_list (db_list, 0);
+    }
+  }
   return db_list;
 }
 
 /* Simple function to create an instance of the dbinfo struct
     Initalizes all the pointers and connects to the database  */
-db_info *init_dbinfo(char *dbname, int oid, int age)
+db_info *
+init_dbinfo (char *dbname, int oid, int age)
 {
-  db_info *newdbinfo=(db_info *)malloc(sizeof(db_info));
-  newdbinfo->insertThreshold=args->tuple_base_threshold;
-  newdbinfo->deleteThreshold=args->tuple_base_threshold;
-  newdbinfo->dbname=(char *)malloc(strlen(dbname)+1);
-  strcpy(newdbinfo->dbname,dbname);
-  newdbinfo->username=NULL;
-  if(NULL != args->user)
-  {
-  	newdbinfo->username=(char *)malloc(strlen(args->user)+1);
-  	strcpy(newdbinfo->username,args->user);
+  db_info *newdbinfo = (db_info *) malloc (sizeof (db_info));
+  newdbinfo->analyze_threshold = args->vacuum_base_threshold;
+  newdbinfo->vacuum_threshold = args->analyze_base_threshold;
+  newdbinfo->dbname = (char *) malloc (strlen (dbname) + 1);
+  strcpy (newdbinfo->dbname, dbname);
+  newdbinfo->username = NULL;
+  if (NULL != args->user) {
+    newdbinfo->username = (char *) malloc (strlen (args->user) + 1);
+    strcpy (newdbinfo->username, args->user);
   }
-  newdbinfo->password=NULL;
-  if(NULL != args->password)
-  {
-  	newdbinfo->password=(char *)malloc(strlen(args->password)+1);
-  	strcpy(newdbinfo->password,args->password);
+  newdbinfo->password = NULL;
+  if (NULL != args->password) {
+    newdbinfo->password = (char *) malloc (strlen (args->password) + 1);
+    strcpy (newdbinfo->password, args->password);
+  }
+  newdbinfo->oid = oid;
+  newdbinfo->age = age;
+  newdbinfo->table_list = DLNewList ();
+  newdbinfo->conn = NULL;
+
+  if (args->debug >= 2) {
+    print_table_list (newdbinfo->table_list);
   }
-  newdbinfo->oid=oid;
-  newdbinfo->age=age;
-  newdbinfo->table_list=DLNewList();
-	newdbinfo->conn=NULL;
-	
-  if(args->debug >= 2) {print_table_list(newdbinfo->table_list);}
 
   return newdbinfo;
 }
 
 /* Function adds and removes databases from the db_list as appropriate */
-void update_db_list(Dllist *db_list)
+void
+update_db_list (Dllist * db_list)
 {
-	int disconnect=0;
-	PGresult *res=NULL;
-	Dlelem *db_elem=DLGetHead(db_list);
-	db_info *dbi=NULL;
-	db_info *dbi_template1=DLE_VAL(db_elem);
-	int i=0,t=0,found_match=0;
-
-  if(args->debug >= 2) {printf("updating the database list\n");}
+  int disconnect = 0;
+  PGresult *res = NULL;
+  Dlelem *db_elem = DLGetHead (db_list);
+  db_info *dbi = NULL;
+  db_info *dbi_template1 = DLE_VAL (db_elem);
+  int i = 0, t = 0, found_match = 0;
+
+  if (args->debug >= 2) {
+    log_entry ("updating the database list");
+    fflush (LOGOUTPUT);
+  }
 
-  if(NULL==dbi_template1->conn)
-  {	dbi_template1->conn=db_connect(dbi_template1);   disconnect=1;}
+  if (NULL == dbi_template1->conn) {
+    dbi_template1->conn = db_connect (dbi_template1);
+    disconnect = 1;
+  }
 
-  if(NULL != dbi_template1->conn)
-  {
-    /* 	Get a resu22lt set that has all the information
-		we will need to both remove databasews from the list
-		that no longer exist and add databases to the list
-		that are new */
-		res=send_query("select oid,datname,age(datfrozenxid) from pg_database where datname!='template0'",dbi_template1);
-		t=PQntuples(res);
-
-		/* First: use the db_list as the outer loop and
-				the result set as the inner loop, this will
-				determine what databases should be removed */
-		while(NULL != db_elem)
-		{
-			dbi=((db_info *)DLE_VAL(db_elem));
-			found_match=0;
-
-			for(i=0;i<t;i++) /* loop through result set looking for a match */
-			{
-				if(dbi->oid==atoi(PQgetvalue(res,i,PQfnumber(res,"oid"))))
-				{
-					found_match=1;
-					/* update the dbi->age so that we ensure xid_wraparound won't happen */
-					dbi->age=atoi(PQgetvalue(res,i,PQfnumber(res,"age")));
-					break;
-				}
-			}
-			if(0==found_match) /*then we didn't find this db_elem in the result set */
-			{
-				Dlelem *elem_to_remove=db_elem;
-				db_elem=DLGetSucc(db_elem);
-				remove_db_from_list(elem_to_remove);
-			}
-			else
-				db_elem=DLGetSucc(db_elem);
-		} /* Done removing dropped databases from the table_list */
-
-		/* Then loop use result set as outer loop and
-				db_list as the inner loop to determine
-				what databases are new */
-		for(i=0;i<t;i++)
-		{
-			db_elem=DLGetHead(db_list);
-			found_match=0;
-			while(NULL != db_elem)
-			{
-				dbi=((db_info *)DLE_VAL(db_elem));
-				if(dbi->oid==atoi(PQgetvalue(res,i,PQfnumber(res,"oid"))))
-				{
-					found_match=1;
-					break;
-				}
-				db_elem=DLGetSucc(db_elem);
-			}
-			if(0==found_match) /*then we didn't find this result now in the tbl_list */
-			{
-				DLAddTail(db_list,DLNewElem(init_dbinfo(PQgetvalue(res,i,PQfnumber(res,"datname")),
-									atoi(PQgetvalue(res,i,PQfnumber(res,"oid"))),atoi(PQgetvalue(res,i,PQfnumber(res,"age"))))));
-				if(args->debug >= 1) {printf("added database: %s\n",((db_info *)DLE_VAL(DLGetTail(db_list)))->dbname);}
-			}
-		} /* end of for loop that adds tables */
-		PQclear(res); res=NULL;
-		if(args->debug >= 3)	{print_db_list(db_list,0);}
-		if(disconnect) db_disconnect(dbi_template1);
-	}
+  if (NULL != dbi_template1->conn) {
+    /* Get a result set that has all the information
+       we will need to both remove databasews from the list
+       that no longer exist and add databases to the list
+       that are new */
+    res = send_query (FROZENOID_QUERY2, dbi_template1);
+    t = PQntuples (res);
+
+    /* First: use the db_list as the outer loop and
+       the result set as the inner loop, this will
+       determine what databases should be removed */
+    while (NULL != db_elem) {
+      dbi = ((db_info *) DLE_VAL (db_elem));
+      found_match = 0;
+
+      for (i = 0; i < t; i++) {	/* loop through result set looking for a match */
+        if (dbi->oid == atoi (PQgetvalue (res, i, PQfnumber (res, "oid")))) {
+          found_match = 1;
+          /* update the dbi->age so that we ensure xid_wraparound won't happen */
+          dbi->age = atoi (PQgetvalue (res, i, PQfnumber (res, "age")));
+          break;
+        }
+      }
+      if (0 == found_match) {	/*then we didn't find this db_elem in the result set */
+	  Dlelem *elem_to_remove = db_elem;
+	  db_elem = DLGetSucc (db_elem);
+	  remove_db_from_list (elem_to_remove);
+      }
+      else
+	  db_elem = DLGetSucc (db_elem);
+    } /* Done removing dropped databases from the table_list */
+
+    /* Then loop use result set as outer loop and
+       db_list as the inner loop to determine
+       what databases are new */
+    for (i = 0; i < t; i++)
+    {
+      db_elem = DLGetHead (db_list);
+      found_match = 0;
+      while (NULL != db_elem)
+      {
+	  dbi = ((db_info *) DLE_VAL (db_elem));
+	  if (dbi->oid == atoi (PQgetvalue (res, i, PQfnumber (res, "oid"))))
+        {
+	    found_match = 1;
+	    break;
+	  }
+	  db_elem = DLGetSucc (db_elem);
+      }
+      if (0 == found_match)	/*then we didn't find this result now in the tbl_list */
+      {
+        DLAddTail (db_list, DLNewElem (init_dbinfo
+	    (PQgetvalue(res, i, PQfnumber (res, "datname")),
+          atoi (PQgetvalue(res, i, PQfnumber (res, "oid"))),
+	    atoi (PQgetvalue(res, i, PQfnumber (res, "age"))))));
+	  if (args->debug >= 1)
+        {
+	    sprintf (logbuffer, "added database: %s",((db_info *) DLE_VAL (DLGetTail (db_list)))->dbname);
+	    log_entry (logbuffer);
+	  }
+      }
+    }				/* end of for loop that adds tables */
+    fflush (LOGOUTPUT);
+    PQclear (res);
+    res = NULL;
+    if (args->debug >= 3) {
+      print_db_list (db_list, 0);
+    }
+    if (disconnect)
+      db_disconnect (dbi_template1);
+  }
 }
 
 /* xid_wraparound_check
@@ -362,81 +503,102 @@ So we do a full database vacuum if age > 1.5billion
 return 0 if nothing happened,
 return 1 if the database needed a database wide vacuum
 */
-int xid_wraparound_check(db_info *dbi)
+int
+xid_wraparound_check (db_info * dbi)
 {
   /* FIXME: should probably do something better here so that we don't vacuum all the
-  databases on the server at the same time.  We have 500million xacts to work with so
-  we should be able to spread the load of full database vacuums a bit */
-	if(1500000000 < dbi->age)
-	{
-		PGresult *res=NULL;
-		res=send_query("vacuum",dbi);
-		/* FIXME: Perhaps should add a check for PQ_COMMAND_OK */
-		PQclear(res);
-		return 1;
-	}
-	return 0;
+     databases on the server at the same time.  We have 500million xacts to work with so
+     we should be able to spread the load of full database vacuums a bit */
+  if (1500000000 < dbi->age) {
+    PGresult *res = NULL;
+    res = send_query ("vacuum", dbi);
+    /* FIXME: Perhaps should add a check for PQ_COMMAND_OK */
+    PQclear (res);
+    return 1;
+  }
+  return 0;
 }
 
 /* Close DB connection, free memory, and remove the node from the list */
-void  remove_db_from_list(Dlelem *db_to_remove)
+void
+remove_db_from_list (Dlelem * db_to_remove)
 {
-  db_info *dbi=((db_info *)DLE_VAL(db_to_remove));
-
-	if(args->debug >= 1) {printf("Removing db: %s from list.\n",dbi->dbname);}
-  DLRemove(db_to_remove);
-  if(dbi->conn)
-		db_disconnect(dbi);
-  if(dbi->dbname)
-	{	free(dbi->dbname); dbi->dbname=NULL;}
-  if(dbi->username)
-	{	free(dbi->username); dbi->username=NULL;}
-  if(dbi->password)
-	{	free(dbi->password); dbi->password=NULL;}
-  if(dbi->table_list)
-	{	free_tbl_list(dbi->table_list); dbi->table_list=NULL;}
-  if(dbi)
-	{	free(dbi); dbi=NULL;}
-  DLFreeElem(db_to_remove);
+  db_info *dbi = ((db_info *) DLE_VAL (db_to_remove));
+
+  if (args->debug >= 1) {
+    sprintf (logbuffer, "Removing db: %s from list.", dbi->dbname);
+    log_entry (logbuffer);
+    fflush (LOGOUTPUT);
+  }
+  DLRemove (db_to_remove);
+  if (dbi->conn)
+    db_disconnect (dbi);
+  if (dbi->dbname) {
+    free (dbi->dbname);
+    dbi->dbname = NULL;
+  }
+  if (dbi->username) {
+    free (dbi->username);
+    dbi->username = NULL;
+  }
+  if (dbi->password) {
+    free (dbi->password);
+    dbi->password = NULL;
+  }
+  if (dbi->table_list) {
+    free_tbl_list (dbi->table_list);
+    dbi->table_list = NULL;
+  }
+  if (dbi) {
+    free (dbi);
+    dbi = NULL;
+  }
+  DLFreeElem (db_to_remove);
 }
 
 /* Function is called before program exit to free all memory
 		mostly it's just to keep valgrind happy */
-void free_db_list(Dllist *db_list)
+void
+free_db_list (Dllist * db_list)
 {
-	Dlelem *db_elem=DLGetHead(db_list);
-	Dlelem *db_elem_to_remove=NULL;
-	while(NULL != db_elem)
-	{
-    db_elem_to_remove=db_elem;
-		db_elem=DLGetSucc(db_elem);
-		remove_db_from_list(db_elem_to_remove);
-		db_elem_to_remove=NULL;
-	}
-	DLFreeList(db_list);
+  Dlelem *db_elem = DLGetHead (db_list);
+  Dlelem *db_elem_to_remove = NULL;
+  while (NULL != db_elem) {
+    db_elem_to_remove = db_elem;
+    db_elem = DLGetSucc (db_elem);
+    remove_db_from_list (db_elem_to_remove);
+    db_elem_to_remove = NULL;
+  }
+  DLFreeList (db_list);
 }
 
-void print_db_list(Dllist *db_list, int print_table_lists)
+void
+print_db_list (Dllist * db_list, int print_table_lists)
 {
-  Dlelem *db_elem=DLGetHead(db_list);
-  while(NULL != db_elem)
-  {
-    print_db_info(((db_info *)DLE_VAL(db_elem)),print_table_lists);
-    db_elem=DLGetSucc(db_elem);
+  Dlelem *db_elem = DLGetHead (db_list);
+  while (NULL != db_elem) {
+    print_db_info (((db_info *) DLE_VAL (db_elem)), print_table_lists);
+    db_elem = DLGetSucc (db_elem);
   }
 }
 
-void print_db_info(db_info *dbi, int print_tbl_list)
+void
+print_db_info (db_info * dbi, int print_tbl_list)
 {
-  printf("dbname: %s\n Username %s\n Passwd %s\n",dbi->dbname,dbi->username,dbi->password);
-  printf(" oid %i\n InsertThresh: %i\n DeleteThresh: %i\n",dbi->oid,dbi->insertThreshold,dbi->deleteThreshold);
-  if(NULL!=dbi->conn)
-    printf(" conn is valid, we are connected\n");
+  sprintf (logbuffer, "dbname: %s Username %s Passwd %s", dbi->dbname,
+	   dbi->username, dbi->password);
+  log_entry (logbuffer);
+  sprintf (logbuffer, " oid %i InsertThresh: %i  DeleteThresh: %i", dbi->oid,
+	   dbi->analyze_threshold, dbi->vacuum_threshold);
+  log_entry (logbuffer);
+  if (NULL != dbi->conn)
+    log_entry (" conn is valid, we are connected");
   else
-    printf(" conn is null, we are not connected.\n");
+    log_entry (" conn is null, we are not connected.");
 
-  if(0 < print_tbl_list)
-    print_table_list(dbi->table_list);
+  fflush (LOGOUTPUT);
+  if (0 < print_tbl_list)
+    print_table_list (dbi->table_list);
 }
 
 /* End of DB List Management Function */
@@ -444,291 +606,407 @@ void print_db_info(db_info *dbi, int print_tbl_list)
 /* Begninning of misc Functions */
 
 
-char *query_table_stats(db_info *dbi)
+char *
+query_table_stats (db_info * dbi)
 {
-  if(!strcmp(dbi->dbname,"template1")) /* Use template1 to monitor the system tables */
-    return (char*)TABLE_STATS_ALL;
+  if (!strcmp (dbi->dbname, "template1"))	/* Use template1 to monitor the system tables */
+    return (char *) TABLE_STATS_ALL;
   else
-    return (char*)TABLE_STATS_USER;
+    return (char *) TABLE_STATS_USER;
 }
 
-/* Perhaps add some test to this function to make sure that the stats we need are availalble */
-PGconn *db_connect(db_info *dbi)
+/* Perhaps add some test to this function to make sure that the stats we need are available */
+PGconn *
+db_connect (db_info * dbi)
 {
-  PGconn *db_conn=PQsetdbLogin(args->host, args->port, NULL, NULL, dbi->dbname, dbi->username, dbi->password);
-  
-  if(CONNECTION_OK != PQstatus(db_conn))
-  {
-    fprintf(stderr,"Failed connection to database %s with error: %s.\n",dbi->dbname,PQerrorMessage(db_conn));
-    PQfinish(db_conn);
-    db_conn=NULL;
+  PGconn *db_conn =
+    PQsetdbLogin (args->host, args->port, NULL, NULL, dbi->dbname,
+		  dbi->username, dbi->password);
+
+  if (CONNECTION_OK != PQstatus (db_conn)) {
+    sprintf (logbuffer, "Failed connection to database %s with error: %s.",
+	     dbi->dbname, PQerrorMessage (db_conn));
+    log_entry (logbuffer);
+    fflush (LOGOUTPUT);
+    PQfinish (db_conn);
+    db_conn = NULL;
   }
   return db_conn;
-} /* end of db_connect() */
+}				/* end of db_connect() */
 
-void db_disconnect(db_info *dbi)
+void
+db_disconnect (db_info * dbi)
 {
-  if(NULL != dbi->conn)
-  {
-    PQfinish(dbi->conn);
-    dbi->conn=NULL;
+  if (NULL != dbi->conn) {
+    PQfinish (dbi->conn);
+    dbi->conn = NULL;
   }
 }
 
-int	check_stats_enabled(db_info *dbi)
+int
+check_stats_enabled (db_info * dbi)
 {
-	PGresult *res=NULL;
-	int ret=0;
-	res=send_query("show stats_row_level",dbi);
-	ret = strcmp("on",PQgetvalue(res,0,PQfnumber(res,"stats_row_level")));
-	PQclear(res);
-	return ret;
+  PGresult *res = NULL;
+  int ret = 0;
+  res = send_query ("show stats_row_level", dbi);
+  ret =
+    strcmp ("on", PQgetvalue (res, 0, PQfnumber (res, "stats_row_level")));
+  PQclear (res);
+  return ret;
 }
 
-PGresult *send_query(const char *query,db_info *dbi)
+PGresult *
+send_query (const char *query, db_info * dbi)
 {
   PGresult *res;
 
-  if(NULL==dbi->conn)
+  if (NULL == dbi->conn)
     return NULL;
 
-  res=PQexec(dbi->conn,query);
+  res = PQexec (dbi->conn, query);
 
-  if(!res)
-  {
-    fprintf(stderr,"Fatal error occured while sending query (%s) to database %s\n",query,dbi->dbname);
-    fprintf(stderr,"The error is \n%s\n",PQresultErrorMessage(res));
+  if (!res) {
+    sprintf (logbuffer,
+	     "Fatal error occured while sending query (%s) to database %s",
+	     query, dbi->dbname);
+    log_entry (logbuffer);
+    sprintf (logbuffer, "The error is [%s]", PQresultErrorMessage (res));
+    log_entry (logbuffer);
+    fflush (LOGOUTPUT);
     return NULL;
   }
-  if(PQresultStatus(res)!=PGRES_TUPLES_OK && PQresultStatus(res)!=PGRES_COMMAND_OK)
-  {
-    fprintf(stderr,"Can not refresh statistics information from the database %s.\n",dbi->dbname);
-    fprintf(stderr,"The error is \n%s\n",PQresultErrorMessage(res));
-    PQclear(res);
+  if (PQresultStatus (res) != PGRES_TUPLES_OK
+      && PQresultStatus (res) != PGRES_COMMAND_OK) {
+    sprintf (logbuffer,
+	     "Can not refresh statistics information from the database %s.",
+	     dbi->dbname);
+    log_entry (logbuffer);
+    sprintf (logbuffer, "The error is [%s]", PQresultErrorMessage (res));
+    log_entry (logbuffer);
+    fflush (LOGOUTPUT);
+    PQclear (res);
     return NULL;
   }
   return res;
-} /* End of send_query() */
+}				/* End of send_query() */
 
 
-void free_cmd_args()
+void
+free_cmd_args ()
 {
-  if(NULL!=args)
-  {
-    if(NULL!=args->user)
-      free(args->user);
-    if(NULL!=args->user)
-      free(args->password);
-  free(args);
+  if (NULL != args) {
+    if (NULL != args->user)
+      free (args->user);
+    if (NULL != args->user)
+      free (args->password);
+    free (args);
   }
 }
 
-cmd_args *get_cmd_args(int argc,char *argv[])
+cmd_args *
+get_cmd_args (int argc, char *argv[])
 {
   int c;
-
-  args=(cmd_args *)malloc(sizeof(cmd_args));
-  args->sleep_base_value=SLEEPVALUE;
-  args->sleep_scaling_factor=SLEEPSCALINGFACTOR;
-  args->tuple_base_threshold=BASETHRESHOLD;
-  args->tuple_scaling_factor=SCALINGFACTOR;
-  args->debug=AUTOVACUUM_DEBUG;
-  args->user=NULL;
-  args->password=NULL;
-  args->host=NULL;
-  args->port=NULL;
-  while (-1 != (c = getopt(argc, argv, "s:S:t:T:d:U:P:H:p:h")))
-	{
-		switch (c)
-		{
-			case 's':
-				args->sleep_base_value=atoi(optarg);
-				break;
-			case 'S':
-				args->sleep_scaling_factor = atof(optarg);
-				break;
-			case 't':
-				args->tuple_base_threshold = atoi(optarg);
-				break;
-			case 'T':
-				args->tuple_scaling_factor = atof(optarg);
-				break;
-			case 'd':
-				args->debug = atoi(optarg);
-				break;
-			case 'U':
-				args->user=optarg;
-				break;
-			case 'P':
-				args->password=optarg;
-				break;
-			case 'H':
-				args->host=optarg;
-				break;
-			case 'p':
-				args->port=optarg;
-				break;
-			case 'h':
-			default:
-				fprintf(stderr, "usage: pg_autovacuum [-d debug][-s sleep base value][-S sleep scaling factor]\n[-t tuple base threshold][-T tulple scaling factor]\n[-U username][-P password][-H host][-p port][-h help]\n");
-				exit(1);
-				break;
-		}
+  args = (cmd_args *) malloc (sizeof (cmd_args));
+  args->sleep_base_value = SLEEPBASEVALUE;
+  args->sleep_scaling_factor = SLEEPSCALINGFACTOR;
+  args->vacuum_base_threshold = VACBASETHRESHOLD;
+  args->vacuum_scaling_factor = VACSCALINGFACTOR;
+  args->analyze_base_threshold = -1;
+  args->analyze_scaling_factor = -1;
+  args->debug = AUTOVACUUM_DEBUG;
+  args->daemonize = 0;
+
+  /* Fixme: Should add some sanity checking such as positive integer values etc */
+  while (-1 != (c = getopt (argc, argv, "s:S:v:V:a:A:d:U:P:H:L:p:hD"))) {
+    switch (c) {
+    case 's':
+      args->sleep_base_value = atoi (optarg);
+      break;
+    case 'S':
+      args->sleep_scaling_factor = atof (optarg);
+      break;
+    case 'v':
+      args->vacuum_base_threshold = atoi (optarg);
+      break;
+    case 'V':
+      args->vacuum_scaling_factor = atof (optarg);
+      break;
+    case 'a':
+      args->analyze_base_threshold = atoi (optarg);
+      break;
+    case 'A':
+      args->analyze_scaling_factor = atof (optarg);
+      break;
+    case 'D':
+      args->daemonize++;
+      break;
+    case 'd':
+      args->debug = atoi (optarg);
+      break;
+    case 'U':
+      args->user = optarg;
+      break;
+    case 'P':
+      args->password = optarg;
+      break;
+    case 'H':
+      args->host = optarg;
+      break;
+    case 'L':
+      args->logfile = optarg;
+      break;
+    case 'p':
+      args->port = optarg;
+      break;
+    case 'h':
+      usage();
+      exit (0);
+    default:
+      /* It's here that we know that things are invalid...
+	 It is not forcibly an error to call usage */
+      fprintf (stderr, "Error: Invalid Command Line Options.\n");
+      usage();
+      exit (1);
+      break;
+    }
+    /* if values for insert thresholds are not specified,
+       then they default to 1/2 of the delete values */
+    if(-1 == args->analyze_base_threshold)
+      args->analyze_base_threshold = args->vacuum_base_threshold / 2;
+    if(-1 == args->analyze_scaling_factor)
+      args->analyze_scaling_factor = args->vacuum_scaling_factor / 2;
   }
-
   return args;
 }
 
-void print_cmd_args()
+void usage()
+{
+  int i=0;
+  float f=0;
+  fprintf (stderr, "usage: pg_autovacuum \n");
+  fprintf (stderr, "   [-D] Daemonize (Detach from tty and run in the background)\n");
+  i=AUTOVACUUM_DEBUG;
+  fprintf (stderr, "   [-d] debug (debug level=0,1,2,3; default=%i)\n",i);
+
+  i=SLEEPBASEVALUE;
+  fprintf (stderr, "   [-s] sleep base value (default=%i)\n",i);
+  f=SLEEPSCALINGFACTOR;
+  fprintf (stderr, "   [-S] sleep scaling factor (default=%f)\n",f);
+
+  i=VACBASETHRESHOLD;
+  fprintf (stderr, "   [-v] vacuum base threshold (default=%i)\n",i);
+  f=VACSCALINGFACTOR;
+  fprintf (stderr, "   [-V] vacuum scaling factor (default=%f)\n",f);
+  i=i/2;
+  fprintf (stderr, "   [-a] analyze base threshold (default=%i)\n",i);
+  f=f/2;
+  fprintf (stderr, "   [-A] analyze scaling factor (default=%f)\n",f);
+
+  fprintf (stderr, "   [-L] logfile (default=none)\n");
+
+  fprintf (stderr, "   [-U] username (libpq default)\n");
+  fprintf (stderr, "   [-P] password (libpq default)\n");
+  fprintf (stderr, "   [-H] host (libpq default)\n");
+  fprintf (stderr, "   [-p] port (libpq default)\n");
+
+  fprintf (stderr, "   [-h] help (Show this output)\n");
+}
+
+void
+print_cmd_args ()
 {
-	printf("Printing command_args\n");
-	printf("  args->host=%s\n",args->host);
-	printf("  args->port=%s\n",args->port);
-	printf("	args->user=%s\n",args->user);
-	printf("	args->password=%s\n",args->password);
-	printf("	args->sleep_base_value=%i\n",args->sleep_base_value);
-	printf("	args->sleep_scaling_factor=%f\n",args->sleep_scaling_factor);
-	printf("	args->tuple_base_threshold=%i\n",args->tuple_base_threshold);
-	printf("	args->tuple_scaling_factor=%f\n",args->tuple_scaling_factor);
-	printf("	args->debug=%i\n",args->debug);
+  sprintf (logbuffer, "Printing command_args");
+  log_entry (logbuffer);
+  sprintf (logbuffer, "  args->host=%s", (args->host) ? args->host : "(null)");
+  log_entry (logbuffer);
+  sprintf (logbuffer, "  args->port=%s", (args->port) ? args->port : "(null)");
+  log_entry (logbuffer);
+  sprintf (logbuffer, "  args->user=%s", (args->user) ? args->user : "(null)");
+  log_entry (logbuffer);
+  sprintf (logbuffer, "  args->password=%s",(args->password) ? args->password : "(null)");
+  log_entry (logbuffer);
+  sprintf (logbuffer, "  args->logfile=%s",(args->logfile) ? args->logfile : "(null)");
+  log_entry (logbuffer);
+  sprintf (logbuffer, "  args->daemonize=%i",args->daemonize);
+  log_entry (logbuffer);
+
+  sprintf (logbuffer, "  args->sleep_base_value=%i", args->sleep_base_value);
+  log_entry (logbuffer);
+  sprintf (logbuffer, "  args->sleep_scaling_factor=%f",args->sleep_scaling_factor);
+  log_entry (logbuffer);
+  sprintf (logbuffer, "  args->vacuum_base_threshold=%i",args->vacuum_base_threshold);
+  log_entry (logbuffer);
+  sprintf (logbuffer, "  args->vacuum_scaling_factor=%f",args->vacuum_scaling_factor);
+  log_entry (logbuffer);
+  sprintf (logbuffer, "  args->analyze_base_threshold=%i",args->analyze_base_threshold);
+  log_entry (logbuffer);
+  sprintf (logbuffer, "  args->analyze_scaling_factor=%f",args->analyze_scaling_factor);
+  log_entry (logbuffer);
+  sprintf (logbuffer, "  args->debug=%i", args->debug);
+  log_entry (logbuffer);
+
+  fflush (LOGOUTPUT);
 }
 
 /* Beginning of AutoVacuum Main Program */
-int main(int argc, char *argv[])
+int
+main (int argc, char *argv[])
 {
   char buf[256];
-  int j=0, loops=0;
-  int numInserts, numDeletes, sleep_secs;
-  Dllist    *db_list;
-  Dlelem    *db_elem,*tbl_elem;
-  db_info   *dbs;
-  tbl_info  *tbl;
-  PGresult  *res;
-  long long       diff=0;
-  struct timeval now,then;
-
-  args=get_cmd_args(argc,argv); /* Get Command Line Args and put them in the args struct */
-
-  if(args->debug >= 2)	{print_cmd_args();}
-
-  db_list=init_db_list();   /* Init the db list with template1 */
-  if(NULL == db_list)
+  int j = 0, loops = 0;
+/*  int numInserts, numDeletes, */
+  int sleep_secs;
+  Dllist *db_list;
+  Dlelem *db_elem, *tbl_elem;
+  db_info *dbs;
+  tbl_info *tbl;
+  PGresult *res=NULL;
+  long long diff = 0;
+  struct timeval now, then;
+
+  args = get_cmd_args (argc, argv);	/* Get Command Line Args and put them in the args struct */
+
+  /* Dameonize if requested */
+  if (1 == args->daemonize){ daemonize(); }
+
+  if (args->logfile) {
+    LOGOUTPUT = fopen (args->logfile, "a");
+    if (!LOGOUTPUT) {
+      fprintf (stderr, "Could not open log file - [%s]\n", args->logfile);
+      exit(-1);
+    }
+  }
+  else {
+    LOGOUTPUT = stderr;
+  }
+  if (args->debug >= 2) {
+    print_cmd_args ();
+  }
+
+  /* Init the db list with template1 */
+  db_list = init_db_list ();
+  if (NULL == db_list)
     return 1;
 
-	if(0!=check_stats_enabled(((db_info*)DLE_VAL(DLGetHead(db_list)))))
-	{
-		printf("Error: GUC variable stats_row_level must be enabled.\n       Please fix the problems and try again.\n");
-		exit(1);
-	}
+  if (0 != check_stats_enabled (((db_info *) DLE_VAL (DLGetHead (db_list))))) {
+    log_entry ("Error: GUC variable stats_row_level must be enabled.");
+    log_entry ("       Please fix the problems and try again.");
+    fflush (LOGOUTPUT);
+
+    exit (1);
+  }
+
+  gettimeofday (&then, 0);	/* for use later to caluculate sleep time */
+
+  while (1) {			/* Main Loop */
+    db_elem = DLGetHead (db_list);	/* Reset cur_db_node to the beginning of the db_list */
 
-	gettimeofday(&then, 0); /* for use later to caluculate sleep time */
+    dbs = ((db_info *) DLE_VAL (db_elem));	/* get pointer to cur_db's db_info struct */
+    if (NULL == dbs->conn) {
+      dbs->conn = db_connect (dbs);
+      if (NULL == dbs->conn) {	/* Serious problem: We can't connect to template1 */
+      	log_entry ("Error: Cannot connect to template1, exiting.");
+      	fflush (LOGOUTPUT);
+      	fclose (LOGOUTPUT);
+      	exit (1);
+      }
+    }
+
+    if (0 == (loops % UPDATE_INTERVAL))	/* Update the list if it's time */
+      update_db_list (db_list);	/* Add and remove databases from the list */
+
+    while (NULL != db_elem) {	/* Loop through databases in list */
+      dbs = ((db_info *) DLE_VAL (db_elem));	/* get pointer to cur_db's db_info struct */
+      if (NULL == dbs->conn)
+      	dbs->conn = db_connect (dbs);
+
+      if (NULL != dbs->conn) {
+      	if (0 == (loops % UPDATE_INTERVAL))	/* Update the list if it's time */
+    	    update_table_list (dbs);	/* Add and remove tables from the list */
 
-	while(1)   /* Main Loop */
+	if (0 == xid_wraparound_check (dbs));
 	{
-		db_elem=DLGetHead(db_list); /* Reset cur_db_node to the beginning of the db_list */
-
-		dbs=((db_info *)DLE_VAL(db_elem)); /* get pointer to cur_db's db_info struct */
-		if(NULL==dbs->conn) 
-		{
-			dbs->conn=db_connect(dbs);
-			if(NULL==dbs->conn) /* Serious problem: We can't connect to template1 */
-			{
-				printf("Error: Cannot connect to template1, exiting.\n");
-				exit(1);
-			}	
-		}
-
-		if(0==(loops % UPDATE_INTERVAL)) /* Update the list if it's time */
-			update_db_list(db_list); /* Add new databases to the list to be checked, and remove databases that no longer exist */
-
-		while(NULL != db_elem) /* Loop through databases in list */
-		{
-      dbs=((db_info *)DLE_VAL(db_elem)); /* get pointer to cur_db's db_info struct */
-      if(NULL==dbs->conn)
-        dbs->conn=db_connect(dbs);
-
-      if(NULL!=dbs->conn)
-      {
-				if(0==(loops % UPDATE_INTERVAL)) /* Update the list if it's time */
-					update_table_list(dbs); /* Add new databases to the list to be checked, and remove databases that no longer exist */
-
-				if(0==xid_wraparound_check(dbs));
-				{
-          res=send_query(query_table_stats(dbs),dbs);  /* Get an updated snapshot of this dbs table stats */
-          for(j=0;j < PQntuples(res);j++) /* loop through result set */
-          {
-            tbl_elem = DLGetHead(dbs->table_list); /* Reset tbl_elem to top of dbs->table_list */
-            while(NULL!=tbl_elem)	/* Loop through tables in list */
-            {
-              tbl=((tbl_info *)DLE_VAL(tbl_elem)); /* set tbl_info = current_table */
-              if(tbl->relfilenode == atoi(PQgetvalue(res,j,PQfnumber(res,"relfilenode"))))
+	  res = send_query (query_table_stats (dbs), dbs);	/* Get an updated snapshot of this dbs table stats */
+	  for (j = 0; j < PQntuples (res); j++) {	/* loop through result set */
+	    tbl_elem = DLGetHead (dbs->table_list);	/* Reset tbl_elem to top of dbs->table_list */
+	    while (NULL != tbl_elem) {	/* Loop through tables in list */
+	      tbl = ((tbl_info *) DLE_VAL (tbl_elem));	/* set tbl_info = current_table */
+	      if (tbl->relfilenode == atoi (PQgetvalue(res, j, PQfnumber (res, "relfilenode")))) {
+		  tbl->curr_analyze_count =
+		    (atol (PQgetvalue (res, j, PQfnumber (res, "n_tup_ins"))) +
+		     atol (PQgetvalue (res, j, PQfnumber (res, "n_tup_upd"))) +
+                 atol (PQgetvalue (res, j, PQfnumber (res, "n_tup_del"))));
+		  tbl->curr_vacuum_count =
+		    (atol (PQgetvalue (res, j, PQfnumber (res, "n_tup_del"))) +
+		     atol (PQgetvalue (res, j, PQfnumber (res, "n_tup_upd"))));
+
+		  /* Check numDeletes to see if we need to vacuum, if so:
+		     Run vacuum analyze (adding analyze is small so we might as well)
+		     Update table thresholds and related information
+		     if numDeletes is not big enough for vacuum then check numInserts for analyze */
+		  if ((tbl->curr_vacuum_count - tbl->CountAtLastVacuum) >= tbl->vacuum_threshold)
+              {
+		    snprintf (buf, sizeof (buf), "vacuum analyze %s", tbl->table_name);
+		    if (args->debug >= 1) {
+		      sprintf (logbuffer, "Performing: %s", buf);
+		      log_entry (logbuffer);
+		      fflush (LOGOUTPUT);
+		    }
+		    send_query (buf, dbs);
+		    update_table_thresholds (dbs, tbl, VACUUM_ANALYZE);
+		    if (args->debug >= 2) {print_table_info (tbl);}
+		  }
+		  else if ((tbl->curr_analyze_count - tbl->CountAtLastAnalyze) >= tbl->analyze_threshold)
               {
-                numInserts=(atol(PQgetvalue(res,j,PQfnumber(res,"n_tup_ins"))) + atol(PQgetvalue(res,j,PQfnumber(res,"n_tup_upd"))));
-                numDeletes=(atol(PQgetvalue(res,j,PQfnumber(res,"n_tup_del"))) + atol(PQgetvalue(res,j,PQfnumber(res,"n_tup_upd"))));
-
-                /* Check numDeletes to see if we need to vacuum, if so:
-                Run vacuum analyze (adding analyze is small so we might as well)
-                Update table thresholds and related information
-                if numDeletes is not big enough for vacuum then check numInserts for analyze */
-                if((numDeletes - tbl->DeletesAtLastVacuum) >= tbl->deleteThreshold)
-                {
-                  snprintf(buf,sizeof(buf),"vacuum %s",tbl->table_name);
-                  if(args->debug >= 1) {printf("Performing: %s\n",buf);}
-                  send_query(buf,dbs);
-                  tbl->DeletesAtLastVacuum=numDeletes;
-    							update_table_thresholds(dbs,tbl);
-                  if(args->debug >= 2)	{print_table_info(tbl);}
-                }
-                else if((numInserts - tbl->InsertsAtLastAnalyze) >= tbl->insertThreshold)
-                {
-                  snprintf(buf,sizeof(buf),"analyze %s",tbl->table_name);
-                  if(args->debug >= 1) {printf("Performing: %s\n",buf);}
-                  send_query(buf,dbs);
-                  tbl->InsertsAtLastAnalyze=numInserts;
-                  tbl->reltuples=atoi(PQgetvalue(res,j,PQfnumber(res,"reltuples")));
-                  tbl->insertThreshold = (args->tuple_base_threshold + args->tuple_scaling_factor*tbl->reltuples);
-                  if(args->debug >= 2)	{print_table_info(tbl);}
-                }
-
-                /* If the stats collector is reporting fewer updates then we have on record
-                then the stats were probably reset, so we need to reset also */
-                if((numInserts < tbl->InsertsAtLastAnalyze)||(numDeletes < tbl->DeletesAtLastVacuum))
-                {
-                  tbl->InsertsAtLastAnalyze=numInserts;
-                  tbl->DeletesAtLastVacuum=numDeletes;
-                }
-                break; /* once we have found a match, no need to keep checking. */
-              }
-              /* Advance the table pointers for the next loop */
-              tbl_elem=DLGetSucc(tbl_elem);
-
-            } /* end for table while loop */
-          } /* end for j loop (tuples in PGresult) */
-				} /* close of if(xid_wraparound_check()) */
-        /* Done working on this db, Clean up, then advance cur_db */
-        PQclear(res);  res=NULL;
-        db_disconnect(dbs);
-			}
-			db_elem=DLGetSucc(db_elem); /* move on to next DB regardless */
-    } /* end of db_list while loop */
+		    snprintf (buf, sizeof (buf), "analyze %s", tbl->table_name);
+		    if (args->debug >= 1) {
+		      sprintf (logbuffer, "Performing: %s", buf);
+		      log_entry (logbuffer);
+		      fflush (LOGOUTPUT);
+		    }
+		    send_query (buf, dbs);
+		    update_table_thresholds (dbs, tbl, ANALYZE_ONLY);
+		    if (args->debug >= 2) { print_table_info (tbl);  }
+		  }
+		
+              break;		/* once we have found a match, no need to keep checking. */
+	      }
+            /* Advance the table pointers for the next loop */
+	      tbl_elem = DLGetSucc (tbl_elem);
+
+	    }			/* end for table while loop */
+	  }			/* end for j loop (tuples in PGresult) */
+	}			/* close of if(xid_wraparound_check()) */
+	/* Done working on this db, Clean up, then advance cur_db */
+	PQclear (res);
+	res = NULL;
+	db_disconnect (dbs);
+      }
+      db_elem = DLGetSucc (db_elem);	/* move on to next DB regardless */
+    }	/* end of db_list while loop */
 
     /* Figure out how long to sleep etc ... */
-    gettimeofday(&now, 0);
+    gettimeofday (&now, 0);
     diff = (now.tv_sec - then.tv_sec) * 1000000 + (now.tv_usec - then.tv_usec);
 
-    sleep_secs = args->sleep_base_value + args->sleep_scaling_factor*diff/1000000;
+    sleep_secs = args->sleep_base_value + args->sleep_scaling_factor * diff / 1000000;
     loops++;
-    if(args->debug >= 2)
-    {	printf("%i All DBs checked in: %lld usec, will sleep for %i secs.\n",loops,diff,sleep_secs);}
+    if (args->debug >= 2) {
+      sprintf (logbuffer,
+	       "%i All DBs checked in: %lld usec, will sleep for %i secs.",
+	       loops, diff, sleep_secs);
+      log_entry (logbuffer);
+    }
 
-    sleep(sleep_secs); /* Larger Pause between outer loops */
+    sleep (sleep_secs);		/* Larger Pause between outer loops */
 
-    gettimeofday(&then, 0);	/* Reset time counter */
+    gettimeofday (&then, 0);	/* Reset time counter */
 
   } /* end of while loop */
 
-  /* 	program is exiting, this should never run, but is here to make compiler / valgrind happy */
-  free_db_list(db_list);
-  free_cmd_args();
+  /* program is exiting, this should never run, but is here to make compiler / valgrind happy */
+  free_db_list (db_list);
+  free_cmd_args ();
   return EXIT_SUCCESS;
 }
diff --git a/contrib/pg_autovacuum/pg_autovacuum.h b/contrib/pg_autovacuum/pg_autovacuum.h
index 18a85bc3d44e5fd7df88e540d3b6e3a96b5b45f9..63a31965361d0099a15ac2b821c2054750e0863b 100644
--- a/contrib/pg_autovacuum/pg_autovacuum.h
+++ b/contrib/pg_autovacuum/pg_autovacuum.h
@@ -2,80 +2,112 @@
  * Header file for pg_autovacuum.c
  * (c) 2003 Matthew T. O'Connor
  */
+
 #include "postgres_fe.h"
 
 #include <unistd.h>
+#ifdef __GLIBC__
+#include <getopt.h>
+#endif
 #include <sys/time.h>
 
+/* These next two lines are correct when pg_autovaccum is compiled
+   from within the postgresql source tree  */
 #include "libpq-fe.h"
 #include "lib/dllist.h"
+/* Had to change the last two lines to compile on
+   Redhat outside of postgresql source tree */
+/*
+#include "/usr/include/libpq-fe.h"
+#include "/usr/include/pgsql/server/lib/dllist.h"
+*/
 
 #define AUTOVACUUM_DEBUG    1
-#define BASETHRESHOLD       100
-#define SCALINGFACTOR       2
-#define SLEEPVALUE          1
-#define SLEEPSCALINGFACTOR	0
+#define VACBASETHRESHOLD    1000
+#define VACSCALINGFACTOR    2
+#define SLEEPBASEVALUE      300
+#define SLEEPSCALINGFACTOR  2
 #define UPDATE_INTERVAL     2
+
+/* these two constants are used to tell update_table_stats what operation we just perfomred */
+#define VACUUM_ANALYZE      0
+#define ANALYZE_ONLY        1
+
 #define TABLE_STATS_ALL     "select a.relfilenode,a.relname,a.relnamespace,a.relpages,a.reltuples,b.schemaname,b.n_tup_ins,b.n_tup_upd,b.n_tup_del from pg_class a, pg_stat_all_tables b where a.relfilenode=b.relid"
 #define TABLE_STATS_USER    "select a.relfilenode,a.relname,a.relnamespace,a.relpages,a.reltuples,b.schemaname,b.n_tup_ins,b.n_tup_upd,b.n_tup_del from pg_class a, pg_stat_user_tables b where a.relfilenode=b.relid"
 #define FRONTEND
+#define PAGES_QUERY "select relfilenode,reltuples,relpages from pg_class where relfilenode=%i"
+#define FROZENOID_QUERY "select oid,age(datfrozenxid) from pg_database where datname = 'template1'"
+#define FROZENOID_QUERY2 "select oid,datname,age(datfrozenxid) from pg_database where datname!='template0'"
 
-struct cmdargs{
-  int tuple_base_threshold,sleep_base_value,debug;
-  float tuple_scaling_factor,sleep_scaling_factor;
-  char *user, *password, *host, *port;
-}; typedef struct cmdargs cmd_args;
+/* define cmd_args stucture */
+struct cmdargs
+{
+  int vacuum_base_threshold, analyze_base_threshold, sleep_base_value, debug, daemonize;
+  float vacuum_scaling_factor, analyze_scaling_factor, sleep_scaling_factor;
+  char *user, *password, *host, *logfile, *port;
+};
+typedef struct cmdargs cmd_args;
 
 /* define cmd_args as global so we can get to them everywhere */
-cmd_args  *args;
-
-struct tableinfo{
-  char *schema_name,*table_name;
-  int insertThreshold,deleteThreshold;
-  int relfilenode,reltuples,relpages;
-  long InsertsAtLastAnalyze; /* equal to: inserts + updates as of the last analyze or initial values at startup */
-  long DeletesAtLastVacuum; /* equal to: deletes + updates as of the last vacuum or initial values at startup */
-  }; typedef struct tableinfo tbl_info;
+cmd_args *args;
 
 /* Might need to add a time value for last time the whold database was vacuumed.
     I think we need to guarantee this happens approx every 1Million TX's  */
-struct dbinfo{
-  int			oid,age;
-  int			insertThreshold,deleteThreshold; /* Use these as defaults for table thresholds */
-  PGconn  *conn;
-  char    *dbname,*username,*password;
-  Dllist  *table_list;
-  }; typedef struct dbinfo db_info;
+struct dbinfo
+{
+  int oid, age;
+  int analyze_threshold, vacuum_threshold;	/* Use these as defaults for table thresholds */
+  PGconn *conn;
+  char *dbname, *username, *password;
+  Dllist *table_list;
+};
+typedef struct dbinfo db_info;
+
+struct tableinfo
+{
+  char *schema_name, *table_name;
+  int  relfilenode, reltuples, relpages;
+  long analyze_threshold, vacuum_threshold;
+  long CountAtLastAnalyze;	/* equal to: inserts + updates as of the last analyze or initial values at startup */
+  long CountAtLastVacuum;	/* equal to: deletes + updates as of the last vacuum or initial values at startup */
+  long curr_analyze_count, curr_vacuum_count; /* Latest values from stats system */
+  db_info *dbi; /* pointer to the database that this table belongs to */
+};
+typedef struct tableinfo tbl_info;
 
 /* Functions for dealing with command line arguements */
-static cmd_args *get_cmd_args(int argc,char *argv[]);
-static void print_cmd_args(void);
-static void free_cmd_args(void);
+static cmd_args *get_cmd_args (int argc, char *argv[]);
+static void print_cmd_args (void);
+static void free_cmd_args (void);
+static void usage (void);
 
 /* Functions for managing database lists */
-static Dllist *init_db_list(void);
-static db_info *init_dbinfo(char *dbname,int oid,int age);
-static void update_db_list(Dllist *db_list);
-static void remove_db_from_list(Dlelem *db_to_remove);
-static void print_db_info(db_info *dbi,int print_table_list);
-static void print_db_list(Dllist *db_list,int print_table_lists);
-static int  xid_wraparound_check(db_info *dbi);
-static void free_db_list(Dllist *db_list);
+static Dllist *init_db_list (void);
+static db_info *init_dbinfo (char *dbname, int oid, int age);
+static void update_db_list (Dllist * db_list);
+static void remove_db_from_list (Dlelem * db_to_remove);
+static void print_db_info (db_info * dbi, int print_table_list);
+static void print_db_list (Dllist * db_list, int print_table_lists);
+static int xid_wraparound_check (db_info * dbi);
+static void free_db_list (Dllist * db_list);
 
 /* Functions for managing table lists */
-static tbl_info *init_table_info(PGresult *conn, int row);
-static void update_table_list(db_info *dbi);
-static void remove_table_from_list(Dlelem *tbl_to_remove);
-static void print_table_list(Dllist *tbl_node);
-static void print_table_info(tbl_info *tbl);
-static void update_table_thresholds(db_info *dbi,tbl_info *tbl);
-static void free_tbl_list(Dllist *tbl_list);
+static tbl_info *init_table_info (PGresult * conn, int row, db_info *dbi);
+static void update_table_list (db_info * dbi);
+static void remove_table_from_list (Dlelem * tbl_to_remove);
+static void print_table_list (Dllist * tbl_node);
+static void print_table_info (tbl_info * tbl);
+static void update_table_thresholds (db_info * dbi, tbl_info * tbl, int vacuum_type);
+static void free_tbl_list (Dllist * tbl_list);
 
 /* A few database helper functions */
-static int	check_stats_enabled(db_info *dbi);
-static PGconn *db_connect(db_info *dbi);
-static void db_disconnect(db_info *dbi);
-static PGresult *send_query(const char *query,db_info *dbi);
-static char *query_table_stats(db_info *dbi);
-
+static int check_stats_enabled (db_info * dbi);
+static PGconn *db_connect (db_info * dbi);
+static void db_disconnect (db_info * dbi);
+static PGresult *send_query (const char *query, db_info * dbi);
+static char *query_table_stats (db_info * dbi);
 
+/* Other Generally needed Functions */
+static void daemonize(void);
+static void log_entry (const char *logentry);