pquery.c 8.5 KB
Newer Older
1 2 3
/*-------------------------------------------------------------------------
 *
 * pquery.c--
4
 *	  POSTGRES process query command code
5 6 7 8 9
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
10
 *	  $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.18 1998/09/01 04:32:14 momjian Exp $
11 12 13
 *
 *-------------------------------------------------------------------------
 */
B
Bruce Momjian 已提交
14 15
#include <string.h>

16 17 18 19 20
#include "postgres.h"

#include "tcop/tcopdebug.h"

#include "utils/palloc.h"
21
#include "nodes/nodes.h"
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
#include "utils/mcxt.h"
#include "miscadmin.h"
#include "utils/portal.h"

#include "nodes/pg_list.h"
#include "nodes/primnodes.h"
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
#include "nodes/memnodes.h"

#include "tcop/dest.h"

#include "executor/execdefs.h"
#include "executor/execdesc.h"
#include "executor/executor.h"
#include "tcop/pquery.h"
M
 
Marc G. Fournier 已提交
38
#include "utils/ps_status.h"
39 40 41

#include "commands/command.h"

42
static char *CreateOperationTag(int operationType);
43
static void ProcessQueryDesc(QueryDesc *queryDesc);
44

45 46

/* ----------------------------------------------------------------
47
 *		CreateQueryDesc
48 49
 * ----------------------------------------------------------------
 */
50
QueryDesc  *
51 52
CreateQueryDesc(Query *parsetree,
				Plan *plantree,
53
				CommandDest dest)
54
{
55
	QueryDesc  *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
56 57 58 59 60 61

	qd->operation = parsetree->commandType;		/* operation */
	qd->parsetree = parsetree;	/* parse tree */
	qd->plantree = plantree;	/* plan */
	qd->dest = dest;			/* output dest */
	return qd;
62 63 64
}

/* ----------------------------------------------------------------
65
 *		CreateExecutorState
66
 *
67
 *		Note: this may someday take parameters -cim 9/18/89
68 69
 * ----------------------------------------------------------------
 */
70
EState *
71
CreateExecutorState(void)
72
{
73 74 75
	EState	   *state;
	extern int	NBuffers;
	long	   *refcount;
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93

	/* ----------------
	 *	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;
94
	state->es_param_exec_vals = NULL;
95 96 97 98 99 100 101

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

	state->es_junkFilter = NULL;

	refcount = (long *) palloc(NBuffers * sizeof(long));
B
Bruce Momjian 已提交
102
	MemSet((char *) refcount, 0, NBuffers * sizeof(long));
103 104 105 106 107 108 109
	state->es_refcount = (int *) refcount;

	/* ----------------
	 *	return the executor state structure
	 * ----------------
	 */
	return state;
110 111 112
}

/* ----------------------------------------------------------------
113
 *		CreateOperationTag
114
 *
115 116
 *		utility to get a string representation of the
 *		query operation.
117 118
 * ----------------------------------------------------------------
 */
119
static char *
120 121
CreateOperationTag(int operationType)
{
122
	char	   *tag;
123 124 125

	switch (operationType)
	{
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
		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;
143 144 145
	}

	return tag;
146 147 148
}

/* ----------------
149
 *		ProcessPortal
150 151 152 153
 * ----------------
 */

void
154
ProcessPortal(char *portalName,
155 156 157
			  Query *parseTree,
			  Plan *plan,
			  EState *state,
158 159
			  TupleDesc attinfo,
			  CommandDest dest)
160
{
161 162
	Portal		portal;
	MemoryContext portalContext;
163 164 165 166 167 168 169 170

	/* ----------------
	 *	 convert the current blank portal into the user-specified
	 *	 portal and initialize the state and query descriptor.
	 * ----------------
	 */

	if (PortalNameIsSpecial(portalName))
171
		elog(ERROR,
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
			 "The portal name %s is reserved for internal use",
			 portalName);

	portal = BlankPortalAssignName(portalName);

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

	/* ----------------
	 *	now create a new blank portal and switch to it.
	 *	Otherwise, the new named portal will be cleaned.
	 *
	 *	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
	 * ----------------
	 */
	portalContext = (MemoryContext)
		PortalGetHeapMemory(GetPortalByName(NULL));

	MemoryContextSwitchTo(portalContext);

	StartPortalAllocMode(DefaultAllocMode, 0);
198 199 200 201
}


/* ----------------------------------------------------------------
202
 *		ProcessQueryDesc
203
 *
204
 *		Read the comments for ProcessQuery() below...
205 206
 * ----------------------------------------------------------------
 */
207
static void
208
ProcessQueryDesc(QueryDesc *queryDesc)
209
{
210 211 212 213 214 215 216 217 218 219 220
	Query	   *parseTree;
	Plan	   *plan;
	int			operation;
	char	   *tag;
	EState	   *state;
	TupleDesc	attinfo;

	bool		isRetrieveIntoPortal;
	bool		isRetrieveIntoRelation;
	char	   *intoName = NULL;
	CommandDest dest;
221 222 223 224 225 226 227 228 229

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

	operation = queryDesc->operation;
230
	PS_SET_STATUS(tag = CreateOperationTag(operation));
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 256 257 258 259 260 261 262
	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;
		}

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 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
	/* ----------------
	 *	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..
	 * ----------------
	 */
	ExecutorRun(queryDesc, state, EXEC_RUN, 0);

	/* 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.
	 * ----------------
	 */
349 350 351 352
	EndCommand(tag, dest);
}

/* ----------------------------------------------------------------
353
 *		ProcessQuery
354
 *
355
 *		Execute a plan, the non-parallel version
356 357 358 359
 * ----------------------------------------------------------------
 */

void
360 361
ProcessQuery(Query *parsetree,
			 Plan *plan,
362
			 CommandDest dest)
363
{
364 365
	QueryDesc  *queryDesc;
	extern int	dontExecute;	/* from postgres.c */
366
	extern void print_plan(Plan *p, Query *parsetree);	/* from print.c */
367

368
	queryDesc = CreateQueryDesc(parsetree, plan, dest);
369

370 371 372 373 374 375 376
	if (dontExecute)
	{
		/* don't execute it, just show the query plan */
		print_plan(plan, parsetree);
	}
	else
		ProcessQueryDesc(queryDesc);
377
}