diff -c pg_autovacuum.orig/README.pg_autovacuum pg_autovacuum/README.pg_autovacuum
*** pg_autovacuum.orig/README.pg_autovacuum	Mon Apr 19 22:30:18 2004
--- pg_autovacuum/README.pg_autovacuum	Mon May 10 09:29:07 2004
***************
*** 79,91 ****
  As of postgresql v7.4 pg_autovacuum is included in the main source
  tree under contrib.  Therefore you merely need to "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, uncompress the
  tar.gz file into the contrib directory and modify the contrib/Makefile
  to include the pg_autovacuum directory.  pg_autovacuum will then be
  built as part of the standard postgresql install.  It is known to work
! with v7.3 releases; it is not presently compatible with v7.2.
  
  make sure that the following are set in postgresql.conf:
  
--- 79,95 ----
  As of postgresql v7.4 pg_autovacuum is included in the main source
  tree under contrib.  Therefore you merely need to "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, uncompress the
  tar.gz file into the contrib directory and modify the contrib/Makefile
  to include the pg_autovacuum directory.  pg_autovacuum will then be
  built as part of the standard postgresql install.  It is known to work
! with v7.3 releases; it is not presently compatible with v7.2.
! 
! Under Windows the normal build procedure outlined above will work just
! fine under MSYS. The resulting .exe can then be run from the command line
! or as a service by installing with the -I option.
  
  make sure that the following are set in postgresql.conf:
  
***************
*** 107,113 ****
  pg_autovacuum has the following optional arguments:
  
  -d debug: 0 silent, 1 basic info, 2 more debug info,  etc...
! -D daemonize: Detach from tty and run in background.
  -s sleep base value: see "Sleeping" below.
  -S sleep scaling factor: see "Sleeping" below.
  -v vacuum base threshold: see "Vacuum and Analyze" below.
--- 111,122 ----
  pg_autovacuum has the following optional arguments:
  
  -d debug: 0 silent, 1 basic info, 2 more debug info,  etc...
! -D daemonize: Detach from tty and run in background (not applicable on Windows)
! -I install service: Install as a service on Windows (other applicable options 
!    specified will be used for future startups).
! -R remove service: Remove Windows service.
! -N service user: The username to run the Windows service under.
! -W service password: The password to run the Windows service under.
  -s sleep base value: see "Sleeping" below.
  -S sleep scaling factor: see "Sleeping" below.
  -v vacuum base threshold: see "Vacuum and Analyze" below.
diff -c pg_autovacuum.orig/TODO pg_autovacuum/TODO
*** pg_autovacuum.orig/TODO	Mon Mar 22 03:57:08 2004
--- pg_autovacuum/TODO	Mon May 10 09:21:00 2004
***************
*** 7,13 ****
  
  _look into possible benifits of pgstattuple contrib work
  
! _Continue trying to reduce server load created by polling.
  
  Done:
  --------------------------------------------------------------------------
--- 7,15 ----
  
  _look into possible benifits of pgstattuple contrib work
  
! _Continue trying to reduce server load created by polling.
! 
! _Use a message resource file under Win32 to get nicely formatted event log entries
  
  Done:
  --------------------------------------------------------------------------
diff -c pg_autovacuum.orig/pg_autovacuum.c pg_autovacuum/pg_autovacuum.c
*** pg_autovacuum.orig/pg_autovacuum.c	Fri Apr  2 00:35:35 2004
--- pg_autovacuum/pg_autovacuum.c	Tue May 11 09:28:11 2004
***************
*** 1,25 ****
  /* 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"
  
! FILE	   *LOGOUTPUT;
! char		logbuffer[4096];
  
  static void
! log_entry(const char *logentry)
! {
  	time_t		curtime;
! 	struct tm  *loctime;
! 	char		timebuffer[128];
  
  	curtime = time(NULL);
  	loctime = localtime(&curtime);
  	strftime(timebuffer, sizeof(timebuffer), "%Y-%m-%d %H:%M:%S %Z", loctime);
! 	fprintf(LOGOUTPUT, "[%s] %s\n", timebuffer, logentry);
  }
  
  /*
--- 1,113 ----
  /* pg_autovacuum.c
   * All the code for the pg_autovacuum program
   * (c) 2003 Matthew T. O'Connor
!  * Revisions by Christopher B. Browne, Liberty RMS
!  * Win32 Service code added by Dave Page
   */
! 
  #include "pg_autovacuum.h"
+ 
+ #ifdef WIN32
+ #include <windows.h>
+ 
+ SERVICE_STATUS          ServiceStatus; 
+ SERVICE_STATUS_HANDLE   hStatus;
+ int                     appMode = 0;
+ #endif
  
! FILE    *LOGOUTPUT;
! char    logbuffer[4096];
  
  static void
