analyze.c 22.0 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.75 1998/05/09 23:29:52 thomas 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
#ifdef PARSEDEBUG
#include "nodes/print.h"
#endif
36

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

48
List	   *extras = NIL;
B
Bruce Momjian 已提交
49

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

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

	while (pl != NIL)
	{
71 72 73 74
#ifdef PARSEDEBUG
		elog(DEBUG,"parse tree from yacc:\n---\n%s\n---\n", nodeToString(lfirst(pl)));
#endif

75
		pstate = make_parsestate(parentParseState);
76
		result->qtrees[i++] = transformStmt(pstate, lfirst(pl));
B
Bruce Momjian 已提交
77 78 79
		if (pstate->p_target_relation != NULL)
			heap_close(pstate->p_target_relation);

80 81 82 83 84 85 86
		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 已提交
87 88
				if (pstate->p_target_relation != NULL)
					heap_close(pstate->p_target_relation);
89 90 91 92
				extras = lnext(extras);
			}
		}
		extras = NIL;
93
		pl = lnext(pl);
B
Bruce Momjian 已提交
94
		pfree(pstate);
95 96 97
	}

	return result;
98 99 100 101
}

/*
 * transformStmt -
102 103
 *	  transform a Parse tree. If it is an optimizable statement, turn it
 *	  into a Query tree.
104
 */
