analyze.c 13.4 KB
Newer Older
1 2 3
/*-------------------------------------------------------------------------
 *
 * analyze.c--
4
 *	  transform the parse tree into a query tree
5 6 7 8 9
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
10
 *	  $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.50 1997/11/25 22:00:27 momjian Exp $
11 12 13
 *
 *-------------------------------------------------------------------------
 */
14

15 16 17 18
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "postgres.h"
V
Vadim B. Mikheev 已提交
19

20 21 22 23 24 25 26 27 28 29 30 31
#include "access/heapam.h"
#include "nodes/makefuncs.h"
#include "nodes/memnodes.h"
#include "nodes/pg_list.h"
#include "parser/analyze.h"
#include "parser/parse_agg.h"
#include "parser/parse_node.h"
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
#include "parser/parse_clause.h"
#include "utils/builtins.h"
#include "utils/mcxt.h"
32

33 34 35 36 37 38 39 40 41
static Query *transformStmt(ParseState *pstate, Node *stmt);
static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
static Query *transformInsertStmt(ParseState *pstate, AppendStmt *stmt);
static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);
static Query *transformExtendStmt(ParseState *pstate, ExtendStmt *stmt);
static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);
static Query *transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt);
static Query *transformUpdateStmt(ParseState *pstate, ReplaceStmt *stmt);
static Query *transformCursorStmt(ParseState *pstate, CursorStmt *stmt);
42

B
Bruce Momjian 已提交
43

44 45
/*
 * parse_analyze -
46
 *	  analyze a list of parse trees and transform them if necessary.
47 48 49 50 51 52
 *
 * Returns a list of transformed parse trees. Optimizable statements are
 * all transformed to Query while the rest stays the same.
 *
 * CALLER is responsible for freeing the QueryTreeList* returned
 */
53
QueryTreeList *
54
parse_analyze(List *pl)
55
{
56 57 58
	QueryTreeList *result;
	ParseState *pstate;
	int			i = 0;
59 60 61 62 63 64 65

	result = malloc(sizeof(QueryTreeList));
	result->len = length(pl);
	result->qtrees = (Query **) malloc(result->len * sizeof(Query *));

	while (pl != NIL)
	{
66
		pstate = make_parsestate();
67 68 69 70 71 72 73 74
		result->qtrees[i++] = transformStmt(pstate, lfirst(pl));
		pl = lnext(pl);
		if (pstate->p_target_relation != NULL)
			heap_close(pstate->p_target_relation);
		free(pstate);
	}

	return result;
75 76 77 78
}

/*
 * transformStmt -
79 80
 *	  transform a Parse tree. If it is an optimizable statement, turn it
 *	  into a Query tree.
81
 */