! log_entry(const char *logentry, int level)
! {      
! 
!         /* Note: Under Windows we dump the log entries to the normal stderr/logfile */
!         /* as well, otherwise it can be a pain to debug service install failures etc. */
!         
  	time_t		curtime;
! 	struct tm       *loctime;
! 	char		timebuffer[128],
!                         slevel[10];
!         
! 
! #ifdef WIN32 
! 	static          HANDLE evtHandle = INVALID_HANDLE_VALUE;
!         static int      last_level;
!         WORD            elevel;
! #endif
!         
!         switch(level) 
!         { 
!                 case LVL_DEBUG: 
!                         sprintf(slevel, "DEBUG:   ");
!                         break;
! 
!                 case LVL_INFO:
!                         sprintf(slevel, "INFO:    ");
!                         break;
!                     
!                 case LVL_WARNING:
!                         sprintf(slevel, "WARNING: ");
!                         break;
!                     
!                 case LVL_ERROR:
!                         sprintf(slevel, "ERROR:   ");
!                         break;
! 
!                 case LVL_EXTRA:
!                         sprintf(slevel, "         ");
!                         break;
!                 
!                 default:
!                         sprintf(slevel, "         ");
!                         break;
!         } 
  
  	curtime = time(NULL);
  	loctime = localtime(&curtime);
  	strftime(timebuffer, sizeof(timebuffer), "%Y-%m-%d %H:%M:%S %Z", loctime);
! 	fprintf(LOGOUTPUT, "[%s] %s%s\n", timebuffer, slevel, logentry);
! 
! #ifdef WIN32 
!         
!         // Restore the previous level if this is extra info
!         if (level == LVL_EXTRA) level = last_level;
!         last_level = level;
!             
!         switch(level) 
!         { 
!                 case LVL_DEBUG: 
!                         elevel = EVENTLOG_INFORMATION_TYPE;
!                         break;
! 
!                 case LVL_INFO:
!                         elevel = EVENTLOG_SUCCESS;
!                         break;
!                     
!                 case LVL_WARNING:
!                         elevel = EVENTLOG_WARNING_TYPE;
!                         break;
!                     
!                 case LVL_ERROR:
!                         elevel = EVENTLOG_ERROR_TYPE;
!                         break;
!                 
!                 default:
!                         elevel = EVENTLOG_SUCCESS;
!                         break;
!         } 
! 	
! 	if (evtHandle == INVALID_HANDLE_VALUE) {
! 		evtHandle = RegisterEventSource(NULL,"PostgreSQL Auto Vacuum");
! 		if (evtHandle == NULL) {
! 			evtHandle = INVALID_HANDLE_VALUE;
! 			return;
! 		}
! 	}
! 
! 	ReportEvent(evtHandle, elevel, 1, 0, NULL, 1, 0, &logentry, NULL);
! #endif
  }
  
  /*
***************
*** 28,34 ****
   *
   * This code is mostly ripped directly from pm_dameonize in postmaster.c with
   * unneeded code removed.
!  */
  static void
  daemonize()
  {
--- 116,123 ----
   *
   * This code is mostly ripped directly from pm_dameonize in postmaster.c with
   * unneeded code removed.
!  */
! #ifndef WIN32
  static void
  daemonize()
  {
***************
*** 37,43 ****
  	pid = fork();
  	if (pid == (pid_t) -1)
  	{
! 		log_entry("Error: cannot disassociate from controlling TTY");
  		fflush(LOGOUTPUT);
  		_exit(1);
  	}
--- 126,132 ----
  	pid = fork();
  	if (pid == (pid_t) -1)
  	{
! 		log_entry("cannot disassociate from controlling TTY", LVL_ERROR);
  		fflush(LOGOUTPUT);
  		_exit(1);
  	}
***************
*** 52,64 ****
  #ifdef HAVE_SETSID
  	if (setsid() < 0)
  	{
! 		log_entry("Error: cannot disassociate from controlling TTY");
  		fflush(LOGOUTPUT);
  		_exit(1);
  	}
  #endif
  
! }
  
  /* Create and return tbl_info struct with initialized to values from row or res */
  static tbl_info *
--- 141,154 ----
  #ifdef HAVE_SETSID
  	if (setsid() < 0)
  	{
! 		log_entry("cannot disassociate from controlling TTY", LVL_ERROR);
  		fflush(LOGOUTPUT);
  		_exit(1);
  	}
  #endif
  
! }
! #endif /* WIN32 */
  
  /* Create and return tbl_info struct with initialized to values from row or res */
  static tbl_info *
***************
*** 68,74 ****
  
  	if (!new_tbl)
  	{
! 		log_entry("init_table_info: Cannot get memory");
  		fflush(LOGOUTPUT);
  		return NULL;
  	}
--- 158,164 ----
  
  	if (!new_tbl)
  	{
! 		log_entry("init_table_info: Cannot get memory", LVL_ERROR);
  		fflush(LOGOUTPUT);
  		return NULL;
  	}
***************
*** 82,88 ****
  		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;
  	}
--- 172,178 ----
  		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", LVL_ERROR);
  		fflush(LOGOUTPUT);
  		return NULL;
  	}
***************
*** 94,100 ****
  			   strlen(new_tbl->schema_name) + 6);
  	if (!new_tbl->table_name)
  	{
! 		log_entry("init_table_info: malloc failed on new_tbl->table_name");
  		fflush(LOGOUTPUT);
  		return NULL;
  	}
--- 184,190 ----
  			   strlen(new_tbl->schema_name) + 6);
  	if (!new_tbl->table_name)
  	{
! 		log_entry("init_table_info: malloc failed on new_tbl->table_name", LVL_ERROR);
  		fflush(LOGOUTPUT);
  		return NULL;
  	}
***************
*** 285,291 ****
  				{
  					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 */
--- 375,381 ----
  				{
  					sprintf(logbuffer, "added table: %s.%s", dbi->dbname,
  							((tbl_info *) DLE_VAL(DLGetTail(dbi->table_list)))->table_name);
! 					log_entry(logbuffer, LVL_DEBUG);
  				}
  			}
  		}						/* end of for loop that adds tables */
***************
*** 308,314 ****
  	if (args->debug >= 1)
  	{
  		sprintf(logbuffer, "Removing table: %s from list.", tbl->table_name);
! 		log_entry(logbuffer);
  		fflush(LOGOUTPUT);
  	}
  	DLRemove(tbl_to_remove);
--- 398,404 ----
  	if (args->debug >= 1)
  	{
  		sprintf(logbuffer, "Removing table: %s from list.", tbl->table_name);
! 		log_entry(logbuffer, LVL_DEBUG);
  		fflush(LOGOUTPUT);
  	}
  	DLRemove(tbl_to_remove);
