analyze.c 23.1 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.79 1998/07/20 20:48:51 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
#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
			te = makeTargetEntry(makeResdom(defval[ndef].adnum,
316
									att[defval[ndef].adnum - 1]->atttypid,
317 318
									att[defval[ndef].adnum - 1]->atttypmod,
									pstrdup(nameout(&(att[defval[ndef].adnum - 1]->attname))),
319
									0, 0, 0),
B
Bruce Momjian 已提交
320
						(Node *) stringToNode(defval[ndef].adbin));
321
			qry->targetList = lappend(qry->targetList, te);
322 323
		}
	}
324

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

328 329 330
	/* The havingQual has a similar meaning as "qual" in the where statement. 
	 * So we can easily use the code from the "where clause" with some additional
         * traversals done in .../optimizer/plan/planner.c */
B
Bruce Momjian 已提交
331 332
	qry->havingQual = transformWhereClause(pstate, stmt->havingClause);

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

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

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

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

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

354 355 356 357
	/* The INSERT INTO ... SELECT ... could have a UNION
	 * in child, so unionClause may be false
	 */
	qry->unionall = stmt->unionall;
358 359
	qry->unionClause = transformUnionClause(stmt->unionClause, qry->targetList);

360 361 362 363 364 365 366 367 368
	/* If there is a havingQual but there are no aggregates, then there is something wrong
	 * with the query because having must contain aggregates in its expressions! 
	 * Otherwise the query could have been formulated using the where clause. */
	if((qry->hasAggs == false) && (qry->havingQual != NULL))
	  {
	    elog(ERROR,"This is not a valid having query!");
	    return (Query *)NIL;
	  }

369
	return (Query *) qry;
370 371
}

B
Bruce Momjian 已提交
372 373 374
/*
 *	makeTableName()
 *	Create a table name from a list of fields.
375 376 377 378
 */
static char *
makeTableName(void *elem,...)
{
379
	va_list		args;
380

381 382
	char	   *name;
	char		buf[NAMEDATALEN + 1];
383

B
Bruce Momjian 已提交
384
	buf[0] = '\0';
385

386
	va_start(args, elem);
387 388 389 390 391

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

B
Bruce Momjian 已提交
395
		if (strlen(buf) > 0)
396 397
			strcat(buf, "_");
		strcat(buf, name);
398

399
		name = va_arg(args, void *);
400 401 402 403
	}

	va_end(args);

404 405
	name = palloc(strlen(buf) + 1);
	strcpy(name, buf);
406 407

	return (name);
B
Bruce Momjian 已提交
408
}
409

B
Bruce Momjian 已提交
410
static char *
411 412 413 414 415 416
CreateIndexName(char *tname, char *cname, char *label, List *indices)
{
	int			pass = 0;
	char	   *iname = NULL;
	List	   *ilist;
	IndexStmt  *index;
417
	char		name2[NAMEDATALEN + 1];
418 419

	/* use working storage, since we might be trying several possibilities */
420
	strcpy(name2, cname);
421 422 423 424 425 426 427 428 429 430 431
	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);
432
			if (strcasecmp(iname, index->idxname) == 0)
433 434 435 436 437 438 439 440 441 442 443 444
				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++;
445
		sprintf(name2, "%s_%d", cname, (pass + 1));
446 447 448
	}

	return (iname);
B
Bruce Momjian 已提交
449
}
450

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

							case CONSTR_DEFAULT:
								if (column->defval != NULL)
512 513
									elog(ERROR, "CREATE TABLE/DEFAULT multiple values specified"
										 " for %s.%s", stmt->relname, column->colname);
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
								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)
536
									constraint->name = makeTableName(stmt->relname, column->colname, NULL);
537 538 539
								break;

							default:
540
								elog(ERROR, "parser: internal error; unrecognized constraint", NULL);
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
								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:
572
						elog(ERROR, "parser: internal error; illegal context for constraint", NULL);
573 574
						break;
					default:
575
						elog(ERROR, "parser: internal error; unrecognized constraint", NULL);
576 577 578 579 580
						break;
				}
				break;

			default:
581
				elog(ERROR, "parser: internal error; unrecognized node", NULL);
582 583 584 585 586 587 588 589 590 591 592 593 594
		}

		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
595 596 597
 *	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
