pquery.c 8.7 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * pquery.c
4
 *	  POSTGRES process query command code
5
 *
B
Add:  
Bruce Momjian 已提交
6 7
 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
 * Portions Copyright (c) 1994, Regents of the University of California
8 9 10
 *
 *
 * IDENTIFICATION
11
 *	  $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.34 2000/06/12 03:40:40 momjian Exp $
12 13 14
 *
 *-------------------------------------------------------------------------
 */
B
Bruce Momjian 已提交
15

16 17
#include "postgres.h"

18
#include "commands/command.h"
19 20 21
#include "executor/execdefs.h"
#include "executor/executor.h"
#include "tcop/pquery.h"
M
 
Marc G. Fournier 已提交
22
#include "utils/ps_status.h"
23

24
static char *CreateOperationTag(int operationType);
25
static void ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset,
B
Bruce Momjian 已提交
26
				 Node *limcount);
27

28 29

/* ----------------------------------------------------------------
30
 *		CreateQueryDesc
31 32
 * ----------------------------------------------------------------
 */
33
QueryDesc  *
34 35
CreateQueryDesc(Query *parsetree,
				Plan *plantree,
36
				CommandDest dest)
37
{
38
	QueryDesc  *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
39 40 41 42 43 44

	qd->operation = parsetree->commandType;		/* operation */
	qd->parsetree = parsetree;	/* parse tree */
	qd->plantree = plantree;	/* plan */
	qd->dest = dest;			/* output dest */
	return qd;
45 46 47
}

/* ----------------------------------------------------------------
48
 *		CreateExecutorState
49
 *
50
 *		Note: this may someday take parameters -cim 9/18/89
51 52
 * ----------------------------------------------------------------
 */
53
EState *
54
CreateExecutorState(void)
55
{
56
	EState	   *state;
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74

	/* ----------------
	 *	create a new executor state
	 * ----------------
	 */
	state = makeNode(EState);

	/* ----------------
	 *	initialize the Executor State structure
	 * ----------------
	 */
	state->es_direction = ForwardScanDirection;
	state->es_range_table = NIL;

	state->es_into_relation_descriptor = NULL;
	state->es_result_relation_info = NULL;

	state->es_param_list_info = NULL;
75
	state->es_param_exec_vals = NULL;
76 77 78 79 80 81 82 83 84 85 86

	state->es_BaseId = 0;
	state->es_tupleTable = NULL;

	state->es_junkFilter = NULL;

	/* ----------------
	 *	return the executor state structure
	 * ----------------
	 */
	return state;
87 88 89
}

/* ----------------------------------------------------------------
90
 *		CreateOperationTag
91
 *
92 93
 *		utility to get a string representation of the
 *		query operation.
94 95
 * ----------------------------------------------------------------
 */
96
static char *
97 98
CreateOperationTag(int operationType)
{
99
	char	   *tag;
100 101 102

	switch (operationType)
	{
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
		case CMD_SELECT:
			tag = "SELECT";
			break;
		case CMD_INSERT:
			tag = "INSERT";
			break;
		case CMD_DELETE:
			tag = "DELETE";
			break;
		case CMD_UPDATE:
			tag = "UPDATE";
			break;
		default:
			elog(DEBUG, "CreateOperationTag: unknown operation type %d",
				 operationType);
			tag = NULL;
			break;
120 121 122
	}

	return tag;
123 124 125
}

/* ----------------
126
 *		ProcessPortal
127 128 129 130
 * ----------------
 */

void
131
ProcessPortal(char *portalName,
132 133 134
			  Query *parseTree,
			  Plan *plan,
			  EState *state,
135 136
			  TupleDesc attinfo,
			  CommandDest dest)
137
{
138 139
	Portal		portal;
	MemoryContext portalContext;
140 141

	/* ----------------
142
	 *	 Check for reserved or already-in-use portal name.
143 144 145 146
	 * ----------------
	 */

	if (PortalNameIsSpecial(portalName))
147
		elog(ERROR,
148 149 150 151 152 153 154 155
			 "The portal name \"%s\" is reserved for internal use",
			 portalName);

	portal = GetPortalByName(portalName);
	if (PortalIsValid(portal))
	{
		/* XXX Should we raise an error rather than closing the old portal? */
		elog(NOTICE, "Closing pre-existing portal \"%s\"",
156
			 portalName);
157 158 159 160 161 162 163 164 165 166 167
		PortalDrop(&portal);
	}

	/* ----------------
	 *	 Convert the current blank portal into the user-specified
	 *	 portal and initialize the state and query descriptor.
	 *
	 *	 Since the parsetree has been created in the current blank portal,
	 *	 we don't have to do any work to copy it into the user-named portal.
	 * ----------------
	 */
168 169 170 171 172 173 174 175 176 177

	portal = BlankPortalAssignName(portalName);

	PortalSetQuery(portal,
				   CreateQueryDesc(parseTree, plan, dest),
				   attinfo,
				   state,
				   PortalCleanup);

	/* ----------------
178 179
	 *	Now create a new blank portal and switch to it.
	 *	Otherwise, the new named portal will be cleaned at statement end.
180 181 182 183 184 185
	 *
	 *	Note: portals will only be supported within a BEGIN...END
	 *	block in the near future.  Later, someone will fix it to
	 *	do what is possible across transaction boundries. -hirohama
	 * ----------------
	 */
B
Bruce Momjian 已提交
186
	portalContext = (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL));
