analyze.c 21.6 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
B
Bruce Momjian 已提交
10
 *	  $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.69 1998/02/06 16:46:28 momjian Exp $
11 12 13
 *
 *-------------------------------------------------------------------------
 */
14

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

B
Bruce Momjian 已提交
20
#include "postgres.h"
21 22 23 24 25 26
#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"
B
Bruce Momjian 已提交
27
#include "parser/parse_clause.h"
28 29 30 31 32
#include "parser/parse_node.h"
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
#include "utils/builtins.h"
#include "utils/mcxt.h"
33

34 35
static Query *transformStmt(ParseState *pstate, Node *stmt);
static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
B
Bruce Momjian 已提交
36
static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt);
37 38 39
static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);
static Query *transformExtendStmt(ParseState *pstate, ExtendStmt *stmt);
static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);
B
Bruce Momjian 已提交
40 41
static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);
static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
42
static Query *transformCursorStmt(ParseState *pstate, SelectStmt *stmt);
43
static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt);
44

45
List   *extras = NIL;
B
Bruce Momjian 已提交
46

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

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

	while (pl != NIL)
	{
68
		pstate = make_parsestate(parentParseState);
69
		result->qtrees[i++] = transformStmt(pstate, lfirst(pl));
B
Bruce Momjian 已提交
70 71 72
		if (pstate->p_target_relation != NULL)
			heap_close(pstate->p_target_relation);

73 74 75 76 77 78 79
		if (extras != NIL)
		{
			result->len += length(extras);
			result->qtrees = (Query **) realloc(result->qtrees, result->len * sizeof(Query *));
			while (extras != NIL)
			{
				result->qtrees[i++] = transformStmt(pstate, lfirst(extras));
B
Bruce Momjian 已提交
80 81
				if (pstate->p_target_relation != NULL)
					heap_close(pstate->p_target_relation);
82 83 84 85
				extras = lnext(extras);
			}
		}
		extras = NIL;
86
		pl = lnext(pl);
B
Bruce Momjian 已提交
87
		pfree(pstate);
88 89 90
	}

	return result;
91 92 93 94
}

/*
 * transformStmt -
95 96
 *	  transform a Parse tree. If it is an optimizable statement, turn it
 *	  into a Query tree.
97
 */
