diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index a19f1a303bb0280e158c1699a70a5d719d8f99d7..6f0c977c70469cf60cf129bed0c84b810a511c44 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.138 2001/06/01 02:41:35 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.139 2001/06/08 21:16:48 petere Exp $ * *------------------------------------------------------------------------- */ @@ -59,7 +59,7 @@ static const char BinarySignature[12] = "PGBCOPY\n\377\r\n\0"; * Static communication variables ... pretty grotty, but COPY has * never been reentrant... */ -int lineno = 0; /* exported for use by elog() -- dz */ +int copy_lineno = 0; /* exported for use by elog() -- dz */ static bool fe_eof; /* @@ -705,14 +705,14 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, values = (Datum *) palloc(attr_count * sizeof(Datum)); nulls = (char *) palloc(attr_count * sizeof(char)); - lineno = 0; + copy_lineno = 0; fe_eof = false; while (!done) { CHECK_FOR_INTERRUPTS(); - lineno++; + copy_lineno++; /* Reset the per-output-tuple exprcontext */ ResetPerTupleExprContext(estate); @@ -920,7 +920,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, /* * Done, clean up */ - lineno = 0; + copy_lineno = 0; pfree(values); pfree(nulls); diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index 79829ca87213f7e45eb770295ca60e476f34777b..e2ffb7bc825abbce04b96993559755541fd6a6ea 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.85 2001/06/02 18:25:17 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.86 2001/06/08 21:16:48 petere Exp $ * *------------------------------------------------------------------------- */ @@ -16,9 +16,6 @@ #include <time.h> #include <fcntl.h> -#ifndef O_RDONLY -#include <sys/file.h> -#endif /* O_RDONLY */ #include <sys/types.h> #include <errno.h> #include <unistd.h> @@ -41,10 +38,6 @@ #include "mb/pg_wchar.h" #endif -extern int errno; - -extern CommandDest whereToSendOutput; - #ifdef ENABLE_SYSLOG /* * 0 = only stdout/stderr @@ -70,9 +63,14 @@ bool Log_pid; static const char *print_timestamp(void); static const char *print_pid(void); +static void send_notice_to_frontend(const char *msg); +static void send_error_to_frontend(const char *msg); +static const char *useful_strerror(int errnum); +static const char *elog_message_prefix(int lev); + static int Debugfile = -1; -static int ElogDebugIndentLevel = 0; + /*-------------------- * elog @@ -119,87 +117,44 @@ elog(int lev, const char *fmt,...) char *fmt_buf = fmt_fixedbuf; char *msg_buf = msg_fixedbuf; - /* this buffer is only used for strange values of lev: */ - char prefix_buf[32]; + /* for COPY line numbers */ + char copylineno_buf[32]; - /* this buffer is only used if errno has a bogus value: */ - char errorstr_buf[32]; const char *errorstr; const char *prefix; const char *cp; char *bp; - int indent = 0; - int space_needed; - int len; + size_t space_needed; /* size of the prefix needed for timestamp and pid, if enabled */ size_t timestamp_size; - if (lev <= DEBUG && Debugfile < 0) - return; /* ignore debug msgs if noplace to send */ + /* ignore debug msgs if noplace to send */ + if (lev == DEBUG && Debugfile < 0) + return; /* Save error str before calling any function that might change errno */ - errorstr = strerror(errno); + errorstr = useful_strerror(errno); /* - * Some strerror()s return an empty string for out-of-range errno. - * This is ANSI C spec compliant, but not exactly useful. + * Convert initialization errors into fatal errors. This is + * probably redundant, because Warn_restart_ready won't be set + * anyway. */ - if (errorstr == NULL || *errorstr == '\0') - { - sprintf(errorstr_buf, "error %d", errno); - errorstr = errorstr_buf; - } + if (lev == ERROR && IsInitProcessingMode()) + lev = FATAL; + /* + * If we are inside a critical section, all errors become + * REALLYFATAL errors. See miscadmin.h. + */ if (lev == ERROR || lev == FATAL) { - - /* - * Convert initialization errors into fatal errors. This is - * probably redundant, because Warn_restart_ready won't be set - * anyway... - */ - if (IsInitProcessingMode()) - lev = FATAL; - - /* - * If we are inside a critical section, all errors become STOP - * errors. See miscadmin.h. - */ if (CritSectionCount > 0) - lev = STOP; + lev = REALLYFATAL; } - /* choose message prefix and indent level */ - switch (lev) - { - case NOIND: - indent = ElogDebugIndentLevel - 1; - if (indent < 0) - indent = 0; - if (indent > 30) - indent = indent % 30; - prefix = "DEBUG: "; - break; - case DEBUG: - indent = ElogDebugIndentLevel; - if (indent < 0) - indent = 0; - if (indent > 30) - indent = indent % 30; - prefix = "DEBUG: "; - break; - case NOTICE: - prefix = "NOTICE: "; - break; - case ERROR: - prefix = "ERROR: "; - break; - default: - sprintf(prefix_buf, "FATAL %d: ", lev); - prefix = prefix_buf; - break; - } + prefix = elog_message_prefix(lev); timestamp_size = 0; if (Log_timestamp) @@ -214,22 +169,36 @@ elog(int lev, const char *fmt,...) * vsnprintf won't know what to do with %m). To keep space * calculation simple, we only allow one %m. */ - space_needed = timestamp_size + strlen(prefix) + indent + (lineno ? 24 : 0) + space_needed = timestamp_size + strlen(prefix) + strlen(fmt) + strlen(errorstr) + 1; - if (space_needed > (int) sizeof(fmt_fixedbuf)) + + if (copy_lineno) + { + /* translator: This string will be truncated at 31 characters. */ + snprintf(copylineno_buf, 32, gettext("copy: line %d, "), copy_lineno); + space_needed += strlen(copylineno_buf); + } + + if (space_needed > sizeof(fmt_fixedbuf)) { - fmt_buf = (char *) malloc(space_needed); + fmt_buf = malloc(space_needed); if (fmt_buf == NULL) { /* We're up against it, convert to out-of-memory error */ fmt_buf = fmt_fixedbuf; - if (lev < FATAL) + if (lev != FATAL && lev != REALLYFATAL) { lev = ERROR; - prefix = "ERROR: "; + prefix = elog_message_prefix(lev); } - fmt = "elog: out of memory"; /* this must fit in - * fmt_fixedbuf! */ + /* + * gettext doesn't allocate memory, except in the very + * first call (which this isn't), so it's safe to + * translate here. Worst case we get the untranslated + * string back. + */ + /* translator: This must fit in fmt_fixedbuf. */ + fmt = gettext("elog: out of memory"); } } @@ -242,26 +211,22 @@ elog(int lev, const char *fmt,...) strcat(fmt_buf, prefix); - bp = fmt_buf + strlen(fmt_buf); - while (indent-- > 0) - *bp++ = ' '; - /* If error was in CopyFrom() print the offending line number -- dz */ - if (lineno) + if (copy_lineno) { - sprintf(bp, "copy: line %d, ", lineno); - bp += strlen(bp); - if (lev == ERROR || lev >= FATAL) - lineno = 0; + strcat(fmt_buf, copylineno_buf); + if (lev == ERROR || lev == FATAL || lev == REALLYFATAL) + copy_lineno = 0; } + bp = fmt_buf + strlen(fmt_buf); + for (cp = fmt; *cp; cp++) { if (cp[0] == '%' && cp[1] != '\0') { if (cp[1] == 'm') { - /* * XXX If there are any %'s in errorstr then vsnprintf * will do the Wrong Thing; do we need to cope? Seems @@ -313,15 +278,15 @@ elog(int lev, const char *fmt,...) if (msg_buf != msg_fixedbuf) free(msg_buf); space_needed *= 2; - msg_buf = (char *) malloc(space_needed); + msg_buf = malloc(space_needed); if (msg_buf == NULL) { /* We're up against it, convert to out-of-memory error */ msg_buf = msg_fixedbuf; - if (lev < FATAL) + if (lev != FATAL && lev != REALLYFATAL) { lev = ERROR; - prefix = "ERROR: "; + prefix = elog_message_prefix(lev); } msg_buf[0] = '\0'; if (Log_timestamp) @@ -329,7 +294,7 @@ elog(int lev, const char *fmt,...) if (Log_pid) strcat(msg_buf, print_pid()); strcat(msg_buf, prefix); - strcat(msg_buf, "elog: out of memory"); + strcat(msg_buf, gettext("elog: out of memory")); break; } } @@ -346,9 +311,6 @@ elog(int lev, const char *fmt,...) switch (lev) { - case NOIND: - syslog_level = LOG_DEBUG; - break; case DEBUG: syslog_level = LOG_DEBUG; break; @@ -364,27 +326,25 @@ elog(int lev, const char *fmt,...) case REALLYFATAL: default: syslog_level = LOG_CRIT; + break; } write_syslog(syslog_level, msg_buf + timestamp_size); } -#endif /* ENABLE_SYSLOG */ +#endif /* ENABLE_SYSLOG */ /* syslog doesn't want a trailing newline, but other destinations do */ strcat(msg_buf, "\n"); - len = strlen(msg_buf); - /* Write to debug file, if open and enabled */ /* NOTE: debug file is typically pointed at stderr */ if (Debugfile >= 0 && Use_syslog <= 1) - write(Debugfile, msg_buf, len); + write(Debugfile, msg_buf, strlen(msg_buf)); if (lev > DEBUG && whereToSendOutput == Remote) { /* Send IPC message to the front-end program */ MemoryContext oldcxt; - char msgtype; /* * Since backend libpq may call palloc(), switch to a context @@ -395,38 +355,24 @@ elog(int lev, const char *fmt,...) oldcxt = MemoryContextSwitchTo(ErrorContext); if (lev == NOTICE) - msgtype = 'N'; + /* exclude the timestamp from msg sent to frontend */ + send_notice_to_frontend(msg_buf + timestamp_size); else { - /* * Abort any COPY OUT in progress when an error is detected. * This hack is necessary because of poor design of copy * protocol. */ pq_endcopyout(true); - msgtype = 'E'; + send_error_to_frontend(msg_buf + timestamp_size); } - /* exclude the timestamp from msg sent to frontend */ - pq_puttextmessage(msgtype, msg_buf + timestamp_size); - - /* - * This flush is normally not necessary, since postgres.c will - * flush out waiting data when control returns to the main loop. - * But it seems best to leave it here, so that the client has some - * clue what happened if the backend dies before getting back to - * the main loop ... error/notice messages should not be a - * performance-critical path anyway, so an extra flush won't hurt - * much ... - */ - pq_flush(); MemoryContextSwitchTo(oldcxt); } if (lev > DEBUG && whereToSendOutput != Remote) { - /* * We are running as an interactive backend, so just send the * message to stderr. But don't send a duplicate if Debugfile @@ -466,7 +412,6 @@ elog(int lev, const char *fmt,...) */ if (lev == FATAL || !Warn_restart_ready || proc_exit_inprogress) { - /* * fflush here is just to improve the odds that we get to see * the error message, in case things are so hosed that @@ -476,7 +421,7 @@ elog(int lev, const char *fmt,...) */ fflush(stdout); fflush(stderr); - proc_exit((int) (proc_exit_inprogress || !IsUnderPostmaster)); + proc_exit(proc_exit_inprogress || !IsUnderPostmaster); } /* @@ -492,9 +437,8 @@ elog(int lev, const char *fmt,...) siglongjmp(Warn_restart, 1); } - if (lev > FATAL) + if (lev == FATAL || lev == REALLYFATAL) { - /* * Serious crash time. Postmaster will observe nonzero process * exit status and kill the other backends too. @@ -511,6 +455,7 @@ elog(int lev, const char *fmt,...) /* We reach here if lev <= NOTICE. OK to return to caller. */ } + int DebugFileOpen(void) { @@ -518,11 +463,9 @@ DebugFileOpen(void) istty; Debugfile = -1; - ElogDebugIndentLevel = 0; if (OutputFileName[0]) { - /* * A debug-output file name was given. * @@ -737,4 +680,104 @@ write_syslog(int level, const char *line) } } -#endif /* ENABLE_SYSLOG */ +#endif /* ENABLE_SYSLOG */ + + + +static void +send_notice_or_error_to_frontend(int type, const char *msg); + + +static void +send_notice_to_frontend(const char *msg) +{ + send_notice_or_error_to_frontend(NOTICE, msg); +} + + +static void +send_error_to_frontend(const char *msg) +{ + send_notice_or_error_to_frontend(ERROR, msg); +} + + +static void +send_notice_or_error_to_frontend(int type, const char *msg) +{ + StringInfo buf; + + AssertArg(type == NOTICE || type == ERROR); + + buf = makeStringInfo(); + + pq_beginmessage(buf); + pq_sendbyte(buf, type == NOTICE ? 'N' : 'E'); + pq_sendstring(buf, msg); + pq_endmessage(buf); + + pfree(buf); + /* + * This flush is normally not necessary, since postgres.c will + * flush out waiting data when control returns to the main loop. + * But it seems best to leave it here, so that the client has some + * clue what happened if the backend dies before getting back to + * the main loop ... error/notice messages should not be a + * performance-critical path anyway, so an extra flush won't hurt + * much ... + */ + pq_flush(); +} + + +static const char *useful_strerror(int errnum) +{ + /* this buffer is only used if errno has a bogus value */ + static char errorstr_buf[48]; + char *str; + + str = strerror(errnum); + + /* + * Some strerror()s return an empty string for out-of-range errno. + * This is ANSI C spec compliant, but not exactly useful. + */ + if (str == NULL || *str == '\0') + { + /* translator: This string will be truncated at 47 characters expanded. */ + snprintf(errorstr_buf, 48, gettext("operating system error %d"), errnum); + str = errorstr_buf; + } + + return str; +} + + + +static const char * +elog_message_prefix(int lev) +{ + const char * prefix = NULL; + + switch (lev) + { + case DEBUG: + prefix = gettext("DEBUG: "); + break; + case NOTICE: + prefix = gettext("NOTICE: "); + break; + case ERROR: + prefix = gettext("ERROR: "); + break; + case FATAL: + prefix = gettext("FATAL 1: "); + break; + case REALLYFATAL: + prefix = gettext("FATAL 2: "); + break; + } + + Assert(prefix != NULL); + return prefix; +} diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h index e949e4cd33072ec1bf5ac2a47e5919c000f56292..9b487f2f375ceefe7510553b26b40c068492b86b 100644 --- a/src/include/commands/copy.h +++ b/src/include/commands/copy.h @@ -7,14 +7,14 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: copy.h,v 1.12 2001/01/24 19:43:23 momjian Exp $ + * $Id: copy.h,v 1.13 2001/06/08 21:16:48 petere Exp $ * *------------------------------------------------------------------------- */ #ifndef COPY_H #define COPY_H -extern int lineno; +extern int copy_lineno; void DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe, char *filename, char *delim, char *null_print); diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h index df616de5786a5421064b8905e750e75acace4fdf..d29dddd40ada409c35b1e8767c3010eb8c1de2c6 100644 --- a/src/include/tcop/tcopprot.h +++ b/src/include/tcop/tcopprot.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: tcopprot.h,v 1.40 2001/03/22 04:01:09 momjian Exp $ + * $Id: tcopprot.h,v 1.41 2001/06/08 21:16:48 petere Exp $ * * OLD COMMENTS * This file was created so that other c files could get the two @@ -21,10 +21,12 @@ #include <setjmp.h> #include "executor/execdesc.h" +#include "tcop/dest.h" extern DLLIMPORT sigjmp_buf Warn_restart; extern bool Warn_restart_ready; extern bool InError; +extern CommandDest whereToSendOutput; extern bool HostnameLookup; extern bool ShowPortNumber; diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index 583897cc41f3530751e4165634a1387b8b8115c8..4c98f4119ca733c8eacee70a905bff65db7d96f6 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: elog.h,v 1.26 2001/03/22 04:01:11 momjian Exp $ + * $Id: elog.h,v 1.27 2001/06/08 21:16:49 petere Exp $ * *------------------------------------------------------------------------- */ @@ -15,36 +15,29 @@ #define ELOG_H /* Error level codes */ -#define NOTICE 0 /* random info - no special action */ +#define NOTICE 0 /* random info, sent to frontend */ #define ERROR (-1) /* user error - return to known state */ #define FATAL 1 /* fatal error - abort process */ #define REALLYFATAL 2 /* take down the other backends with me */ -#define STOP REALLYFATAL #define DEBUG (-2) /* debug message */ + +/* temporary nonsense... */ +#define STOP REALLYFATAL #define LOG DEBUG -#define NOIND (-3) /* debug message, don't indent as far */ /* Configurable parameters */ #ifdef ENABLE_SYSLOG extern int Use_syslog; - #endif extern bool Log_timestamp; extern bool Log_pid; -#ifndef __GNUC__ -extern void elog(int lev, const char *fmt,...); - -#else +extern void elog(int lev, const char *fmt,...) /* This extension allows gcc to check the format string for consistency with the supplied arguments. */ -extern void -elog(int lev, const char *fmt,...) __attribute__((format(printf, 2, 3))); -#endif - extern int DebugFileOpen(void); #endif /* ELOG_H */