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	Thu May  6 14:15:59 2004
***************
*** 1,17 ****
  /* 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];
--- 1,29 ----
  /* 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>
+ 
+ unsigned int sleep();
+ 
+ SERVICE_STATUS          ServiceStatus; 
+ SERVICE_STATUS_HANDLE   hStatus;
+ int                     appMode = 0;
+ #endif
  
  FILE	   *LOGOUTPUT;
  char		logbuffer[4096];
  
  static void
  log_entry(const char *logentry)
! {
! #ifndef WIN32        
  	time_t		curtime;
  	struct tm  *loctime;
  	char		timebuffer[128];
***************
*** 19,25 ****
  	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);
  }
  
  /*
--- 31,58 ----
  	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);
! #else
! 	static HANDLE evtHandle = INVALID_HANDLE_VALUE;
! 	
! 	if (evtHandle == INVALID_HANDLE_VALUE) {
! 		evtHandle = RegisterEventSource(NULL,"PostgreSQL Auto Vacuum Daemon");
! 		if (evtHandle == NULL) {
! 			evtHandle = INVALID_HANDLE_VALUE;
! 			return;
! 		}
! 	}
! 
! 	ReportEvent(evtHandle,
!                         EVENTLOG_SUCCESS, /* FIXME - Proper error levels?? */
!                         0,
!                         0,  /* FIXME - Proper IDs (to get decent messages) */
!                         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()
  {
--- 61,68 ----
   *
   * This code is mostly ripped directly from pm_dameonize in postmaster.c with
   * unneeded code removed.
!  */
! #ifndef WIN32
  static void
  daemonize()
  {
***************
*** 58,64 ****
  	}
  #endif
  
! }
  
  /* Create and return tbl_info struct with initialized to values from row or res */
  static tbl_info *
--- 92,99 ----
  	}
  #endif
  
! }
! #endif /* WIN32 */
  
  /* Create and return tbl_info struct with initialized to values from row or res */
  static tbl_info *
***************
*** 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;
--- 859,871 ----
  	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;    
! #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)
  		{
--- 875,886 ----
  	/*
  	 * 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:hIR")) != -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;
--- 901,912 ----
  				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:
  
  				/*
--- 927,941 ----
  				break;
  			case 'h':
  				usage();
! 				exit(0);
! #ifdef WIN32
! 			case 'I':
! 				args->install_as_service++;
! 				break;
! 			case 'R':
! 				args->remove_as_service++;
! 				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);
  
--- 966,978 ----
  	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");
! #endif
  	i = AUTOVACUUM_DEBUG;
  	fprintf(stderr, "   [-d] debug (debug level=0,1,2,3; default=%i)\n", i);
  
***************
*** 955,964 ****
  	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);
--- 1014,1030 ----
  	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);
! #ifndef WIN32
  	sprintf(logbuffer, "  args->daemonize=%i", args->daemonize);
! 	log_entry(logbuffer);
! #else
! 	sprintf(logbuffer, "  args->install_as_service=%i", args->install_as_service);
! 	log_entry(logbuffer);
! 	sprintf(logbuffer, "  args->remove_as_service=%i", args->remove_as_service);
! 	log_entry(logbuffer);
! #endif
!     
  	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);
***************
*** 976,1023 ****
  
  	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)
--- 1042,1193 ----
  
  	fflush(LOGOUTPUT);
  }
! 
! #ifdef WIN32
! 
! /* Handle control requests from the Service Control Manager */
! static void 
! ControlHandler(DWORD request) 
! { 
!         switch(request) 
!         { 
!                 case SERVICE_CONTROL_STOP: 
!                         log_entry("INFO: Service stopped");
!                         fflush(LOGOUTPUT);
!                         ServiceStatus.dwWin32ExitCode = 0; 
!                         ServiceStatus.dwCurrentState = SERVICE_STOPPED; 
!                         SetServiceStatus (hStatus, &ServiceStatus);
!                         return; 
! 
!                 case SERVICE_CONTROL_SHUTDOWN: 
!                         log_entry("INFO: Service stopped");
!                         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];
! 
! 	// Get the module name
!         GetModuleFileName(NULL, szFilename, MAX_PATH);
! 
! 	// Open the Service Control Manager on the local computer.
! 	schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
! 
! 	// Check connection to the SCM
! 	if (! schSCManager) return -1;
! 
! 	schService = CreateService(
!                 schSCManager,					// SCManager database
! 		TEXT("pg_autovacuum"),				// Name of service
! 		TEXT("PostgreSQL Auto Vacuum Daemon"),	        // 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
! 		NULL,						// Service account
! 		NULL);						// Account password
! 
! 	if (! schService) return -2;
! 
! 	return 0;
! }
! 
! /* Unregister from the Service Control Manager */
! static int
! RemoveService()
! {
! 	SC_HANDLE   schService = NULL;
! 	SC_HANDLE   schSCManager = NULL;
! 
! 	// Open the Service Control Manager on the local computer.
! 	schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
! 
! 	// Check connection to the SCM
! 	if (!schSCManager) return -1;
! 
! 	// Open the service
!         schService = OpenService(schSCManager, TEXT("pg_autovacuum"), SC_MANAGER_ALL_ACCESS);
! 
! 	// Check connection to the service
! 	if (!schService) return -2;
! 
! 	// Delete the service
! 	if (!DeleteService(schService)) return -3;
! 
! 	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;
!   
!                 
!         log_entry("Going...");        
! #ifdef WIN32
! 
!         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) 
!                 { 
!                         // Registering Control Handler failed
!                         return -1; 
!                 }
!         }
!         
!         // We report the running status to SCM. 
!         ServiceStatus.dwCurrentState = SERVICE_RUNNING; 
!         if (!appMode) SetServiceStatus (hStatus, &ServiceStatus);
! 
! #endif /* WIN32 */
!         
  	/* Init the db list with template1 */
  	db_list = init_db_list();
  	if (db_list == NULL)
