analyze.c 31.3 KB
Newer Older
1 2 3
/*-------------------------------------------------------------------------
 *
 * analyze.c--
4
 *	  transform the parse tree into a query tree
5 6 7
 *
 * Copyright (c) 1994, Regents of the University of California
 *
8
 *  $Id: analyze.c,v 1.95 1999/01/25 12:01:05 vadim Exp $
9 10 11
 *
 *-------------------------------------------------------------------------
 */
12

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

B
Bruce Momjian 已提交
18
#include "postgres.h"
19 20 21 22 23 24
#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 已提交
25
#include "parser/parse_clause.h"
26 27 28
#include "parser/parse_node.h"
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
B
Hi!  
Bruce Momjian 已提交
29 30 31 32 33
/***S*I***/
#include "parser/parse_expr.h"
#include "catalog/pg_type.h"
#include "parse.h"

34 35
#include "utils/builtins.h"
#include "utils/mcxt.h"
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 49
static void		transformForUpdate(Query *qry, List *forUpdate);
void			CheckSelectForUpdate(Query *qry);
50

B
Bruce Momjian 已提交
51 52
List	   *extras_before = NIL;
List	   *extras_after = NIL;
B
Bruce Momjian 已提交
53

54 55
/*
 * parse_analyze -
56
 *	  analyze a list of parse trees and transform them if necessary.
57 58 59 60 61
 *
 * Returns a list of transformed parse trees. Optimizable statements are
 * all transformed to Query while the rest stays the same.
 *
 */
62
QueryTreeList *
63
parse_analyze(List *pl, ParseState *parentParseState)
64
{
65 66
	QueryTreeList *result;
	ParseState *pstate;
B
Bruce Momjian 已提交
67
	Query *parsetree;
68
	int			i = 0;
69 70 71 72 73 74 75

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

	while (pl != NIL)
	{
76
		pstate = make_parsestate(parentParseState);
B
Bruce Momjian 已提交
77
		parsetree = transformStmt(pstate, lfirst(pl));
B
Bruce Momjian 已提交
78 79 80
		if (pstate->p_target_relation != NULL)
			heap_close(pstate->p_target_relation);

B
Bruce Momjian 已提交
81
		if (extras_before != NIL)
82
		{
B
Bruce Momjian 已提交
83
			result->len += length(extras_before);
84
			result->qtrees = (Query **) realloc(result->qtrees, result->len * sizeof(Query *));
B
Bruce Momjian 已提交
85
			while (extras_before != NIL)
86
			{
B
Bruce Momjian 已提交
87
				result->qtrees[i++] = transformStmt(pstate, lfirst(extras_before));
B
Bruce Momjian 已提交
88 89
				if (pstate->p_target_relation != NULL)
					heap_close(pstate->p_target_relation);
B
Bruce Momjian 已提交
90
				extras_before = lnext(extras_before);
91 92
			}
		}
B
Bruce Momjian 已提交
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
		extras_before = NIL;

		result->qtrees[i++] = parsetree;

		if (extras_after != NIL)
		{
			result->len += length(extras_after);
			result->qtrees = (Query **) realloc(result->qtrees, result->len * sizeof(Query *));
			while (extras_after != NIL)
			{
				result->qtrees[i++] = transformStmt(pstate, lfirst(extras_after));
				if (pstate->p_target_relation != NULL)
					heap_close(pstate->p_target_relation);
				extras_after = lnext(extras_after);
			}
		}
		extras_after = NIL;

111
		pl = lnext(pl);
B
Bruce Momjian 已提交
112
		pfree(pstate);
113 114 115
	}

	return result;
116 117 118 119
}

/*
 * transformStmt -
120 121
 *	  transform a Parse tree. If it is an optimizable statement, turn it
 *	  into a Query tree.
122
 */