***************
*** 363,382 ****
  print_table_info(tbl_info * tbl)
  {
  	sprintf(logbuffer, "  table name: %s.%s", tbl->dbi->dbname, tbl->table_name);
! 	log_entry(logbuffer);
  	sprintf(logbuffer, "     relid: %u;   relisshared: %i", tbl->relid, tbl->relisshared);
! 	log_entry(logbuffer);
  	sprintf(logbuffer, "     reltuples: %f;  relpages: %u", tbl->reltuples, tbl->relpages);
! 	log_entry(logbuffer);
  	sprintf(logbuffer, "     curr_analyze_count: %li; curr_vacuum_count: %li",
  			tbl->curr_analyze_count, tbl->curr_vacuum_count);
! 	log_entry(logbuffer);
  	sprintf(logbuffer, "     last_analyze_count: %li; last_vacuum_count: %li",
  			tbl->CountAtLastAnalyze, tbl->CountAtLastVacuum);
! 	log_entry(logbuffer);
  	sprintf(logbuffer, "     analyze_threshold: %li; vacuum_threshold: %li",
  			tbl->analyze_threshold, tbl->vacuum_threshold);
! 	log_entry(logbuffer);
  	fflush(LOGOUTPUT);
  }
  
--- 453,472 ----
  print_table_info(tbl_info * tbl)
  {
  	sprintf(logbuffer, "  table name: %s.%s", tbl->dbi->dbname, tbl->table_name);
! 	log_entry(logbuffer, LVL_INFO);
  	sprintf(logbuffer, "     relid: %u;   relisshared: %i", tbl->relid, tbl->relisshared);
! 	log_entry(logbuffer, LVL_INFO);
  	sprintf(logbuffer, "     reltuples: %f;  relpages: %u", tbl->reltuples, tbl->relpages);
! 	log_entry(logbuffer, LVL_INFO);
  	sprintf(logbuffer, "     curr_analyze_count: %li; curr_vacuum_count: %li",
  			tbl->curr_analyze_count, tbl->curr_vacuum_count);
! 	log_entry(logbuffer, LVL_INFO);
  	sprintf(logbuffer, "     last_analyze_count: %li; last_vacuum_count: %li",
  			tbl->CountAtLastAnalyze, tbl->CountAtLastVacuum);
! 	log_entry(logbuffer, LVL_INFO);
  	sprintf(logbuffer, "     analyze_threshold: %li; vacuum_threshold: %li",
  			tbl->analyze_threshold, tbl->vacuum_threshold);
! 	log_entry(logbuffer, LVL_INFO);
  	fflush(LOGOUTPUT);
  }
  
***************
*** 395,401 ****
  	DLAddHead(db_list, DLNewElem(init_dbinfo((char *) "template1", 0, 0)));
  	if (DLGetHead(db_list) == NULL)
  	{							/* Make sure init_dbinfo was successful */
! 		log_entry("init_db_list(): Error creating db_list for db: template1.");
  		fflush(LOGOUTPUT);
  		return NULL;
  	}
--- 485,491 ----
  	DLAddHead(db_list, DLNewElem(init_dbinfo((char *) "template1", 0, 0)));
  	if (DLGetHead(db_list) == NULL)
  	{							/* Make sure init_dbinfo was successful */
! 		log_entry("init_db_list(): Error creating db_list for db: template1.", LVL_ERROR);
  		fflush(LOGOUTPUT);
  		return NULL;
  	}
***************
*** 470,476 ****
  
  	if (args->debug >= 2)
  	{
! 		log_entry("updating the database list");
  		fflush(LOGOUTPUT);
  	}
  
--- 560,566 ----
  
  	if (args->debug >= 2)
  	{
! 		log_entry("updating the database list", LVL_DEBUG);
  		fflush(LOGOUTPUT);
  	}
  
***************
*** 556,562 ****
  				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 */
--- 646,652 ----
  				if (args->debug >= 1)
  				{
  					sprintf(logbuffer, "added database: %s", ((db_info *) DLE_VAL(DLGetTail(db_list)))->dbname);
! 					log_entry(logbuffer, LVL_DEBUG);
  				}
  			}
  		}						/* end of for loop that adds tables */
***************
*** 614,620 ****
  	if (args->debug >= 1)
  	{
  		sprintf(logbuffer, "Removing db: %s from list.", dbi->dbname);
! 		log_entry(logbuffer);
  		fflush(LOGOUTPUT);
  	}
  	DLRemove(db_to_remove);
--- 704,710 ----
  	if (args->debug >= 1)
  	{
  		sprintf(logbuffer, "Removing db: %s from list.", dbi->dbname);
! 		log_entry(logbuffer, LVL_DEBUG);
  		fflush(LOGOUTPUT);
  	}
  	DLRemove(db_to_remove);