105
static Query *
106
transformStmt(ParseState *pstate, Node *parseTree)
107
{
108
	Query	   *result = NULL;
109 110 111

	switch (nodeTag(parseTree))
	{
112 113 114 115
			/*------------------------
			 *	Non-optimizable statements
			 *------------------------
			 */
116 117 118 119
		case T_CreateStmt:
			result = transformCreateStmt(pstate, (CreateStmt *) parseTree);
			break;

120 121 122
		case T_IndexStmt:
			result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
			break;
123

124 125 126
		case T_ExtendStmt:
			result = transformExtendStmt(pstate, (ExtendStmt *) parseTree);
			break;
127

128 129 130
		case T_RuleStmt:
			result = transformRuleStmt(pstate, (RuleStmt *) parseTree);
			break;
131

132 133 134
		case T_ViewStmt:
			{
				ViewStmt   *n = (ViewStmt *) parseTree;
135

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

143 144 145
		case T_VacuumStmt:
			{
				MemoryContext oldcontext;
146

147 148 149 150 151 152 153 154 155 156 157 158
				/*
				 * 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;
159

160 161 162 163
			}
		case T_ExplainStmt:
			{
				ExplainStmt *n = (ExplainStmt *) parseTree;
164

165 166 167 168 169 170
				result = makeNode(Query);
				result->commandType = CMD_UTILITY;
				n->query = transformStmt(pstate, (Node *) n->query);
				result->utilityStmt = (Node *) parseTree;
			}
			break;
171

172 173 174 175
			/*------------------------
			 *	Optimizable statements
			 *------------------------
			 */
B
Bruce Momjian 已提交
176 177
		case T_InsertStmt:
			result = transformInsertStmt(pstate, (InsertStmt *) parseTree);
178
			break;
179

180 181 182
		case T_DeleteStmt:
			result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
			break;
183

B
Bruce Momjian 已提交
184 185
		case T_UpdateStmt:
			result = transformUpdateStmt(pstate, (UpdateStmt *) parseTree);
186
			break;
187

B
Bruce Momjian 已提交
188
		case T_SelectStmt:
189
			if (!((SelectStmt *) parseTree)->portalname)
190 191 192
				result = transformSelectStmt(pstate, (SelectStmt *) parseTree);
			else
				result = transformCursorStmt(pstate, (SelectStmt *) parseTree);
193
			break;
194

195
		default:
196

197 198
			/*
			 * other statments don't require any transformation-- just
B
Bruce Momjian 已提交
199
			 * return the original parsetree, yea!
200 201 202 203 204
			 */
			result = makeNode(Query);
			result->commandType = CMD_UTILITY;
			result->utilityStmt = (Node *) parseTree;
			break;
205 206
	}
	return result;
207 208 209 210
}

/*
 * transformDeleteStmt -
211
 *	  transforms a Delete Statement
212
 */
213
static Query *
214
transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
215
{
216
	Query	   *qry = makeNode(Query);
217

218
	qry->commandType = CMD_DELETE;
219

220 221
	/* set up a range table */
	makeRangeTable(pstate, stmt->relname, NULL);
222

223
	qry->uniqueFlag = NULL;
224

225 226
	/* fix where clause */
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
227
	qry->hasSubLinks = pstate->p_hasSubLinks;
228

229
	qry->rtable = pstate->p_rtable;
230
	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
231

B
Bruce Momjian 已提交
232
	qry->hasAggs = pstate->p_hasAggs;
233
	if (pstate->p_hasAggs)
234
		parseCheckAggregates(pstate, qry);
235

236
	return (Query *) qry;
237 238 239 240
}

/*
 * transformInsertStmt -
241
 *	  transform an Insert Statement
242
 */
243
static Query *
B
Bruce Momjian 已提交
244
transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
245
{
246
	Query	   *qry = makeNode(Query);	/* make a new query tree */
247
	List	   *icolumns;
248

249 250
	qry->commandType = CMD_INSERT;
	pstate->p_is_insert = true;
251

252 253
	/* set up a range table */
	makeRangeTable(pstate, stmt->relname, stmt->fromClause);
254

255
	qry->uniqueFlag = stmt->unique;
256

257
	/* fix the target list */
258
	icolumns = pstate->p_insert_columns = makeTargetNames(pstate, stmt->cols);
259

260
	qry->targetList = transformTargetList(pstate, stmt->targetList);
261

262 263 264 265 266
	/* 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)
	{
267 268 269 270 271
		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 已提交
272
		 * if stmt->cols == NIL then makeTargetNames returns list of all
273 274 275 276
		 * attrs: have to shorter icolumns list...
		 */
		if (stmt->cols == NIL)
		{
277 278 279 280
			List	   *extrl;
			int			i = length(qry->targetList);

			foreach(extrl, icolumns)
281 282 283 284
			{
				if (--i <= 0)
					break;
			}
285
			freeList(lnext(extrl));
286 287
			lnext(extrl) = NIL;
		}
288

289 290
		while (ndef-- > 0)
		{
291 292 293 294 295
			List	   *tl;
			Ident	   *id;
			TargetEntry *te;

			foreach(tl, icolumns)
296 297 298 299 300 301 302
			{
				id = (Ident *) lfirst(tl);
				if (!namestrcmp(&(att[defval[ndef].adnum - 1]->attname), id->name))
					break;
			}
			if (tl != NIL)		/* something given for this attr */
				continue;
303 304 305 306 307 308 309 310 311 312 313

			/*
			 * 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...
314 315 316 317
			 */
			te = makeNode(TargetEntry);
			te->resdom = makeResdom(defval[ndef].adnum,
									att[defval[ndef].adnum - 1]->atttypid,
318 319
								  att[defval[ndef].adnum - 1]->atttypmod,
			   pstrdup(nameout(&(att[defval[ndef].adnum - 1]->attname))),
320 321 322
									0, 0, 0);
			te->fjoin = NULL;
			te->expr = (Node *) stringToNode(defval[ndef].adbin);
323
			qry->targetList = lappend(qry->targetList, te);
324 325
		}
	}
326

327 328
	/* fix where clause */
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
329 330 331

	qry->havingQual = transformWhereClause(pstate, stmt->havingClause);

B
Bruce Momjian 已提交
332
	qry->hasSubLinks = pstate->p_hasSubLinks;
333

334 335
	/* now the range table will not change */
	qry->rtable = pstate->p_rtable;
336
	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
337

338 339 340 341 342 343 344 345 346 347 348
	qry->groupClause = transformGroupClause(pstate,
											stmt->groupClause,
											qry->targetList);

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

B
Bruce Momjian 已提交
349
	qry->hasAggs = pstate->p_hasAggs;
350
	if (pstate->p_hasAggs)
B
Bruce Momjian 已提交
351
		parseCheckAggregates(pstate, qry);
352

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

358
	return (Query *) qry;
359 360
}

B
Bruce Momjian 已提交
361 362 363
/*
 *	makeTableName()
 *	Create a table name from a list of fields.
364 365 366 367
 */
static char *
makeTableName(void *elem,...)
{
368
	va_list		args;
369

370 371
	char	   *name;
	char		buf[NAMEDATALEN + 1];
372

B
Bruce Momjian 已提交
373
	buf[0] = '\0';
374

375
	va_start(args, elem);
376 377 378 379 380

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

B
Bruce Momjian 已提交
384
		if (strlen(buf) > 0)
385 386
			strcat(buf, "_");
		strcat(buf, name);
387

388
		name = va_arg(args, void *);
389 390 391 392
	}

	va_end(args);

393 394
	name = palloc(strlen(buf) + 1);
	strcpy(name, buf);
395 396

	return (name);
B
Bruce Momjian 已提交
397
}
398

