analyze.c 21.7 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.71 1998/02/26 04:33:26 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 586
		if (constraint->contype == CONSTR_PRIMARY)
			if (have_pkey)
587 588 589
				elog(ERROR, "CREATE TABLE/PRIMARY KEY multiple primary keys"
					 " for table %s are not legal", stmt->relname);
			else
590 591
				have_pkey = TRUE;
		else if (constraint->contype != CONSTR_UNIQUE)
592
			elog(ERROR, "parser: internal error; unrecognized deferred constraint", NULL);
593

594 595 596 597 598 599
		index = makeNode(IndexStmt);

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

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

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

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

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

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

			keys = lnext(keys);
		}

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

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

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

	return q;
B
Bruce Momjian 已提交
665
}
666

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

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

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

683
	stmt->rangetable = pstate->p_rtable;
684

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

B
Bruce Momjian 已提交
687
	return qry;
688 689 690 691
}

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

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

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

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

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

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

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

	actions = stmt->actions;

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

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

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

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

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

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


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

	qry->commandType = CMD_SELECT;
772

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

776
	qry->uniqueFlag = stmt->unique;
777

778 779
	qry->into = stmt->into;
	qry->isPortal = FALSE;
780

781
	qry->targetList = transformTargetList(pstate, stmt->targetList);
782

783
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
784
	qry->hasSubLinks = pstate->p_hasSubLinks;
785

786 787
	qry->sortClause = transformSortClause(pstate,
										  stmt->sortClause,
B
Bruce Momjian 已提交
788
										  NIL,
789 790
										  qry->targetList,
										  qry->uniqueFlag);
791

792 793 794 795
	qry->groupClause = transformGroupClause(pstate,
											stmt->groupClause,
											qry->targetList);
	qry->rtable = pstate->p_rtable;
796

B
Bruce Momjian 已提交
797
	qry->hasAggs = pstate->p_hasAggs;
798
	if (pstate->p_hasAggs)
B
Bruce Momjian 已提交
799
		parseCheckAggregates(pstate, qry);
800

801 802
	qry->unionall = stmt->unionall;		/* in child, so unionClause may be
										 * false */
803
	qry->unionClause = transformUnionClause(stmt->unionClause, qry->targetList);
804

805
	return (Query *) qry;
806 807 808 809
}

/*
 * transformUpdateStmt -
810
 *	  transforms an update statement
811 812
 *
 */
813
static Query *
B
Bruce Momjian 已提交
814
transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
815
{
816
	Query	   *qry = makeNode(Query);
817 818 819

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

821 822 823 824 825
	/*
	 * 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);
826

827
	qry->targetList = transformTargetList(pstate, stmt->targetList);
828

829
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
830
	qry->hasSubLinks = pstate->p_hasSubLinks;
831

832
	qry->rtable = pstate->p_rtable;
833

834
	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
835

B
Bruce Momjian 已提交
836
	qry->hasAggs = pstate->p_hasAggs;
837
	if (pstate->p_hasAggs)
838
		parseCheckAggregates(pstate, qry);
839

840
	return (Query *) qry;
841 842 843 844
}

/*
 * transformCursorStmt -
845
 *	  transform a Create Cursor Statement
846 847
 *
 */
848
static Query *
849
transformCursorStmt(ParseState *pstate, SelectStmt *stmt)
850
{
851
	Query	   *qry;
852

853
	qry = transformSelectStmt(pstate, stmt);
854

855 856 857
	qry->into = stmt->portalname;
	qry->isPortal = TRUE;
	qry->isBinary = stmt->binary;		/* internal portal */
858

859
	return qry;
860
}