Index: doc/src/sgml/config.sgml
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/doc/src/sgml/config.sgml,v
retrieving revision 1.158
diff -c -p -r1.158 config.sgml
*** doc/src/sgml/config.sgml	28 Nov 2007 15:42:30 -0000	1.158
--- doc/src/sgml/config.sgml	10 Dec 2007 13:18:42 -0000
*************** local0.*    /var/log/postgresql
*** 3169,3175 ****
          with these columns: timestamp with milliseconds, user name, database
          name, session ID, host:port number, process ID, per-process line
          number, command tag, session start time, virtual transaction ID,
!         regular transaction id, error severity, SQL state code, error message.
          Here is a sample table definition for storing CSV-format log output:
  
  <programlisting>
--- 3169,3180 ----
          with these columns: timestamp with milliseconds, user name, database
          name, session ID, host:port number, process ID, per-process line
          number, command tag, session start time, virtual transaction ID,
!         regular transaction id, error severity, SQL state code, error message,
!         error message detail, hint, the internal query that led to the error
!         if any, the error position thereof, the user query that led to the
!         error if any, the error position thereof, and the location of the
!         error in the PostgreSQL source code (this field is only emitted
!         if <varname>log_error_verbosity</> is set to <literal>verbose</>).
          Here is a sample table definition for storing CSV-format log output:
  
  <programlisting>
*************** CREATE TABLE postgres_log
*** 3189,3194 ****
--- 3194,3207 ----
    error_severity text,
    sql_state_code text,
    message text,
+   detail text,
+   context text,
+   hint text,
+   internal_query text,
+   internal_pos integer,
+   query text,
+   cursor_pos integer,
+   location text,
    PRIMARY KEY (session_id, process_line_num)
  );
  </programlisting>
