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

📄 elog.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
voidFlushErrorState(void){	/*	 * Reset stack to empty.  The only case where it would be more than one	 * deep is if we serviced an error that interrupted construction of	 * another message.  We assume control escaped out of that message	 * construction and won't ever go back.	 */	errordata_stack_depth = -1;	recursion_depth = 0;	/* Delete all data in ErrorContext */	MemoryContextResetAndDeleteChildren(ErrorContext);}/* * ReThrowError --- re-throw a previously copied error * * A handler can do CopyErrorData/FlushErrorState to get out of the error * subsystem, then do some processing, and finally ReThrowError to re-throw * the original error.	This is slower than just PG_RE_THROW() but should * be used if the "some processing" is likely to incur another error. */voidReThrowError(ErrorData *edata){	ErrorData  *newedata;	Assert(edata->elevel == ERROR);	/* Push the data back into the error context */	recursion_depth++;	MemoryContextSwitchTo(ErrorContext);	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")));	}	newedata = &errordata[errordata_stack_depth];	memcpy(newedata, edata, sizeof(ErrorData));	/* Make copies of separately-allocated fields */	if (newedata->message)		newedata->message = pstrdup(newedata->message);	if (newedata->detail)		newedata->detail = pstrdup(newedata->detail);	if (newedata->hint)		newedata->hint = pstrdup(newedata->hint);	if (newedata->context)		newedata->context = pstrdup(newedata->context);	if (newedata->internalquery)		newedata->internalquery = pstrdup(newedata->internalquery);	recursion_depth--;	PG_RE_THROW();}/* * Initialization of error output file */voidDebugFileOpen(void){	int			fd,				istty;	if (OutputFileName[0])	{		/*		 * A debug-output file name was given.		 *		 * Make sure we can write the file, and find out if it's a tty.		 */		if ((fd = open(OutputFileName, O_CREAT | O_APPEND | O_WRONLY,					   0666)) < 0)			ereport(FATAL,					(errcode_for_file_access(),				  errmsg("could not open file \"%s\": %m", OutputFileName)));		istty = isatty(fd);		close(fd);		/*		 * Redirect our stderr to the debug output file.		 */		if (!freopen(OutputFileName, "a", stderr))			ereport(FATAL,					(errcode_for_file_access(),					 errmsg("could not reopen file \"%s\" as stderr: %m",							OutputFileName)));		/*		 * If the file is a tty and we're running under the postmaster, try to		 * send stdout there as well (if it isn't a tty then stderr will block		 * out stdout, so we may as well let stdout go wherever it was going		 * before).		 */		if (istty && IsUnderPostmaster)			if (!freopen(OutputFileName, "a", stdout))				ereport(FATAL,						(errcode_for_file_access(),						 errmsg("could not reopen file \"%s\" as stdout: %m",								OutputFileName)));	}}#ifdef HAVE_SYSLOG/* * Set or update the parameters for syslog logging */voidset_syslog_parameters(const char *ident, int facility){	/*	 * guc.c is likely to call us repeatedly with same parameters, so don't	 * thrash the syslog connection unnecessarily.	Also, we do not re-open	 * the connection until needed, since this routine will get called whether	 * or not Log_destination actually mentions syslog.	 *	 * Note that we make our own copy of the ident string rather than relying	 * on guc.c's.  This may be overly paranoid, but it ensures that we cannot	 * accidentally free a string that syslog is still using.	 */	if (syslog_ident == NULL || strcmp(syslog_ident, ident) != 0 ||		syslog_facility != facility)	{		if (openlog_done)		{			closelog();			openlog_done = false;		}		if (syslog_ident)			free(syslog_ident);		syslog_ident = strdup(ident);		/* if the strdup fails, we will cope in write_syslog() */		syslog_facility = facility;	}}#ifndef PG_SYSLOG_LIMIT#define PG_SYSLOG_LIMIT 128#endif/* * Write a message line to syslog */static voidwrite_syslog(int level, const char *line){	static unsigned long seq = 0;	int			len;	/* Open syslog connection if not done yet */	if (!openlog_done)	{		openlog(syslog_ident ? syslog_ident : "postgres",				LOG_PID | LOG_NDELAY | LOG_NOWAIT,				syslog_facility);		openlog_done = true;	}	/*	 * We add a sequence number to each log message to suppress "same"	 * messages.	 */	seq++;	/*	 * Our problem here is that many syslog implementations don't handle long	 * messages in an acceptable manner. While this function doesn't help that	 * fact, it does work around by splitting up messages into smaller pieces.	 *	 * We divide into multiple syslog() calls if message is too long or if the	 * message contains embedded NewLine(s) '\n'.	 */	len = strlen(line);	if (len > PG_SYSLOG_LIMIT || strchr(line, '\n') != NULL)	{		int			chunk_nr = 0;		while (len > 0)		{			char		buf[PG_SYSLOG_LIMIT + 1];			int			buflen;			int			i;			/* if we start at a newline, move ahead one char */			if (line[0] == '\n')			{				line++;				len--;				continue;			}			strncpy(buf, line, PG_SYSLOG_LIMIT);			buf[PG_SYSLOG_LIMIT] = '\0';			if (strchr(buf, '\n') != NULL)				*strchr(buf, '\n') = '\0';			buflen = strlen(buf);			/* trim to multibyte letter boundary */			buflen = pg_mbcliplen(buf, buflen, buflen);			if (buflen <= 0)				return;			buf[buflen] = '\0';			/* already word boundary? */			if (line[buflen] != '\0' &&				!isspace((unsigned char) line[buflen]))			{				/* try to divide at word boundary */				i = buflen - 1;				while (i > 0 && !isspace((unsigned char) buf[i]))					i--;				if (i > 0)		/* else couldn't divide word boundary */				{					buflen = i;					buf[i] = '\0';				}			}			chunk_nr++;			syslog(level, "[%lu-%d] %s", seq, chunk_nr, buf);			line += buflen;			len -= buflen;		}	}	else	{		/* message short enough */		syslog(level, "[%lu] %s", seq, line);	}}#endif   /* HAVE_SYSLOG */#ifdef WIN32/* * Write a message line to the windows event log */static voidwrite_eventlog(int level, const char *line){	int			eventlevel = EVENTLOG_ERROR_TYPE;	static HANDLE evtHandle = INVALID_HANDLE_VALUE;	if (evtHandle == INVALID_HANDLE_VALUE)	{		evtHandle = RegisterEventSource(NULL, "PostgreSQL");		if (evtHandle == NULL)		{			evtHandle = INVALID_HANDLE_VALUE;			return;		}	}	switch (level)	{		case DEBUG5:		case DEBUG4:		case DEBUG3:		case DEBUG2:		case DEBUG1:		case LOG:		case COMMERROR:		case INFO:		case NOTICE:			eventlevel = EVENTLOG_INFORMATION_TYPE;			break;		case WARNING:			eventlevel = EVENTLOG_WARNING_TYPE;			break;		case ERROR:		case FATAL:		case PANIC:		default:			eventlevel = EVENTLOG_ERROR_TYPE;			break;	}	ReportEvent(evtHandle,				eventlevel,				0,				0,				/* All events are Id 0 */				NULL,				1,				0,				&line,				NULL);}#endif   /* WIN32 *//* * Format tag info for log lines; append to the provided buffer. */static voidlog_line_prefix(StringInfo buf){	/* static counter for line numbers */	static long log_line_number = 0;	/* has counter been reset in current process? */	static int	log_my_pid = 0;	int			format_len;	int			i;	/*	 * This is one of the few places where we'd rather not inherit a static	 * variable's value from the postmaster.  But since we will, reset it when	 * MyProcPid changes.	 */	if (log_my_pid != MyProcPid)	{		log_line_number = 0;		log_my_pid = MyProcPid;	}	log_line_number++;	if (Log_line_prefix == NULL)		return;					/* in case guc hasn't run yet */	format_len = strlen(Log_line_prefix);	for (i = 0; i < format_len; i++)	{		if (Log_line_prefix[i] != '%')		{			/* literal char, just copy */			appendStringInfoChar(buf, Log_line_prefix[i]);			continue;		}		/* go to char after '%' */		i++;		if (i >= format_len)			break;				/* format error - ignore it */		/* process the option */		switch (Log_line_prefix[i])		{			case 'u':				if (MyProcPort)				{					const char *username = MyProcPort->user_name;					if (username == NULL || *username == '\0')						username = _("[unknown]");					appendStringInfo(buf, "%s", username);				}				break;			case 'd':				if (MyProcPort)				{					const char *dbname = MyProcPort->database_name;					if (dbname == NULL || *dbname == '\0')						dbname = _("[unknown]");					appendStringInfo(buf, "%s", dbname);				}				break;			case 'c':				if (MyProcPort)				{					appendStringInfo(buf, "%lx.%x",								   (long) (MyProcPort->session_start.tv_sec),									 MyProcPid);				}				break;			case 'p':				appendStringInfo(buf, "%d", MyProcPid);				break;			case 'l':				appendStringInfo(buf, "%ld", log_line_number);				break;			case 'm':				{					/*					 * Note: for %m, %t, and %s we deliberately use the C					 * library's strftime/localtime, and not the equivalent					 * functions from src/timezone.  This ensures that all					 * backends will report log entries in the same timezone,					 * namely whatever C-library setting they inherit from the					 * postmaster.	If we used src/timezone then local					 * settings of the TimeZone GUC variable would confuse the					 * log.					 */					time_t		stamp_time;					char		strfbuf[128],								msbuf[8];					struct timeval tv;					gettimeofday(&tv, NULL);					stamp_time = tv.tv_sec;					strftime(strfbuf, sizeof(strfbuf),					/* leave room for milliseconds... */					/* Win32 timezone names are too long so don't print them. */#ifndef WIN32							 "%Y-%m-%d %H:%M:%S     %Z",#else							 "%Y-%m-%d %H:%M:%S     ",#endif							 localtime(&stamp_time));					/* 'paste' milliseconds into place... */					sprintf(msbuf, ".%03d", (int) (tv.tv_usec / 1000));					strncpy(strfbuf + 19, msbuf, 4);					appendStringInfoString(buf, strfbuf);				}				break;			case 't':				{					time_t		stamp_time = time(NULL);					char		strfbuf[128];					strftime(strfbuf, sizeof(strfbuf),					/* Win32 timezone names are too long so don't print them. */#ifndef WIN32							 "%Y-%m-%d %H:%M:%S %Z",#else							 "%Y-%m-%d %H:%M:%S",#endif							 localtime(&stamp_time));					appendStringInfoString(buf, strfbuf);				}				break;			case 's':				if (MyProcPort)				{					time_t		stamp_time = MyProcPort->session_start.tv_sec;					char		strfbuf[128];					strftime(strfbuf, sizeof(strfbuf),							 "%Y-%m-%d %H:%M:%S %Z",							 localtime(&stamp_time));					appendStringInfoString(buf, strfbuf);				}				break;			case 'i':				if (MyProcPort)				{					const char *psdisp;					int			displen;					psdisp = get_ps_display(&displen);					appendStringInfo(buf, "%.*s", displen, psdisp);				}				break;			case 'r':				if (MyProcPort && MyProcPort->remote_host)				{					appendStringInfo(buf, "%s", MyProcPort->remote_host);					if (MyProcPort->remote_port &&						MyProcPort->remote_port[0] != '\0')						appendStringInfo(buf, "(%s)",										 MyProcPort->remote_port);				}				break;			case 'h':				if (MyProcPort && MyProcPort->remote_host)					appendStringInfo(buf, "%s", MyProcPort->remote_host);				break;			case 'q':				/* in postmaster and friends, stop if %q is seen */				/* in a backend, just ignore */				if (MyProcPort == NULL)					i = format_len;				break;			case 'x':				if (MyProcPort)				{					if (IsTransactionState())						appendStringInfo(buf, "%u", GetTopTransactionId());					else						appendStringInfo(buf, "%u", InvalidTransactionId);				}				break;			case '%':				appendStringInfoChar(buf, '%');				break;			default:				/* format error - ignore it */				break;		}	}}/* * Unpack MAKE_SQLSTATE code. Note that this returns a pointer to a * static buffer. */char *unpack_sql_state(int sql_state){	static char buf[12];	int			i;	for (i = 0; i < 5; i++)	{		buf[i] = PGUNSIXBIT(sql_state);		sql_state >>= 6;

⌨️ 快捷键说明

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