analyze.c 21.8 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.73 1998/03/30 16:47:02 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))
	{
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

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
			if (!((SelectStmt *) parseTree)->portalname)
183 184 185
				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
	qry->hasSubLinks = pstate->p_hasSubLinks;
221

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
	icolumns = pstate->p_insert_columns = makeTargetNames(pstate, stmt->cols);
252

253
	qry->targetList = transformTargetList(pstate, stmt->targetList);
254

255 256 257 258 259
	/* 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)
	{
260 261 262 263 264
		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
		 * attrs: have to shorter icolumns list...
		 */
		if (stmt->cols == NIL)
		{
270 271 272 273
			List	   *extrl;
			int			i = length(qry->targetList);

			foreach(extrl, icolumns)
274 275 276 277
			{
				if (--i <= 0)
					break;
			}
278
			freeList(lnext(extrl));
279 280
			lnext(extrl) = NIL;
		}
281

282 283
		while (ndef-- > 0)
		{
284 285 286 287 288
			List	   *tl;
			Ident	   *id;
			TargetEntry *te;

			foreach(tl, icolumns)
289 290 291 292 293 294 295
			{
				id = (Ident *) lfirst(tl);
				if (!namestrcmp(&(att[defval[ndef].adnum - 1]->attname), id->name))
					break;
			}
			if (tl != NIL)		/* something given for this attr */
				continue;
296 297 298 299 300 301 302 303 304 305 306

			/*
			 * 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...
307 308 309 310
			 */
			te = makeNode(TargetEntry);
			te->resdom = makeResdom(defval[ndef].adnum,
									att[defval[ndef].adnum - 1]->atttypid,
311 312
								  att[defval[ndef].adnum - 1]->atttypmod,
			   pstrdup(nameout(&(att[defval[ndef].adnum - 1]->attname))),
313 314 315
									0, 0, 0);
			te->fjoin = NULL;
			te->expr = (Node *) stringToNode(defval[ndef].adbin);
316
			qry->targetList = lappend(qry->targetList, te);
317 318
		}
	}
319

320 321
	/* fix where clause */
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
322
	qry->hasSubLinks = pstate->p_hasSubLinks;
323

324 325
	/* now the range table will not change */
	qry->rtable = pstate->p_rtable;
326
	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
327

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

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

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

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

348
	return (Query *) qry;
349 350
}

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

360 361
	char	   *name;
	char		buf[NAMEDATALEN + 1];
362

B
Bruce Momjian 已提交
363
	buf[0] = '\0';
364

365
	va_start(args, elem);
366 367 368 369 370

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

B
Bruce Momjian 已提交
374
		if (strlen(buf) > 0)
375 376
			strcat(buf, "_");
		strcat(buf, name);
377

378
		name = va_arg(args, void *);
379 380 381 382
	}

	va_end(args);

383 384
	name = palloc(strlen(buf) + 1);
	strcpy(name, buf);
385 386

	return (name);
B
Bruce Momjian 已提交
387
}
388

B
Bruce Momjian 已提交
389
static char *
390 391 392 393 394 395
CreateIndexName(char *tname, char *cname, char *label, List *indices)
{
	int			pass = 0;
	char	   *iname = NULL;
	List	   *ilist;
	IndexStmt  *index;
396
	char		name2[NAMEDATALEN + 1];
397 398

	/* use working storage, since we might be trying several possibilities */
399
	strcpy(name2, cname);
400 401 402 403 404 405 406 407 408 409 410
	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);
411
			if (strcasecmp(iname, index->idxname) == 0)
412 413 414 415 416 417 418 419 420 421 422 423
				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++;
424
		sprintf(name2, "%s_%d", cname, (pass + 1));
425 426 427
	}

	return (iname);
B
Bruce Momjian 已提交
428
}
429

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

							case CONSTR_DEFAULT:
								if (column->defval != NULL)
491 492
									elog(ERROR, "CREATE TABLE/DEFAULT multiple values specified"
										 " for %s.%s", stmt->relname, column->colname);
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
								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)
515
									constraint->name = makeTableName(stmt->relname, column->colname, NULL);
516 517 518
								break;

							default:
519
								elog(ERROR, "parser: internal error; unrecognized constraint", NULL);
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 548 549 550
								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:
551
						elog(ERROR, "parser: internal error; illegal context for constraint", NULL);
552 553
						break;
					default:
554
						elog(ERROR, "parser: internal error; unrecognized constraint", NULL);
555 556 557 558 559
						break;
				}
				break;

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

		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
574 575 576
 *	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
577 578 579 580 581 582
 */
	ilist = NIL;
	while (dlist != NIL)
	{
		constraint = lfirst(dlist);
		if (nodeTag(constraint) != T_Constraint)
583
			elog(ERROR, "parser: internal error; unrecognized deferred node", NULL);
584

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

596 597 598 599 600 601
		index = makeNode(IndexStmt);

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

			have_pkey = TRUE;
607
			index->idxname = makeTableName(stmt->relname, "pkey", NULL);
608
		}
609 610 611 612 613 614 615 616
		else
			index->idxname = NULL;

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

618 619 620 621 622 623 624 625 626
		keys = constraint->keys;
		while (keys != NIL)
		{
			key = lfirst(keys);
			columns = stmt->tableElts;
			column = NULL;
			while (columns != NIL)
			{
				column = lfirst(columns);
627 628 629 630
				if (strcasecmp(column->colname, key->name) == 0)
					break;
				else
					column = NULL;
631 632 633
				columns = lnext(columns);
			}
			if (column == NULL)
634
				elog(ERROR, "parser: column '%s' in key does not exist", key->name);
635 636 637 638

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

			if (index->idxname == NULL)
646
				index->idxname = CreateIndexName(stmt->relname, iparam->name, "key", ilist);
647 648 649 650 651

			keys = lnext(keys);
		}

		if (index->idxname == NULL)
652 653
			elog(ERROR, "parser: unable to construct implicit index for table %s"
				 "; name too long", stmt->relname);
654
		else
655 656 657
			elog(NOTICE, "CREATE TABLE/%s will create implicit index %s for table %s",
				 ((constraint->contype == CONSTR_PRIMARY) ? "PRIMARY KEY" : "UNIQUE"),
				 index->idxname, stmt->relname);
658

659
		ilist = lappend(ilist, index);
660 661 662 663 664 665 666
		dlist = lnext(dlist);
	}

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

	return q;
B
Bruce Momjian 已提交
667
}
668

669 670
/*
 * transformIndexStmt -
671
 *	  transforms the qualification of the index statement
672
 */
673
static Query *
674
transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
675
{
B
Bruce Momjian 已提交
676
	Query	   *qry;
677

B
Bruce Momjian 已提交
678 679
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
680

681 682
	/* take care of the where clause */
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
683
	qry->hasSubLinks = pstate->p_hasSubLinks;
684

685
	stmt->rangetable = pstate->p_rtable;
686

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

B
Bruce Momjian 已提交
689
	return qry;
690 691 692 693
}

/*
 * transformExtendStmt -
694
 *	  transform the qualifications of the Extend Index Statement
695 696
 *
 */
697
static Query *
698
transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
699
{
B
Bruce Momjian 已提交
700
	Query	   *qry;
701

B
Bruce Momjian 已提交
702 703
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
704

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

709
	stmt->rangetable = pstate->p_rtable;
710

B
Bruce Momjian 已提交
711 712
	qry->utilityStmt = (Node *) stmt;
	return qry;
713 714 715 716
}

/*
 * transformRuleStmt -
717 718
 *	  transform a Create Rule Statement. The actions is a list of parse
 *	  trees which is transformed into a list of query trees.
719
 */
720
static Query *
721
transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
722
{
B
Bruce Momjian 已提交
723
	Query	   *qry;
724
	List	   *actions;
725

B
Bruce Momjian 已提交
726 727
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
728 729 730

	actions = stmt->actions;

731
	/*
732
	 * transform each statment, like parse_analyze()
733
	 */
734 735
	while (actions != NIL)
	{
736

737 738 739 740 741
		/*
		 * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
		 * equal to 2.
		 */
		addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
742
						   FALSE, FALSE);
743
		addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
744
						   FALSE, FALSE);
745 746 747

		pstate->p_last_resno = 1;
		pstate->p_is_rule = true;		/* for expand all */
748
		pstate->p_hasAggs = false;
749 750 751 752

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

754 755
	/* take care of the where clause */
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
756
	qry->hasSubLinks = pstate->p_hasSubLinks;
757

B
Bruce Momjian 已提交
758 759
	qry->utilityStmt = (Node *) stmt;
	return qry;
760 761 762 763 764
}


/*
 * transformSelectStmt -
765
 *	  transforms a Select Statement
766 767
 *
 */
768
static Query *
B
Bruce Momjian 已提交
769
transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
770
{
771
	Query	   *qry = makeNode(Query);
772 773

	qry->commandType = CMD_SELECT;
774

775 776
	/* set up a range table */
	makeRangeTable(pstate, NULL, stmt->fromClause);
777

778
	qry->uniqueFlag = stmt->unique;
779

780 781
	qry->into = stmt->into;
	qry->isPortal = FALSE;
782

783
	qry->targetList = transformTargetList(pstate, stmt->targetList);
784

785
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
786 787 788 789

        /***S*H***/
	qry->havingQual = transformWhereClause(pstate, stmt->havingClause);

B
Bruce Momjian 已提交
790
	qry->hasSubLinks = pstate->p_hasSubLinks;
791

792 793
	qry->sortClause = transformSortClause(pstate,
										  stmt->sortClause,
B
Bruce Momjian 已提交
794
										  NIL,
795 796
										  qry->targetList,
										  qry->uniqueFlag);
797

798 799 800 801
	qry->groupClause = transformGroupClause(pstate,
											stmt->groupClause,
											qry->targetList);
	qry->rtable = pstate->p_rtable;
802

B
Bruce Momjian 已提交
803
	qry->hasAggs = pstate->p_hasAggs;
804
	if (pstate->p_hasAggs)
B
Bruce Momjian 已提交
805
		parseCheckAggregates(pstate, qry);
806

807 808
	qry->unionall = stmt->unionall;		/* in child, so unionClause may be
										 * false */
809
	qry->unionClause = transformUnionClause(stmt->unionClause, qry->targetList);
810

811
	return (Query *) qry;
812 813 814 815
}

/*
 * transformUpdateStmt -
816
 *	  transforms an update statement
817 818
 *
 */
819
static Query *
B
Bruce Momjian 已提交
820
transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
821
{
822
	Query	   *qry = makeNode(Query);
823 824 825

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

827 828 829 830 831
	/*
	 * 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);
832

833
	qry->targetList = transformTargetList(pstate, stmt->targetList);
834

835
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
836
	qry->hasSubLinks = pstate->p_hasSubLinks;
837

838
	qry->rtable = pstate->p_rtable;
839

840
	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
841

B
Bruce Momjian 已提交
842
	qry->hasAggs = pstate->p_hasAggs;
843
	if (pstate->p_hasAggs)
844
		parseCheckAggregates(pstate, qry);
845

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

/*
 * transformCursorStmt -
851
 *	  transform a Create Cursor Statement
852 853
 *
 */
854
static Query *
855
transformCursorStmt(ParseState *pstate, SelectStmt *stmt)
856
{
857
	Query	   *qry;
858

859
	qry = transformSelectStmt(pstate, stmt);
860

861 862 863
	qry->into = stmt->portalname;
	qry->isPortal = TRUE;
	qry->isBinary = stmt->binary;		/* internal portal */
864

865
	return qry;
866
}