123
static Query *
124
transformStmt(ParseState *pstate, Node *parseTree)
125
{
126
	Query	   *result = NULL;
127 128 129

	switch (nodeTag(parseTree))
	{
130 131 132 133
			/*------------------------
			 *	Non-optimizable statements
			 *------------------------
			 */
134 135 136 137
		case T_CreateStmt:
			result = transformCreateStmt(pstate, (CreateStmt *) parseTree);
			break;

138 139 140
		case T_IndexStmt:
			result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
			break;
141

142 143 144
		case T_ExtendStmt:
			result = transformExtendStmt(pstate, (ExtendStmt *) parseTree);
			break;
145

146 147 148
		case T_RuleStmt:
			result = transformRuleStmt(pstate, (RuleStmt *) parseTree);
			break;
149

150 151 152
		case T_ViewStmt:
			{
				ViewStmt   *n = (ViewStmt *) parseTree;
153

154 155 156 157 158 159
				n->query = (Query *) transformStmt(pstate, (Node *) n->query);
				result = makeNode(Query);
				result->commandType = CMD_UTILITY;
				result->utilityStmt = (Node *) n;
			}
			break;
160

161 162 163
		case T_VacuumStmt:
			{
				MemoryContext oldcontext;
164

165 166 167 168 169 170 171 172 173 174 175 176
				/*
				 * 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;
177

178 179 180 181
			}
		case T_ExplainStmt:
			{
				ExplainStmt *n = (ExplainStmt *) parseTree;
182

183 184 185 186 187 188
				result = makeNode(Query);
				result->commandType = CMD_UTILITY;
				n->query = transformStmt(pstate, (Node *) n->query);
				result->utilityStmt = (Node *) parseTree;
			}
			break;
189

190 191 192 193
			/*------------------------
			 *	Optimizable statements
			 *------------------------
			 */
B
Bruce Momjian 已提交
194 195
		case T_InsertStmt:
			result = transformInsertStmt(pstate, (InsertStmt *) parseTree);
196
			break;
197

198 199 200
		case T_DeleteStmt:
			result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
			break;
201

B
Bruce Momjian 已提交
202 203
		case T_UpdateStmt:
			result = transformUpdateStmt(pstate, (UpdateStmt *) parseTree);
204
			break;
205

B
Bruce Momjian 已提交
206
		case T_SelectStmt:
207
			if (!((SelectStmt *) parseTree)->portalname)
208 209 210
				result = transformSelectStmt(pstate, (SelectStmt *) parseTree);
			else
				result = transformCursorStmt(pstate, (SelectStmt *) parseTree);
211
			break;
212

213
		default:
214

215 216
			/*
			 * other statments don't require any transformation-- just
B
Bruce Momjian 已提交
217
			 * return the original parsetree, yea!
218 219 220 221 222
			 */
			result = makeNode(Query);
			result->commandType = CMD_UTILITY;
			result->utilityStmt = (Node *) parseTree;
			break;
223 224
	}
	return result;
225 226 227 228
}

/*
 * transformDeleteStmt -
229
 *	  transforms a Delete Statement
230
 */
231
static Query *
232
transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
233
{
234
	Query	   *qry = makeNode(Query);
235

236
	qry->commandType = CMD_DELETE;
237

238 239
	/* set up a range table */
	makeRangeTable(pstate, stmt->relname, NULL);
240

241
	qry->uniqueFlag = NULL;
242

243 244
	/* fix where clause */
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
245
	qry->hasSubLinks = pstate->p_hasSubLinks;
246

247
	qry->rtable = pstate->p_rtable;
248
	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
249

B
Bruce Momjian 已提交
250
	qry->hasAggs = pstate->p_hasAggs;
251
	if (pstate->p_hasAggs)
252
		parseCheckAggregates(pstate, qry);
253

254
	return (Query *) qry;
255 256 257 258
}

/*
 * transformInsertStmt -
259
 *	  transform an Insert Statement
260
 */
261
static Query *
B
Bruce Momjian 已提交
262
transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
263
{
264
	Query	   *qry = makeNode(Query);	/* make a new query tree */
265
	List	   *icolumns;
266

267 268
	qry->commandType = CMD_INSERT;
	pstate->p_is_insert = true;
269

270 271
	/* set up a range table */
	makeRangeTable(pstate, stmt->relname, stmt->fromClause);
272

273
	qry->uniqueFlag = stmt->unique;
274

275
	/* fix the target list */
276
	icolumns = pstate->p_insert_columns = makeTargetNames(pstate, stmt->cols);
277

278
	qry->targetList = transformTargetList(pstate, stmt->targetList);
279

280 281 282 283 284
	/* 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)
	{
285
		Form_pg_attribute *att = pstate->p_target_relation->rd_att->attrs;
286 287 288 289
		AttrDefault *defval = pstate->p_target_relation->rd_att->constr->defval;
		int			ndef = pstate->p_target_relation->rd_att->constr->num_defval;

		/*
290 291
		 * if stmt->cols == NIL then makeTargetNames returns list of all attrs.
		 * May have to shorten icolumns list...
292 293 294
		 */
		if (stmt->cols == NIL)
		{
295 296 297 298
			List	   *extrl;
			int			i = length(qry->targetList);

			foreach(extrl, icolumns)
299
			{
300 301 302 303
				/*
				 * decrements first, so if we started with zero items
				 * it will now be negative
				 */
304 305 306
				if (--i <= 0)
					break;
			}
307 308 309 310 311 312 313 314 315 316 317 318 319
			/*
			 * this an index into the targetList,
			 * so make sure we had one to start...
			 */
			if (i >= 0)
			{
				freeList(lnext(extrl));
				lnext(extrl) = NIL;
			}
			else
			{
				icolumns = NIL;
			}
320
		}
321

322 323
		while (ndef-- > 0)
		{
324 325 326 327 328
			List	   *tl;
			Ident	   *id;
			TargetEntry *te;

			foreach(tl, icolumns)
329 330
			{
				id = (Ident *) lfirst(tl);
331
				if (namestrcmp(&(att[defval[ndef].adnum - 1]->attname), id->name) == 0)
332 333 334 335
					break;
			}
			if (tl != NIL)		/* something given for this attr */
				continue;
336 337 338 339 340 341 342 343 344 345 346

			/*
			 * 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...
347
			 */
348
			te = makeTargetEntry(makeResdom(defval[ndef].adnum,
349 350 351 352 353
								   att[defval[ndef].adnum - 1]->atttypid,
								  att[defval[ndef].adnum - 1]->atttypmod,
			   pstrdup(nameout(&(att[defval[ndef].adnum - 1]->attname))),
											0, 0, 0),
							  (Node *) stringToNode(defval[ndef].adbin));
354
			qry->targetList = lappend(qry->targetList, te);
355 356
		}
	}
357

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

361 362 363 364 365 366
	/*
	 * 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 已提交
367 368
	qry->havingQual = transformWhereClause(pstate, stmt->havingClause);

B
Bruce Momjian 已提交
369
	qry->hasSubLinks = pstate->p_hasSubLinks;
370

371 372
	/* now the range table will not change */
	qry->rtable = pstate->p_rtable;
373
	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
374

375 376 377 378 379 380 381 382 383 384 385
	qry->groupClause = transformGroupClause(pstate,
											stmt->groupClause,
											qry->targetList);

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

B
Bruce Momjian 已提交
386
	qry->hasAggs = pstate->p_hasAggs;
387
	if (pstate->p_hasAggs)
B
Bruce Momjian 已提交
388
		parseCheckAggregates(pstate, qry);
389

390 391 392
	/*
	 * The INSERT INTO ... SELECT ... could have a UNION in child, so
	 * unionClause may be false
393
,	 */
B
Hi!  
Bruce Momjian 已提交
394 395 396 397 398 399 400
  	qry->unionall = stmt->unionall;	

 	/***S*I***/
 	/* Just hand through the unionClause and intersectClause. 
 	 * We will handle it in the function Except_Intersect_Rewrite() */
 	qry->unionClause = stmt->unionClause;
 	qry->intersectClause = stmt->intersectClause;	
401

402 403 404 405 406 407 408 409
	/*
	 * 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))
	{
T
Thomas G. Lockhart 已提交
410
		elog(ERROR, "SELECT/HAVING requires aggregates to be valid");
411 412
		return (Query *) NIL;
	}
413

414 415 416
	if (stmt->forUpdate != NULL)
		transformForUpdate(qry, stmt->forUpdate);

417
	return (Query *) qry;
418 419
}

B
Bruce Momjian 已提交
420 421 422
/*
 *	makeTableName()
 *	Create a table name from a list of fields.
423 424 425 426
 */
static char *
makeTableName(void *elem,...)
{
427
	va_list		args;
428

429 430
	char	   *name;
	char		buf[NAMEDATALEN + 1];
431

B
Bruce Momjian 已提交
432
	buf[0] = '\0';
433

434
	va_start(args, elem);
435 436 437 438 439

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

B
Bruce Momjian 已提交
443
		if (strlen(buf) > 0)
444 445
			strcat(buf, "_");
		strcat(buf, name);
446

447
		name = va_arg(args, void *);
448 449 450 451
	}

	va_end(args);

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

455
	return name;
B
Bruce Momjian 已提交
456
}
457

