postgres.c

来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 2,390 行 · 第 1/5 页

C
2,390
字号
/*------------------------------------------------------------------------- * * postgres.c *	  POSTGRES C Backend Interface * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.468.2.4 2006/04/18 00:52:41 momjian Exp $ * * NOTES *	  this is the "main" module of the postgres backend and *	  hence the main module of the "traffic cop". * *------------------------------------------------------------------------- */#include "postgres.h"#include <unistd.h>#include <signal.h>#include <fcntl.h>#include <sys/socket.h>#if HAVE_SYS_SELECT_H#include <sys/select.h>#endif#ifdef HAVE_GETOPT_H#include <getopt.h>#endif#include "access/printtup.h"#include "access/xlog.h"#include "catalog/pg_type.h"#include "commands/async.h"#include "commands/prepare.h"#include "commands/trigger.h"#include "libpq/libpq.h"#include "libpq/pqformat.h"#include "libpq/pqsignal.h"#include "miscadmin.h"#include "nodes/print.h"#include "optimizer/cost.h"#include "optimizer/planner.h"#include "parser/analyze.h"#include "parser/parser.h"#include "rewrite/rewriteHandler.h"#include "storage/freespace.h"#include "storage/ipc.h"#include "storage/pg_shmem.h"#include "storage/proc.h"#include "storage/sinval.h"#include "tcop/fastpath.h"#include "tcop/pquery.h"#include "tcop/tcopprot.h"#include "tcop/utility.h"#include "utils/flatfiles.h"#include "utils/guc.h"#include "utils/lsyscache.h"#include "utils/memutils.h"#include "utils/ps_status.h"#include "mb/pg_wchar.h"#include "pgstat.h"extern int	optind;extern char *optarg;/* ---------------- *		global variables * ---------------- */const char *debug_query_string; /* for pgmonitor and log_min_error_statement *//* Note: whereToSendOutput is initialized for the bootstrap/standalone case */CommandDest whereToSendOutput = DestDebug;/* flag for logging end of session */bool		Log_disconnections = false;LogStmtLevel log_statement = LOGSTMT_NONE;/* GUC variable for maximum stack depth (measured in kilobytes) */int			max_stack_depth = 2048;/* ---------------- *		private variables * ---------------- *//* max_stack_depth converted to bytes for speed of checking */static int	max_stack_depth_bytes = 2048 * 1024;/* stack base pointer (initialized by PostgresMain) *//* Do not make static so PL/Java can modifiy it */char	   *stack_base_ptr = NULL;/* * Flag to mark SIGHUP. Whenever the main loop comes around it * will reread the configuration file. (Better than doing the * reading in the signal handler, ey?) */static volatile sig_atomic_t got_SIGHUP = false;/* * Flag to keep track of whether we have started a transaction. * For extended query protocol this has to be remembered across messages. */static bool xact_started = false;/* * Flag to indicate that we are doing the outer loop's read-from-client, * as opposed to any random read from client that might happen within * commands like COPY FROM STDIN. */static bool DoingCommandRead = false;/* * Flags to implement skip-till-Sync-after-error behavior for messages of * the extended query protocol. */static bool doing_extended_query_message = false;static bool ignore_till_sync = false;/* * If an unnamed prepared statement exists, it's stored here. * We keep it separate from the hashtable kept by commands/prepare.c * in order to reduce overhead for short-lived queries. */static MemoryContext unnamed_stmt_context = NULL;static PreparedStatement *unnamed_stmt_pstmt = NULL;static bool EchoQuery = false;	/* default don't echo *//* * people who want to use EOF should #define DONTUSENEWLINE in * tcop/tcopdebug.h */#ifndef TCOP_DONTUSENEWLINEstatic int	UseNewLine = 1;		/* Use newlines query delimiters (the default) */#elsestatic int	UseNewLine = 0;		/* Use EOF as query delimiters */#endif   /* TCOP_DONTUSENEWLINE *//* ---------------------------------------------------------------- *		decls for routines only used in this file * ---------------------------------------------------------------- */static int	InteractiveBackend(StringInfo inBuf);static int	SocketBackend(StringInfo inBuf);static int	ReadCommand(StringInfo inBuf);static bool log_after_parse(List *raw_parsetree_list,				const char *query_string, char **prepare_string);static List *pg_rewrite_queries(List *querytree_list);static void start_xact_command(void);static void finish_xact_command(void);static bool IsTransactionExitStmt(Node *parsetree);static bool IsTransactionExitStmtList(List *parseTrees);static bool IsTransactionStmtList(List *parseTrees);static void SigHupHandler(SIGNAL_ARGS);static void log_disconnections(int code, Datum arg);/* ---------------------------------------------------------------- *		routines to obtain user input * ---------------------------------------------------------------- *//* ---------------- *	InteractiveBackend() is called for user interactive connections * *	the string entered by the user is placed in its parameter inBuf, *	and we act like a Q message was received. * *	EOF is returned if end-of-file input is seen; time to shut down. * ---------------- */static intInteractiveBackend(StringInfo inBuf){	int			c;				/* character read from getc() */	bool		end = false;	/* end-of-input flag */	bool		backslashSeen = false;	/* have we seen a \ ? */	/*	 * display a prompt and obtain input from the user	 */	printf("backend> ");	fflush(stdout);	/* Reset inBuf to empty */	inBuf->len = 0;	inBuf->data[0] = '\0';	inBuf->cursor = 0;	for (;;)	{		if (UseNewLine)		{			/*			 * if we are using \n as a delimiter, then read characters until			 * the \n.			 */			while ((c = getc(stdin)) != EOF)			{				if (c == '\n')				{					if (backslashSeen)					{						/* discard backslash from inBuf */						inBuf->data[--inBuf->len] = '\0';						backslashSeen = false;						continue;					}					else					{						/* keep the newline character */						appendStringInfoChar(inBuf, '\n');						break;					}				}				else if (c == '\\')					backslashSeen = true;				else					backslashSeen = false;				appendStringInfoChar(inBuf, (char) c);			}			if (c == EOF)				end = true;		}		else		{			/*			 * otherwise read characters until EOF.			 */			while ((c = getc(stdin)) != EOF)				appendStringInfoChar(inBuf, (char) c);			if (inBuf->len == 0)				end = true;		}		if (end)			return EOF;		/*		 * otherwise we have a user query so process it.		 */		break;	}	/* Add '\0' to make it look the same as message case. */	appendStringInfoChar(inBuf, (char) '\0');	/*	 * if the query echo flag was given, print the query..	 */	if (EchoQuery)		printf("statement: %s\n", inBuf->data);	fflush(stdout);	return 'Q';}/* ---------------- *	SocketBackend()		Is called for frontend-backend connections * *	Returns the message type code, and loads message body data into inBuf. * *	EOF is returned if the connection is lost. * ---------------- */static intSocketBackend(StringInfo inBuf){	int			qtype;	/*	 * Get message type code from the frontend.	 */	qtype = pq_getbyte();	if (qtype == EOF)			/* frontend disconnected */	{		ereport(COMMERROR,				(errcode(ERRCODE_PROTOCOL_VIOLATION),				 errmsg("unexpected EOF on client connection")));		return qtype;	}	/*	 * Validate message type code before trying to read body; if we have lost	 * sync, better to say "command unknown" than to run out of memory because	 * we used garbage as a length word.	 *	 * This also gives us a place to set the doing_extended_query_message flag	 * as soon as possible.	 */	switch (qtype)	{		case 'Q':				/* simple query */			doing_extended_query_message = false;			if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)			{				/* old style without length word; convert */				if (pq_getstring(inBuf))				{					ereport(COMMERROR,							(errcode(ERRCODE_PROTOCOL_VIOLATION),							 errmsg("unexpected EOF on client connection")));					return EOF;				}			}			break;		case 'F':				/* fastpath function call */			/* we let fastpath.c cope with old-style input of this */			doing_extended_query_message = false;			break;		case 'X':				/* terminate */			doing_extended_query_message = false;			ignore_till_sync = false;			break;		case 'B':				/* bind */		case 'C':				/* close */		case 'D':				/* describe */		case 'E':				/* execute */		case 'H':				/* flush */		case 'P':				/* parse */			doing_extended_query_message = true;			/* these are only legal in protocol 3 */			if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)				ereport(FATAL,						(errcode(ERRCODE_PROTOCOL_VIOLATION),						 errmsg("invalid frontend message type %d", qtype)));			break;		case 'S':				/* sync */			/* stop any active skip-till-Sync */			ignore_till_sync = false;			/* mark not-extended, so that a new error doesn't begin skip */			doing_extended_query_message = false;			/* only legal in protocol 3 */			if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)				ereport(FATAL,						(errcode(ERRCODE_PROTOCOL_VIOLATION),						 errmsg("invalid frontend message type %d", qtype)));			break;		case 'd':				/* copy data */		case 'c':				/* copy done */		case 'f':				/* copy fail */			doing_extended_query_message = false;			/* these are only legal in protocol 3 */			if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)				ereport(FATAL,						(errcode(ERRCODE_PROTOCOL_VIOLATION),						 errmsg("invalid frontend message type %d", qtype)));			break;		default:			/*			 * Otherwise we got garbage from the frontend.	We treat this as			 * fatal because we have probably lost message boundary sync, and			 * there's no good way to recover.			 */			ereport(FATAL,					(errcode(ERRCODE_PROTOCOL_VIOLATION),					 errmsg("invalid frontend message type %d", qtype)));			break;	}	/*	 * In protocol version 3, all frontend messages have a length word next	 * after the type code; we can read the message contents independently of	 * the type.	 */	if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)	{		if (pq_getmessage(inBuf, 0))			return EOF;			/* suitable message already logged */	}	return qtype;}/* ---------------- *		ReadCommand reads a command from either the frontend or *		standard input, places it in inBuf, and returns the *		message type code (first byte of the message). *		EOF is returned if end of file. * ---------------- */static intReadCommand(StringInfo inBuf){	int			result;	if (whereToSendOutput == DestRemote)		result = SocketBackend(inBuf);	else		result = InteractiveBackend(inBuf);	return result;}/* * prepare_for_client_read -- set up to possibly block on client input * * This must be called immediately before any low-level read from the * client connection.  It is necessary to do it at a sufficiently low level * that there won't be any other operations except the read kernel call * itself between this call and the subsequent client_read_ended() call. * In particular there mustn't be use of malloc() or other potentially * non-reentrant libc functions.  This restriction makes it safe for us * to allow interrupt service routines to execute nontrivial code while * we are waiting for input. */voidprepare_for_client_read(void){	if (DoingCommandRead)	{		/* Enable immediate processing of asynchronous signals */		EnableNotifyInterrupt();		EnableCatchupInterrupt();		/* Allow "die" interrupt to be processed while waiting */		ImmediateInterruptOK = true;		/* And don't forget to detect one that already arrived */		QueryCancelPending = false;		CHECK_FOR_INTERRUPTS();	}}/* * client_read_ended -- get out of the client-input state */voidclient_read_ended(void){	if (DoingCommandRead)	{		ImmediateInterruptOK = false;		QueryCancelPending = false;		/* forget any CANCEL signal */		DisableNotifyInterrupt();		DisableCatchupInterrupt();	}}/* * Parse a query string and pass it through the rewriter. * * A list of Query nodes is returned, since the string might contain * multiple queries and/or the rewriter might expand one query to several. * * NOTE: this routine is no longer used for processing interactive queries, * but it is still needed for parsing of SQL function bodies. */List *pg_parse_and_rewrite(const char *query_string,	/* string to execute */					 Oid *paramTypes,	/* parameter types */					 int numParams)		/* number of parameters */{	List	   *raw_parsetree_list;

⌨️ 快捷键说明

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