187 188 189 190

	MemoryContextSwitchTo(portalContext);

	StartPortalAllocMode(DefaultAllocMode, 0);
191 192 193 194
}


/* ----------------------------------------------------------------
195
 *		ProcessQueryDesc
196
 *
197
 *		Read the comments for ProcessQuery() below...
198 199
 * ----------------------------------------------------------------
 */
200
static void
201
ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
202
{
203 204 205
	Query	   *parseTree;
	Plan	   *plan;
	int			operation;
B
Bruce Momjian 已提交
206
	char	   *tag = NULL;
207 208 209 210 211 212 213
	EState	   *state;
	TupleDesc	attinfo;

	bool		isRetrieveIntoPortal;
	bool		isRetrieveIntoRelation;
	char	   *intoName = NULL;
	CommandDest dest;
214 215 216 217 218 219 220 221 222

	/* ----------------
	 *	get info from the query desc
	 * ----------------
	 */
	parseTree = queryDesc->parsetree;
	plan = queryDesc->plantree;

	operation = queryDesc->operation;
223
	set_ps_display(tag = CreateOperationTag(operation));
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
	dest = queryDesc->dest;

	/* ----------------
	 *	initialize portal/into relation status
	 * ----------------
	 */
	isRetrieveIntoPortal = false;
	isRetrieveIntoRelation = false;

	if (operation == CMD_SELECT)
	{
		if (parseTree->isPortal)
		{
			isRetrieveIntoPortal = true;
			intoName = parseTree->into;
			if (parseTree->isBinary)
			{

				/*
				 * For internal format portals, we change Remote
				 * (externalized form) to RemoteInternal (internalized
				 * form)
				 */
				dest = queryDesc->dest = RemoteInternal;
			}
		}
		else if (parseTree->into != NULL)
		{
			/* select into table */
			isRetrieveIntoRelation = true;
		}

256 257
	}

258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
	/* ----------------
	 *	when performing a retrieve into, we override the normal
	 *	communication destination during the processing of the
	 *	the query.	This only affects the tuple-output function
	 *	- the correct destination will still see BeginCommand()
	 *	and EndCommand() messages.
	 * ----------------
	 */
	if (isRetrieveIntoRelation)
		queryDesc->dest = (int) None;

	/* ----------------
	 *	create a default executor state..
	 * ----------------
	 */
	state = CreateExecutorState();

	/* ----------------
	 *	call ExecStart to prepare the plan for execution
	 * ----------------
	 */
	attinfo = ExecutorStart(queryDesc, state);

	/* ----------------
	 *	 report the query's result type information
	 *	 back to the front end or to whatever destination
	 *	 we're dealing with.
	 * ----------------
	 */
	BeginCommand(NULL,
				 operation,
				 attinfo,
				 isRetrieveIntoRelation,
				 isRetrieveIntoPortal,
				 tag,
				 dest);

	/* ----------------
	 *	Named portals do not do a "fetch all" initially, so now
	 *	we return since ExecMain has been called with EXEC_START
	 *	to initialize the query plan.
	 *
	 *	Note: ProcessPortal transforms the current "blank" portal
	 *		  into a named portal and creates a new blank portal so
	 *		  everything we allocated in the current "blank" memory
	 *		  context will be preserved across queries.  -cim 2/22/91
	 * ----------------
	 */
	if (isRetrieveIntoPortal)
	{
		PortalExecutorHeapMemory = NULL;

		ProcessPortal(intoName,
					  parseTree,
					  plan,
					  state,
					  attinfo,
					  dest);

		EndCommand(tag, dest);
		return;
	}

	/* ----------------
	 *	 Now we get to the important call to ExecutorRun() where we
	 *	 actually run the plan..
	 * ----------------
	 */
326
	ExecutorRun(queryDesc, state, EXEC_RUN, limoffset, limcount);
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341

	/* save infos for EndCommand */
	UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);

	/* ----------------
	 *	 now, we close down all the scans and free allocated resources...
	 * with ExecutorEnd()
	 * ----------------
	 */
	ExecutorEnd(queryDesc, state);

	/* ----------------
	 *	Notify the destination of end of processing.
	 * ----------------
	 */
342 343 344 345
	EndCommand(tag, dest);
}

/* ----------------------------------------------------------------
346
 *		ProcessQuery
347
 *
348
 *		Execute a plan, the non-parallel version
349 350 351 352
 * ----------------------------------------------------------------
 */

void
353 354
ProcessQuery(Query *parsetree,
			 Plan *plan,
355
			 CommandDest dest)
356
{
357 358
	QueryDesc  *queryDesc;
	extern int	dontExecute;	/* from postgres.c */
359
	extern void print_plan(Plan *p, Query *parsetree);	/* from print.c */
360

361
	queryDesc = CreateQueryDesc(parsetree, plan, dest);
362

363 364 365 366 367 368
	if (dontExecute)
	{
		/* don't execute it, just show the query plan */
		print_plan(plan, parsetree);
	}
	else
369
		ProcessQueryDesc(queryDesc, parsetree->limitOffset,
B
Bruce Momjian 已提交
370
						 parsetree->limitCount);
371
}