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