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

📄 prepare.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * prepare.c *	  Prepareable SQL statements via PREPARE, EXECUTE and DEALLOCATE * * This module also implements storage of prepared statements that are * accessed via the extended FE/BE query protocol. * * * Copyright (c) 2002-2005, PostgreSQL Global Development Group * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.42.2.1 2005/12/14 17:06:37 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "commands/explain.h"#include "commands/prepare.h"#include "executor/executor.h"#include "utils/guc.h"#include "optimizer/planner.h"#include "rewrite/rewriteHandler.h"#include "tcop/pquery.h"#include "tcop/tcopprot.h"#include "tcop/utility.h"#include "utils/hsearch.h"#include "utils/memutils.h"/* * The hash table in which prepared queries are stored. This is * per-backend: query plans are not shared between backends. * The keys for this hash table are the arguments to PREPARE and EXECUTE * (statement names); the entries are PreparedStatement structs. */static HTAB *prepared_queries = NULL;static void InitQueryHashTable(void);static ParamListInfo EvaluateParams(EState *estate,			   List *params, List *argtypes);/* * Implements the 'PREPARE' utility statement. */voidPrepareQuery(PrepareStmt *stmt){	const char *commandTag;	Query	   *query;	List	   *query_list,			   *plan_list;	/*	 * Disallow empty-string statement name (conflicts with protocol-level	 * unnamed statement).	 */	if (!stmt->name || stmt->name[0] == '\0')		ereport(ERROR,				(errcode(ERRCODE_INVALID_PSTATEMENT_DEFINITION),				 errmsg("invalid statement name: must not be empty")));	switch (stmt->query->commandType)	{		case CMD_SELECT:			commandTag = "SELECT";			break;		case CMD_INSERT:			commandTag = "INSERT";			break;		case CMD_UPDATE:			commandTag = "UPDATE";			break;		case CMD_DELETE:			commandTag = "DELETE";			break;		default:			ereport(ERROR,					(errcode(ERRCODE_INVALID_PSTATEMENT_DEFINITION),					 errmsg("utility statements cannot be prepared")));			commandTag = NULL;	/* keep compiler quiet */			break;	}	/*	 * Parse analysis is already done, but we must still rewrite and plan the	 * query.	 */	/*	 * Because the planner is not cool about not scribbling on its input, we	 * make a preliminary copy of the source querytree.  This prevents	 * problems in the case that the PREPARE is in a portal or plpgsql	 * function and is executed repeatedly.  (See also the same hack in	 * DECLARE CURSOR and EXPLAIN.)  XXX the planner really shouldn't modify	 * its input ... FIXME someday.	 */	query = copyObject(stmt->query);	/* Rewrite the query. The result could be 0, 1, or many queries. */	AcquireRewriteLocks(query);	query_list = QueryRewrite(query);	/* Generate plans for queries.	Snapshot is already set. */	plan_list = pg_plan_queries(query_list, NULL, false);	/*	 * Save the results.  We don't have the query string for this PREPARE, but	 * we do have the string we got from the client, so use that.	 */	StorePreparedStatement(stmt->name,						   debug_query_string,						   commandTag,						   query_list,						   plan_list,						   stmt->argtype_oids);}/* * Implements the 'EXECUTE' utility statement. */voidExecuteQuery(ExecuteStmt *stmt, DestReceiver *dest, char *completionTag){	PreparedStatement *entry;	char	   *query_string;	List	   *query_list,			   *plan_list;	MemoryContext qcontext;	ParamListInfo paramLI = NULL;	EState	   *estate = NULL;	Portal		portal;	/* Look it up in the hash table */	entry = FetchPreparedStatement(stmt->name, true);	query_string = entry->query_string;	query_list = entry->query_list;	plan_list = entry->plan_list;	qcontext = entry->context;	Assert(list_length(query_list) == list_length(plan_list));	/* Evaluate parameters, if any */	if (entry->argtype_list != NIL)	{		/*		 * Need an EState to evaluate parameters; must not delete it till end		 * of query, in case parameters are pass-by-reference.		 */		estate = CreateExecutorState();		paramLI = EvaluateParams(estate, stmt->params, entry->argtype_list);	}	/*	 * Create a new portal to run the query in	 */	portal = CreateNewPortal();	/*	 * For CREATE TABLE / AS EXECUTE, make a copy of the stored query so that	 * we can modify its destination (yech, but this has always been ugly).	 * For regular EXECUTE we can just use the stored query where it sits,	 * since the executor is read-only.	 */	if (stmt->into)	{		MemoryContext oldContext;		Query	   *query;		oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));		if (query_string)			query_string = pstrdup(query_string);		query_list = copyObject(query_list);		plan_list = copyObject(plan_list);		qcontext = PortalGetHeapMemory(portal);		if (list_length(query_list) != 1)			ereport(ERROR,					(errcode(ERRCODE_WRONG_OBJECT_TYPE),					 errmsg("prepared statement is not a SELECT")));		query = (Query *) linitial(query_list);		if (query->commandType != CMD_SELECT)			ereport(ERROR,					(errcode(ERRCODE_WRONG_OBJECT_TYPE),					 errmsg("prepared statement is not a SELECT")));		query->into = copyObject(stmt->into);		MemoryContextSwitchTo(oldContext);	}	PortalDefineQuery(portal,					  query_string,					  entry->commandTag,					  query_list,					  plan_list,					  qcontext);	/*	 * Run the portal to completion.	 */	PortalStart(portal, paramLI, ActiveSnapshot);	(void) PortalRun(portal, FETCH_ALL, dest, dest, completionTag);	PortalDrop(portal, false);	if (estate)		FreeExecutorState(estate);	/* No need to pfree other memory, MemoryContext will be reset */}/* * Evaluates a list of parameters, using the given executor state. It * requires a list of the parameter expressions themselves, and a list of * their types. It returns a filled-in ParamListInfo -- this can later * be passed to CreateQueryDesc(), which allows the executor to make use * of the parameters during query execution. */static ParamListInfoEvaluateParams(EState *estate, List *params, List *argtypes){	int			nargs = list_length(argtypes);	ParamListInfo paramLI;	List	   *exprstates;	ListCell   *le,			   *la;	int			i = 0;	/* Parser should have caught this error, but check for safety */	if (list_length(params) != nargs)		elog(ERROR, "wrong number of arguments");	exprstates = (List *) ExecPrepareExpr((Expr *) params, estate);	paramLI = (ParamListInfo)		palloc0((nargs + 1) * sizeof(ParamListInfoData));	forboth(le, exprstates, la, argtypes)	{		ExprState  *n = lfirst(le);		bool		isNull;		paramLI[i].value = ExecEvalExprSwitchContext(n,											  GetPerTupleExprContext(estate),													 &isNull,													 NULL);		paramLI[i].kind = PARAM_NUM;		paramLI[i].id = i + 1;		paramLI[i].ptype = lfirst_oid(la);		paramLI[i].isnull = isNull;		i++;	}	paramLI[i].kind = PARAM_INVALID;	return paramLI;}/* * Initialize query hash table upon first use. */static voidInitQueryHashTable(void){	HASHCTL		hash_ctl;	MemSet(&hash_ctl, 0, sizeof(hash_ctl));	hash_ctl.keysize = NAMEDATALEN;	hash_ctl.entrysize = sizeof(PreparedStatement);	prepared_queries = hash_create("Prepared Queries",								   32,								   &hash_ctl,								   HASH_ELEM);}/* * Store all the data pertaining to a query in the hash table using * the specified key. A copy of the data is made in a memory context belonging * to the hash entry, so the caller can dispose of their copy. * * Exception: commandTag is presumed to be a pointer to a constant string, * or possibly NULL, so it need not be copied.	Note that commandTag should * be NULL only if the original query (before rewriting) was empty. */voidStorePreparedStatement(const char *stmt_name,					   const char *query_string,					   const char *commandTag,					   List *query_list,					   List *plan_list,					   List *argtype_list){	PreparedStatement *entry;	MemoryContext oldcxt,				entrycxt;	char	   *qstring;	char		key[NAMEDATALEN];	bool		found;	/* Initialize the hash table, if necessary */	if (!prepared_queries)		InitQueryHashTable();	/* Check for pre-existing entry of same name */	/* See notes in FetchPreparedStatement */	StrNCpy(key, stmt_name, sizeof(key));	hash_search(prepared_queries, key, HASH_FIND, &found);	if (found)		ereport(ERROR,				(errcode(ERRCODE_DUPLICATE_PSTATEMENT),				 errmsg("prepared statement \"%s\" already exists",						stmt_name)));	/* Make a permanent memory context for the hashtable entry */	entrycxt = AllocSetContextCreate(TopMemoryContext,									 stmt_name,									 ALLOCSET_SMALL_MINSIZE,									 ALLOCSET_SMALL_INITSIZE,									 ALLOCSET_SMALL_MAXSIZE);

⌨️ 快捷键说明

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