analyze.c 31.5 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.98 1999/02/08 14:14:11 wieck 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
				result = transformSelectStmt(pstate, (SelectStmt *) parseTree);
210 211 212
				result->limitOffset = ((SelectStmt *)parseTree)->limitOffset;
				result->limitCount = ((SelectStmt *)parseTree)->limitCount;
			}
213 214
			else
				result = transformCursorStmt(pstate, (SelectStmt *) parseTree);
215
			break;
216

217
		default:
218

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

/*
 * transformDeleteStmt -
233
 *	  transforms a Delete Statement
234
 */
235
static Query *
236
transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
237
{
238
	Query	   *qry = makeNode(Query);
239

240
	qry->commandType = CMD_DELETE;
241

242 243
	/* set up a range table */
	makeRangeTable(pstate, stmt->relname, NULL);
244

245
	qry->uniqueFlag = NULL;
246

247 248
	/* fix where clause */
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
B
Bruce Momjian 已提交
249
	qry->hasSubLinks = pstate->p_hasSubLinks;
250

251
	qry->rtable = pstate->p_rtable;
252
	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
253

B
Bruce Momjian 已提交
254
	qry->hasAggs = pstate->p_hasAggs;
255
	if (pstate->p_hasAggs)
256
		parseCheckAggregates(pstate, qry);
257

258
	return (Query *) qry;
259 260 261 262
}

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

271 272
	qry->commandType = CMD_INSERT;
	pstate->p_is_insert = true;
273

274 275
	/* set up a range table */
	makeRangeTable(pstate, stmt->relname, stmt->fromClause);
276

277
	qry->uniqueFlag = stmt->unique;
278

279
	/* fix the target list */
280
	icolumns = pstate->p_insert_columns = makeTargetNames(pstate, stmt->cols);
281

282
	qry->targetList = transformTargetList(pstate, stmt->targetList);
283

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

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

			foreach(extrl, icolumns)
303
			{
304 305 306 307
				/*
				 * decrements first, so if we started with zero items
				 * it will now be negative
				 */
308 309 310
				if (--i <= 0)
					break;
			}
311 312 313 314 315 316 317 318 319 320 321 322 323
			/*
			 * 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;
			}
324
		}
325

326 327
		while (ndef-- > 0)
		{
328 329 330 331 332
			List	   *tl;
			Ident	   *id;
			TargetEntry *te;

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

			/*
			 * 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...
351
			 */
352
			te = makeTargetEntry(makeResdom(defval[ndef].adnum,
353 354 355 356 357
								   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));
358
			qry->targetList = lappend(qry->targetList, te);
359 360
		}
	}
361

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

365 366 367 368 369 370
	/*
	 * 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 已提交
371 372
	qry->havingQual = transformWhereClause(pstate, stmt->havingClause);

B
Bruce Momjian 已提交
373
	qry->hasSubLinks = pstate->p_hasSubLinks;
374

375 376
	/* now the range table will not change */
	qry->rtable = pstate->p_rtable;
377
	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
378

379 380 381 382 383 384 385 386 387 388 389
	qry->groupClause = transformGroupClause(pstate,
											stmt->groupClause,
											qry->targetList);

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

B
Bruce Momjian 已提交
390
	qry->hasAggs = pstate->p_hasAggs;
391
	if (pstate->p_hasAggs)
B
Bruce Momjian 已提交
392
		parseCheckAggregates(pstate, qry);
393

394 395 396
	/*
	 * The INSERT INTO ... SELECT ... could have a UNION in child, so
	 * unionClause may be false
397
,	 */
B
Hi!  
Bruce Momjian 已提交
398 399 400 401 402 403 404
  	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;	
405

406 407 408 409 410 411 412 413
	/*
	 * 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 已提交
414
		elog(ERROR, "SELECT/HAVING requires aggregates to be valid");
415 416
		return (Query *) NIL;
	}
417

418 419 420
	if (stmt->forUpdate != NULL)
		transformForUpdate(qry, stmt->forUpdate);

421
	return (Query *) qry;
422 423
}

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

433 434
	char	   *name;
	char		buf[NAMEDATALEN + 1];
435

B
Bruce Momjian 已提交
436
	buf[0] = '\0';
437

438
	va_start(args, elem);
439 440 441 442 443

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

B
Bruce Momjian 已提交
447
		if (strlen(buf) > 0)
448 449
			strcat(buf, "_");
		strcat(buf, name);
450

451
		name = va_arg(args, void *);
452 453 454 455
	}

	va_end(args);

456 457
	name = palloc(strlen(buf) + 1);
	strcpy(name, buf);
458

459
	return name;
B
Bruce Momjian 已提交
460
}
461

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

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

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

500
	return iname;
B
Bruce Momjian 已提交
501
}
502

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

				if (column->is_sequence)
				{
551 552
					char		  *sname;
					char		  *cstring;
553 554
					CreateSeqStmt *sequence;

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

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

567 568 569 570 571 572
					/* 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
					 */