82
static Query *
83
transformStmt(ParseState *pstate, Node *parseTree)
84
{
85
	Query	   *result = NULL;
86 87 88

	switch (nodeTag(parseTree))
	{
89 90 91 92 93 94 95
			/*------------------------
			 *	Non-optimizable statements
			 *------------------------
			 */
		case T_IndexStmt:
			result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
			break;
96

97 98 99
		case T_ExtendStmt:
			result = transformExtendStmt(pstate, (ExtendStmt *) parseTree);
			break;
100

101 102 103
		case T_RuleStmt:
			result = transformRuleStmt(pstate, (RuleStmt *) parseTree);
			break;
104

105 106 107
		case T_ViewStmt:
			{
				ViewStmt   *n = (ViewStmt *) parseTree;
108

109 110 111 112 113 114
				n->query = (Query *) transformStmt(pstate, (Node *) n->query);
				result = makeNode(Query);
				result->commandType = CMD_UTILITY;
				result->utilityStmt = (Node *) n;
			}
			break;
115

116 117 118
		case T_VacuumStmt:
			{
				MemoryContext oldcontext;
119

120 121 122 123 124 125 126 127 128 129 130 131
				/*
				 * make sure that this Query is allocated in TopMemory
				 * context because vacuum spans transactions and we don't
				 * want to lose the vacuum Query due to end-of-transaction
				 * free'ing
				 */
				oldcontext = MemoryContextSwitchTo(TopMemoryContext);
				result = makeNode(Query);
				result->commandType = CMD_UTILITY;
				result->utilityStmt = (Node *) parseTree;
				MemoryContextSwitchTo(oldcontext);
				break;
132

133 134 135 136
			}
		case T_ExplainStmt:
			{
				ExplainStmt *n = (ExplainStmt *) parseTree;
137

138 139 140 141 142 143
				result = makeNode(Query);
				result->commandType = CMD_UTILITY;
				n->query = transformStmt(pstate, (Node *) n->query);
				result->utilityStmt = (Node *) parseTree;
			}
			break;
144

145 146 147 148 149 150 151
			/*------------------------
			 *	Optimizable statements
			 *------------------------
			 */
		case T_AppendStmt:
			result = transformInsertStmt(pstate, (AppendStmt *) parseTree);
			break;
152

153 154 155
		case T_DeleteStmt:
			result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
			break;
156

157 158 159
		case T_ReplaceStmt:
			result = transformUpdateStmt(pstate, (ReplaceStmt *) parseTree);
			break;
160

161 162 163
		case T_CursorStmt:
			result = transformCursorStmt(pstate, (CursorStmt *) parseTree);
			break;
164

165 166 167
		case T_RetrieveStmt:
			result = transformSelectStmt(pstate, (RetrieveStmt *) parseTree);
			break;
168

169
		default:
170

171 172 173 174 175 176 177 178
			/*
			 * other statments don't require any transformation-- just
			 * return the original parsetree
			 */
			result = makeNode(Query);
			result->commandType = CMD_UTILITY;
			result->utilityStmt = (Node *) parseTree;
			break;
179 180
	}
	return result;
181 182 183 184
}

/*
 * transformDeleteStmt -
185
 *	  transforms a Delete Statement
186
 */
187
static Query *
188
transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
189
{
190
	Query	   *qry = makeNode(Query);
191

192
	qry->commandType = CMD_DELETE;
193

194 195
	/* set up a range table */
	makeRangeTable(pstate, stmt->relname, NULL);
196

197
	qry->uniqueFlag = NULL;
198

199 200
	/* fix where clause */
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
201

202 203 204 205 206 207
	qry->rtable = pstate->p_rtable;
	qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);

	/* make sure we don't have aggregates in the where clause */
	if (pstate->p_numAgg > 0)
		parseCheckAggregates(pstate, qry);
208

209
	return (Query *) qry;
210 211 212 213
}

/*
 * transformInsertStmt -
214
 *	  transform an Insert Statement
215
 */