***************
*** 682,708 ****
  print_db_info(db_info * dbi, int print_tbl_list)
  {
  	sprintf(logbuffer, "dbname: %s", (dbi->dbname) ? dbi->dbname : "(null)");
! 	log_entry(logbuffer);
  	
  	sprintf(logbuffer, "  oid: %u", dbi->oid);
! 	log_entry(logbuffer);
  	
  	sprintf(logbuffer, "  username: %s", (dbi->username) ? dbi->username : "(null)");
! 	log_entry(logbuffer);
  	
  	sprintf(logbuffer, "  password: %s", (dbi->password) ? dbi->password : "(null)");
! 	log_entry(logbuffer);
  	
  	if (dbi->conn != NULL)
! 		log_entry("  conn is valid, (connected)");
  	else
! 		log_entry("  conn is null, (not connected)");
  
  	sprintf(logbuffer, "  default_analyze_threshold: %li", dbi->analyze_threshold);
! 	log_entry(logbuffer);
  	
  	sprintf(logbuffer, "  default_vacuum_threshold: %li", dbi->vacuum_threshold);
! 	log_entry(logbuffer);
  	
  	fflush(LOGOUTPUT);
  	if (print_tbl_list > 0)
--- 772,798 ----
  print_db_info(db_info * dbi, int print_tbl_list)
  {
  	sprintf(logbuffer, "dbname: %s", (dbi->dbname) ? dbi->dbname : "(null)");
! 	log_entry(logbuffer, LVL_INFO);
  	
  	sprintf(logbuffer, "  oid: %u", dbi->oid);
! 	log_entry(logbuffer, LVL_INFO);
  	
  	sprintf(logbuffer, "  username: %s", (dbi->username) ? dbi->username : "(null)");
! 	log_entry(logbuffer, LVL_INFO);
  	
  	sprintf(logbuffer, "  password: %s", (dbi->password) ? dbi->password : "(null)");
! 	log_entry(logbuffer, LVL_INFO);
  	
  	if (dbi->conn != NULL)
! 		log_entry("  conn is valid, (connected)", LVL_INFO);
  	else
! 		log_entry("  conn is null, (not connected)", LVL_INFO);
  
  	sprintf(logbuffer, "  default_analyze_threshold: %li", dbi->analyze_threshold);
! 	log_entry(logbuffer, LVL_INFO);
  	
  	sprintf(logbuffer, "  default_vacuum_threshold: %li", dbi->vacuum_threshold);
! 	log_entry(logbuffer, LVL_INFO);
  	
  	fflush(LOGOUTPUT);
  	if (print_tbl_list > 0)
***************
*** 725,731 ****
  	{
  		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;
--- 815,821 ----
  	{
  		sprintf(logbuffer, "Failed connection to database %s with error: %s.",
  				dbi->dbname, PQerrorMessage(db_conn));
! 		log_entry(logbuffer, LVL_ERROR);
  		fflush(LOGOUTPUT);
  		PQfinish(db_conn);
  		db_conn = NULL;
***************
*** 767,773 ****
  		return NULL;
  
  	if (args->debug >= 4)
! 		log_entry(query);
  
  	res = PQexec(dbi->conn, query);
  
--- 857,863 ----
  		return NULL;
  
  	if (args->debug >= 4)
! 		log_entry(query, LVL_DEBUG);
  
  	res = PQexec(dbi->conn, query);
  
***************
*** 776,784 ****
  		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;
  	}
--- 866,874 ----
  		sprintf(logbuffer,
  		   "Fatal error occured while sending query (%s) to database %s",
  				query, dbi->dbname);
! 		log_entry(logbuffer, LVL_ERROR);
  		sprintf(logbuffer, "The error is [%s]", PQresultErrorMessage(res));
! 		log_entry(logbuffer, LVL_EXTRA);
  		fflush(LOGOUTPUT);
  		return NULL;
  	}
***************
*** 788,796 ****
  		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;
--- 878,886 ----
  		sprintf(logbuffer,
  		  "Can not refresh statistics information from the database %s.",
  				dbi->dbname);
! 		log_entry(logbuffer, LVL_ERROR);
  		sprintf(logbuffer, "The error is [%s]", PQresultErrorMessage(res));
! 		log_entry(logbuffer, LVL_EXTRA);
  		fflush(LOGOUTPUT);
  		PQclear(res);
  		return NULL;
***************
*** 824,831 ****
  	args->vacuum_scaling_factor = VACSCALINGFACTOR;
  	args->analyze_base_threshold = -1;
  	args->analyze_scaling_factor = -1;
! 	args->debug = AUTOVACUUM_DEBUG;
! 	args->daemonize = 0;
  	args->user = 0;
  	args->password = 0;
  	args->host = 0;
--- 914,928 ----
  	args->vacuum_scaling_factor = VACSCALINGFACTOR;
  	args->analyze_base_threshold = -1;
  	args->analyze_scaling_factor = -1;
! 	args->debug = AUTOVACUUM_DEBUG;
! #ifndef WIN32
! 	args->daemonize = 0;
! #else
! 	args->install_as_service = 0;
!         args->remove_as_service = 0;
! 	args->service_user = 0;
! 	args->service_password = 0;        
! #endif
  	args->user = 0;
  	args->password = 0;
  	args->host = 0;
***************
*** 835,842 ****
  	/*
  	 * Fixme: Should add some sanity checking such as positive integer
  	 * values etc
! 	 */
! 	while ((c = getopt(argc, argv, "s:S:v:V:a:A:d:U:P:H:L:p:hD")) != -1)
  	{
  		switch (c)
  		{
--- 932,943 ----
  	/*
  	 * Fixme: Should add some sanity checking such as positive integer
  	 * values etc
! 	 */
! #ifndef WIN32
! 	while ((c = getopt(argc, argv, "s:S:v:V:a:A:d:U:P:H:L:p:hD")) != -1)
! #else
! 	while ((c = getopt(argc, argv, "s:S:v:V:a:A:d:U:P:H:L:p:hIRN:W:")) != -1)        
! #endif
  	{
  		switch (c)
  		{
***************
*** 857,866 ****
  				break;
  			case 'A':
  				args->analyze_scaling_factor = atof(optarg);
! 				break;
  			case 'D':
  				args->daemonize++;
! 				break;
  			case 'd':
  				args->debug = atoi(optarg);
  				break;
--- 958,969 ----
  				break;
  			case 'A':
  				args->analyze_scaling_factor = atof(optarg);
! 				break;
! #ifndef WIN32
  			case 'D':
  				args->daemonize++;
! 				break;
! #endif
  			case 'd':
  				args->debug = atoi(optarg);
  				break;
***************
*** 881,887 ****
  				break;
  			case 'h':
  				usage();
! 				exit(0);
  			default:
  
  				/*
--- 984,1004 ----
  				break;
  			case 'h':
  				usage();
! 				exit(0);
! #ifdef WIN32
! 			case 'I':
! 				args->install_as_service++;
! 				break;
! 			case 'R':
! 				args->remove_as_service++;
! 				break;
! 			case 'N':
! 				args->service_user = optarg;
! 				break;
! 			case 'W':
! 				args->service_password = optarg;
! 				break;
! #endif
  			default:
  
  				/*
***************
*** 912,919 ****
  	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);
  
--- 1029,1043 ----
  	int			i = 0;
  	float		f = 0;
  
! 	fprintf(stderr, "usage: pg_autovacuum \n");
! #ifndef WIN32
! 	fprintf(stderr, "   [-D] Daemonize (Detach from tty and run in the background)\n");
! #else
! 	fprintf(stderr, "   [-I] Install as a Windows service (all other options will be ignored)\n");
! 	fprintf(stderr, "   [-R] Remove as a Windows service (all other options will be ignored)\n");
! 	fprintf(stderr, "   [-N] Username to run service as (only useful when installing as a Windows service)\n");
! 	fprintf(stderr, "   [-W] Password to run service with (only useful when installing as a Windows service)\n");
! #endif
  	i = AUTOVACUUM_DEBUG;
  	fprintf(stderr, "   [-d] debug (debug level=0,1,2,3; default=%i)\n", i);
  
***************
*** 945,1023 ****
  print_cmd_args()
  {
  	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->username=%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[])
! {
  	char		buf[256];
! 	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;
! 	double		diff;
! 	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 (args->daemonize == 1)
! 		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 (db_list == NULL)
--- 1069,1312 ----
  print_cmd_args()
  {
  	sprintf(logbuffer, "Printing command_args");
! 	log_entry(logbuffer, LVL_INFO);
  	sprintf(logbuffer, "  args->host=%s", (args->host) ? args->host : "(null)");
! 	log_entry(logbuffer, LVL_INFO);
  	sprintf(logbuffer, "  args->port=%s", (args->port) ? args->port : "(null)");
! 	log_entry(logbuffer, LVL_INFO);
  	sprintf(logbuffer, "  args->username=%s", (args->user) ? args->user : "(null)");
! 	log_entry(logbuffer, LVL_INFO);
  	sprintf(logbuffer, "  args->password=%s", (args->password) ? args->password : "(null)");
! 	log_entry(logbuffer, LVL_INFO);
  	sprintf(logbuffer, "  args->logfile=%s", (args->logfile) ? args->logfile : "(null)");
! 	log_entry(logbuffer, LVL_INFO);
! #ifndef WIN32
  	sprintf(logbuffer, "  args->daemonize=%i", args->daemonize);
! 	log_entry(logbuffer, LVL_INFO);
! #else
! 	sprintf(logbuffer, "  args->install_as_service=%i", args->install_as_service);
! 	log_entry(logbuffer, LVL_INFO);
! 	sprintf(logbuffer, "  args->remove_as_service=%i", args->remove_as_service);
! 	log_entry(logbuffer, LVL_INFO);
! 	sprintf(logbuffer, "  args->service_user=%s", (args->service_user) ? args->service_user : "(null)");
! 	log_entry(logbuffer, LVL_INFO);
! 	sprintf(logbuffer, "  args->service_password=%s", (args->service_password) ? args->service_password : "(null)");
! 	log_entry(logbuffer, LVL_INFO);
! #endif
!     
  	sprintf(logbuffer, "  args->sleep_base_value=%i", args->sleep_base_value);
! 	log_entry(logbuffer, LVL_INFO);
  	sprintf(logbuffer, "  args->sleep_scaling_factor=%f", args->sleep_scaling_factor);
! 	log_entry(logbuffer, LVL_INFO);
  	sprintf(logbuffer, "  args->vacuum_base_threshold=%i", args->vacuum_base_threshold);
! 	log_entry(logbuffer, LVL_INFO);
  	sprintf(logbuffer, "  args->vacuum_scaling_factor=%f", args->vacuum_scaling_factor);
! 	log_entry(logbuffer, LVL_INFO);
  	sprintf(logbuffer, "  args->analyze_base_threshold=%i", args->analyze_base_threshold);
! 	log_entry(logbuffer, LVL_INFO);
  	sprintf(logbuffer, "  args->analyze_scaling_factor=%f", args->analyze_scaling_factor);
! 	log_entry(logbuffer, LVL_INFO);
  	sprintf(logbuffer, "  args->debug=%i", args->debug);
! 	log_entry(logbuffer, LVL_INFO);
  
  	fflush(LOGOUTPUT);
  }
! 
! #ifdef WIN32
! 
! /* Handle control requests from the Service Control Manager */
! static void 
! ControlHandler(DWORD request) 
! { 
!         switch(request) 
!         { 
!                 case SERVICE_CONTROL_STOP: 
!                 case SERVICE_CONTROL_SHUTDOWN:
!                         log_entry("pg_autovacuum service stopping...", LVL_INFO);
!                         fflush(LOGOUTPUT);
!                         ServiceStatus.dwWin32ExitCode = 0; 
!                         ServiceStatus.dwCurrentState = SERVICE_STOPPED; 
!                         SetServiceStatus (hStatus, &ServiceStatus);
!                         return;  
! 
!                 default:
!                         break;
!         } 
! 
!         /* Report current status */
!         SetServiceStatus (hStatus, &ServiceStatus);
!         
!         return; 
! }
! 
! /* Register with the Service Control Manager */
! static int 
! InstallService()
! {
! 	SC_HANDLE       schService = NULL;
! 	SC_HANDLE       schSCManager = NULL;
! 	char            szFilename[MAX_PATH], 
!                         szKey[MAX_PATH], 
!                         szCommand[MAX_PATH+1024];
!         HKEY            hk = NULL;
!         DWORD           dwData = 0;
! 
!         /*
!          * Register the service with the SCM
!         */
!         GetModuleFileName(NULL, szFilename, MAX_PATH);
! 
! 	/* Open the Service Control Manager on the local computer. */
! 	schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
! 	if (!schSCManager) return -1;
! 
! 	schService = CreateService(
!                 schSCManager,					/* SCManager database */
! 		TEXT("pg_autovacuum"),				/* Name of service */
! 		TEXT("PostgreSQL Auto Vacuum"),	                /* Name to display */
!                 SERVICE_ALL_ACCESS,				/* Desired access */
! 		SERVICE_WIN32_OWN_PROCESS,		        /* Service type */
! 		SERVICE_AUTO_START, 			        /* Start type */
! 		SERVICE_ERROR_NORMAL,			        /* Error control type */
! 		szFilename,					/* Service binary */
! 		NULL,						/* No load ordering group */
! 		NULL,						/* No tag identifier */
! 		NULL,						/* Dependencies */
! 		args->service_user,     			/* Service account */
! 		args->service_password);			/* Account password */
! 
! 	if (!schService) return -2;
! 
!         /*
!          * Rewrite the command line for the service
!         */
!         sprintf(szKey, "SYSTEM\\CurrentControlSet\\Services\\pg_autovacuum");
!         if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_ALL_ACCESS, &hk)) return -3;
!         
!         /* Build the command line */
!         sprintf(szCommand, "\"%s\"", szFilename);
! 	if(args->host) sprintf(szCommand, "%s -H %s", szCommand, args->host);
!         if(args->port) sprintf(szCommand, "%s -p %s", szCommand, args->port);
!         if(args->user) sprintf(szCommand, "%s -U %s", szCommand, args->user);
!         if(args->password) sprintf(szCommand, "%s -p %s", szCommand, args->password);
!         if(args->logfile) sprintf(szCommand, "%s -L %s", szCommand, args->logfile);
!         if(args->sleep_base_value != (int)SLEEPBASEVALUE) sprintf(szCommand, "%s -s %i", szCommand, args->sleep_base_value);
!         if(args->sleep_scaling_factor != (float)SLEEPSCALINGFACTOR) sprintf(szCommand, "%s -S %f", szCommand, args->sleep_scaling_factor);
!         if(args->vacuum_base_threshold != (int)VACBASETHRESHOLD) sprintf(szCommand, "%s -v %i", szCommand, args->vacuum_base_threshold);
!         if(args->vacuum_scaling_factor != (float)VACSCALINGFACTOR) sprintf(szCommand, "%s -V %f", szCommand, args->vacuum_scaling_factor);        
!         if(args->analyze_base_threshold != (int)(VACBASETHRESHOLD / 2)) sprintf(szCommand, "%s -a %i", szCommand, args->analyze_base_threshold);
!         if(args->analyze_scaling_factor != (float)(VACSCALINGFACTOR / 2)) sprintf(szCommand, "%s -A %f", szCommand, args->analyze_scaling_factor); 
!         if(args->debug != (int)AUTOVACUUM_DEBUG) sprintf(szCommand, "%s -d %i", szCommand, args->debug);
! 
!         /* And write the new value */
!         if (RegSetValueEx(hk, "ImagePath", 0, REG_EXPAND_SZ, (LPBYTE)szCommand, (DWORD)strlen(szCommand)+1)) return -4;
!         RegCloseKey(hk); 
!                 
!         /*
!          * Set the Event source for the application log
!         */
!         sprintf(szKey, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\PostgreSQL Auto Vacuum");
!         if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hk, NULL)) return -5;
! 
!         /* TODO Create an actual message file and enable this! */
!         /*
!          * sprintf(szFilename, "C:\\Path\\To\\EventLogMsg.dll");
!          * if (RegSetValueEx(hk, "EventMessageFile", 0, REG_EXPAND_SZ, (LPBYTE)szFilename, (DWORD)strlen(szFilename)+1)) return -6;
!         */
! 
!         /* Set the event types supported */
!         dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE | EVENTLOG_SUCCESS;
!         if (RegSetValueEx(hk, "TypesSupported", 0, REG_DWORD, (LPBYTE)&dwData, sizeof(DWORD))) return -9;
!         
!         RegCloseKey(hk); 
! 	return 0;
! }
! 
! /* Unregister from the Service Control Manager */
! static int
! RemoveService()
! {
! 	SC_HANDLE       schService = NULL;
! 	SC_HANDLE       schSCManager = NULL;
! 	char            szKey[MAX_PATH];
!         HKEY            hk = NULL;
! 
!         /* Open the SCM */
! 	schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
! 	if (!schSCManager) return -1;
! 
! 	/* Open the service */
!         schService = OpenService(schSCManager, TEXT("pg_autovacuum"), SC_MANAGER_ALL_ACCESS);
! 	if (!schService) return -2;
! 
! 	/* Now delete the service */
! 	if (!DeleteService(schService)) return -3;
!  
!         /*
!          * Remove the Event source from the application log
!         */   
!         sprintf(szKey, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application");        
!         if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_ALL_ACCESS, &hk)) return -4;
!         if (RegDeleteKey(hk, "PostgreSQL Auto Vacuum")) return -5;
! 
! 	return 0;
! }
! 
! #endif /* WIN32 */
! 
! static
! int VacuumLoop(int argc, char** argv) 
! { 
  	char		buf[256];
! 	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;
! 	double		diff;
!         
! 	struct timeval  now,
!                         then;       
! #ifdef WIN32
!         
!         if (appMode) 
!                 log_entry("pg_autovacuum starting in Windows Application mode", LVL_INFO);
!         else
!                 log_entry("pg_autovacuum starting in Windows Service mode", LVL_INFO);
! 
!         ServiceStatus.dwServiceType = SERVICE_WIN32; 
!         ServiceStatus.dwCurrentState = SERVICE_START_PENDING; 
!         ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
!         ServiceStatus.dwWin32ExitCode = 0; 
!         ServiceStatus.dwServiceSpecificExitCode = 0; 
!         ServiceStatus.dwCheckPoint = 0; 
!         ServiceStatus.dwWaitHint = 0; 
!         
!         if (!appMode) {
!                 hStatus = RegisterServiceCtrlHandler("pg_autovacuum", (LPHANDLER_FUNCTION)ControlHandler); 
!                 if (hStatus == (SERVICE_STATUS_HANDLE)0) 
!                 { 
!                         return -1; 
!                 }
!         }
!         
!         if (args->debug >= 1)
!                 log_entry("Pausing to allow the database to start", LVL_DEBUG);
!                 
!         /* Delay for 10 secs to allow the DB to startup */
!         Sleep((DWORD)10000);
!         
!         if (args->debug >= 1)
!                 log_entry("Continuing startup", LVL_DEBUG);
!         
! #endif /* WIN32 */
!         
  	/* Init the db list with template1 */
  	db_list = init_db_list();
  	if (db_list == NULL)
***************
*** 1025,1055 ****
  	
  	if (check_stats_enabled(((db_info *) DLE_VAL(DLGetHead(db_list)))) != 0)
  	{
! 		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 */
  
  		dbs = ((db_info *) DLE_VAL(db_elem));	/* get pointer to cur_db's
! 												 * db_info struct */
  		if (dbs->conn == NULL)
  		{
  			dbs->conn = db_connect(dbs);
  			if (dbs->conn == NULL)
  			{					/* Serious problem: We can't connect to
  								 * template1 */
! 				log_entry("Error: Cannot connect to template1, exiting.");
  				fflush(LOGOUTPUT);
! 				fclose(LOGOUTPUT);
  				exit(1);
  			}
  		}
--- 1314,1364 ----
  	
  	if (check_stats_enabled(((db_info *) DLE_VAL(DLGetHead(db_list)))) != 0)
  	{
! 		log_entry("GUC variable stats_row_level must be enabled.", LVL_ERROR);
! 		log_entry("       Please fix the problems and try again.", LVL_EXTRA);
  		fflush(LOGOUTPUT);
  
  		exit(1);
! 	}
!         
  	gettimeofday(&then, 0);		/* for use later to caluculate sleep time */
! 
! #ifndef WIN32
! 	while (1)
! #else
!         /* Set the service status but don't report it yet */
!         ServiceStatus.dwCurrentState = SERVICE_RUNNING; 
!         
!         /* Now we can report the running status */
!         if (args->debug >= 1)
!                 log_entry("Sevice startup complete", LVL_DEBUG);
!         if (!appMode) SetServiceStatus (hStatus, &ServiceStatus);
!         
!         while (ServiceStatus.dwCurrentState == SERVICE_RUNNING)        
! #endif
! 	{	
!                 /* Main Loop */
!                 
  		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 (dbs->conn == NULL)
  		{
  			dbs->conn = db_connect(dbs);
  			if (dbs->conn == NULL)
  			{					/* Serious problem: We can't connect to
  								 * template1 */
! 				log_entry("Cannot connect to template1, exiting.", LVL_ERROR);
  				fflush(LOGOUTPUT);
! 				fclose(LOGOUTPUT);
! #ifdef WIN32
!                                 ServiceStatus.dwCurrentState = SERVICE_STOPPED; 
!                                 ServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; 
!                                 ServiceStatus.dwServiceSpecificExitCode = -1;
!                                 if(!appMode) SetServiceStatus(hStatus, &ServiceStatus);
! #endif
  				exit(1);
  			}
  		}
***************
*** 1119,1125 ****
  									if (args->debug >= 1)
  									{
  										sprintf(logbuffer, "Performing: %s", buf);
! 										log_entry(logbuffer);
  										fflush(LOGOUTPUT);
  									}
  									send_query(buf, dbs);
--- 1428,1434 ----
  									if (args->debug >= 1)
  									{
  										sprintf(logbuffer, "Performing: %s", buf);
! 										log_entry(logbuffer, LVL_DEBUG);
  										fflush(LOGOUTPUT);
  									}
  									send_query(buf, dbs);
***************
*** 1133,1139 ****
  									if (args->debug >= 1)
  									{
  										sprintf(logbuffer, "Performing: %s", buf);
! 										log_entry(logbuffer);
  										fflush(LOGOUTPUT);
  									}
  									send_query(buf, dbs);
--- 1442,1448 ----
  									if (args->debug >= 1)
  									{
  										sprintf(logbuffer, "Performing: %s", buf);
! 										log_entry(logbuffer, LVL_DEBUG);
  										fflush(LOGOUTPUT);
  									}
  									send_query(buf, dbs);
***************
*** 1175,1195 ****
  			sprintf(logbuffer,
  			 "%i All DBs checked in: %.0f usec, will sleep for %i secs.",
  					loops, diff, sleep_secs);
! 			log_entry(logbuffer);
  			fflush(LOGOUTPUT);
  		}
! 
! 		sleep(sleep_secs);		/* Larger Pause between outer loops */
  
  		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();
  	return EXIT_SUCCESS;
  }
--- 1484,1600 ----
  			sprintf(logbuffer,
  			 "%i All DBs checked in: %.0f usec, will sleep for %i secs.",
  					loops, diff, sleep_secs);
! 			log_entry(logbuffer, LVL_DEBUG);
  			fflush(LOGOUTPUT);
  		}
! 
! #ifndef WIN32
! 		sleep(sleep_secs);		/* Larger Pause between outer loops */
! #else
!                 Sleep((DWORD)(sleep_secs * 1000));		/* Larger Pause between outer loops */
! #endif
  
  		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();
!         return 0;
! }
! 
! /* Beginning of AutoVacuum Main Program */
! int
! main(int argc, char *argv[])
! {
!         
! #ifdef WIN32
!         LPVOID lpMsgBuf;
!         SERVICE_TABLE_ENTRY ServiceTable[2];
! #endif
! 
! 	args = get_cmd_args(argc, argv);	/* Get Command Line Args and put
! 										 * them in the args struct */
! #ifndef WIN32
! 	/* Dameonize if requested */
! 	if (args->daemonize == 1)
! 		daemonize();
! #endif
! 
! 	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();
!         
! #ifdef WIN32
!         /* Install as a Windows service if required */
!         if (args->install_as_service) {
!                 if(InstallService() != 0) 
!                 {
!                         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
!                         sprintf(logbuffer, "%s", (char *)lpMsgBuf);
!                         log_entry(logbuffer, LVL_ERROR);
!                         fflush(LOGOUTPUT);
!                         exit(-1);
!                 } 
!                 else
!                 {
!                         log_entry("Successfully installed Windows service", LVL_INFO);
!                         fflush(LOGOUTPUT);
!                         exit(0);
!                 }
!         }
! 
!         /* Remove as a Windows service if required */
!         if (args->remove_as_service) {
!                 if(RemoveService() != 0) 
!                 {
!                         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
!                         sprintf(logbuffer, "%s", (char *)lpMsgBuf);
!                         log_entry(logbuffer, LVL_ERROR);
!                         fflush(LOGOUTPUT);
!                         exit(-1);
!                 }
!                 else
!                 {
!                         log_entry("Successfully removed Windows service", LVL_INFO);
!                         fflush(LOGOUTPUT);
!                         exit(0);
!                 }
!         }
!         
!         // Normal service startup
!         ServiceTable[0].lpServiceName = "pg_autovacuum";
!         ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)VacuumLoop;
! 
!         ServiceTable[1].lpServiceName = NULL;
!         ServiceTable[1].lpServiceProc = NULL;
!     
! 	// Start the control dispatcher thread for our service
!         if(!StartServiceCtrlDispatcher(ServiceTable)) {
!                 appMode = 1;
!                 VacuumLoop(0, NULL);
!         }
! 
! #else /* Unix */
!         
!         /* Call the main program loop. */
!         VacuumLoop(0, NULL);
!         
! #endif /* WIN32 */
!         
  	return EXIT_SUCCESS;
  }