B
Bruce Momjian 已提交
399
static char *
400 401 402 403 404 405
CreateIndexName(char *tname, char *cname, char *label, List *indices)
{
	int			pass = 0;
	char	   *iname = NULL;
	List	   *ilist;
	IndexStmt  *index;
406
	char		name2[NAMEDATALEN + 1];
407 408

	/* use working storage, since we might be trying several possibilities */
409
	strcpy(name2, cname);
410 411 412 413 414 415 416 417 418 419 420
	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);
421
			if (strcasecmp(iname, index->idxname) == 0)
422 423 424 425 426 427 428 429 430 431 432 433
				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++;
434
		sprintf(name2, "%s_%d", cname, (pass + 1));
435 436 437
	}

	return (iname);
B
Bruce Momjian 已提交
438
}
439

440 441 442 443 444 445 446 447 448 449 450 451 452
/*
 * 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;
453
	int			have_pkey = FALSE;
454 455 456 457 458
	List	   *elements;
	Node	   *element;
	List	   *columns;
	List	   *dlist;
	ColumnDef  *column;
459 460
	List	   *constraints,
			   *clist;
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
	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;
483
				columns = lappend(columns, column);
484 485 486 487 488 489 490 491 492 493
				if (column->constraints != NIL)
				{
					clist = column->constraints;
					while (clist != NIL)
					{
						constraint = lfirst(clist);
						switch (constraint->contype)
						{
							case CONSTR_NOTNULL:
								if (column->is_not_null)
494 495
									elog(ERROR, "CREATE TABLE/NOT NULL already specified"
										 " for %s.%s", stmt->relname, column->colname);
496 497 498 499 500
								column->is_not_null = TRUE;
								break;

							case CONSTR_DEFAULT:
								if (column->defval != NULL)
501 502
									elog(ERROR, "CREATE TABLE/DEFAULT multiple values specified"
										 " for %s.%s", stmt->relname, column->colname);
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
								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)
525
									constraint->name = makeTableName(stmt->relname, column->colname, NULL);
526 527 528
								break;

							default:
529
								elog(ERROR, "parser: internal error; unrecognized constraint", NULL);
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
								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:
561
						elog(ERROR, "parser: internal error; illegal context for constraint", NULL);
562 563
						break;
					default:
564
						elog(ERROR, "parser: internal error; unrecognized constraint", NULL);
565 566 567 568 569
						break;
				}
				break;

			default:
570
				elog(ERROR, "parser: internal error; unrecognized node", NULL);
571 572 573 574 575 576 577 578 579 580 581 582 583
		}

		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
584 585 586
 *	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
587 588 589 590 591 592
 */
	ilist = NIL;
	while (dlist != NIL)
	{
		constraint = lfirst(dlist);
		if (nodeTag(constraint) != T_Constraint)
593
			elog(ERROR, "parser: internal error; unrecognized deferred node", NULL);
594

595
		if (constraint->contype == CONSTR_PRIMARY)
596
		{
597
			if (have_pkey)
598 599 600
				elog(ERROR, "CREATE TABLE/PRIMARY KEY multiple primary keys"
					 " for table %s are not legal", stmt->relname);
			else
601
				have_pkey = TRUE;
602
		}
603
		else if (constraint->contype != CONSTR_UNIQUE)
604
			elog(ERROR, "parser: internal error; unrecognized deferred constraint", NULL);
605

606 607 608 609 610 611
		index = makeNode(IndexStmt);

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

			have_pkey = TRUE;
617
			index->idxname = makeTableName(stmt->relname, "pkey", NULL);
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;
627

628 629 630 631 632 633 634 635 636
		keys = constraint->keys;
		while (keys != NIL)
		{
			key = lfirst(keys);
			columns = stmt->tableElts;
			column = NULL;
			while (columns != NIL)
			{
				column = lfirst(columns);
637 638 639 640
				if (strcasecmp(column->colname, key->name) == 0)
					break;
				else
					column = NULL;
641 642 643
				columns = lnext(columns);
			}
			if (column == NULL)
644
				elog(ERROR, "parser: column '%s' in key does not exist", key->name);
645 646 647 648

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

			if (index->idxname == NULL)
656
				index->idxname = CreateIndexName(stmt->relname, iparam->name, "key", ilist);
657 658 659 660 661

			keys = lnext(keys);
		}

		if (index->idxname == NULL)
662 663
			elog(ERROR, "parser: unable to construct implicit index for table %s"
				 "; name too long", stmt->relname);
664
		else
665 666 667
			elog(NOTICE, "CREATE TABLE/%s will create implicit index %s for table %s",
				 ((constraint->contype == CONSTR_PRIMARY) ? "PRIMARY KEY" : "UNIQUE"),
				 index->idxname, stmt->relname);
668

669
		ilist = lappend(ilist, index);
670 671 672 673 674 675 676
		dlist = lnext(dlist);
	}

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

	return q;