598 599 600 601 602 603
 */
	ilist = NIL;
	while (dlist != NIL)
	{
		constraint = lfirst(dlist);
		if (nodeTag(constraint) != T_Constraint)
604
			elog(ERROR, "parser: internal error; unrecognized deferred node", NULL);
605

606
		if (constraint->contype == CONSTR_PRIMARY)
607
		{
608
			if (have_pkey)
609 610 611
				elog(ERROR, "CREATE TABLE/PRIMARY KEY multiple primary keys"
					 " for table %s are not legal", stmt->relname);
			else
612
				have_pkey = TRUE;
613
		}
614
		else if (constraint->contype != CONSTR_UNIQUE)
615
			elog(ERROR, "parser: internal error; unrecognized deferred constraint", NULL);
616

617 618 619 620 621 622
		index = makeNode(IndexStmt);

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

			have_pkey = TRUE;
628
			index->idxname = makeTableName(stmt->relname, "pkey", NULL);
629
		}
630 631 632 633 634 635 636 637
		else
			index->idxname = NULL;

		index->relname = stmt->relname;
		index->accessMethod = "btree";
		index->indexParams = NIL;
		index->withClause = NIL;
		index->whereClause = NULL;
638

639 640 641 642 643 644 645 646 647
		keys = constraint->keys;
		while (keys != NIL)
		{
			key = lfirst(keys);
			columns = stmt->tableElts;
			column = NULL;
			while (columns != NIL)
			{
				column = lfirst(columns);
648 649 650 651
				if (strcasecmp(column->colname, key->name) == 0)
					break;
				else
					column = NULL;
652 653 654
				columns = lnext(columns);
			}
			if (column == NULL)
655
				elog(ERROR, "parser: column '%s' in key does not exist", key->name);
656 657 658 659

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

			if (index->idxname == NULL)
667
				index->idxname = CreateIndexName(stmt->relname, iparam->name, "key", ilist);
668 669 670 671 672

			keys = lnext(keys);
		}

		if (index->idxname == NULL)
673 674
			elog(ERROR, "parser: unable to construct implicit index for table %s"
				 "; name too long", stmt->relname);
675
		else
676 677 678
			elog(NOTICE, "CREATE TABLE/%s will create implicit index %s for table %s",
				 ((constraint->contype == CONSTR_PRIMARY) ? "PRIMARY KEY" : "UNIQUE"),
				 index->idxname, stmt->relname);
679

680
		ilist = lappend(ilist, index);
681 682 683 684 685 686 687
		dlist = lnext(dlist);
	}

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

	return q;
B
Bruce Momjian 已提交
688
}
689

690 691
/*
 * transformIndexStmt -
692
 *	  transforms the qualification of the index statement
693
 */
694
static Query *
695
transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
696
{
B
Bruce Momjian 已提交
697
	Query	   *qry;
698

B
Bruce Momjian 已提交
699 700
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
701

702 703
	/* take care of the where clause */
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
704
	qry->hasSubLinks = pstate->p_hasSubLinks;
705

706
	stmt->rangetable = pstate->p_rtable;
707

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

B
Bruce Momjian 已提交
710
	return qry;
711 712 713 714
}

/*
 * transformExtendStmt -
715
 *	  transform the qualifications of the Extend Index Statement
716 717
 *
 */
718
static Query *
719
transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
720
{
B
Bruce Momjian 已提交
721
	Query	   *qry;
722

B
Bruce Momjian 已提交
723 724
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
725

726 727
	/* take care of the where clause */
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
728 729
	qry->hasSubLinks = pstate->p_hasSubLinks;

730
	stmt->rangetable = pstate->p_rtable;
731

B
Bruce Momjian 已提交
732 733
	qry->utilityStmt = (Node *) stmt;
	return qry;
734 735 736 737
}

/*
 * transformRuleStmt -
738 739
 *	  transform a Create Rule Statement. The actions is a list of parse
 *	  trees which is transformed into a list of query trees.
740
 */
741
static Query *
742
transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
743
{
B
Bruce Momjian 已提交
744
	Query	   *qry;
745
	List	   *actions;
746

B
Bruce Momjian 已提交
747 748
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
749 750 751

	actions = stmt->actions;

752
	/*
753
	 * transform each statment, like parse_analyze()
754
	 */
755 756
	while (actions != NIL)
	{
757

758 759 760 761 762
		/*
		 * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
		 * equal to 2.
		 */
		addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
763
						   FALSE, FALSE);
764
		addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
765
						   FALSE, FALSE);
766 767 768

		pstate->p_last_resno = 1;
		pstate->p_is_rule = true;		/* for expand all */
769
		pstate->p_hasAggs = false;
770 771 772 773

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

775 776
	/* take care of the where clause */
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
777
	qry->hasSubLinks = pstate->p_hasSubLinks;
778

B
Bruce Momjian 已提交
779 780
	qry->utilityStmt = (Node *) stmt;
	return qry;
781 782 783 784 785
}


/*
 * transformSelectStmt -
786
 *	  transforms a Select Statement
787 788
 *
 */
789
static Query *
B
Bruce Momjian 已提交
790
transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
791
{
792
	Query	   *qry = makeNode(Query);
793 794

	qry->commandType = CMD_SELECT;
795

796 797
	/* set up a range table */
	makeRangeTable(pstate, NULL, stmt->fromClause);
798

799
	qry->uniqueFlag = stmt->unique;
800

801 802
	qry->into = stmt->into;
	qry->isPortal = FALSE;
803

804
	qry->targetList = transformTargetList(pstate, stmt->targetList);
805

806
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
807

808 809 810
	/* The havingQual has a similar meaning as "qual" in the where statement. 
	 * So we can easily use the code from the "where clause" with some additional
         * traversals done in .../optimizer/plan/planner.c */
811 812
	qry->havingQual = transformWhereClause(pstate, stmt->havingClause);

B
Bruce Momjian 已提交
813
	qry->hasSubLinks = pstate->p_hasSubLinks;
814

815 816
	qry->sortClause = transformSortClause(pstate,
										  stmt->sortClause,
B
Bruce Momjian 已提交
817
										  NIL,
818 819
										  qry->targetList,
										  qry->uniqueFlag);
820

821 822 823 824
	qry->groupClause = transformGroupClause(pstate,
											stmt->groupClause,
											qry->targetList);
	qry->rtable = pstate->p_rtable;
825

B
Bruce Momjian 已提交
826
	qry->hasAggs = pstate->p_hasAggs;
827
	if (pstate->p_hasAggs)
B
Bruce Momjian 已提交
828
		parseCheckAggregates(pstate, qry);
829

830 831 832 833
	/* The INSERT INTO ... SELECT ... could have a UNION
	 * in child, so unionClause may be false
	 */
	qry->unionall = stmt->unionall;
834
	qry->unionClause = transformUnionClause(stmt->unionClause, qry->targetList);
835

836 837 838 839 840 841 842 843 844
	/* If there is a havingQual but there are no aggregates, then there is something wrong
	 * with the query because having must contain aggregates in its expressions! 
	 * Otherwise the query could have been formulated using the where clause. */
	if((qry->hasAggs == false) && (qry->havingQual != NULL))
	  {
	    elog(ERROR,"This is not a valid having query!");
	    return (Query *)NIL;
	  }

845
	return (Query *) qry;
846 847 848 849
}

/*
 * transformUpdateStmt -
850
 *	  transforms an update statement
851 852
 *
 */
853
static Query *
B
Bruce Momjian 已提交
854
transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
855
{
856
	Query	   *qry = makeNode(Query);
857 858 859

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

861 862 863 864 865
	/*
	 * 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);
866

867
	qry->targetList = transformTargetList(pstate, stmt->targetList);
868

869
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
870
	qry->hasSubLinks = pstate->p_hasSubLinks;
871

872
	qry->rtable = pstate->p_rtable;
873

874
	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
875

B
Bruce Momjian 已提交
876
	qry->hasAggs = pstate->p_hasAggs;
877
	if (pstate->p_hasAggs)
878
		parseCheckAggregates(pstate, qry);
879

880
	return (Query *) qry;
881 882 883 884
}

/*
 * transformCursorStmt -
885
 *	  transform a Create Cursor Statement
886 887
 *
 */
888
static Query *
889
transformCursorStmt(ParseState *pstate, SelectStmt *stmt)
890
{
891
	Query	   *qry;
892

893
	qry = transformSelectStmt(pstate, stmt);
894

895 896 897
	qry->into = stmt->portalname;
	qry->isPortal = TRUE;
	qry->isBinary = stmt->binary;		/* internal portal */
898

899
	return qry;
900
}