Only in pg_autovacuum: pg_autovacuum.exe
diff -c pg_autovacuum.orig/pg_autovacuum.h pg_autovacuum/pg_autovacuum.h
*** pg_autovacuum.orig/pg_autovacuum.h	Mon Mar 15 16:17:30 2004
--- pg_autovacuum/pg_autovacuum.h	Fri May  7 10:53:10 2004
***************
*** 1,7 ****
! /* pg_autovacuum.h
   * Header file for pg_autovacuum.c
   * (c) 2003 Matthew T. O'Connor
   */
  
  #include "postgres_fe.h"
  
--- 1,9 ----
! /* pg_autovacuum.hszCmdline
   * Header file for pg_autovacuum.c
   * (c) 2003 Matthew T. O'Connor
   */
+ 
+ #define FRONTEND
  
  #include "postgres_fe.h"
  
***************
*** 23,29 ****
  #include "/usr/include/pgsql/server/lib/dllist.h"
  */
  
! #define AUTOVACUUM_DEBUG	1
  #define VACBASETHRESHOLD	1000
  #define VACSCALINGFACTOR	2
  #define SLEEPBASEVALUE		300
--- 25,31 ----
  #include "/usr/include/pgsql/server/lib/dllist.h"
  */
  
! #define AUTOVACUUM_DEBUG	0
  #define VACBASETHRESHOLD	1000
  #define VACSCALINGFACTOR	2
  #define SLEEPBASEVALUE		300
