postgres.c

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

C
2,551
字号
	 * Switch to appropriate context for constructing parsetrees.	 *	 * We have two strategies depending on whether the prepared statement is	 * named or not.  For a named prepared statement, we do parsing in	 * MessageContext and copy the finished trees into the prepared	 * statement's private context; then the reset of MessageContext	 * releases temporary space used by parsing and planning.  For an	 * unnamed prepared statement, we assume the statement isn't going to	 * hang around long, so getting rid of temp space quickly is probably	 * not worth the costs of copying parse/plan trees.  So in this case,	 * we set up a special context for the unnamed statement, and do all	 * the parsing/planning therein.	 */	is_named = (stmt_name[0] != '\0');	if (is_named)	{		/* Named prepared statement --- parse in MessageContext */		oldcontext = MemoryContextSwitchTo(MessageContext);	}	else	{		/* Unnamed prepared statement --- release any prior unnamed stmt */		unnamed_stmt_pstmt = NULL;		if (unnamed_stmt_context)		{			DropDependentPortals(unnamed_stmt_context);			MemoryContextDelete(unnamed_stmt_context);		}		unnamed_stmt_context = NULL;		/* create context for parsing/planning */		unnamed_stmt_context =			AllocSetContextCreate(TopMemoryContext,								  "unnamed prepared statement",								  ALLOCSET_DEFAULT_MINSIZE,								  ALLOCSET_DEFAULT_INITSIZE,								  ALLOCSET_DEFAULT_MAXSIZE);		oldcontext = MemoryContextSwitchTo(unnamed_stmt_context);	}	QueryContext = CurrentMemoryContext;	/*	 * Do basic parsing of the query or queries (this should be safe even	 * if we are in aborted transaction state!)	 */	parsetree_list = pg_parse_query(query_string);	/*	 * We only allow a single user statement in a prepared statement. This	 * is mainly to keep the protocol simple --- otherwise we'd need to	 * worry about multiple result tupdescs and things like that.	 */	if (length(parsetree_list) > 1)		ereport(ERROR,				(errcode(ERRCODE_SYNTAX_ERROR),				 errmsg("cannot insert multiple commands into a prepared statement")));	if (parsetree_list != NIL)	{		Node	   *parsetree = (Node *) lfirst(parsetree_list);		int			i;		/*		 * Get the command name for possible use in status display.		 */		commandTag = CreateCommandTag(parsetree);		/*		 * If we are in an aborted transaction, reject all commands except		 * COMMIT/ROLLBACK.  It is important that this test occur before		 * we try to do parse analysis, rewrite, or planning, since all		 * those phases try to do database accesses, which may fail in		 * abort state. (It might be safe to allow some additional utility		 * commands in this state, but not many...)		 */		if (IsAbortedTransactionBlockState())		{			bool		allowit = false;			if (IsA(parsetree, TransactionStmt))			{				TransactionStmt *stmt = (TransactionStmt *) parsetree;				if (stmt->kind == TRANS_STMT_COMMIT ||					stmt->kind == TRANS_STMT_ROLLBACK)					allowit = true;			}			if (!allowit)				ereport(ERROR,						(errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),						 errmsg("current transaction is aborted, "					 "commands ignored until end of transaction block")));		}		/*		 * OK to analyze, rewrite, and plan this query.  Note that the		 * originally specified parameter set is not required to be		 * complete, so we have to use parse_analyze_varparams().		 */		if (log_parser_stats)			ResetUsage();		querytree_list = parse_analyze_varparams(parsetree,												 &paramTypes,												 &numParams);		/*		 * Check all parameter types got determined, and convert array		 * representation to a list for storage.		 */		param_list = NIL;		for (i = 0; i < numParams; i++)		{			Oid			ptype = paramTypes[i];			if (ptype == InvalidOid || ptype == UNKNOWNOID)				ereport(ERROR,						(errcode(ERRCODE_INDETERMINATE_DATATYPE),				  errmsg("could not determine data type of parameter $%d",						 i + 1)));			param_list = lappendo(param_list, ptype);		}		if (log_parser_stats)			ShowUsage("PARSE ANALYSIS STATISTICS");		querytree_list = pg_rewrite_queries(querytree_list);		plantree_list = pg_plan_queries(querytree_list, true);	}	else	{		/* Empty input string.	This is legal. */		commandTag = NULL;		querytree_list = NIL;		plantree_list = NIL;		param_list = NIL;	}	/* If we got a cancel signal in analysis or planning, quit */	CHECK_FOR_INTERRUPTS();	/*	 * Store the query as a prepared statement.  See above comments.	 */	if (is_named)	{		StorePreparedStatement(stmt_name,							   query_string,							   commandTag,							   querytree_list,							   plantree_list,							   param_list);	}	else	{		PreparedStatement *pstmt;		pstmt = (PreparedStatement *) palloc0(sizeof(PreparedStatement));		/* query_string needs to be copied into unnamed_stmt_context */		pstmt->query_string = pstrdup(query_string);		/* the rest is there already */		pstmt->commandTag = commandTag;		pstmt->query_list = querytree_list;		pstmt->plan_list = plantree_list;		pstmt->argtype_list = param_list;		pstmt->context = unnamed_stmt_context;		/* Now the unnamed statement is complete and valid */		unnamed_stmt_pstmt = pstmt;	}	MemoryContextSwitchTo(oldcontext);	QueryContext = NULL;	/*	 * We do NOT close the open transaction command here; that only	 * happens when the client sends Sync.	Instead, do	 * CommandCounterIncrement just in case something happened during	 * parse/plan.	 */	CommandCounterIncrement();	/*	 * Send ParseComplete.	 */	if (whereToSendOutput == Remote)		pq_putemptymessage('1');	if (save_log_statement_stats)		ShowUsage("PARSE MESSAGE STATISTICS");	debug_query_string = NULL;}/* * exec_bind_message * * Process a "Bind" message to create a portal from a prepared statement */static voidexec_bind_message(StringInfo input_message){	const char *portal_name;	const char *stmt_name;	int			numPFormats;	int16	   *pformats = NULL;	int			numParams;	int			numRFormats;	int16	   *rformats = NULL;	int			i;	PreparedStatement *pstmt;	Portal		portal;	ParamListInfo params;	pgstat_report_activity("<BIND>");	set_ps_display("BIND");	/*	 * Start up a transaction command so we can call functions etc. (Note	 * that this will normally change current memory context.) Nothing	 * happens if we are already in one.	 */	start_xact_command();	/* Switch back to message context */	MemoryContextSwitchTo(MessageContext);	/* Get the fixed part of the message */	portal_name = pq_getmsgstring(input_message);	stmt_name = pq_getmsgstring(input_message);	/* Get the parameter format codes */	numPFormats = pq_getmsgint(input_message, 2);	if (numPFormats > 0)	{		pformats = (int16 *) palloc(numPFormats * sizeof(int16));		for (i = 0; i < numPFormats; i++)			pformats[i] = pq_getmsgint(input_message, 2);	}	/* Get the parameter value count */	numParams = pq_getmsgint(input_message, 2);	if (numPFormats > 1 && numPFormats != numParams)		ereport(ERROR,				(errcode(ERRCODE_PROTOCOL_VIOLATION),		errmsg("bind message has %d parameter formats but %d parameters",			   numPFormats, numParams)));	/* 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 (numParams != length(pstmt->argtype_list))		ereport(ERROR,				(errcode(ERRCODE_PROTOCOL_VIOLATION),				 errmsg("bind message supplies %d parameters, but prepared statement \"%s\" requires %d",					numParams, stmt_name, length(pstmt->argtype_list))));	/*	 * Create the portal.  Allow silent replacement of an existing portal	 * only if the unnamed portal is specified.	 */	if (portal_name[0] == '\0')		portal = CreatePortal(portal_name, true, true);	else		portal = CreatePortal(portal_name, false, false);	PortalDefineQuery(portal,					  pstmt->query_string,					  pstmt->commandTag,					  pstmt->query_list,					  pstmt->plan_list,					  pstmt->context);	/*	 * Fetch parameters, if any, and store in the portal's memory context.	 *	 * In an aborted transaction, we can't risk calling user-defined	 * functions, but we can't fail to Bind either, so bind all parameters	 * to null values.	 */	if (numParams > 0)	{		bool		isaborted = IsAbortedTransactionBlockState();		List	   *l;		MemoryContext oldContext;		oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));		params = (ParamListInfo)			palloc0((numParams + 1) * sizeof(ParamListInfoData));		i = 0;		foreach(l, pstmt->argtype_list)		{			Oid			ptype = lfirsto(l);			int32		plength;			bool		isNull;			plength = pq_getmsgint(input_message, 4);			isNull = (plength == -1);			if (!isNull)			{				const char *pvalue = pq_getmsgbytes(input_message, plength);				if (isaborted)				{					/* We don't bother to check the format in this case */					isNull = true;				}				else				{					int16		pformat;					StringInfoData pbuf;					char		csave;					if (numPFormats > 1)						pformat = pformats[i];					else if (numPFormats > 0)						pformat = pformats[0];					else						pformat = 0;	/* default = text */					/*					 * Rather than copying data around, we just set up a					 * phony StringInfo pointing to the correct portion of					 * the message buffer.	We assume we can scribble on					 * the message buffer so as to maintain the convention					 * that StringInfos have a trailing null.  This is					 * grotty but is a big win when dealing with very					 * large parameter strings.					 */					pbuf.data = (char *) pvalue;					pbuf.maxlen = plength + 1;					pbuf.len = plength;					pbuf.cursor = 0;					csave = pbuf.data[plength];					pbuf.data[plength] = '\0';					if (pformat == 0)					{						Oid			typInput;						Oid			typElem;						char	   *pstring;						getTypeInputInfo(ptype, &typInput, &typElem);						/*						 * We have to do encoding conversion before						 * calling the typinput routine.						 */						pstring = (char *)							pg_client_to_server((unsigned char *) pbuf.data,												plength);						params[i].value =							OidFunctionCall3(typInput,											 CStringGetDatum(pstring),											 ObjectIdGetDatum(typElem),											 Int32GetDatum(-1));						/* Free result of encoding conversion, if any */						if (pstring != pbuf.data)							pfree(pstring);					}					else if (pformat == 1)					{						Oid			typReceive;						Oid			typElem;						/*						 * Call the parameter type's binary input						 * converter						 */						getTypeBinaryInputInfo(ptype, &typReceive, &typElem);						params[i].value =							OidFunctionCall2(typReceive,											 PointerGetDatum(&pbuf),											 ObjectIdGetDatum(typElem));						/* Trouble if it didn't eat the whole buffer */						if (pbuf.cursor != pbuf.len)							ereport(ERROR,									(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),									 errmsg("incorrect binary data format in bind parameter %d",											i + 1)));					}					else					{						ereport(ERROR,								(errcode(ERRCODE_INVALID_PARAMETER_VALUE),								 errmsg("unsupported format code: %d",										pformat)));					}					/* Restore message buffer contents */					pbuf.data[plength] = csave;				}			}			params[i].kind = PARAM_NUM;			params[i].id = i + 1;			params[i].isnull = isNull;			i++;		}		params[i].kind = PARAM_INVALID;		MemoryContextSwitchTo(oldContext);	}	else		params = NULL;	/* Get the result format codes */	numRFormats = pq_getmsgint(input_message, 2);	if (numRFormats > 0)	{		rformats = (int16 *) palloc(numRFormats * sizeof(int16));		for (i = 0; i < numRFormats; i++)			rformats[i] = pq_getmsgint(input_message, 2);	}	pq_getmsgend(input_message);	/*	 * Start portal execution.	 */	PortalStart(portal, params);	/*	 * Apply the result format requests to the portal.	 */	PortalSetResultFormat(portal, numRFormats, rformats);	/*	 * Send BindComplete.	 */	if (whereToSendOutput == Remote)		pq_putemptymessage('2');}/* * exec_execute_message * * Process an "Execute" message for a portal */static voidexec_execute_message(const char *portal_name, long max_rows){	CommandDest dest;	DestReceiver *receiver;	Portal		portal;	bool		is_trans_stmt = false;	bool		is_trans_exit = false;	bool		completed;	char		completionTag[COMPLETION_TAG_BUFSIZE];	/* Adjust destination to tell printtup.c what to do */	dest = whereToSendOutput;	if (dest == Remote)		dest = RemoteExecute;	portal = GetPortalByName(portal_name);	if (!PortalIsValid(portal))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_CURSOR),				 errmsg("portal \"%s\" does not exist", portal_name)));	/*	 * If the original query was a null string, just return	 * EmptyQueryResponse.	 */	if (portal->commandTag == NULL)	{		Assert(portal->parseTrees == NIL);		NullCommand(dest);		return;	}	if (portal->sourceText)	{		debug_query_string = portal->sourceText;		pgstat_report_activity(portal->sourceText);	}	else	{		debug_query_string = "execute message";		pgstat_report_activity("<EXECUTE>");	}	set_ps_display(portal->commandTag);	BeginCommand(portal->commandTag, dest);	/* Check for transaction-control commands */	if (length(portal->parseTrees) == 1)

⌨️ 快捷键说明

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