Index: src/backend/utils/error/elog.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/utils/error/elog.c,v
retrieving revision 1.198
diff -c -p -r1.198 elog.c
*** src/backend/utils/error/elog.c	15 Nov 2007 21:14:40 -0000	1.198
--- src/backend/utils/error/elog.c	10 Dec 2007 12:49:51 -0000
*************** static const char *error_severity(int el
*** 134,140 ****
  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_pipe_chunks(char *data, int len, int dest);
- static void get_csv_error_message(StringInfo buf, ErrorData *edata);
  static void write_csvlog(ErrorData *edata);
  
  /*
--- 134,139 ----
*************** log_line_prefix(StringInfo buf)
*** 1616,1629 ****
  /*
   * append a CSV'd version of a string to a StringInfo
   * We use the PostgreSQL defaults for CSV, i.e. quote = escape = '"'
   */
- 
  static inline void
  appendCSVLiteral(StringInfo buf, const char *data)
  {
  	const char *p = data;
  	char		c;
  
  	appendStringInfoCharMacro(buf, '"');
  	while ((c = *p++) != '\0')
  	{
--- 1615,1632 ----
  /*
   * append a CSV'd version of a string to a StringInfo
   * We use the PostgreSQL defaults for CSV, i.e. quote = escape = '"'
+  * If it's NULL, append nothing.
   */
  static inline void
  appendCSVLiteral(StringInfo buf, const char *data)
  {
  	const char *p = data;
  	char		c;
  
+ 	/* avoid confusing an empty string with NULL */
+ 	if (p == NULL)
+ 		return;
+ 
  	appendStringInfoCharMacro(buf, '"');
  	while ((c = *p++) != '\0')
  	{
*************** appendCSVLiteral(StringInfo buf, const c
*** 1642,1649 ****
  static void
  write_csvlog(ErrorData *edata)
  {
- 	StringInfoData msgbuf;
  	StringInfoData buf;
  
  	/* static counter for line numbers */
  	static long log_line_number = 0;
--- 1645,1652 ----
  static void
  write_csvlog(ErrorData *edata)
  {
  	StringInfoData buf;
+ 	bool	print_stmt = false;
  
  	/* static counter for line numbers */
  	static long log_line_number = 0;
*************** write_csvlog(ErrorData *edata)
*** 1664,1670 ****
  	}
  	log_line_number++;
  
- 	initStringInfo(&msgbuf);
  	initStringInfo(&buf);
  
  	/*
--- 1667,1672 ----
*************** write_csvlog(ErrorData *edata)
*** 1715,1740 ****
  
  	/* username */
  	if (MyProcPort)
! 	{
! 		const char *username = MyProcPort->user_name;
! 
! 		if (username == NULL || *username == '\0')
! 			username = _("[unknown]");
! 
! 		appendCSVLiteral(&buf, username);
! 	}
  	appendStringInfoChar(&buf, ',');
  
  	/* databasename */
  	if (MyProcPort)
! 	{
! 		const char *dbname = MyProcPort->database_name;
! 
! 		if (dbname == NULL || *dbname == '\0')
! 			dbname = _("[unknown]");
! 
! 		appendCSVLiteral(&buf, dbname);
! 	}
  	appendStringInfoChar(&buf, ',');
  
  	/* session id */
--- 1717,1728 ----
  
  	/* username */
  	if (MyProcPort)
! 		appendCSVLiteral(&buf, MyProcPort->user_name);
  	appendStringInfoChar(&buf, ',');
  
  	/* databasename */
  	if (MyProcPort)
! 		appendCSVLiteral(&buf, MyProcPort->database_name);
  	appendStringInfoChar(&buf, ',');
  
  	/* session id */
*************** write_csvlog(ErrorData *edata)
*** 1762,1774 ****
  	/* PS display */
  	if (MyProcPort)
  	{
  		const char *psdisp;
  		int			displen;
  
  		psdisp = get_ps_display(&displen);
! 		appendStringInfo(&msgbuf, "%.*s", displen, psdisp);
  		appendCSVLiteral(&buf, msgbuf.data);
! 		resetStringInfo(&msgbuf);
  	}
  	appendStringInfoChar(&buf, ',');
  
--- 1750,1766 ----
  	/* PS display */
  	if (MyProcPort)
  	{
+ 		StringInfoData msgbuf;
  		const char *psdisp;
  		int			displen;
  
+ 		initStringInfo(&msgbuf);
+ 
  		psdisp = get_ps_display(&displen);
! 		appendStringInfo(&msgbuf, "%*s", displen, psdisp);
  		appendCSVLiteral(&buf, msgbuf.data);
! 	
! 		pfree(msgbuf.data);
  	}
  	appendStringInfoChar(&buf, ',');
  
*************** write_csvlog(ErrorData *edata)
*** 1796,1808 ****
  	appendStringInfoChar(&buf, ',');
  
  	/* Error severity */
! 	appendStringInfo(&buf, "%s,", error_severity(edata->elevel));
  
  	/* SQL state code */
! 	appendStringInfo(&buf, "%s,", unpack_sql_state(edata->sqlerrcode));
  
! 	/* Error message and cursor position if any */
! 	get_csv_error_message(&buf, edata);
  
  	appendStringInfoChar(&buf, '\n');
  
--- 1788,1863 ----
  	appendStringInfoChar(&buf, ',');
  
  	/* Error severity */
! 	appendStringInfo(&buf, "%s", error_severity(edata->elevel));
! 	appendStringInfoChar(&buf, ',');
  
  	/* SQL state code */
! 	appendStringInfo(&buf, "%s", unpack_sql_state(edata->sqlerrcode));
! 	appendStringInfoChar(&buf, ',');
! 
! 	/* errmessage */
! 	appendCSVLiteral(&buf, edata->message);
! 	appendStringInfoCharMacro(&buf, ',');
! 
! 	/* errdetail */
! 	appendCSVLiteral(&buf, edata->detail);
! 	appendStringInfoCharMacro(&buf, ',');
! 
! 	/* errcontext -- XXX maybe multiline -- need to do something about that? */
! 	appendCSVLiteral(&buf, edata->context);
! 	appendStringInfoCharMacro(&buf, ',');
! 
! 	/* errhint */
! 	appendCSVLiteral(&buf, edata->hint);
! 	appendStringInfoCharMacro(&buf, ',');
! 
! 	/* internal query */
! 	appendCSVLiteral(&buf, edata->internalquery);
! 	appendStringInfoCharMacro(&buf, ',');
! 
! 	/* if printed internal query, print internal pos too */
! 	if (edata->internalpos > 0 && edata->internalquery != NULL)
! 		appendStringInfo(&buf, "%d", edata->internalpos);
! 	appendStringInfoCharMacro(&buf, ',');
! 
! 	/* the user query is only reported if not disabled by the caller */
! 	if (is_log_level_output(edata->elevel, log_min_error_statement) &&
! 		debug_query_string != NULL &&
! 		!edata->hide_stmt)
! 		print_stmt = true;
! 	if (print_stmt)
! 		appendCSVLiteral(&buf, debug_query_string);
! 	appendStringInfoCharMacro(&buf, ',');
! 	if (print_stmt && edata->cursorpos > 0)
! 		appendStringInfo(&buf, "%d", edata->cursorpos);
! 	appendStringInfoCharMacro(&buf, ',');
  
! 	/* file error location */
! 	if (Log_error_verbosity >= PGERROR_VERBOSE)
! 	{
! 		/* assume no newlines in funcname or filename... */
! 		if (edata->funcname && edata->filename)
! 		{
! 			StringInfoData	msgbuf;
! 
! 			initStringInfo(&msgbuf);
! 			appendStringInfo(&msgbuf, "%s, %s:%d",
! 							 edata->funcname, edata->filename,
! 							 edata->lineno);
! 			appendCSVLiteral(&buf, msgbuf.data);
! 			pfree(msgbuf.data);
! 		}
! 		else if (edata->filename)
! 		{
! 			StringInfoData	msgbuf;
! 
! 			initStringInfo(&msgbuf);
! 			appendStringInfo(&msgbuf, "%s:%d",
! 							 edata->filename, edata->lineno);
! 			appendCSVLiteral(&buf, msgbuf.data);
! 			pfree(msgbuf.data);
! 		}
! 	}
  
  	appendStringInfoChar(&buf, '\n');
  
*************** write_csvlog(ErrorData *edata)
*** 1812,1851 ****
  	else
  		write_pipe_chunks(buf.data, buf.len, LOG_DESTINATION_CSVLOG);
  
- 	pfree(msgbuf.data);
  	pfree(buf.data);
  }
  
  /*
-  * Appends the buffer with the error message and the cursor position, all
-  * CSV escaped.
-  */
- static void
- get_csv_error_message(StringInfo buf, ErrorData *edata)
- {
- 	char	   *msg = edata->message ? edata->message : _("missing error text");
- 	char		c;
- 
- 	appendStringInfoCharMacro(buf, '"');
- 
- 	while ((c = *msg++) != '\0')
- 	{
- 		if (c == '"')
- 			appendStringInfoCharMacro(buf, '"');
- 		appendStringInfoCharMacro(buf, c);
- 	}
- 
- 	if (edata->cursorpos > 0)
- 		appendStringInfo(buf, _(" at character %d"),
- 						 edata->cursorpos);
- 	else if (edata->internalpos > 0)
- 		appendStringInfo(buf, _(" at character %d"),
- 						 edata->internalpos);
- 
- 	appendStringInfoCharMacro(buf, '"');
- }
- 
- /*
   * Unpack MAKE_SQLSTATE code. Note that this returns a pointer to a
   * static buffer.
   */
--- 1867,1876 ----