B
Bruce Momjian 已提交
458
static char *
459
CreateIndexName(char *table_name, char *column_name, char *label, List *indices)
460 461 462 463 464
{
	int			pass = 0;
	char	   *iname = NULL;
	List	   *ilist;
	IndexStmt  *index;
465
	char		name2[NAMEDATALEN + 1];
466 467

	/* use working storage, since we might be trying several possibilities */
468
	strcpy(name2, column_name);
469 470
	while (iname == NULL)
	{
471
		iname = makeTableName(table_name, name2, label, NULL);
472 473 474 475 476 477 478 479
		/* unable to make a name at all? then quit */
		if (iname == NULL)
			break;

		ilist = indices;
		while (ilist != NIL)
		{
			index = lfirst(ilist);
480
			if (strcasecmp(iname, index->idxname) == 0)
481 482 483 484 485 486 487 488 489 490 491 492
				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++;
493
		sprintf(name2, "%s_%d", column_name, (pass + 1));
494 495
	}

496
	return iname;
B
Bruce Momjian 已提交
497
}
498

499 500 501 502 503 504 505 506 507 508 509 510 511
/*
 * 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;
512
	int			have_pkey = FALSE;
513 514 515 516 517
	List	   *elements;
	Node	   *element;
	List	   *columns;
	List	   *dlist;
	ColumnDef  *column;
518 519
	List	   *constraints,
			   *clist;
520 521 522
	Constraint *constraint;
	List	   *keys;
	Ident	   *key;
B
Bruce Momjian 已提交
523
	List	   *blist = NIL;
524
	List	   *ilist = NIL;
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542
	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;
543
				columns = lappend(columns, column);
544 545 546

				if (column->is_sequence)
				{
547 548
					char		  *sname;
					char		  *cstring;
549 550
					CreateSeqStmt *sequence;

551 552
					sname = makeTableName(stmt->relname, column->colname, "seq", NULL);

553 554
					constraint = makeNode(Constraint);
					constraint->contype = CONSTR_DEFAULT;
555
					constraint->name = sname;
556
					cstring = palloc(9 + strlen(constraint->name) + 2 + 1);
557 558 559 560 561 562
					strcpy(cstring, "nextval('");
					strcat(cstring, constraint->name);
					strcat(cstring, "')");
					constraint->def = cstring;
					constraint->keys = NULL;

563 564 565 566 567 568
					/* The parser only allows PRIMARY KEY as a constraint for the SERIAL type.
					 * So, if there is a constraint of any kind, assume it is that.
					 * If PRIMARY KEY is specified, then don't need to gin up a UNIQUE constraint
					 * since that will be covered already.
					 * - thomas 1998-09-15
					 */
569
					if (column->constraints != NIL)
570
					{
571
						column->constraints = lappend(column->constraints, constraint);
572
					}
573
					else
574
					{
575 576
						column->constraints = lcons(constraint, NIL);

577 578 579 580 581 582
						constraint = makeNode(Constraint);
						constraint->contype = CONSTR_UNIQUE;
						constraint->name = makeTableName(stmt->relname, column->colname, "key", NULL);
						column->constraints = lappend(column->constraints, constraint);
					}

583
					sequence = makeNode(CreateSeqStmt);
584
					sequence->seqname = pstrdup(sname);
585 586 587
					sequence->options = NIL;

					elog(NOTICE, "CREATE TABLE will create implicit sequence %s for SERIAL column %s.%s",
588
					  sequence->seqname, stmt->relname, column->colname);
589

B
Bruce Momjian 已提交
590
					blist = lcons(sequence, NIL);
591 592
				}