98
static Query *
99
transformStmt(ParseState *pstate, Node *parseTree)
100
{
101
	Query	   *result = NULL;
102 103 104

	switch (nodeTag(parseTree))
	{
B
Bruce Momjian 已提交
105 106 107 108
		/*------------------------
		 *	Non-optimizable statements
		 *------------------------
		 */
109 110 111 112
		case T_CreateStmt:
			result = transformCreateStmt(pstate, (CreateStmt *) parseTree);
			break;

113 114 115
		case T_IndexStmt:
			result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
			break;
116

117 118 119
		case T_ExtendStmt:
			result = transformExtendStmt(pstate, (ExtendStmt *) parseTree);
			break;
120

121 122 123
		case T_RuleStmt:
			result = transformRuleStmt(pstate, (RuleStmt *) parseTree);
			break;
124

125 126 127
		case T_ViewStmt:
			{
				ViewStmt   *n = (ViewStmt *) parseTree;
128

129 130 131 132 133 134
				n->query = (Query *) transformStmt(pstate, (Node *) n->query);
				result = makeNode(Query);
				result->commandType = CMD_UTILITY;
				result->utilityStmt = (Node *) n;
			}
			break;
135

136 137 138
		case T_VacuumStmt:
			{
				MemoryContext oldcontext;
139

140 141 142 143 144 145 146 147 148 149 150 151
				/*
				 * 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;
152

153 154 155 156
			}
		case T_ExplainStmt:
			{
				ExplainStmt *n = (ExplainStmt *) parseTree;
157

158 159 160 161 162 163
				result = makeNode(Query);
				result->commandType = CMD_UTILITY;
				n->query = transformStmt(pstate, (Node *) n->query);
				result->utilityStmt = (Node *) parseTree;
			}
			break;
164

B
Bruce Momjian 已提交
165 166 167 168
		/*------------------------
		 *	Optimizable statements
		 *------------------------
		 */
B
Bruce Momjian 已提交
169 170
		case T_InsertStmt:
			result = transformInsertStmt(pstate, (InsertStmt *) parseTree);
171
			break;
172

173 174 175
		case T_DeleteStmt:
			result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
			break;
176

B
Bruce Momjian 已提交
177 178
		case T_UpdateStmt:
			result = transformUpdateStmt(pstate, (UpdateStmt *) parseTree);
179
			break;
180

B
Bruce Momjian 已提交
181
		case T_SelectStmt:
182 183 184 185
			if (!((SelectStmt *)parseTree)->portalname)
				result = transformSelectStmt(pstate, (SelectStmt *) parseTree);
			else
				result = transformCursorStmt(pstate, (SelectStmt *) parseTree);
186
			break;
187

188
		default:
189

190 191
			/*
			 * other statments don't require any transformation-- just
B
Bruce Momjian 已提交
192
			 * return the original parsetree, yea!
193 194 195 196 197
			 */
			result = makeNode(Query);
			result->commandType = CMD_UTILITY;
			result->utilityStmt = (Node *) parseTree;
			break;
198 199
	}
	return result;
200 201 202 203
}

/*
 * transformDeleteStmt -
204
 *	  transforms a Delete Statement
205
 */
206
static Query *
207
transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
208
{
209
	Query	   *qry = makeNode(Query);
210

211
	qry->commandType = CMD_DELETE;
212

213 214
	/* set up a range table */
	makeRangeTable(pstate, stmt->relname, NULL);
215

216
	qry->uniqueFlag = NULL;
217

218 219
	/* fix where clause */
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
220 221
	qry->hasSubLinks = pstate->p_hasSubLinks;
	
222
	qry->rtable = pstate->p_rtable;
223
	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
224

B
Bruce Momjian 已提交
225
	qry->hasAggs = pstate->p_hasAggs;
226
	if (pstate->p_hasAggs)
227
		parseCheckAggregates(pstate, qry);
228

229
	return (Query *) qry;
230 231 232 233
}

/*
 * transformInsertStmt -
234
 *	  transform an Insert Statement
235
 */
236
static Query *
B
Bruce Momjian 已提交
237
transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
238
{
239
	Query	   *qry = makeNode(Query);	/* make a new query tree */
240
	List	   *icolumns;
241

242 243
	qry->commandType = CMD_INSERT;
	pstate->p_is_insert = true;
244

245 246
	/* set up a range table */
	makeRangeTable(pstate, stmt->relname, stmt->fromClause);
247

248
	qry->uniqueFlag = stmt->unique;
249

250
	/* fix the target list */
251 252
	icolumns = pstate->p_insert_columns = makeTargetNames(pstate, stmt->cols);
	
253
	qry->targetList = transformTargetList(pstate, stmt->targetList);
254 255 256 257 258 259 260 261 262 263 264
	
	/* 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;
		
		/* 
B
Bruce Momjian 已提交
265
		 * if stmt->cols == NIL then makeTargetNames returns list of all
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
		 * 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);
		}
	}
	
319 320
	/* fix where clause */
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
321 322
	qry->hasSubLinks = pstate->p_hasSubLinks;
	
323 324
	/* now the range table will not change */
	qry->rtable = pstate->p_rtable;
325
	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
326

327 328 329 330 331 332 333 334 335 336 337
	qry->groupClause = transformGroupClause(pstate,
											stmt->groupClause,
											qry->targetList);

	/* fix order clause */
	qry->sortClause = transformSortClause(pstate,
										  NIL,
										  NIL,
										  qry->targetList,
										  qry->uniqueFlag);

B
Bruce Momjian 已提交
338
	qry->hasAggs = pstate->p_hasAggs;
339
	if (pstate->p_hasAggs)
B
Bruce Momjian 已提交
340
		parseCheckAggregates(pstate, qry);
341

B
Bruce Momjian 已提交
342
	/* The INSERT INTO ... SELECT ... could have a UNION */
343 344 345
	qry->unionall = stmt->unionall;	/* in child, so unionClause may be false */
	qry->unionClause = transformUnionClause(stmt->unionClause, qry->targetList);

346
	return (Query *) qry;
347 348
}

B
Bruce Momjian 已提交
349 350 351
/*
 *	makeTableName()
 *	Create a table name from a list of fields.
352 353 354 355 356 357 358 359 360
 */
static char *
makeTableName(void *elem,...)
{
	va_list	args;

	char   *name;
	char	buf[NAMEDATALEN+1];

B
Bruce Momjian 已提交
361
	buf[0] = '\0';
362 363 364 365 366 367 368 369 370 371

	va_start(args,elem);

	name = elem;
	while (name != NULL)
	{
		/* not enough room for next part? then return nothing */
		if ((strlen(buf)+strlen(name)) >= (sizeof(buf)-1))
			return (NULL);

B
Bruce Momjian 已提交
372 373
		if (strlen(buf) > 0)
			strcat(buf,"_");
374 375 376 377 378 379 380 381 382 383 384
		strcat(buf,name);

		name = va_arg(args,void *);
	}

	va_end(args);

	name = palloc(strlen(buf)+1);
	strcpy(name,buf);

	return (name);
B
Bruce Momjian 已提交
385
}
386

B
Bruce Momjian 已提交
387
static char *
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
CreateIndexName(char *tname, char *cname, char *label, List *indices)
{
	int			pass = 0;
	char	   *iname = NULL;
	List	   *ilist;
	IndexStmt  *index;
	char		name2[NAMEDATALEN+1];

	/* use working storage, since we might be trying several possibilities */
	strcpy(name2,cname);
	while (iname == NULL)
	{
		iname = makeTableName(tname, name2, label, NULL);
		/* unable to make a name at all? then quit */
		if (iname == NULL)
			break;

		ilist = indices;
		while (ilist != NIL)
		{
			index = lfirst(ilist);
			if (strcasecmp(iname,index->idxname) == 0)
				break;

			ilist = lnext(ilist);
		}
		/* ran through entire list? then no name conflict found so done */
		if (ilist == NIL)
			break;

		/* the last one conflicted, so try a new name component */
		pfree(iname);
		iname = NULL;
		pass++;
		sprintf(name2, "%s_%d", cname, (pass+1));
	}

	return (iname);
B
Bruce Momjian 已提交
426
}
427

428 429 430 431 432 433 434 435 436 437 438 439 440
/*
 * transformCreateStmt -
 *	  transforms the "create table" statement
 *	  SQL92 allows constraints to be scattered all over, so thumb through
 *	   the columns and collect all constraints into one place.
 *	  If there are any implied indices (e.g. UNIQUE or PRIMARY KEY)
 *	   then expand those into multiple IndexStmt blocks.
 *	  - thomas 1997-12-02
 */
static Query *
transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
{
	Query	   *q;
441
	int			have_pkey = FALSE;
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
	List	   *elements;
	Node	   *element;
	List	   *columns;
	List	   *dlist;
	ColumnDef  *column;
	List	   *constraints, *clist;
	Constraint *constraint;
	List	   *keys;
	Ident	   *key;
	List	   *ilist;
	IndexStmt  *index;
	IndexElem  *iparam;

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

	elements = stmt->tableElts;
	constraints = stmt->constraints;
	columns = NIL;
	dlist = NIL;

	while (elements != NIL)
	{
		element = lfirst(elements);
		switch (nodeTag(element))
		{
			case T_ColumnDef:
				column = (ColumnDef *) element;
				columns = lappend(columns,column);
				if (column->constraints != NIL)
				{
					clist = column->constraints;
					while (clist != NIL)
					{
						constraint = lfirst(clist);
						switch (constraint->contype)
						{
							case CONSTR_NOTNULL:
								if (column->is_not_null)
481
									elog(ERROR,"CREATE TABLE/NOT NULL already specified"
482 483 484 485 486 487
										" for %s.%s", stmt->relname, column->colname);
								column->is_not_null = TRUE;
								break;

							case CONSTR_DEFAULT:
								if (column->defval != NULL)
488
									elog(ERROR,"CREATE TABLE/DEFAULT multiple values specified"
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
										" for %s.%s", stmt->relname, column->colname);
								column->defval = constraint->def;
								break;

							case CONSTR_PRIMARY:
								if (constraint->name == NULL)
									constraint->name = makeTableName(stmt->relname, "pkey", NULL);
								if (constraint->keys == NIL)
									constraint->keys = lappend(constraint->keys, column);
								dlist = lappend(dlist, constraint);
								break;

							case CONSTR_UNIQUE:
								if (constraint->name == NULL)
									constraint->name = makeTableName(stmt->relname, column->colname, "key", NULL);
								if (constraint->keys == NIL)
									constraint->keys = lappend(constraint->keys, column);
								dlist = lappend(dlist, constraint);
								break;

							case CONSTR_CHECK:
								constraints = lappend(constraints, constraint);
								if (constraint->name == NULL)
512
									constraint->name = makeTableName(stmt->relname, column->colname, NULL);
513 514 515
								break;

							default:
516
								elog(ERROR,"parser: internal error; unrecognized constraint",NULL);
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
								break;
						}
						clist = lnext(clist);
					}
				}
				break;

			case T_Constraint:
				constraint = (Constraint *) element;
				switch (constraint->contype)
				{
					case CONSTR_PRIMARY:
						if (constraint->name == NULL)
							constraint->name = makeTableName(stmt->relname, "pkey", NULL);
						dlist = lappend(dlist, constraint);
						break;

					case CONSTR_UNIQUE:
#if FALSE
						if (constraint->name == NULL)
							constraint->name = makeTableName(stmt->relname, "key", NULL);
#endif
						dlist = lappend(dlist, constraint);
						break;

					case CONSTR_CHECK:
						constraints = lappend(constraints, constraint);
						break;

					case CONSTR_NOTNULL:
					case CONSTR_DEFAULT:
548
						elog(ERROR,"parser: internal error; illegal context for constraint",NULL);
549 550
						break;
					default:
551
						elog(ERROR,"parser: internal error; unrecognized constraint",NULL);
552 553 554 555 556
						break;
				}
				break;

			default:
557
				elog(ERROR,"parser: internal error; unrecognized node",NULL);
558 559 560 561 562 563 564 565 566 567 568 569 570
		}

		elements = lnext(elements);
	}

	stmt->tableElts = columns;
	stmt->constraints = constraints;

/* Now run through the "deferred list" to complete the query transformation.
 * For PRIMARY KEYs, mark each column as NOT NULL and create an index.
 * For UNIQUE, create an index as for PRIMARY KEYS, but do not insist on NOT NULL.
 *
 * Note that this code does not currently look for all possible redundant cases
571 572 573
 *  and either ignore or stop with warning. The create might fail later when
 *  names for indices turn out to be redundant, or a user might have specified
 *  extra useless indices which might hurt performance. - thomas 1997-12-08
574 575 576 577 578 579
 */
	ilist = NIL;
	while (dlist != NIL)
	{
		constraint = lfirst(dlist);
		if (nodeTag(constraint) != T_Constraint)
580
			elog(ERROR,"parser: internal error; unrecognized deferred node",NULL);
581

582 583
		if (constraint->contype == CONSTR_PRIMARY)
			if (have_pkey)
584
				elog(ERROR,"CREATE TABLE/PRIMARY KEY multiple primary keys"
585 586 587 588
					" for table %s are not legal", stmt->relname);
			else 
				have_pkey = TRUE;
		else if (constraint->contype != CONSTR_UNIQUE)
589
			elog(ERROR,"parser: internal error; unrecognized deferred constraint",NULL);
590

591 592 593 594 595 596
		index = makeNode(IndexStmt);

		index->unique = TRUE;
		if (constraint->name != NULL)
			index->idxname = constraint->name;
		else if (constraint->contype == CONSTR_PRIMARY)
597 598
		{
			if (have_pkey)
599
				elog(ERROR,"CREATE TABLE/PRIMARY KEY multiple keys for table %s are not legal", stmt->relname);
600 601

			have_pkey = TRUE;
602
			index->idxname = makeTableName(stmt->relname, "pkey", NULL);
603
		}
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
		else
			index->idxname = NULL;

		index->relname = stmt->relname;
		index->accessMethod = "btree";
		index->indexParams = NIL;
		index->withClause = NIL;
		index->whereClause = NULL;
 
		keys = constraint->keys;
		while (keys != NIL)
		{
			key = lfirst(keys);
			columns = stmt->tableElts;
			column = NULL;
			while (columns != NIL)
			{
				column = lfirst(columns);
				if (strcasecmp(column->colname,key->name) == 0) break;
				else column = NULL;
				columns = lnext(columns);
			}
			if (column == NULL)
627
				elog(ERROR,"parser: column '%s' in key does not exist",key->name);
628 629 630 631 632 633 634 635 636 637 638

			if (constraint->contype == CONSTR_PRIMARY)
				column->is_not_null = TRUE;
			iparam = makeNode(IndexElem);
			iparam->name = strcpy(palloc(strlen(column->colname)+1), column->colname);
			iparam->args = NIL;
			iparam->class = NULL;
			iparam->tname = NULL;
			index->indexParams = lappend(index->indexParams, iparam);

			if (index->idxname == NULL)
639
				index->idxname = CreateIndexName(stmt->relname, iparam->name, "key", ilist);
640 641 642 643 644

			keys = lnext(keys);
		}

		if (index->idxname == NULL)
645
			elog(ERROR,"parser: unable to construct implicit index for table %s"
646
				"; name too long", stmt->relname);
647 648 649 650
		else
			elog(NOTICE,"CREATE TABLE/%s will create implicit index %s for table %s",
				((constraint->contype == CONSTR_PRIMARY)? "PRIMARY KEY": "UNIQUE"),
				index->idxname, stmt->relname);
651

652
		ilist = lappend(ilist, index);
653 654 655 656 657 658 659
		dlist = lnext(dlist);
	}

	q->utilityStmt = (Node *) stmt;
	extras = ilist;

	return q;
B
Bruce Momjian 已提交
660
}
661

662 663
/*
 * transformIndexStmt -
664
 *	  transforms the qualification of the index statement
665
 */
666
static Query *
667
transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
668
{
B
Bruce Momjian 已提交
669
	Query	   *qry;
670

B
Bruce Momjian 已提交
671 672
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
673

674 675
	/* take care of the where clause */
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
676 677
	qry->hasSubLinks = pstate->p_hasSubLinks;
	
678
	stmt->rangetable = pstate->p_rtable;
679

B
Bruce Momjian 已提交
680
	qry->utilityStmt = (Node *) stmt;
681

B
Bruce Momjian 已提交
682
	return qry;
683 684 685 686
}

/*
 * transformExtendStmt -
687
 *	  transform the qualifications of the Extend Index Statement
688 689
 *
 */
690
static Query *
691
transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
692
{
B
Bruce Momjian 已提交
693
	Query	   *qry;
694

B
Bruce Momjian 已提交
695 696
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
697

698 699
	/* take care of the where clause */
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
700 701
	qry->hasSubLinks = pstate->p_hasSubLinks;

702
	stmt->rangetable = pstate->p_rtable;
703

B
Bruce Momjian 已提交
704 705
	qry->utilityStmt = (Node *) stmt;
	return qry;
706 707 708 709
}

/*
 * transformRuleStmt -
710 711
 *	  transform a Create Rule Statement. The actions is a list of parse
 *	  trees which is transformed into a list of query trees.
712
 */
713
static Query *
714
transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
715
{
B
Bruce Momjian 已提交
716
	Query	   *qry;
717
	List	   *actions;
718

B
Bruce Momjian 已提交
719 720
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
721 722 723

	actions = stmt->actions;

724
	/*
725
	 * transform each statment, like parse_analyze()
726
	 */
727 728
	while (actions != NIL)
	{
729

730 731 732 733 734
		/*
		 * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
		 * equal to 2.
		 */
		addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
735
						   FALSE, FALSE);
736
		addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
737
						   FALSE, FALSE);
738 739 740

		pstate->p_last_resno = 1;
		pstate->p_is_rule = true;		/* for expand all */
741
		pstate->p_hasAggs = false;
742 743 744 745

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

747 748
	/* take care of the where clause */
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
749
	qry->hasSubLinks = pstate->p_hasSubLinks;
750

B
Bruce Momjian 已提交
751 752
	qry->utilityStmt = (Node *) stmt;
	return qry;
753 754 755 756 757
}