B
Bruce Momjian 已提交
677
}
678

679 680
/*
 * transformIndexStmt -
681
 *	  transforms the qualification of the index statement
682
 */
683
static Query *
684
transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
685
{
B
Bruce Momjian 已提交
686
	Query	   *qry;
687

B
Bruce Momjian 已提交
688 689
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
690

691 692
	/* take care of the where clause */
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
693
	qry->hasSubLinks = pstate->p_hasSubLinks;
694

695
	stmt->rangetable = pstate->p_rtable;
696

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

B
Bruce Momjian 已提交
699
	return qry;
700 701 702 703
}

/*
 * transformExtendStmt -
704
 *	  transform the qualifications of the Extend Index Statement
705 706
 *
 */
707
static Query *
708
transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
709
{
B
Bruce Momjian 已提交
710
	Query	   *qry;
711

B
Bruce Momjian 已提交
712 713
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
714

715 716
	/* take care of the where clause */
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
717 718
	qry->hasSubLinks = pstate->p_hasSubLinks;

719
	stmt->rangetable = pstate->p_rtable;
720

B
Bruce Momjian 已提交
721 722
	qry->utilityStmt = (Node *) stmt;
	return qry;
723 724 725 726
}

/*
 * transformRuleStmt -
727 728
 *	  transform a Create Rule Statement. The actions is a list of parse
 *	  trees which is transformed into a list of query trees.
729
 */