593 594 595 596 597 598 599 600 601 602
				if (column->constraints != NIL)
				{
					clist = column->constraints;
					while (clist != NIL)
					{
						constraint = lfirst(clist);
						switch (constraint->contype)
						{
							case CONSTR_NOTNULL:
								if (column->is_not_null)
603 604
									elog(ERROR, "CREATE TABLE/NOT NULL already specified"
										 " for %s.%s", stmt->relname, column->colname);
605 606 607 608 609
								column->is_not_null = TRUE;
								break;

							case CONSTR_DEFAULT:
								if (column->defval != NULL)
610 611
									elog(ERROR, "CREATE TABLE/DEFAULT multiple values specified"
										 " for %s.%s", stmt->relname, column->colname);
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633
								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)
634
									constraint->name = makeTableName(stmt->relname, column->colname, NULL);
635 636 637
								break;

							default:
T
Thomas G. Lockhart 已提交
638
								elog(ERROR, "parser: unrecognized constraint (internal error)", NULL);
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669
								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:
T
Thomas G. Lockhart 已提交
670
						elog(ERROR, "parser: illegal context for constraint (internal error)", NULL);
671 672
						break;
					default:
T
Thomas G. Lockhart 已提交
673
						elog(ERROR, "parser: unrecognized constraint (internal error)", NULL);
674 675 676 677 678
						break;
				}
				break;

			default:
T
Thomas G. Lockhart 已提交
679
				elog(ERROR, "parser: unrecognized node (internal error)", NULL);
680 681 682 683 684 685 686 687 688 689 690 691 692
		}

		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