216
static Query *
217
transformInsertStmt(ParseState *pstate, AppendStmt *stmt)
218
{
219
	Query	   *qry = makeNode(Query);	/* make a new query tree */
220
	List	   *icolumns;
221

222 223
	qry->commandType = CMD_INSERT;
	pstate->p_is_insert = true;
224

225 226
	/* set up a range table */
	makeRangeTable(pstate, stmt->relname, stmt->fromClause);
227

228
	qry->uniqueFlag = NULL;
229

230
	/* fix the target list */
231 232
	icolumns = pstate->p_insert_columns = makeTargetNames(pstate, stmt->cols);
	
233
	qry->targetList = transformTargetList(pstate, stmt->targetList);
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 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
	
	/* DEFAULT handling */
	if (length(qry->targetList) < pstate->p_target_relation->rd_att->natts &&
		pstate->p_target_relation->rd_att->constr &&
		pstate->p_target_relation->rd_att->constr->num_defval > 0)
	{
		AttributeTupleForm	   *att = pstate->p_target_relation->rd_att->attrs;
		AttrDefault			   *defval = pstate->p_target_relation->rd_att->constr->defval;
		int						ndef = pstate->p_target_relation->rd_att->constr->num_defval;
		
		/* 
		 * if stmt->cols == NIL then makeTargetNames returns list of all 
		 * attrs: have to shorter icolumns list...
		 */
		if (stmt->cols == NIL)
		{
			List   *extrl;
			int		i = length(qry->targetList);
			
			foreach (extrl, icolumns)
			{
				if (--i <= 0)
					break;
			}
			freeList (lnext(extrl));
			lnext(extrl) = NIL;
		}
		
		while (ndef-- > 0)
		{
			List		   *tl;
			Ident		   *id;
			TargetEntry	   *te;
			
			foreach (tl, icolumns)
			{
				id = (Ident *) lfirst(tl);
				if (!namestrcmp(&(att[defval[ndef].adnum - 1]->attname), id->name))
					break;
			}
			if (tl != NIL)		/* something given for this attr */
				continue;
			/* 
			 * Nothing given for this attr with DEFAULT expr, so
			 * add new TargetEntry to qry->targetList. 
			 * Note, that we set resno to defval[ndef].adnum:
			 * it's what transformTargetList()->make_targetlist_expr()
			 * does for INSERT ... SELECT. But for INSERT ... VALUES
			 * pstate->p_last_resno is used. It doesn't matter for 
			 * "normal" using (planner creates proper target list
			 * in preptlist.c), but may break RULEs in some way.
			 * It seems better to create proper target list here...
			 */
			te = makeNode(TargetEntry);
			te->resdom = makeResdom(defval[ndef].adnum,
									att[defval[ndef].adnum - 1]->atttypid,
									att[defval[ndef].adnum - 1]->attlen,
									pstrdup(nameout(&(att[defval[ndef].adnum - 1]->attname))),
									0, 0, 0);
			te->fjoin = NULL;
			te->expr = (Node *) stringToNode(defval[ndef].adbin);
			qry->targetList = lappend (qry->targetList, te);
		}
	}
	
299 300
	/* fix where clause */
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
301

302 303 304
	/* now the range table will not change */
	qry->rtable = pstate->p_rtable;
	qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
305

306 307
	if (pstate->p_numAgg > 0)
		finalizeAggregates(pstate, qry);
308

309
	return (Query *) qry;
310 311 312 313
}

/*
 * transformIndexStmt -
314
 *	  transforms the qualification of the index statement
315
 */
316
static Query *
317
transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
318
{
319
	Query	   *q;
320

321 322
	q = makeNode(Query);
	q->commandType = CMD_UTILITY;
323

324 325 326
	/* take care of the where clause */
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
	stmt->rangetable = pstate->p_rtable;
327

328 329 330
	q->utilityStmt = (Node *) stmt;

	return q;
331 332 333 334
}

/*
 * transformExtendStmt -
335
 *	  transform the qualifications of the Extend Index Statement
336 337
 *
 */
338
static Query *
339
transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
340
{
341
	Query	   *q;
342

343 344
	q = makeNode(Query);
	q->commandType = CMD_UTILITY;
345

346 347 348
	/* take care of the where clause */
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
	stmt->rangetable = pstate->p_rtable;
349

350 351
	q->utilityStmt = (Node *) stmt;
	return q;
352 353 354 355
}

/*
 * transformRuleStmt -
356 357
 *	  transform a Create Rule Statement. The actions is a list of parse
 *	  trees which is transformed into a list of query trees.
358
 */
359
static Query *
360
transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
361
{
362 363
	Query	   *q;
	List	   *actions;
364 365 366 367 368 369

	q = makeNode(Query);
	q->commandType = CMD_UTILITY;

	actions = stmt->actions;

370
	/*
371
	 * transform each statment, like parse_analyze()
372
	 */
373 374
	while (actions != NIL)
	{
375

376 377 378 379 380
		/*
		 * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
		 * equal to 2.
		 */
		addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
381
						   FALSE, FALSE);
382
		addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
383
						   FALSE, FALSE);
384 385 386 387 388 389 390 391 392

		pstate->p_last_resno = 1;
		pstate->p_is_rule = true;		/* for expand all */
		pstate->p_numAgg = 0;
		pstate->p_aggs = NULL;

		lfirst(actions) = transformStmt(pstate, lfirst(actions));
		actions = lnext(actions);
	}
393

394 395
	/* take care of the where clause */
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
396

397 398
	q->utilityStmt = (Node *) stmt;
	return q;
399 400 401 402 403
}


/*
 * transformSelectStmt -
404
 *	  transforms a Select Statement
405 406
 *
 */
