OSDN Git Service

9258dd9fbc326cda4e787484f520b12710948f7a
[pg-rex/syncrep.git] / src / backend / utils / error / elog.c
1 /*-------------------------------------------------------------------------
2  *
3  * elog.c
4  *        error logger
5  *
6  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.102 2002/09/02 05:42:54 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include <time.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <signal.h>
22 #include <sys/time.h>
23 #include <ctype.h>
24 #ifdef HAVE_SYSLOG
25 #include <syslog.h>
26 #endif
27
28 #include "commands/copy.h"
29 #include "libpq/libpq.h"
30 #include "libpq/pqformat.h"
31 #include "miscadmin.h"
32 #include "storage/ipc.h"
33 #include "storage/proc.h"
34 #include "tcop/tcopprot.h"
35 #include "utils/memutils.h"
36 #include "utils/guc.h"
37
38 #include "mb/pg_wchar.h"
39
40 #ifdef HAVE_SYSLOG
41 /*
42  * 0 = only stdout/stderr
43  * 1 = stdout+stderr and syslog
44  * 2 = syslog only
45  * ... in theory anyway
46  */
47 int                     Use_syslog = 0;
48 char       *Syslog_facility;
49 char       *Syslog_ident;
50
51 static void write_syslog(int level, const char *line);
52
53 #else
54 #define Use_syslog 0
55 #endif
56
57 bool            Log_timestamp;
58 bool            Log_pid;
59
60 #define TIMESTAMP_SIZE 20               /* format `YYYY-MM-DD HH:MM:SS ' */
61 #define PID_SIZE 9                              /* format `[123456] ' */
62
63 static const char *print_timestamp(void);
64 static const char *print_pid(void);
65 static void send_message_to_frontend(int type, const char *msg);
66 static const char *useful_strerror(int errnum);
67 static const char *elog_message_prefix(int lev);
68
69 static int      Debugfile = -1;
70
71
72 /*--------------------
73  * elog
74  *              Primary error logging function.
75  *
76  * 'lev': error level; indicates recovery action to take, if any.
77  * 'fmt': a printf-style string.
78  * Additional arguments, if any, are formatted per %-escapes in 'fmt'.
79  *
80  * In addition to the usual %-escapes recognized by printf, "%m" in
81  * fmt is replaced by the error message for the current value of errno.
82  *
83  * Note: no newline is needed at the end of the fmt string, since
84  * elog will provide one for the output methods that need it.
85  *
86  * If 'lev' is ERROR or worse, control does not return to the caller.
87  * See elog.h for the error level definitions.
88  *--------------------
89  */
90 void
91 elog(int lev, const char *fmt,...)
92 {
93         va_list         ap;
94         /*
95          * The expanded format and final output message are dynamically
96          * allocated if necessary, but not if they fit in the "reasonable
97          * size" buffers shown here.  In extremis, we'd rather depend on
98          * having a few hundred bytes of stack space than on malloc() still
99          * working (since memory-clobber errors often take out malloc first).
100          * Don't make these buffers unreasonably large though, on pain of
101          * having to chase a bug with no error message.
102          *
103          * Note that we use malloc() not palloc() because we want to retain
104          * control if we run out of memory.  palloc() would recursively call
105          * elog(ERROR), which would be all right except if we are working on a
106          * FATAL or PANIC error.        We'd lose track of the fatal condition
107          * and report a mere ERROR to outer loop, which would be a Bad Thing.
108          * So, we substitute an appropriate message in-place, without
109          * downgrading the level if it's above ERROR.
110          */
111         char            fmt_fixedbuf[128];
112         char            msg_fixedbuf[256];
113         char       *fmt_buf = fmt_fixedbuf;
114         char       *msg_buf = msg_fixedbuf;
115         char            copylineno_buf[32];     /* for COPY line numbers */
116         const char *errorstr;
117         const char *prefix;
118         const char *cp;
119         char       *bp;
120         size_t          space_needed;
121         size_t          timestamp_size; /* prefix len for timestamp+pid */
122         bool            output_to_server = false;
123         bool            output_to_client = false;
124
125         /* Check for old elog calls.  Codes were renumbered in 7.3. 2002-02-24 */
126         if (lev < DEBUG5)
127                 elog(FATAL, "Pre-7.3 object file made an elog() call.  Recompile.");
128
129         /*
130          * Convert initialization errors into fatal errors. This is probably
131          * redundant, because Warn_restart_ready won't be set anyway.
132          */
133         if (lev == ERROR && IsInitProcessingMode())
134                 lev = FATAL;
135
136         /*
137          * If we are inside a critical section, all errors become PANIC
138          * errors.      See miscadmin.h.
139          */
140         if (lev >= ERROR)
141         {
142                 if (CritSectionCount > 0)
143                         lev = PANIC;
144         }
145
146         /* Determine whether message is enabled for server log output */
147         /* Complicated because LOG is sorted out-of-order for this purpose */
148         if (lev == LOG || lev == COMMERROR)
149         {
150                 if (server_min_messages == LOG)
151                         output_to_server = true;
152                 else if (server_min_messages < FATAL)
153                         output_to_server = true;
154         }
155         else
156         {
157                 /* lev != LOG */
158                 if (server_min_messages == LOG)
159                 {
160                         if (lev >= FATAL)
161                                 output_to_server = true;
162                 }
163                 /* Neither is LOG */
164                 else if (lev >= server_min_messages)
165                         output_to_server = true;
166         }
167
168         /* Determine whether message is enabled for client output */
169         if (whereToSendOutput == Remote && lev != COMMERROR)
170         {
171                 /*
172                  * client_min_messages is honored only after we complete the
173                  * authentication handshake.  This is required both for security
174                  * reasons and because many clients can't handle NOTICE messages
175                  * during authentication.
176                  */
177                 if (ClientAuthInProgress)
178                         output_to_client = (lev >= ERROR);
179                 else
180                         output_to_client = (lev >= client_min_messages || lev == INFO);
181         }
182
183         /* Skip formatting effort if non-error message will not be output */
184         if (lev < ERROR && !output_to_server && !output_to_client)
185                 return;
186
187         /* Save error str before calling any function that might change errno */
188         errorstr = useful_strerror(errno);
189
190         /* Internationalize the error format string */
191         fmt = gettext(fmt);
192
193         /* Begin formatting by determining prefix information */
194         prefix = elog_message_prefix(lev);
195
196         timestamp_size = 0;
197         if (Log_timestamp)
198                 timestamp_size += TIMESTAMP_SIZE;
199         if (Log_pid)
200                 timestamp_size += PID_SIZE;
201
202         /*
203          * Set up the expanded format, consisting of the prefix string plus
204          * input format, with any %m replaced by strerror() string (since
205          * vsnprintf won't know what to do with %m).  To keep space
206          * calculation simple, we only allow one %m.
207          */
208         space_needed = timestamp_size + strlen(prefix) +
209                                    strlen(fmt) + strlen(errorstr) + 1;
210
211         if (copy_lineno)
212         {
213                 /*
214                  * Prints the failure line of the COPY.  Wow, what a hack!  bjm
215                  * Translator:  Error message will be truncated at 31 characters.
216                  */
217                 snprintf(copylineno_buf, 32, gettext("copy: line %d, "), copy_lineno);
218                 space_needed += strlen(copylineno_buf);
219         }
220
221         if (space_needed > sizeof(fmt_fixedbuf))
222         {
223                 fmt_buf = malloc(space_needed);
224                 if (fmt_buf == NULL)
225                 {
226                         /* We're up against it, convert to out-of-memory error */
227                         fmt_buf = fmt_fixedbuf;
228                         if (lev < ERROR)
229                         {
230                                 lev = ERROR;
231                                 prefix = elog_message_prefix(lev);
232                         }
233
234                         /*
235                          * gettext doesn't allocate memory, except in the very first
236                          * call (which this isn't), so it's safe to translate here.
237                          * Worst case we get the untranslated string back.
238                          */
239                         /* translator: This must fit in fmt_fixedbuf. */
240                         fmt = gettext("elog: out of memory");
241                 }
242         }
243
244         fmt_buf[0] = '\0';
245
246         if (Log_timestamp)
247                 strcat(fmt_buf, print_timestamp());
248         if (Log_pid)
249                 strcat(fmt_buf, print_pid());
250
251         strcat(fmt_buf, prefix);
252
253         /* If error was in CopyFrom() print the offending line number -- dz */
254         if (copy_lineno)
255         {
256                 strcat(fmt_buf, copylineno_buf);
257                 if (lev >= ERROR)
258                         copy_lineno = 0;
259         }
260
261         bp = fmt_buf + strlen(fmt_buf);
262
263         for (cp = fmt; *cp; cp++)
264         {
265                 if (cp[0] == '%' && cp[1] != '\0')
266                 {
267                         if (cp[1] == 'm')
268                         {
269                                 /*
270                                  * XXX If there are any %'s in errorstr then vsnprintf
271                                  * will do the Wrong Thing; do we need to cope? Seems
272                                  * unlikely that % would appear in system errors.
273                                  */
274                                 strcpy(bp, errorstr);
275
276                                 /*
277                                  * copy the rest of fmt literally, since we can't afford
278                                  * to insert another %m.
279                                  */
280                                 strcat(bp, cp + 2);
281                                 bp += strlen(bp);
282                                 break;
283                         }
284                         else
285                         {
286                                 /* copy % and next char --- this avoids trouble with %%m */
287                                 *bp++ = *cp++;
288                                 *bp++ = *cp;
289                         }
290                 }
291                 else
292                         *bp++ = *cp;
293         }
294         *bp = '\0';
295
296         /*
297          * Now generate the actual output text using vsnprintf(). Be sure to
298          * leave space for \n added later as well as trailing null.
299          */
300         space_needed = sizeof(msg_fixedbuf);
301         for (;;)
302         {
303                 int                     nprinted;
304
305                 va_start(ap, fmt);
306                 nprinted = vsnprintf(msg_buf, space_needed - 2, fmt_buf, ap);
307                 va_end(ap);
308
309                 /*
310                  * Note: some versions of vsnprintf return the number of chars
311                  * actually stored, but at least one returns -1 on failure. Be
312                  * conservative about believing whether the print worked.
313                  */
314                 if (nprinted >= 0 && nprinted < space_needed - 3)
315                         break;
316                 /* It didn't work, try to get a bigger buffer */
317                 if (msg_buf != msg_fixedbuf)
318                         free(msg_buf);
319                 space_needed *= 2;
320                 msg_buf = malloc(space_needed);
321                 if (msg_buf == NULL)
322                 {
323                         /* We're up against it, convert to out-of-memory error */
324                         msg_buf = msg_fixedbuf;
325                         if (lev < ERROR)
326                         {
327                                 lev = ERROR;
328                                 prefix = elog_message_prefix(lev);
329                         }
330                         msg_buf[0] = '\0';
331                         if (Log_timestamp)
332                                 strcat(msg_buf, print_timestamp());
333                         if (Log_pid)
334                                 strcat(msg_buf, print_pid());
335                         strcat(msg_buf, prefix);
336                         strcat(msg_buf, gettext("elog: out of memory"));
337                         break;
338                 }
339         }
340
341
342         /*
343          * Message prepared; send it where it should go
344          */
345
346 #ifdef HAVE_SYSLOG
347         /* Write to syslog, if enabled */
348         if (output_to_server && Use_syslog >= 1)
349         {
350                 int                     syslog_level;
351
352                 switch (lev)
353                 {
354                         case DEBUG5:
355                         case DEBUG4:
356                         case DEBUG3:
357                         case DEBUG2:
358                         case DEBUG1:
359                                 syslog_level = LOG_DEBUG;
360                                 break;
361                         case LOG:
362                         case COMMERROR:
363                         case INFO:
364                                 syslog_level = LOG_INFO;
365                                 break;
366                         case NOTICE:
367                         case WARNING:
368                                 syslog_level = LOG_NOTICE;
369                                 break;
370                         case ERROR:
371                                 syslog_level = LOG_WARNING;
372                                 break;
373                         case FATAL:
374                                 syslog_level = LOG_ERR;
375                                 break;
376                         case PANIC:
377                         default:
378                                 syslog_level = LOG_CRIT;
379                                 break;
380                 }
381
382                 write_syslog(syslog_level, msg_buf + timestamp_size);
383         }
384 #endif   /* HAVE_SYSLOG */
385
386         /* syslog doesn't want a trailing newline, but other destinations do */
387         strcat(msg_buf, "\n");
388
389         /* Write to stderr, if enabled */
390         if (output_to_server && (Use_syslog <= 1 || whereToSendOutput == Debug))
391                 write(2, msg_buf, strlen(msg_buf));
392
393         /* Send to client, if enabled */
394         if (output_to_client)
395         {
396                 /* Send IPC message to the front-end program */
397                 MemoryContext oldcxt;
398
399                 /*
400                  * Since backend libpq may call palloc(), switch to a context
401                  * where there's fairly likely to be some free space.  After all
402                  * the pushups above, we don't want to drop the ball by running
403                  * out of space now...
404                  */
405                 oldcxt = MemoryContextSwitchTo(ErrorContext);
406
407                 if (lev <= WARNING)
408                         /* exclude the timestamp from msg sent to frontend */
409                         send_message_to_frontend(lev, msg_buf + timestamp_size);
410                 else
411                 {
412                         /*
413                          * Abort any COPY OUT in progress when an error is detected.
414                          * This hack is necessary because of poor design of copy
415                          * protocol.
416                          */
417                         pq_endcopyout(true);
418                         send_message_to_frontend(ERROR, msg_buf + timestamp_size);
419                 }
420
421                 MemoryContextSwitchTo(oldcxt);
422         }
423
424         /* done with the message, release space */
425         if (fmt_buf != fmt_fixedbuf)
426                 free(fmt_buf);
427         if (msg_buf != msg_fixedbuf)
428                 free(msg_buf);
429
430         /* If the user wants this elog() generating query logged,
431          * do so. We only want to log if the query has been
432          * written to debug_query_string. Also, avoid infinite loops.
433          */
434
435         if(lev != LOG && lev >= log_min_error_statement && debug_query_string)
436                 elog(LOG,"statement: %s",debug_query_string);
437
438         /*
439          * Perform error recovery action as specified by lev.
440          */
441         if (lev == ERROR || lev == FATAL)
442         {
443                 /* Prevent immediate interrupt while entering error recovery */
444                 ImmediateInterruptOK = false;
445
446                 /*
447                  * If we just reported a startup failure, the client will
448                  * disconnect on receiving it, so don't send any more to the client.
449                  */
450                 if (!Warn_restart_ready && whereToSendOutput == Remote)
451                         whereToSendOutput = None;
452
453                 /*
454                  * For a FATAL error, we let proc_exit clean up and exit.
455                  *
456                  * If we have not yet entered the main backend loop (ie, we are in
457                  * the postmaster or in backend startup), we also go directly to
458                  * proc_exit.  The same is true if anyone tries to report an error
459                  * after proc_exit has begun to run.  (It's proc_exit's
460                  * responsibility to see that this doesn't turn into infinite
461                  * recursion!)  But in the latter case, we exit with nonzero exit
462                  * code to indicate that something's pretty wrong.  We also want
463                  * to exit with nonzero exit code if not running under the
464                  * postmaster (for example, if we are being run from the initdb
465                  * script, we'd better return an error status).
466                  */
467                 if (lev == FATAL || !Warn_restart_ready || proc_exit_inprogress)
468                 {
469                         /*
470                          * fflush here is just to improve the odds that we get to see
471                          * the error message, in case things are so hosed that
472                          * proc_exit crashes.  Any other code you might be tempted to
473                          * add here should probably be in an on_proc_exit callback
474                          * instead.
475                          */
476                         fflush(stdout);
477                         fflush(stderr);
478                         proc_exit(proc_exit_inprogress || !IsUnderPostmaster);
479                 }
480
481                 /*
482                  * Guard against infinite loop from elog() during error recovery.
483                  */
484                 if (InError)
485                         elog(PANIC, "elog: error during error recovery, giving up!");
486                 InError = true;
487
488                 /*
489                  * Otherwise we can return to the main loop in postgres.c.
490                  */
491                 siglongjmp(Warn_restart, 1);
492         }
493
494         if (lev == PANIC)
495         {
496                 /*
497                  * Serious crash time. Postmaster will observe nonzero process
498                  * exit status and kill the other backends too.
499                  *
500                  * XXX: what if we are *in* the postmaster?  proc_exit() won't kill
501                  * our children...
502                  */
503                 ImmediateInterruptOK = false;
504                 fflush(stdout);
505                 fflush(stderr);
506                 proc_exit(2);
507         }
508
509         /* We reach here if lev <= WARNING.     OK to return to caller. */
510 }
511
512
513 int
514 DebugFileOpen(void)
515 {
516         int                     fd,
517                                 istty;
518
519         Debugfile = -1;
520
521         if (OutputFileName[0])
522         {
523                 /*
524                  * A debug-output file name was given.
525                  *
526                  * Make sure we can write the file, and find out if it's a tty.
527                  */
528                 if ((fd = open(OutputFileName, O_CREAT | O_APPEND | O_WRONLY,
529                                            0666)) < 0)
530                         elog(FATAL, "DebugFileOpen: open of %s: %m",
531                                  OutputFileName);
532                 istty = isatty(fd);
533                 close(fd);
534
535                 /*
536                  * Redirect our stderr to the debug output file.
537                  */
538                 if (!freopen(OutputFileName, "a", stderr))
539                         elog(FATAL, "DebugFileOpen: %s reopen as stderr: %m",
540                                  OutputFileName);
541                 Debugfile = fileno(stderr);
542
543                 /*
544                  * If the file is a tty and we're running under the postmaster,
545                  * try to send stdout there as well (if it isn't a tty then stderr
546                  * will block out stdout, so we may as well let stdout go wherever
547                  * it was going before).
548                  */
549                 if (istty && IsUnderPostmaster)
550                         if (!freopen(OutputFileName, "a", stdout))
551                                 elog(FATAL, "DebugFileOpen: %s reopen as stdout: %m",
552                                          OutputFileName);
553                 return Debugfile;
554         }
555
556         /*
557          * If no filename was specified, send debugging output to stderr. If
558          * stderr has been hosed, try to open a file.
559          */
560         fd = fileno(stderr);
561         if (fcntl(fd, F_GETFD, 0) < 0)
562         {
563                 snprintf(OutputFileName, MAXPGPATH, "%s/pg.errors.%d",
564                                  DataDir, (int) MyProcPid);
565                 fd = open(OutputFileName, O_CREAT | O_APPEND | O_WRONLY, 0666);
566         }
567         if (fd < 0)
568                 elog(FATAL, "DebugFileOpen: could not open debugging file");
569
570         Debugfile = fd;
571         return Debugfile;
572 }
573
574
575 /*
576  * Return a timestamp string like
577  *
578  *       "2000-06-04 13:12:03 "
579  */
580 static const char *
581 print_timestamp(void)
582 {
583         time_t          curtime;
584         static char buf[TIMESTAMP_SIZE + 1];
585
586         curtime = time(NULL);
587
588         strftime(buf, sizeof(buf),
589                          "%Y-%m-%d %H:%M:%S ",
590                          localtime(&curtime));
591
592         return buf;
593 }
594
595
596
597 /*
598  * Return a string like
599  *
600  *         "[123456] "
601  *
602  * with the current pid.
603  */
604 static const char *
605 print_pid(void)
606 {
607         static char buf[PID_SIZE + 1];
608
609         snprintf(buf, PID_SIZE + 1, "[%d]      ", (int) MyProcPid);
610         return buf;
611 }
612
613
614
615 #ifdef HAVE_SYSLOG
616
617 #ifndef PG_SYSLOG_LIMIT
618 #define PG_SYSLOG_LIMIT 128
619 #endif
620
621 /*
622  * Write a message line to syslog if the syslog option is set.
623  *
624  * Our problem here is that many syslog implementations don't handle
625  * long messages in an acceptable manner. While this function doesn't
626  * help that fact, it does work around by splitting up messages into
627  * smaller pieces.
628  */
629 static void
630 write_syslog(int level, const char *line)
631 {
632         static bool openlog_done = false;
633         static unsigned long seq = 0;
634         static int      syslog_fac = LOG_LOCAL0;
635
636         int                     len = strlen(line);
637
638         if (Use_syslog == 0)
639                 return;
640
641         if (!openlog_done)
642         {
643                 if (strcasecmp(Syslog_facility, "LOCAL0") == 0)
644                         syslog_fac = LOG_LOCAL0;
645                 if (strcasecmp(Syslog_facility, "LOCAL1") == 0)
646                         syslog_fac = LOG_LOCAL1;
647                 if (strcasecmp(Syslog_facility, "LOCAL2") == 0)
648                         syslog_fac = LOG_LOCAL2;
649                 if (strcasecmp(Syslog_facility, "LOCAL3") == 0)
650                         syslog_fac = LOG_LOCAL3;
651                 if (strcasecmp(Syslog_facility, "LOCAL4") == 0)
652                         syslog_fac = LOG_LOCAL4;
653                 if (strcasecmp(Syslog_facility, "LOCAL5") == 0)
654                         syslog_fac = LOG_LOCAL5;
655                 if (strcasecmp(Syslog_facility, "LOCAL6") == 0)
656                         syslog_fac = LOG_LOCAL6;
657                 if (strcasecmp(Syslog_facility, "LOCAL7") == 0)
658                         syslog_fac = LOG_LOCAL7;
659                 openlog(Syslog_ident, LOG_PID | LOG_NDELAY, syslog_fac);
660                 openlog_done = true;
661         }
662
663         /*
664          * We add a sequence number to each log message to suppress "same"
665          * messages.
666          */
667         seq++;
668
669         /* divide into multiple syslog() calls if message is too long */
670         /* or if the message contains embedded NewLine(s) '\n' */
671         if (len > PG_SYSLOG_LIMIT || strchr(line, '\n') != NULL)
672         {
673                 int                     chunk_nr = 0;
674
675                 while (len > 0)
676                 {
677                         char            buf[PG_SYSLOG_LIMIT + 1];
678                         int                     buflen;
679                         int                     l;
680                         int                     i;
681
682                         /* if we start at a newline, move ahead one char */
683                         if (line[0] == '\n')
684                         {
685                                 line++;
686                                 len--;
687                                 continue;
688                         }
689
690                         strncpy(buf, line, PG_SYSLOG_LIMIT);
691                         buf[PG_SYSLOG_LIMIT] = '\0';
692                         if (strchr(buf, '\n') != NULL)
693                                 *strchr(buf, '\n') = '\0';
694
695                         l = strlen(buf);
696
697                         /* trim to multibyte letter boundary */
698                         buflen = pg_mbcliplen(buf, l, l);
699                         if (buflen <= 0)
700                                 return;
701                         buf[buflen] = '\0';
702                         l = strlen(buf);
703
704                         /* already word boundary? */
705                         if (isspace((unsigned char) line[l]) || line[l] == '\0')
706                                 buflen = l;
707                         else
708                         {
709                                 /* try to divide at word boundary */
710                                 i = l - 1;
711                                 while (i > 0 && !isspace((unsigned char) buf[i]))
712                                         i--;
713
714                                 if (i <= 0)             /* couldn't divide word boundary */
715                                         buflen = l;
716                                 else
717                                 {
718                                         buflen = i;
719                                         buf[i] = '\0';
720                                 }
721                         }
722
723                         chunk_nr++;
724
725                         syslog(level, "[%lu-%d] %s", seq, chunk_nr, buf);
726                         line += buflen;
727                         len -= buflen;
728                 }
729         }
730         else
731         {
732                 /* message short enough */
733                 syslog(level, "[%lu] %s", seq, line);
734         }
735 }
736 #endif   /* HAVE_SYSLOG */
737
738
739 static void
740 send_message_to_frontend(int type, const char *msg)
741 {
742         StringInfoData buf;
743
744         AssertArg(type <= ERROR);
745
746         pq_beginmessage(&buf);
747         pq_sendbyte(&buf, type != ERROR ? 'N' : 'E'); /* N is INFO, NOTICE,
748                                                                                                    * or WARNING */
749         pq_sendstring(&buf, msg);
750         pq_endmessage(&buf);
751
752         /*
753          * This flush is normally not necessary, since postgres.c will flush
754          * out waiting data when control returns to the main loop. But it
755          * seems best to leave it here, so that the client has some clue what
756          * happened if the backend dies before getting back to the main loop
757          * ... error/notice messages should not be a performance-critical path
758          * anyway, so an extra flush won't hurt much ...
759          */
760         pq_flush();
761 }
762
763
764 static const char *
765 useful_strerror(int errnum)
766 {
767         /* this buffer is only used if errno has a bogus value */
768         static char errorstr_buf[48];
769         char       *str;
770
771         if (errnum == ERANGE)
772                 /* small trick to save creating many regression test result files */
773                 str = gettext("Numerical result out of range");
774         else
775                 str = strerror(errnum);
776
777         /*
778          * Some strerror()s return an empty string for out-of-range errno.
779          * This is ANSI C spec compliant, but not exactly useful.
780          */
781         if (str == NULL || *str == '\0')
782         {
783                 /*
784                  * translator: This string will be truncated at 47 characters
785                  * expanded.
786                  */
787                 snprintf(errorstr_buf, 48, gettext("operating system error %d"),
788                                  errnum);
789                 str = errorstr_buf;
790         }
791
792         return str;
793 }
794
795
796
797 static const char *
798 elog_message_prefix(int lev)
799 {
800         const char *prefix = NULL;
801
802         switch (lev)
803         {
804                 case DEBUG1:
805                 case DEBUG2:
806                 case DEBUG3:
807                 case DEBUG4:
808                 case DEBUG5:
809                         prefix = gettext("DEBUG:  ");
810                         break;
811                 case LOG:
812                 case COMMERROR:
813                         prefix = gettext("LOG:  ");
814                         break;
815                 case INFO:
816                         prefix = gettext("INFO:  ");
817                         break;
818                 case NOTICE:
819                         prefix = gettext("NOTICE:  ");
820                         break;
821                 case WARNING:
822                         prefix = gettext("WARNING:  ");
823                         break;
824                 case ERROR:
825                         prefix = gettext("ERROR:  ");
826                         break;
827                 case FATAL:
828                         prefix = gettext("FATAL:  ");
829                         break;
830                 case PANIC:
831                         prefix = gettext("PANIC:  ");
832                         break;
833         }
834
835         Assert(prefix != NULL);
836         return prefix;
837 }
838
839
840