693 694 695
 *	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
696 697 698 699 700
 */
	while (dlist != NIL)
	{
		constraint = lfirst(dlist);
		if (nodeTag(constraint) != T_Constraint)
T
Thomas G. Lockhart 已提交
701
			elog(ERROR, "parser: unrecognized deferred node (internal error)", NULL);
702

703
		if (constraint->contype == CONSTR_PRIMARY)
704
		{
705
			if (have_pkey)
706 707 708
				elog(ERROR, "CREATE TABLE/PRIMARY KEY multiple primary keys"
					 " for table %s are not legal", stmt->relname);
			else
709
				have_pkey = TRUE;
710
		}
711
		else if (constraint->contype != CONSTR_UNIQUE)
T
Thomas G. Lockhart 已提交
712
			elog(ERROR, "parser: unrecognized deferred constraint (internal error)", NULL);
713

714 715 716 717 718 719
		index = makeNode(IndexStmt);

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

			have_pkey = TRUE;
725
			index->primary = TRUE;
726
			index->idxname = makeTableName(stmt->relname, "pkey", NULL);
727
		}
728
		else
729 730
		{
			index->primary = FALSE;
731
			index->idxname = NULL;
732
		}
733 734 735 736 737 738

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

740 741 742 743 744 745 746 747 748
		keys = constraint->keys;
		while (keys != NIL)
		{
			key = lfirst(keys);
			columns = stmt->tableElts;
			column = NULL;
			while (columns != NIL)
			{
				column = lfirst(columns);
749 750 751 752
				if (strcasecmp(column->colname, key->name) == 0)
					break;
				else
					column = NULL;
753 754 755
				columns = lnext(columns);
			}
			if (column == NULL)
T
Thomas G. Lockhart 已提交
756
				elog(ERROR, "CREATE TABLE column '%s' in key does not exist", key->name);
757 758 759 760

			if (constraint->contype == CONSTR_PRIMARY)
				column->is_not_null = TRUE;
			iparam = makeNode(IndexElem);
761
			iparam->name = strcpy(palloc(strlen(column->colname) + 1), column->colname);
762 763
			iparam->args = NIL;
			iparam->class = NULL;
764
			iparam->typename = NULL;
765 766 767
			index->indexParams = lappend(index->indexParams, iparam);

			if (index->idxname == NULL)
768
				index->idxname = CreateIndexName(stmt->relname, iparam->name, "key", ilist);
769 770 771 772 773

			keys = lnext(keys);
		}

		if (index->idxname == NULL)
T
Thomas G. Lockhart 已提交
774
			elog(ERROR, "CREATE TABLE unable to construct implicit index for table %s"
775
				 "; name too long", stmt->relname);
776
		else
777 778 779
			elog(NOTICE, "CREATE TABLE/%s will create implicit index %s for table %s",
				 ((constraint->contype == CONSTR_PRIMARY) ? "PRIMARY KEY" : "UNIQUE"),
				 index->idxname, stmt->relname);
780

781
		ilist = lappend(ilist, index);
782 783 784 785
		dlist = lnext(dlist);
	}

	q->utilityStmt = (Node *) stmt;
B
Bruce Momjian 已提交
786 787
	extras_before = blist;
	extras_after = ilist;
788 789

	return q;
B
Bruce Momjian 已提交
790
}
791

792 793
/*
 * transformIndexStmt -
794
 *	  transforms the qualification of the index statement
795
 */
796
static Query *
797
transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
798
{
B
Bruce Momjian 已提交
799
	Query	   *qry;
800

B
Bruce Momjian 已提交
801 802
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
803

804 805
	/* take care of the where clause */
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
806
	qry->hasSubLinks = pstate->p_hasSubLinks;
807

808
	stmt->rangetable = pstate->p_rtable;
809

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

B
Bruce Momjian 已提交
812
	return qry;
813 814 815 816
}