407
static Query *
408
transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt)
409
{
410
	Query	   *qry = makeNode(Query);
411 412

	qry->commandType = CMD_SELECT;
413

414 415
	/* set up a range table */
	makeRangeTable(pstate, NULL, stmt->fromClause);
416

417
	qry->uniqueFlag = stmt->unique;
418

419 420
	qry->into = stmt->into;
	qry->isPortal = FALSE;
421

422 423
	/* fix the target list */
	qry->targetList = transformTargetList(pstate, stmt->targetList);
424

425 426
	/* fix where clause */
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
427

428 429 430
	/* check subselect clause */
	if (stmt->selectClause)
		elog(NOTICE, "UNION not yet supported; using first SELECT only", NULL);
431

432 433 434
	/* check subselect clause */
	if (stmt->havingClause)
		elog(NOTICE, "HAVING not yet supported; ignore clause", NULL);
435

436 437 438 439 440
	/* fix order clause */
	qry->sortClause = transformSortClause(pstate,
										  stmt->sortClause,
										  qry->targetList,
										  qry->uniqueFlag);
441

442 443 444 445 446
	/* fix group by clause */
	qry->groupClause = transformGroupClause(pstate,
											stmt->groupClause,
											qry->targetList);
	qry->rtable = pstate->p_rtable;
447

448 449
	if (pstate->p_numAgg > 0)
		finalizeAggregates(pstate, qry);
450

451
	return (Query *) qry;
452 453 454 455
}

/*
 * transformUpdateStmt -
456
 *	  transforms an update statement
457 458
 *
 */
459
static Query *
460
transformUpdateStmt(ParseState *pstate, ReplaceStmt *stmt)
461
{
462
	Query	   *qry = makeNode(Query);
463 464 465

	qry->commandType = CMD_UPDATE;
	pstate->p_is_update = true;
466

467 468 469 470 471
	/*
	 * the FROM clause is non-standard SQL syntax. We used to be able to
	 * do this with REPLACE in POSTQUEL so we keep the feature.
	 */
	makeRangeTable(pstate, stmt->relname, stmt->fromClause);
472

473 474
	/* fix the target list */
	qry->targetList = transformTargetList(pstate, stmt->targetList);
475

476 477
	/* fix where clause */
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
478

479 480
	qry->rtable = pstate->p_rtable;
	qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
481

482 483 484
	/* make sure we don't have aggregates in the where clause */
	if (pstate->p_numAgg > 0)
		parseCheckAggregates(pstate, qry);
485

486
	return (Query *) qry;
487 488 489 490
}

/*
 * transformCursorStmt -
491
 *	  transform a Create Cursor Statement
492 493
 *
 */
494
static Query *
495
transformCursorStmt(ParseState *pstate, CursorStmt *stmt)
496
{
497
	Query	   *qry = makeNode(Query);
498

499 500 501 502 503 504
	/*
	 * in the old days, a cursor statement is a 'retrieve into portal'; If
	 * you change the following, make sure you also go through the code in
	 * various places that tests the kind of operation.
	 */
	qry->commandType = CMD_SELECT;
505

506 507
	/* set up a range table */
	makeRangeTable(pstate, NULL, stmt->fromClause);
508

509
	qry->uniqueFlag = stmt->unique;
510

511 512 513
	qry->into = stmt->portalname;
	qry->isPortal = TRUE;
	qry->isBinary = stmt->binary;		/* internal portal */
514

515 516
	/* fix the target list */
	qry->targetList = transformTargetList(pstate, stmt->targetList);
517

518 519
	/* fix where clause */
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
520

521 522 523 524 525 526 527 528 529
	/* fix order clause */
	qry->sortClause = transformSortClause(pstate,
										  stmt->sortClause,
										  qry->targetList,
										  qry->uniqueFlag);
	/* fix group by clause */
	qry->groupClause = transformGroupClause(pstate,
											stmt->groupClause,
											qry->targetList);
M
Fixes:  
Marc G. Fournier 已提交
530

531
	qry->rtable = pstate->p_rtable;
532

533 534
	if (pstate->p_numAgg > 0)
		finalizeAggregates(pstate, qry);
535

536
	return (Query *) qry;
537
}