/*
 * transformSelectStmt -
758
 *	  transforms a Select Statement
759 760
 *
 */
761
static Query *
B
Bruce Momjian 已提交
762
transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
763
{
764
	Query	   *qry = makeNode(Query);
765 766

	qry->commandType = CMD_SELECT;
767

768 769
	/* set up a range table */
	makeRangeTable(pstate, NULL, stmt->fromClause);
770

771
	qry->uniqueFlag = stmt->unique;
772

773 774
	qry->into = stmt->into;
	qry->isPortal = FALSE;
775

776
	qry->targetList = transformTargetList(pstate, stmt->targetList);
777

778
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
779
	qry->hasSubLinks = pstate->p_hasSubLinks;
780

781 782
	qry->sortClause = transformSortClause(pstate,
										  stmt->sortClause,
B
Bruce Momjian 已提交
783
										  NIL,
784 785
										  qry->targetList,
										  qry->uniqueFlag);
786

787 788 789 790
	qry->groupClause = transformGroupClause(pstate,
											stmt->groupClause,
											qry->targetList);
	qry->rtable = pstate->p_rtable;
791

B
Bruce Momjian 已提交
792
	qry->hasAggs = pstate->p_hasAggs;
793
	if (pstate->p_hasAggs)
B
Bruce Momjian 已提交
794
		parseCheckAggregates(pstate, qry);
795

796
	qry->unionall = stmt->unionall;	/* in child, so unionClause may be false */
797
	qry->unionClause = transformUnionClause(stmt->unionClause, qry->targetList);
798

799
	return (Query *) qry;
800 801 802 803
}

