4242 *
4343 *
4444 * IDENTIFICATION
45- * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.198 2007/11/15 21:14:40 momjian Exp $
45+ * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.199 2007/12/11 15:19:05 alvherre Exp $
4646 *
4747 *-------------------------------------------------------------------------
4848 */
@@ -134,7 +134,6 @@ static const char *error_severity(int elevel);
134134static void append_with_tabs (StringInfo buf ,const char * str );
135135static bool is_log_level_output (int elevel ,int log_min_level );
136136static void write_pipe_chunks (char * data ,int len ,int dest );
137- static void get_csv_error_message (StringInfo buf ,ErrorData * edata );
138137static void write_csvlog (ErrorData * edata );
139138
140139/*
@@ -1612,18 +1611,21 @@ log_line_prefix(StringInfo buf)
16121611}
16131612}
16141613
1615-
16161614/*
16171615 * append a CSV'd version of a string to a StringInfo
16181616 * We use the PostgreSQL defaults for CSV, i.e. quote = escape = '"'
1617+ * If it's NULL, append nothing.
16191618 */
1620-
16211619static inline void
16221620appendCSVLiteral (StringInfo buf ,const char * data )
16231621{
16241622const char * p = data ;
16251623char c ;
16261624
1625+ /* avoid confusing an empty string with NULL */
1626+ if (p == NULL )
1627+ return ;
1628+
16271629appendStringInfoCharMacro (buf ,'"' );
16281630while ((c = * p ++ )!= '\0' )
16291631{
@@ -1635,15 +1637,14 @@ appendCSVLiteral(StringInfo buf, const char *data)
16351637}
16361638
16371639/*
1638- * Constructs the error message, depending on the Errordata it gets,
1639- * in CSV (comma separated values) format. The COPY command
1640- * can then be used to load the messages into a table.
1640+ * Constructs the error message, depending on the Errordata it gets, in a CSV
1641+ * format which is described in doc/src/sgml/config.sgml.
16411642 */
16421643static void
16431644write_csvlog (ErrorData * edata )
16441645{
1645- StringInfoData msgbuf ;
16461646StringInfoData buf ;
1647+ bool print_stmt = false;
16471648
16481649/* static counter for line numbers */
16491650static long log_line_number = 0 ;
@@ -1664,24 +1665,15 @@ write_csvlog(ErrorData *edata)
16641665}
16651666log_line_number ++ ;
16661667
1667- initStringInfo (& msgbuf );
16681668initStringInfo (& buf );
16691669
1670- /*
1671- * The format of the log output in CSV format: timestamp with
1672- * milliseconds, username, databasename, session id, host and port number,
1673- * process id, process line number, command tag, session start time,
1674- * virtual transaction id, regular transaction id, error severity, sql
1675- * state code, error message.
1676- */
1677-
1678- /* timestamp_with_milliseconds */
16791670
16801671/*
1681- * Check if the timestamp is already calculated for the syslog message, if
1682- * it is, then no need to calculate it again, will use the same, else get
1683- * the current timestamp. This is done to put same timestamp in both
1684- * syslog and csvlog messages.
1672+ * timestamp with milliseconds
1673+ *
1674+ * Check if the timestamp is already calculated for the syslog message,
1675+ * and use it if so. Otherwise, get the current timestamp. This is done
1676+ * to put same timestamp in both syslog and csvlog messages.
16851677 */
16861678if (formatted_log_time [0 ]== '\0' )
16871679{
@@ -1715,38 +1707,26 @@ write_csvlog(ErrorData *edata)
17151707
17161708/* username */
17171709if (MyProcPort )
1718- {
1719- const char * username = MyProcPort -> user_name ;
1720-
1721- if (username == NULL || * username == '\0' )
1722- username = _ ("[unknown]" );
1723-
1724- appendCSVLiteral (& buf ,username );
1725- }
1710+ appendCSVLiteral (& buf ,MyProcPort -> user_name );
17261711appendStringInfoChar (& buf ,',' );
17271712
1728- /*databasename */
1713+ /*database name */
17291714if (MyProcPort )
1730- {
1731- const char * dbname = MyProcPort -> database_name ;
1732-
1733- if (dbname == NULL || * dbname == '\0' )
1734- dbname = _ ("[unknown]" );
1735-
1736- appendCSVLiteral (& buf ,dbname );
1737- }
1715+ appendCSVLiteral (& buf ,MyProcPort -> database_name );
17381716appendStringInfoChar (& buf ,',' );
17391717
17401718/* session id */
17411719appendStringInfo (& buf ,"%lx.%x" , (long )MyStartTime ,MyProcPid );
17421720appendStringInfoChar (& buf ,',' );
17431721
1744- /* Remote host and port(is it safe to not quote this?) */
1722+ /* Remote host and port */
17451723if (MyProcPort && MyProcPort -> remote_host )
17461724{
1725+ appendStringInfoChar (& buf ,'"' );
17471726appendStringInfo (& buf ,"%s" ,MyProcPort -> remote_host );
17481727if (MyProcPort -> remote_port && MyProcPort -> remote_port [0 ]!= '\0' )
17491728appendStringInfo (& buf ,":%s" ,MyProcPort -> remote_port );
1729+ appendStringInfoChar (& buf ,'"' );
17501730}
17511731appendStringInfoChar (& buf ,',' );
17521732
@@ -1762,13 +1742,17 @@ write_csvlog(ErrorData *edata)
17621742/* PS display */
17631743if (MyProcPort )
17641744{
1745+ StringInfoData msgbuf ;
17651746const char * psdisp ;
17661747int displen ;
17671748
1749+ initStringInfo (& msgbuf );
1750+
17681751psdisp = get_ps_display (& displen );
17691752appendStringInfo (& msgbuf ,"%.*s" ,displen ,psdisp );
17701753appendCSVLiteral (& buf ,msgbuf .data );
1771- resetStringInfo (& msgbuf );
1754+
1755+ pfree (msgbuf .data );
17721756}
17731757appendStringInfoChar (& buf ,',' );
17741758
@@ -1787,7 +1771,7 @@ write_csvlog(ErrorData *edata)
17871771
17881772/* Virtual transaction id */
17891773/* keep VXID format in sync with lockfuncs.c */
1790- if (MyProc != NULL )
1774+ if (MyProc != NULL && MyProc -> backendId != InvalidBackendId )
17911775appendStringInfo (& buf ,"%d/%u" ,MyProc -> backendId ,MyProc -> lxid );
17921776appendStringInfoChar (& buf ,',' );
17931777
@@ -1796,53 +1780,77 @@ write_csvlog(ErrorData *edata)
17961780appendStringInfoChar (& buf ,',' );
17971781
17981782/* Error severity */
1799- appendStringInfo (& buf ,"%s," ,error_severity (edata -> elevel ));
1783+ appendStringInfo (& buf ,"%s" ,error_severity (edata -> elevel ));
1784+ appendStringInfoChar (& buf ,',' );
18001785
18011786/* SQL state code */
1802- appendStringInfo (& buf ,"%s," ,unpack_sql_state (edata -> sqlerrcode ));
1787+ appendStringInfo (& buf ,"%s" ,unpack_sql_state (edata -> sqlerrcode ));
1788+ appendStringInfoChar (& buf ,',' );
18031789
1804- /* Error message and cursor position if any */
1805- get_csv_error_message (& buf ,edata );
1790+ /* errmessage */
1791+ appendCSVLiteral (& buf ,edata -> message );
1792+ appendStringInfoCharMacro (& buf ,',' );
18061793
1807- appendStringInfoChar (& buf ,'\n' );
1794+ /* errdetail */
1795+ appendCSVLiteral (& buf ,edata -> detail );
1796+ appendStringInfoCharMacro (& buf ,',' );
18081797
1809- /* If in the syslogger process, try to write messages direct to file */
1810- if (am_syslogger )
1811- write_syslogger_file (buf .data ,buf .len ,LOG_DESTINATION_CSVLOG );
1812- else
1813- write_pipe_chunks (buf .data ,buf .len ,LOG_DESTINATION_CSVLOG );
1798+ /* errhint */
1799+ appendCSVLiteral (& buf ,edata -> hint );
1800+ appendStringInfoCharMacro (& buf ,',' );
18141801
1815- pfree ( msgbuf . data );
1816- pfree ( buf . data );
1817- }
1802+ /* internal query */
1803+ appendCSVLiteral ( & buf , edata -> internalquery );
1804+ appendStringInfoCharMacro ( & buf , ',' );
18181805
1819- /*
1820- * Appends the buffer with the error message and the cursor position, all
1821- * CSV escaped.
1822- */
1823- static void
1824- get_csv_error_message (StringInfo buf ,ErrorData * edata )
1825- {
1826- char * msg = edata -> message ?edata -> message :_ ("missing error text" );
1827- char c ;
1806+ /* if printed internal query, print internal pos too */
1807+ if (edata -> internalpos > 0 && edata -> internalquery != NULL )
1808+ appendStringInfo (& buf ,"%d" ,edata -> internalpos );
1809+ appendStringInfoCharMacro (& buf ,',' );
18281810
1829- appendStringInfoCharMacro (buf ,'"' );
1811+ /* errcontext */
1812+ appendCSVLiteral (& buf ,edata -> context );
1813+ appendStringInfoCharMacro (& buf ,',' );
18301814
1831- while ((c = * msg ++ )!= '\0' )
1815+ /* user query --- only reported if not disabled by the caller */
1816+ if (is_log_level_output (edata -> elevel ,log_min_error_statement )&&
1817+ debug_query_string != NULL &&
1818+ !edata -> hide_stmt )
1819+ print_stmt = true;
1820+ if (print_stmt )
1821+ appendCSVLiteral (& buf ,debug_query_string );
1822+ appendStringInfoCharMacro (& buf ,',' );
1823+ if (print_stmt && edata -> cursorpos > 0 )
1824+ appendStringInfo (& buf ,"%d" ,edata -> cursorpos );
1825+ appendStringInfoCharMacro (& buf ,',' );
1826+
1827+ /* file error location */
1828+ if (Log_error_verbosity >=PGERROR_VERBOSE )
18321829{
1833- if (c == '"' )
1834- appendStringInfoCharMacro (buf ,'"' );
1835- appendStringInfoCharMacro (buf ,c );
1830+ StringInfoData msgbuf ;
1831+
1832+ initStringInfo (& msgbuf );
1833+
1834+ if (edata -> funcname && edata -> filename )
1835+ appendStringInfo (& msgbuf ,"%s, %s:%d" ,
1836+ edata -> funcname ,edata -> filename ,
1837+ edata -> lineno );
1838+ else if (edata -> filename )
1839+ appendStringInfo (& msgbuf ,"%s:%d" ,
1840+ edata -> filename ,edata -> lineno );
1841+ appendCSVLiteral (& buf ,msgbuf .data );
1842+ pfree (msgbuf .data );
18361843}
18371844
1838- if (edata -> cursorpos > 0 )
1839- appendStringInfo (buf ,_ (" at character %d" ),
1840- edata -> cursorpos );
1841- else if (edata -> internalpos > 0 )
1842- appendStringInfo (buf ,_ (" at character %d" ),
1843- edata -> internalpos );
1845+ appendStringInfoChar (& buf ,'\n' );
18441846
1845- appendStringInfoCharMacro (buf ,'"' );
1847+ /* If in the syslogger process, try to write messages direct to file */
1848+ if (am_syslogger )
1849+ write_syslogger_file (buf .data ,buf .len ,LOG_DESTINATION_CSVLOG );
1850+ else
1851+ write_pipe_chunks (buf .data ,buf .len ,LOG_DESTINATION_CSVLOG );
1852+
1853+ pfree (buf .data );
18461854}
18471855
18481856/*