⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 elog.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
/*------------------------------------------------------------------------- * * elog.c *	  error logging and reporting * * Some notes about recursion and errors during error processing: * * We need to be robust about recursive-error scenarios --- for example, * if we run out of memory, it's important to be able to report that fact. * There are a number of considerations that go into this. * * First, distinguish between re-entrant use and actual recursion.	It * is possible for an error or warning message to be emitted while the * parameters for an error message are being computed.	In this case * errstart has been called for the outer message, and some field values * may have already been saved, but we are not actually recursing.	We handle * this by providing a (small) stack of ErrorData records.	The inner message * can be computed and sent without disturbing the state of the outer message. * (If the inner message is actually an error, this isn't very interesting * because control won't come back to the outer message generator ... but * if the inner message is only debug or log data, this is critical.) * * Second, actual recursion will occur if an error is reported by one of * the elog.c routines or something they call.	By far the most probable * scenario of this sort is "out of memory"; and it's also the nastiest * to handle because we'd likely also run out of memory while trying to * report this error!  Our escape hatch for this case is to reset the * ErrorContext to empty before trying to process the inner error.	Since * ErrorContext is guaranteed to have at least 8K of space in it (see mcxt.c), * we should be able to process an "out of memory" message successfully. * Since we lose the prior error state due to the reset, we won't be able * to return to processing the original error, but we wouldn't have anyway. * (NOTE: the escape hatch is not used for recursive situations where the * inner message is of less than ERROR severity; in that case we just * try to process it and return normally.  Usually this will work, but if * it ends up in infinite recursion, we will PANIC due to error stack * overflow.) * * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.167.2.1 2005/11/22 18:23:23 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <fcntl.h>#include <time.h>#include <unistd.h>#include <signal.h>#include <ctype.h>#ifdef HAVE_SYSLOG#include <syslog.h>#endif#include "libpq/libpq.h"#include "libpq/pqformat.h"#include "mb/pg_wchar.h"#include "miscadmin.h"#include "postmaster/postmaster.h"#include "postmaster/syslogger.h"#include "storage/ipc.h"#include "tcop/tcopprot.h"#include "utils/memutils.h"#include "utils/guc.h"#include "utils/ps_status.h"/* Global variables */ErrorContextCallback *error_context_stack = NULL;sigjmp_buf *PG_exception_stack = NULL;/* GUC parameters */PGErrorVerbosity Log_error_verbosity = PGERROR_VERBOSE;char	   *Log_line_prefix = NULL;		/* format for extra log line info */int			Log_destination = LOG_DESTINATION_STDERR;#ifdef HAVE_SYSLOGstatic bool openlog_done = false;static char *syslog_ident = NULL;static int	syslog_facility = LOG_LOCAL0;static void write_syslog(int level, const char *line);#endif#ifdef WIN32static void write_eventlog(int level, const char *line);#endif/* We provide a small stack of ErrorData records for re-entrant cases */#define ERRORDATA_STACK_SIZE  5static ErrorData errordata[ERRORDATA_STACK_SIZE];static int	errordata_stack_depth = -1; /* index of topmost active frame */static int	recursion_depth = 0;	/* to detect actual recursion *//* Macro for checking errordata_stack_depth is reasonable */#define CHECK_STACK_DEPTH() \	do { \		if (errordata_stack_depth < 0) \		{ \			errordata_stack_depth = -1; \			ereport(ERROR, (errmsg_internal("errstart was not called"))); \		} \	} while (0)static void log_line_prefix(StringInfo buf);static void send_message_to_server_log(ErrorData *edata);static void send_message_to_frontend(ErrorData *edata);static char *expand_fmt_string(const char *fmt, ErrorData *edata);static const char *useful_strerror(int errnum);static const char *error_severity(int elevel);static void append_with_tabs(StringInfo buf, const char *str);/* * errstart --- begin an error-reporting cycle * * Create a stack entry and store the given parameters in it.  Subsequently, * errmsg() and perhaps other routines will be called to further populate * the stack entry.  Finally, errfinish() will be called to actually process * the error report. * * Returns TRUE in normal case.  Returns FALSE to short-circuit the error * report (if it's a warning or lower and not to be reported anywhere). */boolerrstart(int elevel, const char *filename, int lineno,		 const char *funcname){	ErrorData  *edata;	bool		output_to_server = false;	bool		output_to_client = false;	int			i;	/*	 * Check some cases in which we want to promote an error into a more	 * severe error.  None of this logic applies for non-error messages.	 */	if (elevel >= ERROR)	{		/*		 * If we are inside a critical section, all errors become PANIC		 * errors.	See miscadmin.h.		 */		if (CritSectionCount > 0)			elevel = PANIC;		/*		 * Check reasons for treating ERROR as FATAL:		 *		 * 1. we have no handler to pass the error to (implies we are in the		 * postmaster or in backend startup).		 *		 * 2. ExitOnAnyError mode switch is set (initdb uses this).		 *		 * 3. the error occurred after proc_exit has begun to run.	(It's		 * proc_exit's responsibility to see that this doesn't turn into		 * infinite recursion!)		 */		if (elevel == ERROR)		{			if (PG_exception_stack == NULL ||				ExitOnAnyError ||				proc_exit_inprogress)				elevel = FATAL;		}		/*		 * If the error level is ERROR or more, errfinish is not going to		 * return to caller; therefore, if there is any stacked error already		 * in progress it will be lost.  This is more or less okay, except we		 * do not want to have a FATAL or PANIC error downgraded because the		 * reporting process was interrupted by a lower-grade error.  So check		 * the stack and make sure we panic if panic is warranted.		 */		for (i = 0; i <= errordata_stack_depth; i++)			elevel = Max(elevel, errordata[i].elevel);	}	/*	 * Now decide whether we need to process this report at all; if it's	 * warning or less and not enabled for logging, just return FALSE without	 * starting up any error logging machinery.	 */	/* Determine whether message is enabled for server log output */	if (IsPostmasterEnvironment)	{		/* Complicated because LOG is sorted out-of-order for this purpose */		if (elevel == LOG || elevel == COMMERROR)		{			if (log_min_messages == LOG)				output_to_server = true;			else if (log_min_messages < FATAL)				output_to_server = true;		}		else		{			/* elevel != LOG */			if (log_min_messages == LOG)			{				if (elevel >= FATAL)					output_to_server = true;			}			/* Neither is LOG */			else if (elevel >= log_min_messages)				output_to_server = true;		}	}	else	{		/* In bootstrap/standalone case, do not sort LOG out-of-order */		output_to_server = (elevel >= log_min_messages);	}	/* Determine whether message is enabled for client output */	if (whereToSendOutput == DestRemote && elevel != COMMERROR)	{		/*		 * client_min_messages is honored only after we complete the		 * authentication handshake.  This is required both for security		 * reasons and because many clients can't handle NOTICE messages		 * during authentication.		 */		if (ClientAuthInProgress)			output_to_client = (elevel >= ERROR);		else			output_to_client = (elevel >= client_min_messages ||								elevel == INFO);	}	/* Skip processing effort if non-error message will not be output */	if (elevel < ERROR && !output_to_server && !output_to_client)		return false;	/*	 * Okay, crank up a stack entry to store the info in.	 */	if (recursion_depth++ > 0 && elevel >= ERROR)	{		/*		 * Ooops, error during error processing.  Clear ErrorContext as		 * discussed at top of file.  We will not return to the original		 * error's reporter or handler, so we don't need it.		 */		MemoryContextReset(ErrorContext);		/*		 * If we recurse more than once, the problem might be something broken		 * in a context traceback routine.	Abandon them too.		 */		if (recursion_depth > 2)			error_context_stack = NULL;	}	if (++errordata_stack_depth >= ERRORDATA_STACK_SIZE)	{		/*		 * Wups, stack not big enough.	We treat this as a PANIC condition		 * because it suggests an infinite loop of errors during error		 * recovery.		 */		errordata_stack_depth = -1;		/* make room on stack */		ereport(PANIC, (errmsg_internal("ERRORDATA_STACK_SIZE exceeded")));	}	/* Initialize data for this error frame */	edata = &errordata[errordata_stack_depth];	MemSet(edata, 0, sizeof(ErrorData));	edata->elevel = elevel;	edata->output_to_server = output_to_server;	edata->output_to_client = output_to_client;	edata->filename = filename;	edata->lineno = lineno;	edata->funcname = funcname;	/* Select default errcode based on elevel */	if (elevel >= ERROR)		edata->sqlerrcode = ERRCODE_INTERNAL_ERROR;	else if (elevel == WARNING)		edata->sqlerrcode = ERRCODE_WARNING;	else		edata->sqlerrcode = ERRCODE_SUCCESSFUL_COMPLETION;	/* errno is saved here so that error parameter eval can't change it */	edata->saved_errno = errno;	recursion_depth--;	return true;}/* * errfinish --- end an error-reporting cycle * * Produce the appropriate error report(s) and pop the error stack. * * If elevel is ERROR or worse, control does not return to the caller. * See elog.h for the error level definitions. */voiderrfinish(int dummy,...){	ErrorData  *edata = &errordata[errordata_stack_depth];	int			elevel = edata->elevel;	MemoryContext oldcontext;	ErrorContextCallback *econtext;	recursion_depth++;	CHECK_STACK_DEPTH();	/*	 * Do processing in ErrorContext, which we hope has enough reserved space	 * to report an error.	 */	oldcontext = MemoryContextSwitchTo(ErrorContext);	/*	 * Call any context callback functions.  Errors occurring in callback	 * functions will be treated as recursive errors --- this ensures we will	 * avoid infinite recursion (see errstart).	 */	for (econtext = error_context_stack;		 econtext != NULL;		 econtext = econtext->previous)		(*econtext->callback) (econtext->arg);	/*	 * If ERROR (not more nor less) we pass it off to the current handler.	 * Printing it and popping the stack is the responsibility of the handler.	 */	if (elevel == ERROR)	{		/*		 * We do some minimal cleanup before longjmp'ing so that handlers can		 * execute in a reasonably sane state.		 */		/* This is just in case the error came while waiting for input */		ImmediateInterruptOK = false;		/*		 * Reset InterruptHoldoffCount in case we ereport'd from inside an		 * interrupt holdoff section.  (We assume here that no handler will		 * itself be inside a holdoff section.	If necessary, such a handler		 * could save and restore InterruptHoldoffCount for itself, but this		 * should make life easier for most.)		 */		InterruptHoldoffCount = 0;		CritSectionCount = 0;	/* should be unnecessary, but... */		/*		 * Note that we leave CurrentMemoryContext set to ErrorContext. The		 * handler should reset it to something else soon.		 */		recursion_depth--;		PG_RE_THROW();	}	/*	 * If we are doing FATAL or PANIC, abort any old-style COPY OUT in	 * progress, so that we can report the message before dying.  (Without	 * this, pq_putmessage will refuse to send the message at all, which is	 * what we want for NOTICE messages, but not for fatal exits.) This hack	 * is necessary because of poor design of old-style copy protocol.	Note	 * we must do this even if client is fool enough to have set	 * client_min_messages above FATAL, so don't look at output_to_client.	 */	if (elevel >= FATAL && whereToSendOutput == DestRemote)		pq_endcopyout(true);	/* Emit the message to the right places */	EmitErrorReport();	/* Now free up subsidiary data attached to stack entry, and release it */	if (edata->message)		pfree(edata->message);	if (edata->detail)		pfree(edata->detail);	if (edata->hint)		pfree(edata->hint);	if (edata->context)		pfree(edata->context);	if (edata->internalquery)		pfree(edata->internalquery);	errordata_stack_depth--;	/* Exit error-handling context */	MemoryContextSwitchTo(oldcontext);	recursion_depth--;	/*	 * Perform error recovery action as specified by elevel.	 */	if (elevel == FATAL)	{		/*		 * For a FATAL error, we let proc_exit clean up and exit.		 */		ImmediateInterruptOK = false;		/*		 * If we just reported a startup failure, the client will disconnect		 * on receiving it, so don't send any more to the client.		 */		if (PG_exception_stack == NULL && whereToSendOutput == DestRemote)			whereToSendOutput = DestNone;		/*		 * fflush here is just to improve the odds that we get to see the		 * error message, in case things are so hosed that proc_exit crashes.		 * Any other code you might be tempted to add here should probably be		 * in an on_proc_exit callback instead.		 */		fflush(stdout);		fflush(stderr);		/*		 * If proc_exit is already running, we exit with nonzero exit code to		 * indicate that something's pretty wrong.  We also want to exit with		 * nonzero exit code if not running under the postmaster (for example,		 * if we are being run from the initdb script, we'd better return an		 * error status).		 */		proc_exit(proc_exit_inprogress || !IsUnderPostmaster);	}	if (elevel >= PANIC)	{		/*		 * Serious crash time. Postmaster will observe nonzero process exit		 * status and kill the other backends too.		 *		 * XXX: what if we are *in* the postmaster?  abort() won't kill our		 * children...		 */		ImmediateInterruptOK = false;		fflush(stdout);		fflush(stderr);		abort();	}	/* We reach here if elevel <= WARNING. OK to return to caller. */}/* * errcode --- add SQLSTATE error code to the current error * * The code is expected to be represented as per MAKE_SQLSTATE(). */interrcode(int sqlerrcode){	ErrorData  *edata = &errordata[errordata_stack_depth];	/* we don't bother incrementing recursion_depth */	CHECK_STACK_DEPTH();	edata->sqlerrcode = sqlerrcode;	return 0;					/* return value does not matter */}/* * errcode_for_file_access --- add SQLSTATE error code to the current error * * The SQLSTATE code is chosen based on the saved errno value.	We assume * that the failing operation was some type of disk file access. * * NOTE: the primary error message string should generally include %m * when this is used. */interrcode_for_file_access(void){	ErrorData  *edata = &errordata[errordata_stack_depth];	/* we don't bother incrementing recursion_depth */	CHECK_STACK_DEPTH();	switch (edata->saved_errno)	{			/* Permission-denied failures */		case EPERM:				/* Not super-user */		case EACCES:			/* Permission denied */#ifdef EROFS		case EROFS:				/* Read only file system */#endif			edata->sqlerrcode = ERRCODE_INSUFFICIENT_PRIVILEGE;			break;			/* File not found */		case ENOENT:			/* No such file or directory */			edata->sqlerrcode = ERRCODE_UNDEFINED_FILE;			break;			/* Duplicate file */		case EEXIST:			/* File exists */			edata->sqlerrcode = ERRCODE_DUPLICATE_FILE;			break;			/* Wrong object type or state */		case ENOTDIR:			/* Not a directory */		case EISDIR:			/* Is a directory */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -