postgres.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,551 行 · 第 1/5 页

C
2,551
字号
	{		Query	   *query = (Query *) lfirst(portal->parseTrees);		if (query->commandType == CMD_UTILITY &&			query->utilityStmt != NULL &&			IsA(query->utilityStmt, TransactionStmt))		{			TransactionStmt *stmt = (TransactionStmt *) query->utilityStmt;			is_trans_stmt = true;			if (stmt->kind == TRANS_STMT_COMMIT ||				stmt->kind == TRANS_STMT_ROLLBACK)				is_trans_exit = true;		}	}	/*	 * Create dest receiver in MessageContext (we don't want it in	 * transaction context, because that may get deleted if portal	 * contains VACUUM).	 */	receiver = CreateDestReceiver(dest, portal);	/*	 * Ensure we are in a transaction command (this should normally be the	 * case already due to prior BIND).	 */	start_xact_command();	/*	 * If we are in aborted transaction state, the only portals we can	 * actually run are those containing COMMIT or ROLLBACK commands.	 */	if (IsAbortedTransactionBlockState())	{		if (!is_trans_exit)			ereport(ERROR,					(errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),					 errmsg("current transaction is aborted, "					 "commands ignored until end of transaction block")));	}	/* Check for cancel signal before we start execution */	CHECK_FOR_INTERRUPTS();	/*	 * Okay to run the portal.	 */	if (max_rows <= 0)		max_rows = FETCH_ALL;	completed = PortalRun(portal,						  max_rows,						  receiver,						  receiver,						  completionTag);	(*receiver->rDestroy) (receiver);	if (completed)	{		if (is_trans_stmt)		{			/*			 * If this was a transaction control statement, commit it.	We			 * will start a new xact command for the next command (if			 * any).			 */			finish_xact_command();		}		else		{			/*			 * We need a CommandCounterIncrement after every query, except			 * those that start or end a transaction block.			 */			CommandCounterIncrement();		}		/* Send appropriate CommandComplete to client */		EndCommand(completionTag, dest);	}	else	{		/* Portal run not complete, so send PortalSuspended */		if (whereToSendOutput == Remote)			pq_putemptymessage('s');	}	debug_query_string = NULL;}/* * exec_describe_statement_message * * Process a "Describe" message for a prepared statement */static voidexec_describe_statement_message(const char *stmt_name){	PreparedStatement *pstmt;	TupleDesc	tupdesc;	List	   *l;	StringInfoData buf;	/* Find prepared statement */	if (stmt_name[0] != '\0')		pstmt = FetchPreparedStatement(stmt_name, true);	else	{		/* special-case the unnamed statement */		pstmt = unnamed_stmt_pstmt;		if (!pstmt)			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_PSTATEMENT),				   errmsg("unnamed prepared statement does not exist")));	}	if (whereToSendOutput != Remote)		return;					/* can't actually do anything... */	/*	 * First describe the parameters...	 */	pq_beginmessage(&buf, 't'); /* parameter description message type */	pq_sendint(&buf, length(pstmt->argtype_list), 2);	foreach(l, pstmt->argtype_list)	{		Oid			ptype = lfirsto(l);		pq_sendint(&buf, (int) ptype, 4);	}	pq_endmessage(&buf);	/*	 * Next send RowDescription or NoData to describe the result...	 */	tupdesc = FetchPreparedStatementResultDesc(pstmt);	if (tupdesc)	{		List	   *targetlist;		if (ChoosePortalStrategy(pstmt->query_list) == PORTAL_ONE_SELECT)			targetlist = ((Query *) lfirst(pstmt->query_list))->targetList;		else			targetlist = NIL;		SendRowDescriptionMessage(tupdesc, targetlist, NULL);	}	else		pq_putemptymessage('n');	/* NoData */}/* * exec_describe_portal_message * * Process a "Describe" message for a portal */static voidexec_describe_portal_message(const char *portal_name){	Portal		portal;	portal = GetPortalByName(portal_name);	if (!PortalIsValid(portal))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_CURSOR),				 errmsg("portal \"%s\" does not exist", portal_name)));	if (whereToSendOutput != Remote)		return;					/* can't actually do anything... */	if (portal->tupDesc)	{		List	   *targetlist;		if (portal->strategy == PORTAL_ONE_SELECT)			targetlist = ((Query *) lfirst(portal->parseTrees))->targetList;		else			targetlist = NIL;		SendRowDescriptionMessage(portal->tupDesc, targetlist,								  portal->formats);	}	else		pq_putemptymessage('n');	/* NoData */}/* * Convenience routines for starting/committing a single command. */static voidstart_xact_command(void){	if (!xact_started)	{		ereport(DEBUG3,				(errmsg_internal("StartTransactionCommand")));		StartTransactionCommand();		/* Set statement timeout running, if any */		if (StatementTimeout > 0)			enable_sig_alarm(StatementTimeout, true);		xact_started = true;	}}static voidfinish_xact_command(void){	if (xact_started)	{		/* Invoke IMMEDIATE constraint triggers */		DeferredTriggerEndQuery();		/* Cancel any active statement timeout before committing */		disable_sig_alarm(true);		/* Now commit the command */		ereport(DEBUG3,				(errmsg_internal("CommitTransactionCommand")));		CommitTransactionCommand();#ifdef MEMORY_CONTEXT_CHECKING		/* Check all memory contexts that weren't freed during commit */		/* (those that were, were checked before being deleted) */		MemoryContextCheck(TopMemoryContext);#endif#ifdef SHOW_MEMORY_STATS		/* Print mem stats after each commit for leak tracking */		if (ShowStats)			MemoryContextStats(TopMemoryContext);#endif		xact_started = false;	}}/* -------------------------------- *		signal handler routines used in PostgresMain() * -------------------------------- *//* * quickdie() occurs when signalled SIGQUIT by the postmaster. * * Some backend has bought the farm, * so we need to stop what we're doing and exit. */voidquickdie(SIGNAL_ARGS){	PG_SETMASK(&BlockSig);	/*	 * Ideally this should be ereport(FATAL), but then we'd not get	 * control back (perhaps could fix by doing local sigsetjmp?)	 */	ereport(WARNING,			(errcode(ERRCODE_CRASH_SHUTDOWN),		errmsg("terminating connection because of crash of another server process"),	   errdetail("The postmaster has commanded this server process to roll back"				 " the current transaction and exit, because another"				 " server process exited abnormally and possibly corrupted"				 " shared memory."),			 errhint("In a moment you should be able to reconnect to the"					 " database and repeat your command.")));	/*	 * DO NOT proc_exit() -- we're here because shared memory may be	 * corrupted, so we don't want to try to clean up our transaction.	 * Just nail the windows shut and get out of town.	 *	 * Note we do exit(1) not exit(0).	This is to force the postmaster into	 * a system reset cycle if some idiot DBA sends a manual SIGQUIT to a	 * random backend.	This is necessary precisely because we don't clean	 * up our shared memory state.	 */	exit(1);}/* * Shutdown signal from postmaster: abort transaction and exit * at soonest convenient time */voiddie(SIGNAL_ARGS){	int			save_errno = errno;	/* Don't joggle the elbow of proc_exit */	if (!proc_exit_inprogress)	{		InterruptPending = true;		ProcDiePending = true;		/*		 * If it's safe to interrupt, and we're waiting for input or a		 * lock, service the interrupt immediately		 */		if (ImmediateInterruptOK && InterruptHoldoffCount == 0 &&			CritSectionCount == 0)		{			/* bump holdoff count to make ProcessInterrupts() a no-op */			/* until we are done getting ready for it */			InterruptHoldoffCount++;			DisableNotifyInterrupt();			/* Make sure CheckDeadLock won't run while shutting down... */			LockWaitCancel();			InterruptHoldoffCount--;			ProcessInterrupts();		}	}	errno = save_errno;}/* * Timeout or shutdown signal from postmaster during client authentication. * Simply exit(0). * * XXX: possible future improvement: try to send a message indicating * why we are disconnecting.  Problem is to be sure we don't block while * doing so, nor mess up the authentication message exchange. */voidauthdie(SIGNAL_ARGS){	exit(0);}/* * Query-cancel signal from postmaster: abort current transaction * at soonest convenient time */static voidStatementCancelHandler(SIGNAL_ARGS){	int			save_errno = errno;	/*	 * Don't joggle the elbow of proc_exit, nor an already-in-progress	 * abort	 */	if (!proc_exit_inprogress && !InError)	{		InterruptPending = true;		QueryCancelPending = true;		/*		 * If it's safe to interrupt, and we're waiting for a lock,		 * service the interrupt immediately.  No point in interrupting if		 * we're waiting for input, however.		 */		if (ImmediateInterruptOK && InterruptHoldoffCount == 0 &&			CritSectionCount == 0)		{			/* bump holdoff count to make ProcessInterrupts() a no-op */			/* until we are done getting ready for it */			InterruptHoldoffCount++;			if (LockWaitCancel())			{				DisableNotifyInterrupt();				InterruptHoldoffCount--;				ProcessInterrupts();			}			else				InterruptHoldoffCount--;		}	}	errno = save_errno;}/* signal handler for floating point exception */static voidFloatExceptionHandler(SIGNAL_ARGS){	ereport(ERROR,			(errcode(ERRCODE_FLOATING_POINT_EXCEPTION),			 errmsg("floating-point exception"),		   errdetail("An invalid floating-point operation was signaled. "					 "This probably means an out-of-range result or an "					 "invalid operation, such as division by zero.")));}/* SIGHUP: set flag to re-read config file at next convenient time */static voidSigHupHandler(SIGNAL_ARGS){	got_SIGHUP = true;}/* * ProcessInterrupts: out-of-line portion of CHECK_FOR_INTERRUPTS() macro * * If an interrupt condition is pending, and it's safe to service it, * then clear the flag and accept the interrupt.  Called only when * InterruptPending is true. */voidProcessInterrupts(void){	/* OK to accept interrupt now? */	if (InterruptHoldoffCount != 0 || CritSectionCount != 0)		return;	InterruptPending = false;	if (ProcDiePending)	{		ProcDiePending = false;		QueryCancelPending = false;		/* ProcDie trumps QueryCancel */		ImmediateInterruptOK = false;	/* not idle anymore */		DisableNotifyInterrupt();		ereport(FATAL,				(errcode(ERRCODE_ADMIN_SHUTDOWN),		 errmsg("terminating connection due to administrator command")));	}	if (QueryCancelPending)	{		QueryCancelPending = false;		ImmediateInterruptOK = false;	/* not idle anymore */		DisableNotifyInterrupt();		ereport(ERROR,				(errcode(ERRCODE_QUERY_CANCELED),				 errmsg("canceling query due to user request")));	}	/* If we get here, do nothing (probably, QueryCancelPending was reset) */}static voidusage(char *progname){	printf(gettext("%s is the PostgreSQL stand-alone backend.  It is not\nintended to be used by normal users.\n\n"), progname);	printf(gettext("Usage:\n  %s [OPTION]... [DBNAME]\n\n"), progname);	printf(gettext("Options:\n"));#ifdef USE_ASSERT_CHECKING	printf(gettext("  -A 1|0          enable/disable run-time assert checking\n"));#endif	printf(gettext("  -B NBUFFERS     number of shared buffers\n"));	printf(gettext("  -c NAME=VALUE   set run-time parameter\n"));	printf(gettext("  -d 0-5          debugging level (0 is off)\n"));	printf(gettext("  -D DATADIR      database directory\n"));	printf(gettext("  -e              use European date input format (DMY)\n"));	printf(gettext("  -E              echo query before execution\n"));	printf(gettext("  -F              turn fsync off\n"));	printf(gettext("  -N              do not use newline as interactive query delimiter\n"));	printf(gettext("  -o FILENAME     send stdout and stderr to given file\n"));	printf(gettext("  -P              disable system indexes\n"));	printf(gettext("  -s              show statistics after each query\n"));	printf(gettext("  -S SORT-MEM     set amount of memory for sorts (in kbytes)\n"));	printf(gettext("  --describe-config  describe configuration parameters, then exit\n"));	printf(gettext("  --help          show this help, then exit\n"));	printf(gettext("  --version       output version information, then exit\n"));	printf(gettext("\nDeveloper options:\n"));	printf(gettext("  -f s|i|n|m|h    forbid use of some plan types\n"));	printf(gettext("  -i              do not execute queries\n"));	printf(gettext("  -O              allow system table structure changes\n"));	printf(gettext("  -t pa|pl|ex     show timings after each query\n"));	printf(gettext("  -W NUM          wait NUM seconds to allow attach from a debugger\n"));	printf(gettext("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));}/* ---------------------------------------------------------------- * PostgresMain *	   postgres main loop -- all backends, interactive or otherwise start here * * argc/argv are the command line arguments to be used.  (When being forked * by the postmaster, these are not the original argv array of the process.) * username is the (possibly authenticated) PostgreSQL user name to be used * for the session. * ---------------------------------------------------------------- */intPostgresMain(int argc, char *argv[], const char *username){	int			flag;	const char *dbname = NULL;	char	   *potential_DataDir = NULL;	bool		secure;	int			errs = 0;	int			debug_flag = 0;	GucContext	ctx,				debug_context;	GucSource	gucsource;	char	   *tmp;	int			firstchar;	StringInfoData	input_message;	volatile bool send_rfq = true;	/*	 * Catch standard options before doing much else.  This even works on	 * systems without getopt_long.	 */	if (!IsUnderPostmaster && argc > 1)	{		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)		{			usage(argv[0]);			exit(0);		}		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)

⌨️ 快捷键说明

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