730
static Query *
731
transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
732
{
B
Bruce Momjian 已提交
733
	Query	   *qry;
734
	List	   *actions;
735

B
Bruce Momjian 已提交
736 737
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
738 739 740

	actions = stmt->actions;

741
	/*
742
	 * transform each statment, like parse_analyze()
743
	 */
744 745
	while (actions != NIL)
	{
746

747 748 749 750 751
		/*
		 * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
		 * equal to 2.
		 */
		addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
752
						   FALSE, FALSE);
753
		addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
754
						   FALSE, FALSE);
755 756 757

		pstate->p_last_resno = 1;
		pstate->p_is_rule = true;		/* for expand all */
758
		pstate->p_hasAggs = false;
759 760 761 762

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

764 765
	/* take care of the where clause */
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
766
	qry->hasSubLinks = pstate->p_hasSubLinks;
767

B
Bruce Momjian 已提交
768 769
	qry->utilityStmt = (Node *) stmt;
	return qry;
770 771 772 773 774
}


/*
 * transformSelectStmt -
775
 *	  transforms a Select Statement
776 777
 *
 */
778
static Query *
B
Bruce Momjian 已提交
779
transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
780
{
781
	Query	   *qry = makeNode(Query);
782 783

	qry->commandType = CMD_SELECT;
784

785 786
	/* set up a range table */
	makeRangeTable(pstate, NULL, stmt->fromClause);
787

788
	qry->uniqueFlag = stmt->unique;
789

790 791
	qry->into = stmt->into;
	qry->isPortal = FALSE;
792

793
	qry->targetList = transformTargetList(pstate, stmt->targetList);
794

795
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
796 797 798

	qry->havingQual = transformWhereClause(pstate, stmt->havingClause);

B
Bruce Momjian 已提交
799
	qry->hasSubLinks = pstate->p_hasSubLinks;
800

801 802
	qry->sortClause = transformSortClause(pstate,
										  stmt->sortClause,
B
Bruce Momjian 已提交
803
										  NIL,
804 805
										  qry->targetList,
										  qry->uniqueFlag);
806

807 808 809 810
	qry->groupClause = transformGroupClause(pstate,
											stmt->groupClause,
											qry->targetList);
	qry->rtable = pstate->p_rtable;
811

B
Bruce Momjian 已提交
812
	qry->hasAggs = pstate->p_hasAggs;
813
	if (pstate->p_hasAggs)
B
Bruce Momjian 已提交
814
		parseCheckAggregates(pstate, qry);
815

816 817
	qry->unionall = stmt->unionall;		/* in child, so unionClause may be
										 * false */
818
	qry->unionClause = transformUnionClause(stmt->unionClause, qry->targetList);
819

820
	return (Query *) qry;
821 822 823 824
}

/*
 * transformUpdateStmt -
825
 *	  transforms an update statement
826 827
 *
 */
828
static Query *
B
Bruce Momjian 已提交
829
transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
830
{
831
	Query	   *qry = makeNode(Query);
832 833 834

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

836 837 838 839 840
	/*
	 * 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);
841

842
	qry->targetList = transformTargetList(pstate, stmt->targetList);
843

844
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
845
	qry->hasSubLinks = pstate->p_hasSubLinks;
846

847
	qry->rtable = pstate->p_rtable;
848

849
	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
850

B
Bruce Momjian 已提交
851
	qry->hasAggs = pstate->p_hasAggs;
852
	if (pstate->p_hasAggs)
853
		parseCheckAggregates(pstate, qry);
854

855
	return (Query *) qry;
856 857 858 859
}

/*
 * transformCursorStmt -
860
 *	  transform a Create Cursor Statement
861 862
 *
 */
863
static Query *
864
transformCursorStmt(ParseState *pstate, SelectStmt *stmt)
865
{
866
	Query	   *qry;
867

868
	qry = transformSelectStmt(pstate, stmt);
869

870 871 872
	qry->into = stmt->portalname;
	qry->isPortal = TRUE;
	qry->isBinary = stmt->binary;		/* internal portal */
873

874
	return qry;
875
}