***************
*** 36,65 ****
  
  #define TABLE_STATS_QUERY	"select a.oid,a.relname,a.relnamespace,a.relpages,a.relisshared,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.oid=b.relid and a.relkind = 'r'"
  
- #define FRONTEND
  #define PAGES_QUERY "select oid,reltuples,relpages from pg_class where oid=%u"
  #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'"
  
  /* define atooid */
! #define atooid(x)  ((Oid) strtoul((x), NULL, 10))
  
  /* 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;
  
--- 38,85 ----
  
  #define TABLE_STATS_QUERY	"select a.oid,a.relname,a.relnamespace,a.relpages,a.relisshared,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.oid=b.relid and a.relkind = 'r'"
  
  #define PAGES_QUERY "select oid,reltuples,relpages from pg_class where oid=%u"
  #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'"
  
  /* define atooid */
! #define atooid(x)  ((Oid) strtoul((x), NULL, 10))
! 
! /* Log levels */
! enum 
! {
!     LVL_DEBUG = 1,
!     LVL_INFO,
!     LVL_WARNING,
!     LVL_ERROR,
!     LVL_EXTRA
! };
  
  /* define cmd_args stucture */
  struct cmdargs
  {
! 	int	vacuum_base_threshold,
! 		analyze_base_threshold,
! 		sleep_base_value,
! 		debug,
! #ifndef WIN32
! 		daemonize;
! #else                    
!                 install_as_service,
!                 remove_as_service;
! #endif
! 	float	vacuum_scaling_factor,
! 		analyze_scaling_factor,
! 		sleep_scaling_factor;
! 	char	*user,
! 		*password,
! #ifdef WIN32
!                 *service_user,
!                 *service_password,
! #endif
! 		*host,
! 		*logfile,
! 		*port;
  };
  typedef struct cmdargs cmd_args;
  