573
					if (column->constraints != NIL)
574
					{
575
						column->constraints = lappend(column->constraints, constraint);
576
					}
577
					else
578
					{
579 580
						column->constraints = lcons(constraint, NIL);

581 582 583 584 585 586
						constraint = makeNode(Constraint);
						constraint->contype = CONSTR_UNIQUE;
						constraint->name = makeTableName(stmt->relname, column->colname, "key", NULL);
						column->constraints = lappend(column->constraints, constraint);
					}

587
					sequence = makeNode(CreateSeqStmt);
588
					sequence->seqname = pstrdup(sname);
589 590 591
					sequence->options = NIL;

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

B
Bruce Momjian 已提交
594
					blist = lcons(sequence, NIL);
595 596
				}

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

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

							default:
T
Thomas G. Lockhart 已提交
642
								elog(ERROR, "parser: unrecognized constraint (internal error)", NULL);
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 670 671 672 673
								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 已提交
674
						elog(ERROR, "parser: illegal context for constraint (internal error)", NULL);
675 676
						break;
					default:
T
Thomas G. Lockhart 已提交
677
						elog(ERROR, "parser: unrecognized constraint (internal error)", NULL);
678 679 680 681 682
						break;
				}
				break;

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

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

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

718 719 720
		index = makeNode(IndexStmt);

		index->unique = TRUE;
M
 
Marc G. Fournier 已提交
721
		index->primary = (constraint->contype == CONSTR_PRIMARY ? TRUE:FALSE);
722 723 724
		if (constraint->name != NULL)
			index->idxname = constraint->name;
		else if (constraint->contype == CONSTR_PRIMARY)
725 726
		{
			if (have_pkey)
727
				elog(ERROR, "CREATE TABLE/PRIMARY KEY multiple keys for table %s are not legal", stmt->relname);
728 729

			have_pkey = TRUE;
730
			index->idxname = makeTableName(stmt->relname, "pkey", NULL);
731
		}
732 733 734 735 736 737 738 739
		else
			index->idxname = NULL;

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

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

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

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

			keys = lnext(keys);
		}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

M
 
Marc G. Fournier 已提交
854
	/*
855 856 857 858 859
	 * '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 已提交
860
	 */
861 862 863 864
	if (stmt->actions == NIL)
	{
		Query	   *nothing_qry = makeNode(Query);

M
 
Marc G. Fournier 已提交
865 866 867 868 869 870 871 872 873 874 875 876
		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);
	}

877 878
	actions = stmt->actions;

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

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

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

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

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

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


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

	qry->commandType = CMD_SELECT;
924

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

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

930
	qry->into = stmt->into;
931
	qry->isTemp = stmt->istemp;
932
	qry->isPortal = FALSE;
933

934
	qry->targetList = transformTargetList(pstate, stmt->targetList);
935

936
	qry->qual = transformWhereClause(pstate, stmt->whereClause);
937

938 939 940
	/*
	 * 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 已提交
941
	 * with some additional traversals done in optimizer/plan/planner.c
942
	 */
943 944
	qry->havingQual = transformWhereClause(pstate, stmt->havingClause);

B
Bruce Momjian 已提交
945
	qry->hasSubLinks = pstate->p_hasSubLinks;
946

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

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

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

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

 	/***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;
973

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

986 987 988
	if (stmt->forUpdate != NULL)
		transformForUpdate(qry, stmt->forUpdate);

989
	return (Query *) qry;
990 991 992 993
}

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

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

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

1011
	qry->targetList = transformTargetList(pstate, stmt->targetList);
1012

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

1016
	qry->rtable = pstate->p_rtable;
1017

1018
	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
1019

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

1024
	return (Query *) qry;
1025 1026 1027 1028
}

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

1037
	qry = transformSelectStmt(pstate, stmt);
1038

1039
	qry->into = stmt->portalname;
1040
	qry->isTemp = stmt->istemp;
1041 1042
	qry->isPortal = TRUE;
	qry->isBinary = stmt->binary;		/* internal portal */
1043

1044
	return qry;
1045
}
B
Hi!  
Bruce Momjian 已提交
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

/***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)
{
1083
  Node *result = NULL;
B
Hi!  
Bruce Momjian 已提交
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 1137 1138 1139
  
  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;  
}
1140

1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
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");
}

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

1162 1163
	CheckSelectForUpdate(qry);

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 1208 1209 1210
	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;
}