/*
 * transformExtendStmt -
817
 *	  transform the qualifications of the Extend Index Statement
818 819
 *
 */
820
static Query *
821
transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
822
{
B
Bruce Momjian 已提交
823
	Query	   *qry;
824

B
Bruce Momjian 已提交
825 826
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
827

828 829
	/* take care of the where clause */
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
830 831
	qry->hasSubLinks = pstate->p_hasSubLinks;

832
	stmt->rangetable = pstate->p_rtable;
833

B
Bruce Momjian 已提交
834 835
	qry->utilityStmt = (Node *) stmt;
	return qry;
836 837 838 839
}

/*
 * transformRuleStmt -
840 841
 *	  transform a Create Rule Statement. The actions is a list of parse
 *	  trees which is transformed into a list of query trees.
842
 */
843
static Query *
844
transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
845
{
B
Bruce Momjian 已提交
846
	Query	   *qry;
M
 
Marc G. Fournier 已提交
847
	Query	   *action;
848
	List	   *actions;
849

B
Bruce Momjian 已提交
850 851
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
852

M
 
Marc G. Fournier 已提交
853
	/*
854 855 856 857 858
	 * 'instead nothing' rules with a qualification need a query a
	 * rangetable so the rewrite handler can add the negated rule
	 * qualification to the original query. We create a query with the new
	 * command type CMD_NOTHING here that is treated special by the
	 * rewrite system.
M
 
Marc G. Fournier 已提交
859
	 */
860 861 862 863
	if (stmt->actions == NIL)
	{
		Query	   *nothing_qry = makeNode(Query);

M
 
Marc G. Fournier 已提交
864 865 866 867 868 869 870 871 872 873 874 875
		nothing_qry->commandType = CMD_NOTHING;

		addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
						   FALSE, FALSE);
		addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
						   FALSE, FALSE);

		nothing_qry->rtable = pstate->p_rtable;

		stmt->actions = lappend(NIL, nothing_qry);
	}

876 877
	actions = stmt->actions;

878
	/*
879
	 * transform each statment, like parse_analyze()
880
	 */
881 882
	while (actions != NIL)
	{
883

884 885 886 887 888
		/*
		 * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
		 * equal to 2.
		 */
		addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
889
						   FALSE, FALSE);
890
		addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
891
						   FALSE, FALSE);
892 893 894

		pstate->p_last_resno = 1;
		pstate->p_is_rule = true;		/* for expand all */
895
		pstate->p_hasAggs = false;
896

897
		action = (Query *) lfirst(actions);
M
 
Marc G. Fournier 已提交
898 899
		if (action->commandType != CMD_NOTHING)
			lfirst(actions) = transformStmt(pstate, lfirst(actions));
900 901
		actions = lnext(actions);
	}
902

903 904
	/* take care of the where clause */
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
905
	qry->hasSubLinks = pstate->p_hasSubLinks;
906

B
Bruce Momjian 已提交
907 908
	qry->utilityStmt = (Node *) stmt;
	return qry;
909 910 911 912 913
}


/*
 * transformSelectStmt -
914
 *	  transforms a Select Statement
915 916
 *
 */