***************
*** 70,110 ****
  	I think we need to guarantee this happens approx every 1Million TX's  */
  struct dbinfo
  {
! 	Oid			oid;
  	long		age;
  	long		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;
! 	float		reltuples;
! 	int			relisshared;
! 	Oid			relid,
! 				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[]);
--- 90,132 ----
  	I think we need to guarantee this happens approx every 1Million TX's  */
  struct dbinfo
  {
! 	Oid             oid;
  	long		age;
  	long		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;
! 	float	reltuples;
! 	int	relisshared;
! 	Oid	relid,
! 		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;
+ 
+ /* The main program loop function */
+ static int VacuumLoop(int argc, char** argv);
  
  /* Functions for dealing with command line arguements */
  static cmd_args *get_cmd_args(int argc, char *argv[]);
***************
*** 137,142 ****
  static void db_disconnect(db_info * dbi);
  static PGresult *send_query(const char *query, db_info * dbi);
  
! /* Other Generally needed Functions */
! static void daemonize(void);
! static void log_entry(const char *logentry);
--- 159,175 ----
  static void db_disconnect(db_info * dbi);
  static PGresult *send_query(const char *query, db_info * dbi);
  
! /* Other Generally needed Functions */
! #ifndef WIN32
! static void daemonize(void);
! #endif
! static void log_entry(const char *logentry, int level);
! 
! #ifdef WIN32
! /* Windows Service related functions */
! static void ControlHandler(DWORD request);
! static int InstallService();
! static int RemoveService();
! #endif
! 
! 

