*** pgsql/src/backend/utils/misc/postgresql.conf.sample	2007-03-30 11:23:12.000000000 +1000
--- workingpgsql/src/backend/utils/misc/postgresql.conf.sample	2007-03-30 11:43:18.000000000 +1000
***************
*** 227,233 ****
  # - Where to Log -
  
  #log_destination = 'stderr'		# Valid values are combinations of 
! 					# stderr, syslog and eventlog, 
  					# depending on platform.
  
  # This is used when logging to stderr:
--- 227,233 ----
  # - Where to Log -
  
  #log_destination = 'stderr'		# Valid values are combinations of 
! 					# stderr, syslog, sqllog and eventlog, 
  					# depending on platform.
  
  # This is used when logging to stderr:
***************
*** 235,241 ****
  					# files
  					# (change requires restart)
  
! # These are only used if redirect_stderr is on:
  #log_directory = 'pg_log'		# Directory where log files are written
  					# Can be absolute or relative to PGDATA
  #log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # Log file name pattern.
--- 235,241 ----
  					# files
  					# (change requires restart)
  
! # These are only used if redirect_stderr is on, or if log_destination is sqllog:
  #log_directory = 'pg_log'		# Directory where log files are written
  					# Can be absolute or relative to PGDATA
  #log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # Log file name pattern.