917
static Query *
B
Bruce Momjian 已提交
918
transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
919
{
920
	Query	   *qry = makeNode(Query);
921 922

	qry->commandType = CMD_SELECT;
923

924 925
	/* set up a range table */
	makeRangeTable(pstate, NULL, stmt->fromClause);
926

927
	qry->uniqueFlag = stmt->unique;
928

929 930
	qry->into = stmt->into;
	qry->isPortal = FALSE;
931

932
	qry->targetList = transformTargetList(pstate, stmt->targetList);
933

934
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
935

936 937 938
	/*
	 * The havingQual has a similar meaning as "qual" in the where
	 * statement. So we can easily use the code from the "where clause"
T
Thomas G. Lockhart 已提交
939
	 * with some additional traversals done in optimizer/plan/planner.c
940
	 */
941 942
	qry->havingQual = transformWhereClause(pstate, stmt->havingClause);

B
Bruce Momjian 已提交
943
	qry->hasSubLinks = pstate->p_hasSubLinks;
944

945 946
	qry->sortClause = transformSortClause(pstate,
										  stmt->sortClause,
B
Bruce Momjian 已提交
947
										  NIL,
948 949
										  qry->targetList,
										  qry->uniqueFlag);
950

951 952 953 954
	qry->groupClause = transformGroupClause(pstate,
											stmt->groupClause,
											qry->targetList);
	qry->rtable = pstate->p_rtable;
955

B
Bruce Momjian 已提交
956
	qry->hasAggs = pstate->p_hasAggs;
957
	if (pstate->p_hasAggs)
B
Bruce Momjian 已提交
958
		parseCheckAggregates(pstate, qry);
959

960 961 962
	/*
	 * The INSERT INTO ... SELECT ... could have a UNION in child, so
	 * unionClause may be false
963 964
	 */
	qry->unionall = stmt->unionall;
B
Hi!  
Bruce Momjian 已提交
965 966 967 968 969 970

 	/***S*I***/
 	/* Just hand through the unionClause and intersectClause. 
 	 * We will handle it in the function Except_Intersect_Rewrite() */
 	qry->unionClause = stmt->unionClause;
 	qry->intersectClause = stmt->intersectClause;
971

972 973 974 975 976 977 978 979
	/*
	 * 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))
	{
T
Thomas G. Lockhart 已提交
980
		elog(ERROR, "SELECT/HAVING requires aggregates to be valid");
981 982
		return (Query *) NIL;
	}
983

984 985 986
	if (stmt->forUpdate != NULL)
		transformForUpdate(qry, stmt->forUpdate);

987
	return (Query *) qry;
988 989 990 991
}

/*
 * transformUpdateStmt -
992
 *	  transforms an update statement
993 994
 *
 */
995
static Query *
B
Bruce Momjian 已提交
996
transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
997
{
998
	Query	   *qry = makeNode(Query);
999 1000 1001

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

1003 1004 1005 1006 1007
	/*
	 * 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);
1008

1009
	qry->targetList = transformTargetList(pstate, stmt->targetList);
1010

1011
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
1012
	qry->hasSubLinks = pstate->p_hasSubLinks;
1013

1014
	qry->rtable = pstate->p_rtable;
1015

1016
	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
1017

B
Bruce Momjian 已提交
1018
	qry->hasAggs = pstate->p_hasAggs;
1019
	if (pstate->p_hasAggs)
1020
		parseCheckAggregates(pstate, qry);
1021

1022
	return (Query *) qry;
1023 1024 1025 1026
}

/*
 * transformCursorStmt -
1027
 *	  transform a Create Cursor Statement
1028 1029
 *
 */
1030
static Query *
1031
transformCursorStmt(ParseState *pstate, SelectStmt *stmt)
1032
{
1033
	Query	   *qry;
1034

1035
	qry = transformSelectStmt(pstate, stmt);
1036

1037 1038 1039
	qry->into = stmt->portalname;
	qry->isPortal = TRUE;
	qry->isBinary = stmt->binary;		/* internal portal */
1040

1041
	return qry;
1042
}
B
Hi!  
Bruce Momjian 已提交
1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136

/***S*I***/
/* This function steps through the tree
 * built up by the select_w_o_sort rule
 * and builds a list of all SelectStmt Nodes found
 * The built up list is handed back in **select_list.
 * If one of the SelectStmt Nodes has the 'unionall' flag
 * set to true *unionall_present hands back 'true' */
void 
create_select_list(Node *ptr, List **select_list, bool *unionall_present)
{
  if(IsA(ptr, SelectStmt)) {
    *select_list = lappend(*select_list, ptr);    
    if(((SelectStmt *)ptr)->unionall == TRUE) *unionall_present = TRUE;    
    return;    
  }
  
  /* Recursively call for all arguments. A NOT expr has no lexpr! */
  if (((A_Expr *)ptr)->lexpr != NULL) 
     create_select_list(((A_Expr *)ptr)->lexpr, select_list, unionall_present);
  create_select_list(((A_Expr *)ptr)->rexpr, select_list, unionall_present);
}

/* Changes the A_Expr Nodes to Expr Nodes and exchanges ANDs and ORs.
 * The reason for the exchange is easy: We implement INTERSECTs and EXCEPTs 
 * by rewriting these queries to semantically equivalent queries that use
 * IN and NOT IN subselects. To be able to use all three operations 
 * (UNIONs INTERSECTs and EXCEPTs) in one complex query we have to 
 * translate the queries into Disjunctive Normal Form (DNF). Unfortunately
 * there is no function 'dnfify' but there is a function 'cnfify'
 * which produces DNF when we exchange ANDs and ORs before calling
 * 'cnfify' and exchange them back in the result.
 *
 * If an EXCEPT or INTERSECT is present *intersect_present
 * hands back 'true' */ 
Node *A_Expr_to_Expr(Node *ptr, bool *intersect_present)
{
  Node *result;
  
  switch(nodeTag(ptr))
    {
    case T_A_Expr:
      {
	A_Expr *a = (A_Expr *)ptr;
	
	switch (a->oper)
	  {
	  case AND:
	    {
	      Expr *expr = makeNode(Expr);
	      Node	   *lexpr = A_Expr_to_Expr(((A_Expr *)ptr)->lexpr, intersect_present);
	      Node	   *rexpr = A_Expr_to_Expr(((A_Expr *)ptr)->rexpr, intersect_present);

	      *intersect_present = TRUE;
	      
	      expr->typeOid = BOOLOID;
	      expr->opType = OR_EXPR;
	      expr->args = makeList(lexpr, rexpr, -1);
	      result = (Node *) expr;
	      break;	      
	    }	  	  
	  case OR:
	    {
	      Expr *expr = makeNode(Expr);
	      Node	   *lexpr = A_Expr_to_Expr(((A_Expr *)ptr)->lexpr, intersect_present);
	      Node	   *rexpr = A_Expr_to_Expr(((A_Expr *)ptr)->rexpr, intersect_present);

	      expr->typeOid = BOOLOID;
	      expr->opType = AND_EXPR;
	      expr->args = makeList(lexpr, rexpr, -1);
	      result = (Node *) expr;
	      break;	      
	    }
	  case NOT:
	    {
	      Expr *expr = makeNode(Expr);
	      Node	   *rexpr = A_Expr_to_Expr(((A_Expr *)ptr)->rexpr, intersect_present);

	      expr->typeOid = BOOLOID;
	      expr->opType = NOT_EXPR;
	      expr->args = makeList(rexpr, -1);
	      result = (Node *) expr;
	      break;	      
	    }
	  }	
	break;	
      }
    default:
      {
	result = ptr;
      }      
    }
  return result;  
}
1137

1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150
void
CheckSelectForUpdate(Query *qry)
{
	if (qry->unionClause != NULL)
		elog(ERROR, "SELECT FOR UPDATE is not allowed with UNION/INTERSECT/EXCEPT clause");
	if (qry->uniqueFlag != NULL)
		elog(ERROR, "SELECT FOR UPDATE is not allowed with DISTINCT clause");
	if (qry->groupClause != NULL)
		elog(ERROR, "SELECT FOR UPDATE is not allowed with GROUP BY clause");
	if (qry->hasAggs)
		elog(ERROR, "SELECT FOR UPDATE is not allowed with AGGREGATE");
}

1151 1152 1153 1154 1155 1156 1157 1158
static void
transformForUpdate(Query *qry, List *forUpdate)
{
	List	   *rowMark = NULL;
	RowMark	   *newrm;
	List	   *l;
	Index		i;

1159 1160
	CheckSelectForUpdate(qry);

1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
	if (lfirst(forUpdate) == NULL)		/* all tables */
	{
		i = 1;
		foreach (l, qry->rtable)
		{
			newrm = makeNode(RowMark);
			newrm->rti = i++;
			newrm->info = ROW_MARK_FOR_UPDATE|ROW_ACL_FOR_UPDATE;
			rowMark = lappend(rowMark, newrm);
		}
		qry->rowMark = nconc(qry->rowMark, rowMark);
		return;
	}

	foreach (l, forUpdate)
	{
		List   *l2;
		List   *l3;

		i = 1;
		foreach (l2, qry->rtable)
		{
			if (strcmp(((RangeTblEntry*)lfirst(l2))->refname, lfirst(l)) == 0)
			{
				foreach (l3, rowMark)
				{
					if (((RowMark*)lfirst(l3))->rti == i)	/* duplicate */
						break;
				}
				if (l3 == NULL)
				{
					newrm = makeNode(RowMark);
					newrm->rti = i;
					newrm->info = ROW_MARK_FOR_UPDATE|ROW_ACL_FOR_UPDATE;
					rowMark = lappend(rowMark, newrm);
				}
				break;
			}
			i++;
		}
		if (l2 == NULL)
			elog(ERROR, "FOR UPDATE: relation %s not found in FROM clause", lfirst(l));
	}

	qry->rowMark = rowMark;
	return;
}