/*
 * transformUpdateStmt -
804
 *	  transforms an update statement
805 806
 *
 */
807
static Query *
B
Bruce Momjian 已提交
808
transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
809
{
810
	Query	   *qry = makeNode(Query);
811 812 813

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

815 816 817 818 819
	/*
	 * 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);
820

821
	qry->targetList = transformTargetList(pstate, stmt->targetList);
822

823
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
824
	qry->hasSubLinks = pstate->p_hasSubLinks;
825

826
	qry->rtable = pstate->p_rtable;
827

828
	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
829

B
Bruce Momjian 已提交
830
	qry->hasAggs = pstate->p_hasAggs;
831
	if (pstate->p_hasAggs)
832
		parseCheckAggregates(pstate, qry);
833

834
	return (Query *) qry;
835 836 837 838
}

/*
 * transformCursorStmt -
839
 *	  transform a Create Cursor Statement
840 841
 *
 */
842
static Query *
843
transformCursorStmt(ParseState *pstate, SelectStmt *stmt)
844
{
845
	Query	   *qry;
846

847
	qry = transformSelectStmt(pstate, stmt);
848

849 850 851
	qry->into = stmt->portalname;
	qry->isPortal = TRUE;
	qry->isBinary = stmt->binary;		/* internal portal */
852

853
	return qry;
854
}