*** pgsql/src/backend/utils/misc/guc.c	2007-03-30 11:23:12.000000000 +1000
--- workingpgsql/src/backend/utils/misc/guc.c	2007-03-30 11:45:59.000000000 +1000
***************
*** 2137,2143 ****
  	{
  		{"log_destination", PGC_SIGHUP, LOGGING_WHERE,
  			gettext_noop("Sets the destination for server log output."),
! 			gettext_noop("Valid values are combinations of \"stderr\", \"syslog\", "
  						 "and \"eventlog\", depending on the platform."),
  			GUC_LIST_INPUT
  		},
--- 2137,2143 ----
  	{
  		{"log_destination", PGC_SIGHUP, LOGGING_WHERE,
  			gettext_noop("Sets the destination for server log output."),
! 			gettext_noop("Valid values are combinations of \"stderr\", \"syslog\", \"sqllog\","
  						 "and \"eventlog\", depending on the platform."),
  			GUC_LIST_INPUT
  		},
***************
*** 6025,6030 ****
--- 6025,6032 ----
  
  		if (pg_strcasecmp(tok, "stderr") == 0)
  			newlogdest |= LOG_DESTINATION_STDERR;
+ 		else if (pg_strcasecmp(tok, "sqllog") == 0)
+ 			newlogdest |= LOG_DESTINATION_SQL;
  #ifdef HAVE_SYSLOG
  		else if (pg_strcasecmp(tok, "syslog") == 0)
  			newlogdest |= LOG_DESTINATION_SYSLOG;
*** pgsql/src/backend/utils/error/elog.c	2007-03-03 10:37:23.000000000 +1100
--- workingpgsql/src/backend/utils/error/elog.c	2007-04-01 15:59:06.000000000 +1000
***************
*** 78,83 ****
--- 78,85 ----
  
  extern pid_t SysLoggerPID;
  
+ char timestamp[128];
+ 
  /* GUC parameters */
  PGErrorVerbosity Log_error_verbosity = PGERROR_VERBOSE;
  char	   *Log_line_prefix = NULL;		/* format for extra log line info */
***************
*** 125,130 ****
--- 127,136 ----
  static void append_with_tabs(StringInfo buf, const char *str);
  static bool is_log_level_output(int elevel, int log_min_level);
  
+ static void write_sqllog(ErrorData *edata);
+ static void get_error_message(StringInfo buf, ErrorData *edata);
+ static void get_timestamp(StringInfo buf);
+ static size_t escape_string_literal(char *to, const char *from);
  
  /*
   * errstart --- begin an error-reporting cycle
***************
*** 1428,1468 ****
  				appendStringInfo(buf, "%ld", log_line_number);
  				break;
  			case 'm':
! 				{
! 					/*
! 					 * Note: for %m, %t, and %s we deliberately use the C
! 					 * library's strftime/localtime, and not the equivalent
! 					 * functions from src/timezone.  This ensures that all
! 					 * backends will report log entries in the same timezone,
! 					 * namely whatever C-library setting they inherit from the
! 					 * postmaster.	If we used src/timezone then local
! 					 * settings of the TimeZone GUC variable would confuse the
! 					 * log.
! 					 */
! 					time_t		stamp_time;
! 					char		strfbuf[128],
! 								msbuf[8];
! 					struct timeval tv;
! 
! 					gettimeofday(&tv, NULL);
! 					stamp_time = tv.tv_sec;
! 
! 					strftime(strfbuf, sizeof(strfbuf),
! 					/* leave room for milliseconds... */
! 					/* Win32 timezone names are too long so don't print them */
! #ifndef WIN32
! 							 "%Y-%m-%d %H:%M:%S     %Z",
! #else
! 							 "%Y-%m-%d %H:%M:%S     ",
! #endif
! 							 localtime(&stamp_time));
! 
! 					/* 'paste' milliseconds into place... */
! 					sprintf(msbuf, ".%03d", (int) (tv.tv_usec / 1000));
! 					strncpy(strfbuf + 19, msbuf, 4);
! 
! 					appendStringInfoString(buf, strfbuf);
! 				}
  				break;
  			case 't':
  				{
--- 1434,1440 ----
  				appendStringInfo(buf, "%ld", log_line_number);
  				break;
  			case 'm':
! 				get_timestamp(buf);
  				break;
  			case 't':
  				{
***************
*** 1574,1579 ****
--- 1546,1552 ----
  {
  	StringInfoData buf;
  
+ 	memset(timestamp, '\0', sizeof(timestamp));
  	initStringInfo(&buf);
  
  	log_line_prefix(&buf);
***************
*** 1582,1598 ****
  	if (Log_error_verbosity >= PGERROR_VERBOSE)
  		appendStringInfo(&buf, "%s: ", unpack_sql_state(edata->sqlerrcode));
  
! 	if (edata->message)
! 		append_with_tabs(&buf, edata->message);
! 	else
! 		append_with_tabs(&buf, _("missing error text"));
! 
! 	if (edata->cursorpos > 0)
! 		appendStringInfo(&buf, _(" at character %d"),
! 						 edata->cursorpos);
! 	else if (edata->internalpos > 0)
! 		appendStringInfo(&buf, _(" at character %d"),
! 						 edata->internalpos);
  
  	appendStringInfoChar(&buf, '\n');
  
--- 1555,1562 ----
  	if (Log_error_verbosity >= PGERROR_VERBOSE)
  		appendStringInfo(&buf, "%s: ", unpack_sql_state(edata->sqlerrcode));
  
! 	/* Get the error message and cursor position if any. */
! 	get_error_message(&buf, edata);
  
  	appendStringInfoChar(&buf, '\n');
  
***************
*** 1728,1734 ****
  
  	/* If in the syslogger process, try to write messages direct to file */
  	if (am_syslogger)
! 		write_syslogger_file(buf.data, buf.len);
  
  	pfree(buf.data);
  }
--- 1692,1702 ----
  
  	/* If in the syslogger process, try to write messages direct to file */
  	if (am_syslogger)
! 		write_syslogger_file(buf.data, buf.len, STDERR_LOG);
! 
! 	/* Output log in sql format, if enabled */
! 	if(Log_destination & LOG_DESTINATION_SQL) 
! 		write_sqllog(edata);
  
  	pfree(buf.data);
  }
***************
*** 2105,2107 ****
--- 2073,2375 ----
  
  	return false;
  }
+ 
+ /* 
+  * Constructs the error message, depending on the Errordata it gets from the
+  * calling functions, in CSV (comma seperated values) format. The COPY command 
+  * can then be used to load the messages into a table.
+  */
+ static void
+ write_sqllog(ErrorData *edata)
+ {
+ 	char *sql_log_stmt = NULL;
+ 	StringInfoData msgbuf;
+ 	StringInfoData buf;
+ 
+ 	initStringInfo(&msgbuf);
+ 	initStringInfo(&buf);
+ 
+ 	/* 
+ 	 * The format of error message in CSV format:
+ 	 * timestamp with milliseconds, username, databasename, session id,
+ 	 * host and port number, process id, command tag, session start time,
+ 	 * transaction id, error severity, sql state code, statement or error
+ 	 * message.
+ 	 */
+ 	
+ 	/* timestamp_with_milliseconds */
+ 	/* 
+ 	 * Check if the timestamp is already calculated for the syslog message,
+ 	 * if it is, then no need to calculate it again, will use the same,
+ 	 * else get the current timestamp. This is done to put same timestamp
+ 	 * in syslog and sqllog messages.
+ 	 */
+ 	if (timestamp[0] == '\0')
+ 		get_timestamp(&buf);
+ 	else
+ 		appendStringInfoString(&buf, timestamp);
+ 
+ 	appendStringInfoString(&buf, ",");
+ 
+ 	/* username */
+ 	if (MyProcPort)
+ 	{
+ 		const char *username = MyProcPort->user_name;
+ 		if (username == NULL || *username == '\0')
+ 			username = _("[unknown]");
+ 		appendStringInfo(&buf, "%s,", username);
+ 	}
+ 	else
+ 		appendStringInfoString(&buf, "NULL,");
+ 
+ 	/* databasename */
+ 	if (MyProcPort)
+ 	{
+ 		const char *dbname = MyProcPort->database_name;
+ 
+ 		if (dbname == NULL || *dbname == '\0')
+ 			dbname = _("[unknown]");
+ 		appendStringInfo(&buf, "%s,", dbname);
+ 	}
+ 	else
+ 		appendStringInfoString(&buf, "NULL,");
+ 
+ 	/* session id */
+ 	if (MyProcPort)
+ 	{
+ 		appendStringInfo(&buf, "%lx.%x,",
+ 				 (long) (MyProcPort->session_start), MyProcPid);
+ 	}
+ 	else
+ 		appendStringInfoString(&buf, "NULL,");
+ 
+ 	/* Remote host and port */
+ 	if (MyProcPort)
+ 	{
+ 		if (MyProcPort->remote_host)
+ 		{
+ 			appendStringInfo(&buf, "%s", MyProcPort->remote_host);
+ 			if (MyProcPort->remote_port &&
+ 				MyProcPort->remote_port[0] != '\0')
+ 				appendStringInfo(&buf, "(%s),",
+ 						 MyProcPort->remote_port);
+ 			else
+ 				appendStringInfoString(&buf, "(NULL),");
+ 		}
+ 		else
+ 			appendStringInfoString(&buf, "NULL,");
+ 	}
+ 	else
+ 		appendStringInfoString(&buf, "NULL,");
+ 			
+ 
+ 	/* Process id */
+ 	if (MyProcPid != 0)
+ 		appendStringInfo(&buf, "%d,", MyProcPid);
+ 	else
+ 		appendStringInfoString(&buf, "NULL,");
+ 
+ 	/* Command tag */
+ 	if (MyProcPort)
+ 	{
+ 		const char *psdisp;
+ 		int			displen;
+ 
+ 		psdisp = get_ps_display(&displen);
+ 		appendStringInfo(&buf, "%.*s,", displen, psdisp);
+ 	}
+ 	else
+ 	appendStringInfoString(&buf, "NULL,");
+ 
+ 	/* session start timestamp */
+ 	if (MyProcPort)
+ 	{
+ 		char		strfbuf[128];
+ 
+ 		strftime(strfbuf, sizeof(strfbuf),
+ 		/* Win32 timezone names are too long so don't print them */
+ #ifndef WIN32
+ 			 "%Y-%m-%d %H:%M:%S %Z",
+ #else
+ 			 "%Y-%m-%d %H:%M:%S",
+ #endif
+ 		localtime(&MyProcPort->session_start));
+ 		appendStringInfoString(&buf, strfbuf);
+ 		appendStringInfoString(&buf, ",");
+ 	}
+ 	else
+ 		appendStringInfoString(&buf, "NULL,");
+ 
+ 	/* Transaction id */
+ 	if (MyProcPort)
+ 	{
+ 		if (IsTransactionState())
+ 			appendStringInfo(&buf, "%u,", GetTopTransactionId());
+ 		else
+ 			appendStringInfo(&buf, "%u,", InvalidTransactionId);
+ 	}
+ 	else
+ 		appendStringInfoString(&buf, "NULL,");
+ 
+ 	/* Error severity */
+ 	if (error_severity(edata->elevel) != NULL)
+ 		appendStringInfo(&buf, "%s,", error_severity(edata->elevel));
+ 	else
+ 		appendStringInfoString(&buf, "NULL,");
+ 	
+ 	/* SQL state code */
+ 	if (Log_error_verbosity >= PGERROR_VERBOSE)
+ 		appendStringInfo(&buf, "%s,", 
+ 				 unpack_sql_state(edata->sqlerrcode));
+ 	else
+ 		appendStringInfoString(&buf, "NULL,");
+ 
+ 	/* Get the error message and cursor position if any */
+ 	get_error_message(&msgbuf, edata);
+ 	sql_log_stmt = palloc(strlen(msgbuf.data) * 2 + 1);	
+ 	escape_string_literal(sql_log_stmt, msgbuf.data);
+ 
+ 	appendStringInfo(&buf, "\"%s\"", sql_log_stmt);
+ 	appendStringInfoString(&buf, "\n");
+ 	print_sqllog(buf);
+ 
+ 	pfree(msgbuf.data);
+ 	pfree(buf.data);
+ }
+ 
+ /*
+  * Appends the buffer with the error message and the cursor position.
+  */
+ static void
+ get_error_message(StringInfo buf, ErrorData *edata)
+ {
+ 	StringInfoData msgbuf;
+ 
+ 	initStringInfo(&msgbuf);
+ 
+ 	if (edata->message)
+ 		append_with_tabs(&msgbuf, edata->message);
+ 	else
+ 		append_with_tabs(&msgbuf, _("missing error text"));
+ 
+ 	if (edata->cursorpos > 0)
+ 		appendStringInfo(&msgbuf, _(" at character %d"),
+ 						 edata->cursorpos);
+ 	else if (edata->internalpos > 0)
+ 		appendStringInfo(&msgbuf, _(" at character %d"),
+ 						 edata->internalpos);
+ 	appendStringInfo(buf, "%s", pstrdup(msgbuf.data));
+ }
+ 
+ /*
+  * Calculates and returns the timestamp
+  */
+ static void
+ get_timestamp(StringInfo buf)
+ {
+ 	/*
+ 	 * Note: for %m, %t, and %s we deliberately use the C
+ 	 * library's strftime/localtime, and not the equivalent
+ 	 * functions from src/timezone.  This ensures that all
+ 	 * backends will report log entries in the same timezone,
+ 	 * namely whatever C-library setting they inherit from the
+ 	 * postmaster.	If we used src/timezone then local
+ 	 * settings of the TimeZone GUC variable would confuse the
+ 	 * log.
+ 	 */
+ 	time_t		stamp_time;
+ 	char		msbuf[8];
+ 	struct timeval tv;
+ 
+ 	gettimeofday(&tv, NULL);
+ 	stamp_time = tv.tv_sec;
+ 
+ 	strftime(timestamp, sizeof(timestamp),
+ 	/* leave room for milliseconds... */
+ 	/* Win32 timezone names are too long so don't print them. */
+ #ifndef WIN32
+ 		 "%Y-%m-%d %H:%M:%S     %Z",
+ #else
+ 		 "%Y-%m-%d %H:%M:%S     ",
+ #endif
+ 	localtime(&stamp_time));
+ 
+ 	/* 'paste' milliseconds into place... */
+ 	sprintf(msbuf, ".%03d", (int) (tv.tv_usec / 1000));
+ 	strncpy(timestamp + 19, msbuf, 4);
+ 
+ 	appendStringInfoString(buf, timestamp);
+ }
+ 
+ /*
+  * Escapes special characters in the string to conform
+  * with the sql type output
+  */
+ static size_t
+ escape_string_literal(char *to, const char *from)
+ {
+ 	const char *source = from;
+ 	char	   *target = to;
+ 	size_t		remaining = 0;
+ 
+ 	if (from == NULL)
+ 		return remaining;
+ 		
+ 	remaining = strlen(from);
+ 	
+ 	while (remaining > 0 && *source != '\0')
+ 	{
+ 		char		c = *source;
+ 		int			len;
+ 		int			i;
+ 
+ 		/* Fast path for plain ASCII */
+ 		if (!IS_HIGHBIT_SET(c))
+ 		{
+ 			/* Apply quoting if needed */
+ 			if (SQL_STR_DOUBLE(c, false))
+ 				*target++ = c;
+ 			/* Copy the character */
+ 			*target++ = c;
+ 			source++;
+ 			remaining--;
+ 			continue;
+ 		}
+ 
+ 		/* Slow path for possible multibyte characters */
+ 		len = pg_encoding_mblen(pg_get_client_encoding(), source);
+ 
+ 		/* Copy the character */
+ 		for (i = 0; i < len; i++)
+ 		{
+ 			if (remaining == 0 || *source == '\0')
+ 				break;
+ 			*target++ = *source++;
+ 			remaining--;
+ 		}
+ 
+ 		/*
+ 		 * If we hit premature end of string (ie, incomplete multibyte
+ 		 * character), try to pad out to the correct length with spaces. We
+ 		 * may not be able to pad completely, but we will always be able to
+ 		 * insert at least one pad space (since we'd not have quoted a
+ 		 * multibyte character).  This should be enough to make a string that
+ 		 * the server will error out on.
+ 		 */
+ 		if (i < len)
+ 		{
+ 			for (; i < len; i++)
+ 			{
+ 				if (((size_t) (target - to)) / 2 >= strlen(from))
+ 					break;
+ 				*target++ = ' ';
+ 			}
+ 			break;
+ 		}
+ 	}
+ 
+ 	/* Write the terminating NUL character. */
+ 	*target = '\0';
+ 
+ 	return target - to;
+ }
*** pgsql/src/backend/postmaster/syslogger.c	2007-01-06 09:19:36.000000000 +1100
--- workingpgsql/src/backend/postmaster/syslogger.c	2007-03-31 12:52:21.481757312 +1000
***************
*** 81,94 ****
--- 81,97 ----
  static bool pipe_eof_seen = false;
  
  static FILE *syslogFile = NULL;
+ static FILE *sqllogFile = NULL;
  
  static char *last_file_name = NULL;
  
  /* These must be exported for EXEC_BACKEND case ... annoying */
  #ifndef WIN32
  int			syslogPipe[2] = {-1, -1};
+ int			sqllogPipe[2] = {-1, -1};
  #else
  HANDLE		syslogPipe[2] = {0, 0};
+ HANDLE		sqllogPipe[2] = {0, 0};
  #endif
  
  #ifdef WIN32
***************
*** 108,119 ****
  static pid_t syslogger_forkexec(void);
  static void syslogger_parseArgs(int argc, char *argv[]);
  #endif
! static void write_syslogger_file_binary(const char *buffer, int count);
  
  #ifdef WIN32
  static unsigned int __stdcall pipeThread(void *arg);
  #endif
  static void logfile_rotate(bool time_based_rotation);
  static char *logfile_getname(pg_time_t timestamp);
  static void set_next_rotation_time(void);
  static void sigHupHandler(SIGNAL_ARGS);
--- 111,124 ----
  static pid_t syslogger_forkexec(void);
  static void syslogger_parseArgs(int argc, char *argv[]);
  #endif
! static void read_log_pipe(int log_type);
! static void write_syslogger_file_binary(const char *buffer, int count, int log_type);
  
  #ifdef WIN32
  static unsigned int __stdcall pipeThread(void *arg);
  #endif
  static void logfile_rotate(bool time_based_rotation);
+ static void logfile_rotate_worker(bool time_based_rotation, char* filename, FILE **dest_file);
  static char *logfile_getname(pg_time_t timestamp);
  static void set_next_rotation_time(void);
  static void sigHupHandler(SIGNAL_ARGS);
***************
*** 150,156 ****
  	 * assumes that all interesting messages generated in the syslogger will
  	 * come through elog.c and will be sent to write_syslogger_file.
  	 */
! 	if (redirection_done)
  	{
  		int			fd = open(NULL_DEV, O_WRONLY, 0);
  
--- 155,161 ----
  	 * assumes that all interesting messages generated in the syslogger will
  	 * come through elog.c and will be sent to write_syslogger_file.
  	 */
! 	if ((Redirect_stderr) && (redirection_done) )
  	{
  		int			fd = open(NULL_DEV, O_WRONLY, 0);
  
***************
*** 176,185 ****
--- 181,198 ----
  	if (syslogPipe[1] >= 0)
  		close(syslogPipe[1]);
  	syslogPipe[1] = -1;
+ 	
+ 	if (sqllogPipe[1] >= 0)
+ 		close(sqllogPipe[1]);
+ 	sqllogPipe[1] = -1;
  #else
  	if (syslogPipe[1])
  		CloseHandle(syslogPipe[1]);
  	syslogPipe[1] = 0;
+ 	
+ 	if (sqllogPipe[1])
+ 		CloseHandle(sqllogPipe[1]);
+ 	sqllogPipe[1] = 0;
  #endif
  
  	/*
***************
*** 244,257 ****
  	{
  		bool		time_based_rotation = false;
  
- #ifndef WIN32
- 		char		logbuffer[1024];
- 		int			bytesRead;
- 		int			rc;
- 		fd_set		rfds;
- 		struct timeval timeout;
- #endif
- 
  		if (got_SIGHUP)
  		{
  			got_SIGHUP = false;
--- 257,262 ----
***************
*** 298,366 ****
  		if (!rotation_requested && Log_RotationSize > 0)
  		{
  			/* Do a rotation if file is too big */
! 			if (ftell(syslogFile) >= Log_RotationSize * 1024L)
  				rotation_requested = true;
  		}
  
  		if (rotation_requested)
  			logfile_rotate(time_based_rotation);
  
! #ifndef WIN32
! 
! 		/*
! 		 * Wait for some data, timing out after 1 second
! 		 */
! 		FD_ZERO(&rfds);
! 		FD_SET(syslogPipe[0], &rfds);
! 		timeout.tv_sec = 1;
! 		timeout.tv_usec = 0;
! 
! 		rc = select(syslogPipe[0] + 1, &rfds, NULL, NULL, &timeout);
! 
! 		if (rc < 0)
! 		{
! 			if (errno != EINTR)
! 				ereport(LOG,
! 						(errcode_for_socket_access(),
! 						 errmsg("select() failed in logger process: %m")));
! 		}
! 		else if (rc > 0 && FD_ISSET(syslogPipe[0], &rfds))
! 		{
! 			bytesRead = piperead(syslogPipe[0],
! 								 logbuffer, sizeof(logbuffer));
! 
! 			if (bytesRead < 0)
! 			{
! 				if (errno != EINTR)
! 					ereport(LOG,
! 							(errcode_for_socket_access(),
! 							 errmsg("could not read from logger pipe: %m")));
! 			}
! 			else if (bytesRead > 0)
! 			{
! 				write_syslogger_file_binary(logbuffer, bytesRead);
! 				continue;
! 			}
! 			else
! 			{
! 				/*
! 				 * Zero bytes read when select() is saying read-ready means
! 				 * EOF on the pipe: that is, there are no longer any processes
! 				 * with the pipe write end open.  Therefore, the postmaster
! 				 * and all backends are shut down, and we are done.
! 				 */
! 				pipe_eof_seen = true;
! 			}
! 		}
! #else							/* WIN32 */
! 
! 		/*
! 		 * On Windows we leave it to a separate thread to transfer data and
! 		 * detect pipe EOF.  The main thread just wakes up once a second to
! 		 * check for SIGHUP and rotation conditions.
! 		 */
! 		pg_usleep(1000000L);
! #endif   /* WIN32 */
  
  		if (pipe_eof_seen)
  		{
--- 303,329 ----
  		if (!rotation_requested && Log_RotationSize > 0)
  		{
  			/* Do a rotation if file is too big */
! 			if ( (syslogFile) && (ftell(syslogFile) >= Log_RotationSize * 1024L) )
! 				rotation_requested = true;
! 
! 			/* As a first version, we will rotate both the log 
! 			 * files if either of them is big. The difference 
! 			 * between these two files are not going to be that
! 			 * great anyway. */
! 			if ( (sqllogFile) && (ftell(sqllogFile) >= Log_RotationSize * 1024L) )
  				rotation_requested = true;
  		}
  
  		if (rotation_requested)
  			logfile_rotate(time_based_rotation);
  
! 		/* Read the syslog pipe if redirect_stderr is on. */
! 		if (Redirect_stderr)
! 			read_log_pipe(STDERR_LOG);
! 
! 		/* Read the sqllog pipe if sqllog is on. */
! 		if (Log_destination & LOG_DESTINATION_SQL)
! 			read_log_pipe(SQL_LOG);
  
  		if (pipe_eof_seen)
  		{
***************
*** 388,394 ****
  	pid_t		sysloggerPid;
  	char	   *filename;
  
! 	if (!Redirect_stderr)
  		return 0;
  
  	/*
--- 351,357 ----
  	pid_t		sysloggerPid;
  	char	   *filename;
  
! 	if ( (!Redirect_stderr) && (!(Log_destination & LOG_DESTINATION_SQL)) )
  		return 0;
  
  	/*
***************
*** 403,431 ****
  	 * pipe open, so we can pass it down to the reincarnated syslogger. This
  	 * is a bit klugy but we have little choice.
  	 */
! #ifndef WIN32
! 	if (syslogPipe[0] < 0)
  	{
! 		if (pgpipe(syslogPipe) < 0)
! 			ereport(FATAL,
! 					(errcode_for_socket_access(),
! 					 (errmsg("could not create pipe for syslog: %m"))));
! 	}
  #else
! 	if (!syslogPipe[0])
! 	{
! 		SECURITY_ATTRIBUTES sa;
  
! 		memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
! 		sa.nLength = sizeof(SECURITY_ATTRIBUTES);
! 		sa.bInheritHandle = TRUE;
  
! 		if (!CreatePipe(&syslogPipe[0], &syslogPipe[1], &sa, 32768))
! 			ereport(FATAL,
! 					(errcode_for_file_access(),
! 					 (errmsg("could not create pipe for syslog: %m"))));
  	}
  #endif
  
  	/*
  	 * Create log directory if not present; ignore errors
--- 366,427 ----
  	 * pipe open, so we can pass it down to the reincarnated syslogger. This
  	 * is a bit klugy but we have little choice.
  	 */
! 
! 	/* Create the syslog pipe only if we need to redirect stderr */
! 	if (Redirect_stderr)
  	{
! #ifndef WIN32
! 		if (syslogPipe[0] < 0)
! 		{
! 			if (pgpipe(syslogPipe) < 0)
! 				ereport(FATAL,
! 						(errcode_for_socket_access(),
! 						 (errmsg("could not create pipe for syslog: %m"))));
! 		}
  #else
! 		if (!syslogPipe[0])
! 		{
! 			SECURITY_ATTRIBUTES sa;
  
! 			memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
! 			sa.nLength = sizeof(SECURITY_ATTRIBUTES);
! 			sa.bInheritHandle = TRUE;
  
! 			if (!CreatePipe(&syslogPipe[0], &syslogPipe[1], &sa, SYSLOG_BUFFER_SIZE))
! 				ereport(FATAL,
! 						(errcode_for_file_access(),
! 						 (errmsg("could not create pipe for syslog: %m"))));
! 		}
! #endif
  	}
+ 
+ 	/* Create the sql log pipe if we need SQL type log output */
+ 	if (Log_destination & LOG_DESTINATION_SQL)
+ 	{
+ #ifndef WIN32
+ 		if (sqllogPipe[0] < 0)
+ 		{
+ 			if (pgpipe(sqllogPipe) < 0)
+ 				ereport(FATAL,
+ 						(errcode_for_socket_access(),
+ 						(errmsg("could not create pipe for sqllog: %m"))));
+ 		}
+ #else
+ 		if (!sqllogPipe[0])
+ 		{
+ 			SECURITY_ATTRIBUTES sa;
+ 	
+ 			memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
+ 			sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ 			sa.bInheritHandle = TRUE;
+ 	
+ 			if (!CreatePipe(&sqllogPipe[0], &sqllogPipe[1], &sa, SYSLOG_BUFFER_SIZE))
+ 				ereport(FATAL,
+ 						(errcode_for_file_access(),
+ 						(errmsg("could not create pipe for sqllog: %m"))));
+ 		}
  #endif
+ 	}
  
  	/*
  	 * Create log directory if not present; ignore errors
***************
*** 438,452 ****
  	 */
  	filename = logfile_getname(time(NULL));
  
! 	syslogFile = fopen(filename, "a");
  
! 	if (!syslogFile)
! 		ereport(FATAL,
! 				(errcode_for_file_access(),
! 				 (errmsg("could not create log file \"%s\": %m",
! 						 filename))));
  
! 	setvbuf(syslogFile, NULL, LBF_MODE, 0);
  
  	pfree(filename);
  
--- 434,463 ----
  	 */
  	filename = logfile_getname(time(NULL));
  
! 	if (Redirect_stderr)
! 	{
! 		syslogFile = fopen(filename, "a");
! 		if (!syslogFile)
! 			ereport(FATAL,
! 					(errcode_for_file_access(),
! 					 (errmsg("could not create log file \"%s\": %m",
! 							 filename))));
  
! 		setvbuf(syslogFile, NULL, LBF_MODE, 0);
! 	}
  
! 	if (Log_destination & LOG_DESTINATION_SQL)
! 	{
! 		sqllogFile = fopen(strcat(filename, ".sql"), "a");
! 		if (!sqllogFile)
! 		{
! 			ereport(FATAL,
! 					(errcode_for_file_access(),
! 						(errmsg("could not create log file \"%s\": %m",
! 							strcat(filename, ".sql")))));
! 		}
! 		setvbuf(sqllogFile, NULL, LBF_MODE, 0);
! 	}
  
  	pfree(filename);
  
***************
*** 482,488 ****
  			/* success, in postmaster */
  
  			/* now we redirect stderr, if not done already */
! 			if (!redirection_done)
  			{
  #ifndef WIN32
  				fflush(stdout);
--- 493,499 ----
  			/* success, in postmaster */
  
  			/* now we redirect stderr, if not done already */
! 			if (Redirect_stderr && !redirection_done)
  			{
  #ifndef WIN32
  				fflush(stdout);
***************
*** 516,524 ****
  				redirection_done = true;
  			}
  
! 			/* postmaster will never write the file; close it */
! 			fclose(syslogFile);
  			syslogFile = NULL;
  			return (int) sysloggerPid;
  	}
  
--- 527,541 ----
  				redirection_done = true;
  			}
  
! 			/* postmaster will never write the files; close it */
! 			if (syslogFile)
! 				fclose(syslogFile);
  			syslogFile = NULL;
+ 
+ 			if (sqllogFile)
+ 				fclose(sqllogFile);
+ 			sqllogFile = NULL;
+ 
  			return (int) sysloggerPid;
  	}
  
***************
*** 537,547 ****
  static pid_t
  syslogger_forkexec(void)
  {
! 	char	   *av[10];
! 	int			ac = 0,
! 				bufc = 0,
! 				i;
! 	char		numbuf[2][32];
  
  	av[ac++] = "postgres";
  	av[ac++] = "--forklog";
--- 554,564 ----
  static pid_t
  syslogger_forkexec(void)
  {
! 	char	*av[11];
! 	int	ac = 0,
! 		bufc = 0,
! 		i;
! 	char	numbuf[3][32];
  
  	av[ac++] = "postgres";
  	av[ac++] = "--forklog";
***************
*** 554,559 ****
--- 571,581 ----
  	else
  		strcpy(numbuf[bufc++], "-1");
  	snprintf(numbuf[bufc++], 32, "%d", (int) redirection_done);
+ 
+ 	if (sqllogFile != NULL)
+ 		snprintf(numbuf[bufc++], 32, "%d", fileno(sqllogFile));
+ 	else
+ 		strcpy(numbuf[bufc++], "-1");
  #else							/* WIN32 */
  	if (syslogFile != NULL)
  		snprintf(numbuf[bufc++], 32, "%ld",
***************
*** 561,566 ****
--- 583,594 ----
  	else
  		strcpy(numbuf[bufc++], "0");
  	snprintf(numbuf[bufc++], 32, "%d", (int) redirection_done);
+ 
+ 	if (sqllogFile != NULL)
+ 		snprintf(numbuf[bufc++], 32, "%ld",
+ 				 _get_osfhandle(_fileno(sqllogFile)));
+ 	else
+ 		strcpy(numbuf[bufc++], "0");
  #endif   /* WIN32 */
  
  	/* Add to the arg list */
***************
*** 584,590 ****
  {
  	int			fd;
  
! 	Assert(argc == 5);
  	argv += 3;
  
  #ifndef WIN32
--- 612,618 ----
  {
  	int			fd;
  
! 	Assert(argc == 6);
  	argv += 3;
  
  #ifndef WIN32
***************
*** 595,600 ****
--- 623,635 ----
  		setvbuf(syslogFile, NULL, LBF_MODE, 0);
  	}
  	redirection_done = (bool) atoi(*argv++);
+ 
+ 	fd = atoi(*argv++);
+ 	if (fd != -1)
+ 	{
+ 		sqllogFile = fdopen(fd, "a");
+ 		setvbuf(sqllogFile, NULL, LBF_MODE, 0);
+ 	}
  #else							/* WIN32 */
  	fd = atoi(*argv++);
  	if (fd != 0)
***************
*** 607,612 ****
--- 642,658 ----
  		}
  	}
  	redirection_done = (bool) atoi(*argv++);
+ 
+ 	fd = atoi(*argv++);
+ 	if (fd != 0)
+ 	{
+ 		fd = _open_osfhandle(fd, _O_APPEND);
+ 		if (fd > 0)
+ 		{
+ 			sqllogFile = fdopen(fd, "a");
+ 			setvbuf(sqllogFile, NULL, LBF_MODE, 0);
+ 		}
+ 	}
  #endif   /* WIN32 */
  }
  #endif   /* EXEC_BACKEND */
***************
*** 625,631 ****
   * even though its stderr does not point at the syslog pipe.
   */
  void
! write_syslogger_file(const char *buffer, int count)
  {
  #ifdef WIN32
  
--- 671,677 ----
   * even though its stderr does not point at the syslog pipe.
   */
  void
! write_syslogger_file(const char *buffer, int count, int log_type)
  {
  #ifdef WIN32
  
***************
*** 649,663 ****
  		n++;
  		if (n >= sizeof(convbuf) - 1)
  		{
! 			write_syslogger_file_binary(convbuf, n);
  			p = convbuf;
  			n = 0;
  		}
  	}
  	if (n > 0)
! 		write_syslogger_file_binary(convbuf, n);
  #else							/* !WIN32 */
! 	write_syslogger_file_binary(buffer, count);
  #endif
  }
  
--- 695,709 ----
  		n++;
  		if (n >= sizeof(convbuf) - 1)
  		{
! 			write_syslogger_file_binary(convbuf, n, log_type);
  			p = convbuf;
  			n = 0;
  		}
  	}
  	if (n > 0)
! 		write_syslogger_file_binary(convbuf, n, log_type);
  #else							/* !WIN32 */
! 	write_syslogger_file_binary(buffer, count, log_type);
  #endif
  }
  
***************
*** 668,682 ****
   * so we must send it to the file without further translation.
   */
  static void
! write_syslogger_file_binary(const char *buffer, int count)
  {
! 	int			rc;
  
  #ifndef WIN32
! 	rc = fwrite(buffer, 1, count, syslogFile);
  #else
  	EnterCriticalSection(&sysfileSection);
! 	rc = fwrite(buffer, 1, count, syslogFile);
  	LeaveCriticalSection(&sysfileSection);
  #endif
  
--- 714,742 ----
   * so we must send it to the file without further translation.
   */
  static void
! write_syslogger_file_binary(const char *buffer, int count, int log_type)
  {
! 	int	rc;
! 	FILE	**fh = NULL;
! 
! 	/* Select the file to write to based on the log_type. */
! 	switch (log_type)
! 	{
! 		case STDERR_LOG:
! 				fh = (FILE **) &syslogFile;
! 				break;
! 		case SQL_LOG:
! 				fh = (FILE **) &sqllogFile;
! 				break;
! 		default:
! 			return;
! 	}
  
  #ifndef WIN32
! 	rc = fwrite(buffer, 1, count, *fh);
  #else
  	EnterCriticalSection(&sysfileSection);
! 	rc = fwrite(buffer, 1, count, *fh);
  	LeaveCriticalSection(&sysfileSection);
  #endif
  
***************
*** 700,722 ****
  	DWORD		bytesRead;
  	char		logbuffer[1024];
  
  	for (;;)
  	{
! 		if (!ReadFile(syslogPipe[0], logbuffer, sizeof(logbuffer),
! 					  &bytesRead, 0))
  		{
! 			DWORD		error = GetLastError();
  
! 			if (error == ERROR_HANDLE_EOF ||
! 				error == ERROR_BROKEN_PIPE)
! 				break;
! 			_dosmaperr(error);
! 			ereport(LOG,
! 					(errcode_for_file_access(),
! 					 errmsg("could not read from logger pipe: %m")));
  		}
- 		else if (bytesRead > 0)
- 			write_syslogger_file_binary(logbuffer, bytesRead);
  	}
  
  	/* We exit the above loop only upon detecting pipe EOF */
--- 760,807 ----
  	DWORD		bytesRead;
  	char		logbuffer[1024];
  
+ 	DWORD		sqllogbytesRead;
+ 	char		sqllogbuffer[1024];
+ 	
  	for (;;)
  	{
! 		if(Redirect_stderr)
  		{
! 			if (!ReadFile(syslogPipe[0], logbuffer, sizeof(logbuffer),
! 						  &bytesRead, 0))
! 			{
! 				DWORD		error = GetLastError();
  
! 				if (error == ERROR_HANDLE_EOF ||
! 					error == ERROR_BROKEN_PIPE)
! 					break;
! 				_dosmaperr(error);
! 				ereport(LOG,
! 						(errcode_for_file_access(),
! 						 errmsg("could not read from logger pipe: %m")));
! 			}
! 			else if (bytesRead > 0)
! 				write_syslogger_file_binary(logbuffer, bytesRead, STDERR_LOG);
! 		}
! 
! 		if(Log_destination & LOG_DESTINATION_SQL)
! 		{
! 			if (!ReadFile(sqllogPipe[0], sqllogbuffer, sizeof(sqllogbuffer),
! 						  &sqllogbytesRead, 0))
! 			{
! 				DWORD		error = GetLastError();
! 
! 				if (error == ERROR_HANDLE_EOF ||
! 					error == ERROR_BROKEN_PIPE)
! 					break;
! 				_dosmaperr(error);
! 				ereport(LOG,
! 						(errcode_for_file_access(),
! 						 errmsg("could not read from logger pipe: %m")));
! 			}
! 			else if (sqllogbytesRead > 0)
! 				write_syslogger_file_binary(sqllogbuffer, sqllogbytesRead, SQL_LOG);
  		}
  	}
  
  	/* We exit the above loop only upon detecting pipe EOF */
***************
*** 727,739 ****
  #endif   /* WIN32 */
  
  /*
!  * perform logfile rotation
   */
  static void
  logfile_rotate(bool time_based_rotation)
  {
  	char	   *filename;
- 	FILE	   *fh;
  
  	rotation_requested = false;
  
--- 812,923 ----
  #endif   /* WIN32 */
  
  /*
!  * Reads the requested pipe.
!  *
!  * This method is common for both syslog and sql log pipes.
!  * Based on the log_type this method will know which pipe to read and passes
!  * the data to the appropriate file type.
!  */
! static void
! read_log_pipe(int log_type)
! {
! 
! #ifndef WIN32
! 	char		logbuffer[1024];
! 	int		bytesRead = 0;
! 	int		rc;
! 	fd_set		rfds;
! 	bool		dataInPipe = false;
! 	struct timeval timeout;
! 
! 	/*
! 	 * Set timeout for a second
! 	 */
! 	timeout.tv_sec = 1;
! 	timeout.tv_usec = 0;
! 
! 	switch (log_type)
! 	{
! 		case STDERR_LOG:
! 				FD_ZERO(&rfds);
! 				FD_SET(syslogPipe[0], &rfds);
! 				rc = select(syslogPipe[0] + 1, &rfds, NULL, NULL, &timeout);
! 				if (rc < 0)
! 				{
! 					if (errno != EINTR)
! 						ereport(LOG,
! 							(errcode_for_socket_access(),
! 							 errmsg("select() failed in logger process: %m")));
! 				}
! 				else if (rc > 0 && FD_ISSET(syslogPipe[0], &rfds))
! 				{
! 					bytesRead = piperead(syslogPipe[0], logbuffer, sizeof(logbuffer));
! 					dataInPipe = true;
! 				}
! 				break;
! 		case SQL_LOG:
! 				FD_ZERO(&rfds);
! 				FD_SET(sqllogPipe[0], &rfds);
! 				rc = select(sqllogPipe[0] + 1, &rfds, NULL, NULL, &timeout);
! 				if (rc < 0)
! 				{
! 					if (errno != EINTR)
! 						ereport(LOG,
! 							(errcode_for_socket_access(),
! 							 errmsg("select() failed in logger process: %m")));
! 				}
! 				else if (rc > 0 && FD_ISSET(sqllogPipe[0], &rfds))
! 				{
! 					bytesRead = piperead(sqllogPipe[0], logbuffer, sizeof(logbuffer));
! 					dataInPipe = true;
! 				}
! 				break;
! 		default:
! 			return;
! 	}
! 
! 	if (dataInPipe)
! 	{
! 		if (bytesRead < 0)
! 		{
! 			if (errno != EINTR)
! 				ereport(LOG,
! 					(errcode_for_socket_access(),
! 					errmsg("could not read from logger pipe: %m")));
! 		}
! 		else if (bytesRead > 0)
! 		{
! 			write_syslogger_file_binary(logbuffer, bytesRead, log_type);
! 		}
! 		else
! 		{
! 			/*
! 			* Zero bytes read when select() is saying read-ready means
! 			* EOF on the pipe: that is, there are no longer any processes
! 			* with the pipe write end open.  Therefore, the postmaster
! 			* and all backends are shut down, and we are done.
! 			*/
! 			pipe_eof_seen = true;
! 		}
! 	}
! #else						/* WIN32 */
! 		/*
! 		* On Windows we leave it to a separate thread to transfer data and
! 		* detect pipe EOF.  The main thread just wakes up once a second to
! 		* check for SIGHUP and rotation conditions.
! 		*/
! 		pg_usleep(1000000L);
! #endif   /* WIN32 */
! }
! 
! /*
!  * Log file rotation controller. Decides the filename and which file needs
!  * to be rotated. The worker method below this does the actual rotation.
   */
  static void
  logfile_rotate(bool time_based_rotation)
  {
  	char	   *filename;
  
  	rotation_requested = false;
  
***************
*** 747,752 ****
--- 931,958 ----
  	else
  		filename = logfile_getname(time(NULL));
  
+ 	if (Redirect_stderr)
+ 		logfile_rotate_worker(time_based_rotation, filename, (FILE **) &syslogFile);
+ 
+ 	if (Log_destination & LOG_DESTINATION_SQL)
+ 		logfile_rotate_worker(time_based_rotation, strcat(filename, ".sql"), (FILE **) &sqllogFile);
+ 
+ 	set_next_rotation_time();
+ 
+ 	/* instead of pfree'ing filename, remember it for next time */
+ 	if (last_file_name != NULL)
+ 		pfree(last_file_name);
+ 	last_file_name = filename;
+ }
+ 
+ /*
+  * logfile rotation worker - Does the actual file rotation 
+  */
+ static void
+ logfile_rotate_worker(bool time_based_rotation, char* filename, FILE **dest_file)
+ {
+ 	FILE	   *fh;
+ 
  	/*
  	 * Decide whether to overwrite or append.  We can overwrite if (a)
  	 * Log_truncate_on_rotation is set, (b) the rotation was triggered by
***************
*** 797,814 ****
  #ifdef WIN32
  	EnterCriticalSection(&sysfileSection);
  #endif
! 	fclose(syslogFile);
! 	syslogFile = fh;
  #ifdef WIN32
  	LeaveCriticalSection(&sysfileSection);
  #endif
- 
- 	set_next_rotation_time();
- 
- 	/* instead of pfree'ing filename, remember it for next time */
- 	if (last_file_name != NULL)
- 		pfree(last_file_name);
- 	last_file_name = filename;
  }
  
  
--- 1003,1013 ----
  #ifdef WIN32
  	EnterCriticalSection(&sysfileSection);
  #endif
! 	fclose(*dest_file);
! 	*dest_file = fh;
  #ifdef WIN32
  	LeaveCriticalSection(&sysfileSection);
  #endif
  }
  
  
*** pgsql/src/backend/postmaster/postmaster.c	2007-03-30 11:22:36.000000000 +1000
--- workingpgsql/src/backend/postmaster/postmaster.c	2007-03-30 12:09:27.000000000 +1000
***************
*** 336,343 ****
  	HANDLE		PostmasterHandle;
  	HANDLE		initial_signal_pipe;
  	HANDLE		syslogPipe[2];
  #else
! 	int			syslogPipe[2];
  #endif
  	char		my_exec_path[MAXPGPATH];
  	char		pkglib_path[MAXPGPATH];
--- 336,345 ----
  	HANDLE		PostmasterHandle;
  	HANDLE		initial_signal_pipe;
  	HANDLE		syslogPipe[2];
+ 	HANDLE		sqllogPipe[2];
  #else
! 	int		syslogPipe[2];
! 	int		sqllogPipe[2];
  #endif
  	char		my_exec_path[MAXPGPATH];
  	char		pkglib_path[MAXPGPATH];
***************
*** 1225,1231 ****
  		}
  
  		/* If we have lost the system logger, try to start a new one */
! 		if (SysLoggerPID == 0 && Redirect_stderr)
  			SysLoggerPID = SysLogger_Start();
  
  		/*
--- 1227,1234 ----
  		}
  
  		/* If we have lost the system logger, try to start a new one */
! 		if ( (SysLoggerPID == 0 && Redirect_stderr) || 
! 		     (SysLoggerPID == 0 && (Log_destination & LOG_DESTINATION_SQL)) )
  			SysLoggerPID = SysLogger_Start();
  
  		/*
***************
*** 1775,1784 ****
--- 1778,1795 ----
  		if (syslogPipe[0] >= 0)
  			close(syslogPipe[0]);
  		syslogPipe[0] = -1;
+ 
+ 		if (sqllogPipe[0] >= 0)
+ 			close(sqllogPipe[0]);
+ 		sqllogPipe[0] = -1;
  #else
  		if (syslogPipe[0])
  			CloseHandle(syslogPipe[0]);
  		syslogPipe[0] = 0;
+ 
+ 		if (sqllogPipe[0])
+ 			CloseHandle(sqllogPipe[0]);
+ 		sqllogPipe[0] = 0;
  #endif
  	}
  }
***************
*** 3957,3962 ****
--- 3968,3974 ----
  #endif
  
  	memcpy(&param->syslogPipe, &syslogPipe, sizeof(syslogPipe));
+ 	memcpy(&param->sqllogPipe, &sqllogPipe, sizeof(sqllogPipe));
  
  	strlcpy(param->my_exec_path, my_exec_path, MAXPGPATH);
  
***************
*** 4158,4163 ****
--- 4170,4176 ----
  #endif
  
  	memcpy(&syslogPipe, &param->syslogPipe, sizeof(syslogPipe));
+ 	memcpy(&sqllogPipe, &param->sqllogPipe, sizeof(sqllogPipe));
  
  	strlcpy(my_exec_path, param->my_exec_path, MAXPGPATH);
  
*** pgsql/src/include/utils/elog.h	2007-03-03 10:37:23.000000000 +1100
--- workingpgsql/src/include/utils/elog.h	2007-03-30 12:10:18.000000000 +1000
***************
*** 281,286 ****
--- 281,287 ----
  #define LOG_DESTINATION_STDERR	 1
  #define LOG_DESTINATION_SYSLOG	 2
  #define LOG_DESTINATION_EVENTLOG 4
+ #define LOG_DESTINATION_SQL	8
  
  /* Other exported functions */
  extern void DebugFileOpen(void);
*** pgsql/src/include/postmaster/syslogger.h	2007-01-06 09:19:57.000000000 +1100
--- workingpgsql/src/include/postmaster/syslogger.h	2007-03-30 14:14:26.000000000 +1000
***************
*** 12,17 ****
--- 12,22 ----
  #ifndef _SYSLOGGER_H
  #define _SYSLOGGER_H
  
+ #define SYSLOG_BUFFER_SIZE	32768
+ 
+ #define STDERR_LOG	1
+ #define SQL_LOG		2
+ 
  /* GUC options */
  extern bool Redirect_stderr;
  extern int	Log_RotationAge;
***************
*** 24,40 ****
  
  #ifndef WIN32
  extern int	syslogPipe[2];
  #else
  extern HANDLE syslogPipe[2];
  #endif
  
  
  extern int	SysLogger_Start(void);
  
! extern void write_syslogger_file(const char *buffer, int count);
  
  #ifdef EXEC_BACKEND
  extern void SysLoggerMain(int argc, char *argv[]);
  #endif
  
  #endif   /* _SYSLOGGER_H */
--- 29,57 ----
  
  #ifndef WIN32
  extern int	syslogPipe[2];
+ extern int	sqllogPipe[2];
  #else
  extern HANDLE syslogPipe[2];
+ extern HANDLE sqllogPipe[2];
  #endif
  
  
  extern int	SysLogger_Start(void);
  
! extern void write_syslogger_file(const char *buffer, int count, int log_type);
  
  #ifdef EXEC_BACKEND
  extern void SysLoggerMain(int argc, char *argv[]);
  #endif
  
+ #ifdef WIN32
+ DWORD writtenbytes;
+ #define print_sqllog(b) \
+ WriteFile(sqllogPipe[1], b.data, b.len, &writtenbytes, NULL); 
+ #else
+ #define print_sqllog(b) \
+ write(sqllogPipe[1], b.data, b.len);
+ #endif
+ 
+ 
  #endif   /* _SYSLOGGER_H */
*** org/doc/src/sgml/config.sgml	Fri Mar 30 18:04:47 2007
--- pgsql/doc/src/sgml/config.sgml	Fri Mar 30 17:45:03 2007
***************
*** 2229,2235 ****
         <para>
          <productname>PostgreSQL</productname> supports several methods
           for logging server messages, including
!          <systemitem>stderr</systemitem> and
           <systemitem>syslog</systemitem>. On Windows, 
           <systemitem>eventlog</systemitem> is also supported. Set this
           parameter to a list of desired log destinations separated by
--- 2229,2235 ----
         <para>
          <productname>PostgreSQL</productname> supports several methods
           for logging server messages, including
!          <systemitem>stderr</systemitem>, <systemitem>sqllog</systemitem> and
           <systemitem>syslog</systemitem>. On Windows, 
           <systemitem>eventlog</systemitem> is also supported. Set this
           parameter to a list of desired log destinations separated by
***************
*** 2267,2274 ****
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</> is enabled, this parameter
!         determines the directory in which log files will be created.
          It can be specified as an absolute path, or relative to the
          cluster data directory.
          This parameter can only be set in the <filename>postgresql.conf</>
--- 2267,2274 ----
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</> is enabled or <varname>log_destination</> is set to <systemitem>sqllog</systemitem>, 
!         this parameter determines the directory in which log files will be created.
          It can be specified as an absolute path, or relative to the
          cluster data directory.
          This parameter can only be set in the <filename>postgresql.conf</>
***************
*** 2284,2291 ****
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</varname> is enabled, this parameter
!         sets the file names of the created log files.  The value
          is treated as a <systemitem>strftime</systemitem> pattern,
          so <literal>%</literal>-escapes
          can be used to specify time-varying file names.
--- 2284,2291 ----
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</varname> is enabled or <varname>log_destination</> is set to <systemitem>sqllog</systemitem>,
! 	this parameter sets the file names of the created log files.  The value
          is treated as a <systemitem>strftime</systemitem> pattern,
          so <literal>%</literal>-escapes
          can be used to specify time-varying file names.
***************
*** 2308,2315 ****
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</varname> is enabled, this parameter
!         determines the maximum lifetime of an individual log file.
          After this many minutes have elapsed, a new log file will
          be created.  Set to zero to disable time-based creation of
          new log files.
--- 2308,2315 ----
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</varname> is enabled or <varname>log_destination</> is set to <systemitem>sqllog</systemitem>,
! 	this parameter determines the maximum lifetime of an individual log file.
          After this many minutes have elapsed, a new log file will
          be created.  Set to zero to disable time-based creation of
          new log files.
***************
*** 2326,2333 ****
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</varname> is enabled, this parameter
!         determines the maximum size of an individual log file.
          After this many kilobytes have been emitted into a log file,
          a new log file will be created.  Set to zero to disable size-based
          creation of new log files.
--- 2326,2333 ----
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</varname> is enabled or <varname>log_destination</> is set to <systemitem>sqllog</systemitem>,
! 	this parameter determines the maximum size of an individual log file.
          After this many kilobytes have been emitted into a log file,
          a new log file will be created.  Set to zero to disable size-based
          creation of new log files.
***************
*** 2344,2351 ****
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</varname> is enabled, this parameter will cause
!         <productname>PostgreSQL</productname> to truncate (overwrite),
          rather than append to, any existing log file of the same name.
          However, truncation will occur only when a new file is being opened
          due to time-based rotation, not during server startup or size-based
--- 2344,2351 ----
        </indexterm>
        <listitem>
         <para>
!         When <varname>redirect_stderr</varname> is enabled or <varname>log_destination</> is set to <systemitem>sqllog</systemitem>,
! 	this parameter will cause <productname>PostgreSQL</productname> to truncate (overwrite),
          rather than append to, any existing log file of the same name.
          However, truncation will occur only when a new file is being opened
          due to time-based rotation, not during server startup or size-based
***************
*** 2386,2393 ****
        </indexterm>
        <listitem>
         <para>
!         When logging to <application>syslog</> is enabled, this parameter
!         determines the <application>syslog</application>
          <quote>facility</quote> to be used.  You can choose
          from <literal>LOCAL0</>, <literal>LOCAL1</>,
          <literal>LOCAL2</>, <literal>LOCAL3</>, <literal>LOCAL4</>,
--- 2386,2393 ----
        </indexterm>
        <listitem>
         <para>
!         When logging to <application>syslog</> is enabled or <varname>log_destination</> is set to <application>sqllog</application>,
! 	this parameter determines the <application>syslog</application>
          <quote>facility</quote> to be used.  You can choose
          from <literal>LOCAL0</>, <literal>LOCAL1</>,
          <literal>LOCAL2</>, <literal>LOCAL3</>, <literal>LOCAL4</>,
***************
*** 2408,2415 ****
        </indexterm>
         <listitem>
          <para>
!          When logging to <application>syslog</> is enabled, this parameter
!          determines the program name used to identify
           <productname>PostgreSQL</productname> messages in
           <application>syslog</application> logs. The default is
           <literal>postgres</literal>.
--- 2408,2415 ----
        </indexterm>
         <listitem>
          <para>
!          When logging to <application>syslog</> is enabled or <varname>log_destination</> is set to <application>sqllog</application>,
! 	 this parameter determines the program name used to identify
           <productname>PostgreSQL</productname> messages in
           <application>syslog</application> logs. The default is
           <literal>postgres</literal>.