***************
*** 1030,1041 ****
  		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 */
  
--- 1200,1217 ----
  		fflush(LOGOUTPUT);
  
  		exit(1);
! 	}
!         
  	gettimeofday(&then, 0);		/* for use later to caluculate sleep time */
! 
! #ifndef WIN32
! 	while (1)
! #else
!         while (ServiceStatus.dwCurrentState == SERVICE_RUNNING)        
! #endif
! 	{	
!                 /* Main Loop */
!                 
  		db_elem = DLGetHead(db_list);	/* Reset cur_db_node to the
  										 * beginning of the db_list */
  
***************
*** 1049,1055 ****
  								 * template1 */
  				log_entry("Error: Cannot connect to template1, exiting.");
  				fflush(LOGOUTPUT);
! 				fclose(LOGOUTPUT);
  				exit(1);
  			}
  		}
--- 1225,1236 ----
  								 * template1 */
  				log_entry("Error: Cannot connect to template1, exiting.");
  				fflush(LOGOUTPUT);
! 				fclose(LOGOUTPUT);
! #ifdef WIN32
!                                 ServiceStatus.dwCurrentState = SERVICE_STOPPED; 
!                                 ServiceStatus.dwWin32ExitCode = -1; 
!                                 if(!appMode) SetServiceStatus(hStatus, &ServiceStatus);
! #endif
  				exit(1);
  			}
  		}
***************
*** 1183,1195 ****
  
  		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;
  }
--- 1364,1469 ----
  
  		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, "Error: %s", (char *)lpMsgBuf);
!                         log_entry(logbuffer);
!                         fflush(LOGOUTPUT);
!                         exit(-1);
!                 } 
!                 else
!                 {
!                         log_entry("INFO: Successfully installed Windows service");
!                         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, "Error: %s", (char *)lpMsgBuf);
!                         log_entry(logbuffer);
!                         fflush(LOGOUTPUT);
!                         exit(-1);
!                 }
!                 else
!                 {
!                         log_entry("INFO: Successfully removed Windows service");
!                         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)) {
!                 log_entry("INFO: pg_autovacuum starting in Windows Application mode");
!                 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	Thu May  6 13:12:55 2004
***************
*** 2,7 ****
--- 2,9 ----
   * Header file for pg_autovacuum.c
   * (c) 2003 Matthew T. O'Connor
   */
+ 
+ #define FRONTEND
  
  #include "postgres_fe.h"
  
***************
*** 36,42 ****
  
  #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'"
--- 38,43 ----
***************
*** 50,57 ****
  	int			vacuum_base_threshold,
  				analyze_base_threshold,
  				sleep_base_value,
! 				debug,
! 				daemonize;
  	float		vacuum_scaling_factor,
  				analyze_scaling_factor,
  				sleep_scaling_factor;
--- 51,63 ----
  	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;
***************
*** 105,110 ****
--- 111,119 ----
  								 * 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);
--- 146,162 ----
  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);
! 
! #ifdef WIN32
! /* Windows Service related functions */
! static void ControlHandler(DWORD request);
! static int InstallService();
! static int RemoveService();
! #endif
! 
! 

