analyze.c 46.9 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.129 2000/01/15 02:59:31 petere Exp $
9 10 11
 *
 *-------------------------------------------------------------------------
 */
12

Bruce Momjian's avatar
Bruce Momjian committed
13
#include "postgres.h"
Bruce Momjian's avatar
Bruce Momjian committed
14

15
#include "access/heapam.h"
Jan Wieck's avatar
Jan Wieck committed
16 17
#include "catalog/catname.h"
#include "catalog/pg_index.h"
Bruce Momjian's avatar
Bruce Momjian committed
18
#include "catalog/pg_type.h"
19
#include "nodes/makefuncs.h"
Bruce Momjian's avatar
Bruce Momjian committed
20
#include "parse.h"
21 22
#include "parser/analyze.h"
#include "parser/parse_agg.h"
Bruce Momjian's avatar
Bruce Momjian committed
23
#include "parser/parse_clause.h"
24 25 26
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
#include "utils/builtins.h"
27

28 29
static Query *transformStmt(ParseState *pstate, Node *stmt);
static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
Bruce Momjian's avatar
Bruce Momjian committed
30
static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt);
31 32 33
static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);
static Query *transformExtendStmt(ParseState *pstate, ExtendStmt *stmt);
static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);
Bruce Momjian's avatar
Bruce Momjian committed
34 35
static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);
static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
36
static Query *transformCursorStmt(ParseState *pstate, SelectStmt *stmt);
37
static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt);
38

Bruce Momjian's avatar
Bruce Momjian committed
39
static void transformForUpdate(Query *qry, List *forUpdate);
Jan Wieck's avatar
Jan Wieck committed
40
static void transformFkeyGetPrimaryKey(FkConstraint *fkconstraint);
Bruce Momjian's avatar
Bruce Momjian committed
41
void		CheckSelectForUpdate(Query *qry);
42

43 44 45 46
/* kluge to return extra info from transformCreateStmt() */
static List	   *extras_before;
static List	   *extras_after;

Bruce Momjian's avatar
Bruce Momjian committed
47

48 49
/*
 * parse_analyze -
50
 *	  analyze a list of parse trees and transform them if necessary.
51 52 53 54 55
 *
 * Returns a list of transformed parse trees. Optimizable statements are
 * all transformed to Query while the rest stays the same.
 *
 */
56
List *
57
parse_analyze(List *pl, ParseState *parentParseState)
58
{
Bruce Momjian's avatar
Bruce Momjian committed
59
	List	   *result = NIL;
60
	ParseState *pstate;
Bruce Momjian's avatar
Bruce Momjian committed
61
	Query	   *parsetree;
62 63 64

	while (pl != NIL)
	{
65
		extras_before = extras_after = NIL;
66
		pstate = make_parsestate(parentParseState);
67

Bruce Momjian's avatar
Bruce Momjian committed
68
		parsetree = transformStmt(pstate, lfirst(pl));
Bruce Momjian's avatar
Bruce Momjian committed
69
		if (pstate->p_target_relation != NULL)
70
			heap_close(pstate->p_target_relation, AccessShareLock);
71 72
		pstate->p_target_relation = NULL;
		pstate->p_target_rangetblentry = NULL;
Bruce Momjian's avatar
Bruce Momjian committed
73

74
		while (extras_before != NIL)
75
		{
76
			result = lappend(result,
77
							 transformStmt(pstate, lfirst(extras_before)));
78
			if (pstate->p_target_relation != NULL)
79
				heap_close(pstate->p_target_relation, AccessShareLock);
80 81
			pstate->p_target_relation = NULL;
			pstate->p_target_rangetblentry = NULL;
82
			extras_before = lnext(extras_before);
83
		}
Bruce Momjian's avatar
Bruce Momjian committed
84

85
		result = lappend(result, parsetree);
Bruce Momjian's avatar
Bruce Momjian committed
86

87
		while (extras_after != NIL)
Bruce Momjian's avatar
Bruce Momjian committed
88
		{
89 90 91
			result = lappend(result,
							 transformStmt(pstate, lfirst(extras_after)));
			if (pstate->p_target_relation != NULL)
92
				heap_close(pstate->p_target_relation, AccessShareLock);
93 94
			pstate->p_target_relation = NULL;
			pstate->p_target_rangetblentry = NULL;
95
			extras_after = lnext(extras_after);
Bruce Momjian's avatar
Bruce Momjian committed
96 97
		}

98
		pfree(pstate);
99
		pl = lnext(pl);
100 101 102
	}

	return result;
103 104 105 106
}

/*
 * transformStmt -
107 108
 *	  transform a Parse tree. If it is an optimizable statement, turn it
 *	  into a Query tree.
109
 */
110
static Query *
111
transformStmt(ParseState *pstate, Node *parseTree)
112
{
113
	Query	   *result = NULL;
114 115 116

	switch (nodeTag(parseTree))
	{
117 118 119 120
			/*------------------------
			 *	Non-optimizable statements
			 *------------------------
			 */
121 122 123 124
		case T_CreateStmt:
			result = transformCreateStmt(pstate, (CreateStmt *) parseTree);
			break;

125 126 127
		case T_IndexStmt:
			result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
			break;
128

129 130 131
		case T_ExtendStmt:
			result = transformExtendStmt(pstate, (ExtendStmt *) parseTree);
			break;
132

133 134 135
		case T_RuleStmt:
			result = transformRuleStmt(pstate, (RuleStmt *) parseTree);
			break;
136

137 138 139
		case T_ViewStmt:
			{
				ViewStmt   *n = (ViewStmt *) parseTree;
140

141 142 143 144 145 146
				n->query = (Query *) transformStmt(pstate, (Node *) n->query);
				result = makeNode(Query);
				result->commandType = CMD_UTILITY;
				result->utilityStmt = (Node *) n;
			}
			break;
147

148 149 150
		case T_VacuumStmt:
			{
				MemoryContext oldcontext;
151

152 153 154 155 156 157 158 159 160 161 162 163
				/*
				 * 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);
			}
164 165
			break;

166 167 168
		case T_ExplainStmt:
			{
				ExplainStmt *n = (ExplainStmt *) parseTree;
169

170 171 172 173 174 175
				result = makeNode(Query);
				result->commandType = CMD_UTILITY;
				n->query = transformStmt(pstate, (Node *) n->query);
				result->utilityStmt = (Node *) parseTree;
			}
			break;
176

177 178 179 180
			/*------------------------
			 *	Optimizable statements
			 *------------------------
			 */
Bruce Momjian's avatar
Bruce Momjian committed
181 182
		case T_InsertStmt:
			result = transformInsertStmt(pstate, (InsertStmt *) parseTree);
183
			break;
184

185 186 187
		case T_DeleteStmt:
			result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
			break;
188

Bruce Momjian's avatar
Bruce Momjian committed
189 190
		case T_UpdateStmt:
			result = transformUpdateStmt(pstate, (UpdateStmt *) parseTree);
191
			break;
192

Bruce Momjian's avatar
Bruce Momjian committed
193
		case T_SelectStmt:
194
			if (!((SelectStmt *) parseTree)->portalname)
195
			{
196
				result = transformSelectStmt(pstate, (SelectStmt *) parseTree);
Bruce Momjian's avatar
Bruce Momjian committed
197 198
				result->limitOffset = ((SelectStmt *) parseTree)->limitOffset;
				result->limitCount = ((SelectStmt *) parseTree)->limitCount;
199
			}
200 201
			else
				result = transformCursorStmt(pstate, (SelectStmt *) parseTree);
202
			break;
203

204
		default:
205

206 207
			/*
			 * other statments don't require any transformation-- just
Bruce Momjian's avatar
Bruce Momjian committed
208
			 * return the original parsetree, yea!
209 210 211 212 213
			 */
			result = makeNode(Query);
			result->commandType = CMD_UTILITY;
			result->utilityStmt = (Node *) parseTree;
			break;
214 215
	}
	return result;
216 217 218 219
}

/*
 * transformDeleteStmt -
220
 *	  transforms a Delete Statement
221
 */
222
static Query *
223
transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
224
{
225
	Query	   *qry = makeNode(Query);
226

227
	qry->commandType = CMD_DELETE;
228

229
	/* set up a range table */
230 231
	makeRangeTable(pstate, NULL, NULL);
	setTargetTable(pstate, stmt->relname);
232

233
	qry->uniqueFlag = NULL;
234

235
	/* fix where clause */
236
	qry->qual = transformWhereClause(pstate, stmt->whereClause, NULL);
237

238
	qry->rtable = pstate->p_rtable;
239
	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
240

241
	qry->hasSubLinks = pstate->p_hasSubLinks;
Bruce Momjian's avatar
Bruce Momjian committed
242
	qry->hasAggs = pstate->p_hasAggs;
243
	if (pstate->p_hasAggs)
244
		parseCheckAggregates(pstate, qry);
245

246
	return (Query *) qry;
247 248 249 250
}

/*
 * transformInsertStmt -
251
 *	  transform an Insert Statement
252
 */
253
static Query *
Bruce Momjian's avatar
Bruce Momjian committed
254
transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
255
{
256 257
	Query	   *qry = makeNode(Query);
	Node	   *fromQual;
258
	List	   *icolumns;
259 260 261
	List	   *attrnos;
	List	   *attnos;
	int			numuseratts;
262 263
	List	   *tl;
	TupleDesc	rd_att;
264

265 266
	qry->commandType = CMD_INSERT;
	pstate->p_is_insert = true;
267

268 269 270 271 272 273 274 275 276 277
	/*----------
	 * Initial processing steps are just like SELECT, which should not
	 * be surprising, since we may be handling an INSERT ... SELECT.
	 * It is important that we finish processing all the SELECT subclauses
	 * before we start doing any INSERT-specific processing; otherwise
	 * the behavior of SELECT within INSERT might be different from a
	 * stand-alone SELECT.  (Indeed, Postgres up through 6.5 had bugs of
	 * just that nature...)
	 *----------
	 */
278

279 280
	/* set up a range table --- note INSERT target is not in it yet */
	makeRangeTable(pstate, stmt->fromClause, &fromQual);
281

282
	qry->uniqueFlag = stmt->unique;
283

284
	qry->targetList = transformTargetList(pstate, stmt->targetList);
285

286
	qry->qual = transformWhereClause(pstate, stmt->whereClause, fromQual);
287

288 289
	/* Initial processing of HAVING clause is just like WHERE clause.
	 * Additional work will be done in optimizer/plan/planner.c.
290
	 */
291
	qry->havingQual = transformWhereClause(pstate, stmt->havingClause, NULL);
Bruce Momjian's avatar
Bruce Momjian committed
292

293 294 295 296
	qry->groupClause = transformGroupClause(pstate,
											stmt->groupClause,
											qry->targetList);

297 298 299
	/* An InsertStmt has no sortClause, but we still call
	 * transformSortClause because it also handles uniqueFlag.
	 */
300 301 302 303 304
	qry->sortClause = transformSortClause(pstate,
										  NIL,
										  qry->targetList,
										  qry->uniqueFlag);

305
	qry->hasSubLinks = pstate->p_hasSubLinks;
Bruce Momjian's avatar
Bruce Momjian committed
306
	qry->hasAggs = pstate->p_hasAggs;
307
	if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
Bruce Momjian's avatar
Bruce Momjian committed
308
		parseCheckAggregates(pstate, qry);
309

310 311
	/*
	 * The INSERT INTO ... SELECT ... could have a UNION in child, so
312
	 * unionClause may be false
Bruce Momjian's avatar
Bruce Momjian committed
313 314 315 316 317 318 319 320 321
	 */
	qry->unionall = stmt->unionall;

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

323
	/*
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
	 * Now we are done with SELECT-like processing, and can get on with
	 * transforming the target list to match the INSERT target columns.
	 *
	 * In particular, it's time to add the INSERT target to the rangetable.
	 * (We didn't want it there until now since it shouldn't be visible in
	 * the SELECT part.)
	 */
	setTargetTable(pstate, stmt->relname);

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

	/* Prepare to assign non-conflicting resnos to resjunk attributes */
	if (pstate->p_last_resno <= pstate->p_target_relation->rd_rel->relnatts)
		pstate->p_last_resno = pstate->p_target_relation->rd_rel->relnatts + 1;

	/* Validate stmt->cols list, or build default list if no list given */
342
	icolumns = checkInsertTargets(pstate, stmt->cols, &attrnos);
343 344

	/* Prepare non-junk columns for assignment to target table */
345 346
	numuseratts = 0;
	attnos = attrnos;
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
	foreach(tl, qry->targetList)
	{
		TargetEntry *tle = (TargetEntry *) lfirst(tl);
		Resdom	   *resnode = tle->resdom;
		Ident	   *id;

		if (resnode->resjunk)
		{
			/* Resjunk nodes need no additional processing, but be sure they
			 * have names and resnos that do not match any target columns;
			 * else rewriter or planner might get confused.
			 */
			resnode->resname = "?resjunk?";
			resnode->resno = (AttrNumber) pstate->p_last_resno++;
			continue;
		}
363
		if (icolumns == NIL || attnos == NIL)
364 365
			elog(ERROR, "INSERT has more expressions than target columns");
		id = (Ident *) lfirst(icolumns);
366 367 368
		updateTargetListEntry(pstate, tle, id->name, lfirsti(attnos),
							  id->indirection);
		numuseratts++;
369
		icolumns = lnext(icolumns);
370
		attnos = lnext(attnos);
371 372
	}

373 374 375 376 377 378 379 380 381 382
	/*
	 * It is possible that the targetlist has fewer entries than were in
	 * the columns list.  We do not consider this an error (perhaps we
	 * should, if the columns list was explictly given?).  We must truncate
	 * the attrnos list to only include the attrs actually provided,
	 * else we will fail to apply defaults for them below.
	 */
	if (icolumns != NIL)
		attrnos = ltruncate(numuseratts, attrnos);

383 384 385
	/*
	 * Add targetlist items to assign DEFAULT values to any columns that
	 * have defaults and were not assigned to by the user.
386
	 *
387 388
	 * XXX wouldn't it make more sense to do this further downstream,
	 * after the rule rewriter?
389
	 */
390 391
	rd_att = pstate->p_target_relation->rd_att;
	if (rd_att->constr && rd_att->constr->num_defval > 0)
392
	{
393 394 395 396
		Form_pg_attribute *att = rd_att->attrs;
		AttrDefault *defval = rd_att->constr->defval;
		int			ndef = rd_att->constr->num_defval;

397
		while (--ndef >= 0)
398
		{
399 400 401
			AttrNumber		attrno = defval[ndef].adnum;
			Form_pg_attribute thisatt = att[attrno - 1];
			TargetEntry	   *te;
402

403 404
			if (intMember((int) attrno, attrnos))
				continue;		/* there was a user-specified value */
405 406 407 408 409
			/*
			 * No user-supplied value, so add a targetentry with DEFAULT expr
			 * and correct data for the target column.
			 */
			te = makeTargetEntry(
410
				makeResdom(attrno,
411 412
						   thisatt->atttypid,
						   thisatt->atttypmod,
413
						   pstrdup(NameStr(thisatt->attname)),
414 415 416 417 418 419 420
						   0, 0, false),
				stringToNode(defval[ndef].adbin));
			qry->targetList = lappend(qry->targetList, te);
			/*
			 * Make sure the value is coerced to the target column type
			 * (might not be right type if it's not a constant!)
			 */
421 422
			updateTargetListEntry(pstate, te, te->resdom->resname, attrno,
								  NIL);
423
		}
424
	}
425

426 427 428
	if (stmt->forUpdate != NULL)
		transformForUpdate(qry, stmt->forUpdate);

429 430 431
	/* in case of subselects in default clauses... */
	qry->hasSubLinks = pstate->p_hasSubLinks;

432
	return (Query *) qry;
433 434
}

Bruce Momjian's avatar
Bruce Momjian committed
435
/*
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
 *	makeObjectName()
 *
 *	Create a name for an implicitly created index, sequence, constraint, etc.
 *
 *	The parameters are: the original table name, the original field name, and
 *	a "type" string (such as "seq" or "pkey").  The field name and/or type
 *	can be NULL if not relevant.
 *
 *	The result is a palloc'd string.
 *
 *	The basic result we want is "name1_name2_type", omitting "_name2" or
 *	"_type" when those parameters are NULL.  However, we must generate
 *	a name with less than NAMEDATALEN characters!  So, we truncate one or
 *	both names if necessary to make a short-enough string.  The type part
 *	is never truncated (so it had better be reasonably short).
 *
 *	To reduce the probability of collisions, we might someday add more
 *	smarts to this routine, like including some "hash" characters computed
 *	from the truncated characters.  Currently it seems best to keep it simple,
 *	so that the generated names are easily predictable by a person.
456 457
 */
static char *
458
makeObjectName(char *name1, char *name2, char *typename)
459
{
460
	char	   *name;
461 462 463 464 465 466 467 468
	int			overhead = 0;	/* chars needed for type and underscores */
	int			availchars;		/* chars available for name(s) */
	int			name1chars;		/* chars allocated to name1 */
	int			name2chars;		/* chars allocated to name2 */
	int			ndx;

	name1chars = strlen(name1);
	if (name2)
469
	{
470 471 472 473 474 475 476
		name2chars = strlen(name2);
		overhead++;				/* allow for separating underscore */
	}
	else
		name2chars = 0;
	if (typename)
		overhead += strlen(typename) + 1;
477

478
	availchars = NAMEDATALEN-1 - overhead;
479

480 481 482 483 484 485 486 487 488 489
	/* If we must truncate,  preferentially truncate the longer name.
	 * This logic could be expressed without a loop, but it's simple and
	 * obvious as a loop.
	 */
	while (name1chars + name2chars > availchars)
	{
		if (name1chars > name2chars)
			name1chars--;
		else
			name2chars--;
490 491
	}

492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
	/* Now construct the string using the chosen lengths */
	name = palloc(name1chars + name2chars + overhead + 1);
	strncpy(name, name1, name1chars);
	ndx = name1chars;
	if (name2)
	{
		name[ndx++] = '_';
		strncpy(name+ndx, name2, name2chars);
		ndx += name2chars;
	}
	if (typename)
	{
		name[ndx++] = '_';
		strcpy(name+ndx, typename);
	}
	else
		name[ndx] = '\0';
509

510
	return name;
Bruce Momjian's avatar
Bruce Momjian committed
511
}
512

Bruce Momjian's avatar
Bruce Momjian committed
513
static char *
514
CreateIndexName(char *table_name, char *column_name, char *label, List *indices)
515 516 517 518
{
	int			pass = 0;
	char	   *iname = NULL;
	List	   *ilist;
519 520 521 522 523 524 525 526
	char		typename[NAMEDATALEN];

	/* The type name for makeObjectName is label, or labelN if that's
	 * necessary to prevent collisions among multiple indexes for the same
	 * table.  Note there is no check for collisions with already-existing
	 * indexes; this ought to be rethought someday.
	 */
	strcpy(typename, label);
527

528
	for (;;)
529
	{
530
		iname = makeObjectName(table_name, column_name, typename);
531

532
		foreach(ilist, indices)
533
		{
534
			IndexStmt  *index = lfirst(ilist);
535
			if (strcasecmp(iname, index->idxname) == 0)
536 537 538 539 540 541 542 543
				break;
		}
		/* 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);
544
		sprintf(typename, "%s%d", label, ++pass);
545 546
	}

547
	return iname;
Bruce Momjian's avatar
Bruce Momjian committed
548
}
549

550 551 552 553 554 555 556 557 558 559 560 561
/*
 * 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)
{
Jan Wieck's avatar
Jan Wieck committed
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
	Query		   *q;
	List		   *elements;
	Node		   *element;
	List		   *columns;
	List		   *dlist;
	ColumnDef	   *column;
	List		   *constraints,
				   *clist;
	Constraint	   *constraint;
	List		   *fkconstraints,	/* List of FOREIGN KEY constraints to */
				   *fkclist;		/* add finally */
	FkConstraint   *fkconstraint;
	List		   *keys;
	Ident		   *key;
	List		   *blist = NIL;	/* "before list" of things to do before
									 * creating the table */
	List		   *ilist = NIL;	/* "index list" of things to do after
									 * creating the table */
	IndexStmt	   *index,
				   *pkey = NULL;
	IndexElem	   *iparam;
583 584 585 586

	q = makeNode(Query);
	q->commandType = CMD_UTILITY;

Jan Wieck's avatar
Jan Wieck committed
587
	fkconstraints = NIL;
588 589 590 591
	constraints = stmt->constraints;
	columns = NIL;
	dlist = NIL;

592 593 594
	/*
	 * Run through each primary element in the table creation clause
	 */
595
	foreach(elements, stmt->tableElts)
596 597 598 599 600 601
	{
		element = lfirst(elements);
		switch (nodeTag(element))
		{
			case T_ColumnDef:
				column = (ColumnDef *) element;
602
				columns = lappend(columns, column);
603

604
				/* Special case SERIAL type? */
605 606
				if (column->is_sequence)
				{
Bruce Momjian's avatar
Bruce Momjian committed
607
					char	   *sname;
608 609 610
					char	   *qstring;
					A_Const	   *snamenode;
					FuncCall   *funccallnode;
611 612
					CreateSeqStmt *sequence;

613 614
					sname = makeObjectName(stmt->relname, column->colname,
										   "seq");
615 616 617 618 619 620 621 622 623 624 625 626
					/*
					 * Create an expression tree representing the function
					 * call  nextval('"sequencename"')
					 */
					qstring = palloc(strlen(sname) + 2 + 1);
					sprintf(qstring, "\"%s\"", sname);
					snamenode = makeNode(A_Const);
					snamenode->val.type = T_String;
					snamenode->val.val.str = qstring;
					funccallnode = makeNode(FuncCall);
					funccallnode->funcname = "nextval";
					funccallnode->args = lcons(snamenode, NIL);
627 628
					funccallnode->agg_star = false;
					funccallnode->agg_distinct = false;
629

630 631
					constraint = makeNode(Constraint);
					constraint->contype = CONSTR_DEFAULT;
632
					constraint->name = sname;
633 634
					constraint->raw_expr = (Node *) funccallnode;
					constraint->cooked_expr = NULL;
635 636
					constraint->keys = NULL;

637
					column->constraints = lappend(column->constraints, constraint);
638

639 640
					constraint = makeNode(Constraint);
					constraint->contype = CONSTR_UNIQUE;
641 642 643
					constraint->name = makeObjectName(stmt->relname,
													  column->colname,
													  "key");
644
					column->constraints = lappend(column->constraints, constraint);
645

646
					sequence = makeNode(CreateSeqStmt);
647
					sequence->seqname = pstrdup(sname);
648 649
					sequence->options = NIL;

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

Bruce Momjian's avatar
Bruce Momjian committed
653
					blist = lcons(sequence, NIL);
654 655
				}

656 657
				/* Process column constraints, if any... */
				foreach(clist, column->constraints)
658
				{
659
					constraint = lfirst(clist);
Jan Wieck's avatar
Jan Wieck committed
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676

					/* ----------
					 * If this column constraint is a FOREIGN KEY
					 * constraint, then we fill in the current attributes
					 * name and throw it into the list of FK constraints
					 * to be processed later.
					 * ----------
					 */
					if (nodeTag(constraint) == T_FkConstraint)
					{
						Ident	*id = makeNode(Ident);
						id->name		= column->colname;
						id->indirection	= NIL;
						id->isRel		= false;

						fkconstraint = (FkConstraint *)constraint;
						fkconstraint->fk_attrs = lappend(NIL, id);
677

Jan Wieck's avatar
Jan Wieck committed
678 679 680 681
						fkconstraints = lappend(fkconstraints, constraint);
						continue;
					}

682
					switch (constraint->contype)
683
					{
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734
						case CONSTR_NULL:

							/*
							 * We should mark this explicitly, so we
							 * can tell if NULL and NOT NULL are both
							 * specified
							 */
							if (column->is_not_null)
								elog(ERROR, "CREATE TABLE/(NOT) NULL conflicting declaration"
									 " for '%s.%s'", stmt->relname, column->colname);
							column->is_not_null = FALSE;
							break;

						case CONSTR_NOTNULL:
							if (column->is_not_null)
								elog(ERROR, "CREATE TABLE/NOT NULL already specified"
									 " for '%s.%s'", stmt->relname, column->colname);
							column->is_not_null = TRUE;
							break;

						case CONSTR_DEFAULT:
							if (column->raw_default != NULL)
								elog(ERROR, "CREATE TABLE/DEFAULT multiple values specified"
									 " for '%s.%s'", stmt->relname, column->colname);
							column->raw_default = constraint->raw_expr;
							Assert(constraint->cooked_expr == NULL);
							break;

						case CONSTR_PRIMARY:
							if (constraint->name == NULL)
								constraint->name = makeObjectName(stmt->relname, NULL, "pkey");
							if (constraint->keys == NIL)
								constraint->keys = lappend(constraint->keys, column);
							dlist = lappend(dlist, constraint);
							break;

						case CONSTR_UNIQUE:
							if (constraint->name == NULL)
								constraint->name = makeObjectName(stmt->relname, column->colname, "key");
							if (constraint->keys == NIL)
								constraint->keys = lappend(constraint->keys, column);
							dlist = lappend(dlist, constraint);
							break;

						case CONSTR_CHECK:
							if (constraint->name == NULL)
								constraint->name = makeObjectName(stmt->relname, column->colname, NULL);
							constraints = lappend(constraints, constraint);
							break;

						default:
735
							elog(ERROR, "parser: unrecognized constraint (internal error)");
736
							break;
737 738 739 740 741 742 743 744 745 746
					}
				}
				break;

			case T_Constraint:
				constraint = (Constraint *) element;
				switch (constraint->contype)
				{
					case CONSTR_PRIMARY:
						if (constraint->name == NULL)
747
							constraint->name = makeObjectName(stmt->relname, NULL, "pkey");
748 749 750 751 752 753 754 755 756 757 758 759 760
						dlist = lappend(dlist, constraint);
						break;

					case CONSTR_UNIQUE:
						dlist = lappend(dlist, constraint);
						break;

					case CONSTR_CHECK:
						constraints = lappend(constraints, constraint);
						break;

					case CONSTR_NOTNULL:
					case CONSTR_DEFAULT:
761
						elog(ERROR, "parser: illegal context for constraint (internal error)");
762 763
						break;
					default:
764
						elog(ERROR, "parser: unrecognized constraint (internal error)");
765 766 767 768
						break;
				}
				break;

Jan Wieck's avatar
Jan Wieck committed
769 770 771 772 773 774 775 776 777
			case T_FkConstraint:
				/* ----------
				 * Table level FOREIGN KEY constraints are already complete.
				 * Just remember for later.
				 * ----------
				 */
				fkconstraints = lappend(fkconstraints, element);
				break;

778
			default:
779
				elog(ERROR, "parser: unrecognized node (internal error)");
780 781 782 783 784 785 786 787 788 789 790
		}
	}

	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
791
 *	and either ignore or stop with warning. The create might fail later when
792
 *	names for indices turn out to be duplicated, or a user might have specified
793
 *	extra useless indices which might hurt performance. - thomas 1997-12-08
794 795 796 797
 */
	while (dlist != NIL)
	{
		constraint = lfirst(dlist);
798 799
		Assert(nodeTag(constraint) == T_Constraint);
		Assert((constraint->contype == CONSTR_PRIMARY)
Bruce Momjian's avatar
Bruce Momjian committed
800
			   || (constraint->contype == CONSTR_UNIQUE));
801

802 803 804
		index = makeNode(IndexStmt);

		index->unique = TRUE;
Bruce Momjian's avatar
Bruce Momjian committed
805
		index->primary = (constraint->contype == CONSTR_PRIMARY ? TRUE : FALSE);
806
		if (index->primary)
807
		{
808
			if (pkey != NULL)
809
				elog(ERROR, "CREATE TABLE/PRIMARY KEY multiple primary keys"
810
					 " for table '%s' are not allowed", stmt->relname);
811
			pkey = (IndexStmt *) index;
812
		}
813

814
		if (constraint->name != NULL)
815
			index->idxname = pstrdup(constraint->name);
816
		else if (constraint->contype == CONSTR_PRIMARY)
817
			index->idxname = makeObjectName(stmt->relname, NULL, "pkey");
818 819 820 821 822 823 824 825
		else
			index->idxname = NULL;

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

827 828 829 830 831 832 833 834 835
		keys = constraint->keys;
		while (keys != NIL)
		{
			key = lfirst(keys);
			columns = stmt->tableElts;
			column = NULL;
			while (columns != NIL)
			{
				column = lfirst(columns);
836 837 838 839
				if (strcasecmp(column->colname, key->name) == 0)
					break;
				else
					column = NULL;
840 841 842
				columns = lnext(columns);
			}
			if (column == NULL)
843
				elog(ERROR, "CREATE TABLE column '%s' in key does not exist", key->name);
844 845 846 847

			if (constraint->contype == CONSTR_PRIMARY)
				column->is_not_null = TRUE;
			iparam = makeNode(IndexElem);
848
			iparam->name = pstrdup(column->colname);
849 850
			iparam->args = NIL;
			iparam->class = NULL;
851
			iparam->typename = NULL;
852 853 854
			index->indexParams = lappend(index->indexParams, iparam);

			if (index->idxname == NULL)
855
				index->idxname = CreateIndexName(stmt->relname, iparam->name, "key", ilist);
856 857 858 859

			keys = lnext(keys);
		}

860 861
		if (index->idxname == NULL)	/* should not happen */
			elog(ERROR, "CREATE TABLE: failed to make implicit index name");
862

863
		ilist = lappend(ilist, index);
864 865 866
		dlist = lnext(dlist);
	}

867 868 869 870 871
/* OK, now finally, if there is a primary key, then make sure that there aren't any redundant
 * unique indices defined on columns. This can arise if someone specifies UNIQUE explicitly
 * or if a SERIAL column was defined along with a table PRIMARY KEY constraint.
 * - thomas 1999-05-11
 */
872
	if (pkey != NULL)
873 874 875 876 877
	{
		dlist = ilist;
		ilist = NIL;
		while (dlist != NIL)
		{
878 879 880
			List *pcols, *icols;
			int plen, ilen;
			int	keep = TRUE;
881 882

			index = lfirst(dlist);
883 884
			pcols = pkey->indexParams;
			icols = index->indexParams;
885

886 887 888 889 890
			plen = length(pcols);
			ilen = length(icols);

			/* Not the same as the primary key? Then we should look... */
			if ((index != pkey) && (ilen == plen))
891
			{
892 893 894 895 896 897 898
				keep = FALSE;
				while ((pcols != NIL) && (icols != NIL))
				{
					IndexElem *pcol = lfirst(pcols);
					IndexElem *icol = lfirst(icols);
					char *pname = pcol->name;
					char *iname = icol->name;
Bruce Momjian's avatar
Bruce Momjian committed
899

900 901 902 903 904 905 906 907 908
					/* different names? then no match... */
					if (strcmp(iname, pname) != 0)
					{
						keep = TRUE;
						break;
					}
					pcols = lnext(pcols);
					icols = lnext(icols);
				}
909 910 911 912 913 914 915 916 917 918 919 920 921
			}

			if (keep)
				ilist = lappend(ilist, index);
			dlist = lnext(dlist);
		}
	}

	dlist = ilist;
	while (dlist != NIL)
	{
		index = lfirst(dlist);
		elog(NOTICE, "CREATE TABLE/%s will create implicit index '%s' for table '%s'",
Bruce Momjian's avatar
Bruce Momjian committed
922
			 (index->primary ? "PRIMARY KEY" : "UNIQUE"),
923 924 925 926
			 index->idxname, stmt->relname);
		dlist = lnext(dlist);
	}

927
	q->utilityStmt = (Node *) stmt;
Bruce Momjian's avatar
Bruce Momjian committed
928 929
	extras_before = blist;
	extras_after = ilist;
930

Jan Wieck's avatar
Jan Wieck committed
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962
	/*
	 * Now process the FOREIGN KEY constraints and add appropriate
	 * queries to the extras_after statements list.
	 *
	 */
	if (fkconstraints != NIL)
	{
		CreateTrigStmt	   *fk_trigger;
		List			   *fk_attr;
		List			   *pk_attr;
		Ident			   *id;

		elog(NOTICE, "CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)");

		foreach (fkclist, fkconstraints)
		{
			fkconstraint = (FkConstraint *)lfirst(fkclist);

			/*
			 * If the constraint has no name, set it to <unnamed>
			 *
			 */
			if (fkconstraint->constr_name == NULL)
				fkconstraint->constr_name = "<unnamed>";

			/*
			 * If the attribute list for the referenced table was
			 * omitted, lookup for the definition of the primary key
			 *
			 */
			if (fkconstraint->fk_attrs != NIL && fkconstraint->pk_attrs == NIL)
				transformFkeyGetPrimaryKey(fkconstraint);
963

Jan Wieck's avatar
Jan Wieck committed
964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
			/*
			 * Build a CREATE CONSTRAINT TRIGGER statement for the CHECK
			 * action.
			 *
			 */
			fk_trigger = (CreateTrigStmt *)makeNode(CreateTrigStmt);
			fk_trigger->trigname		= fkconstraint->constr_name;
			fk_trigger->relname			= stmt->relname;
			fk_trigger->funcname		= "RI_FKey_check_ins";
			fk_trigger->before			= false;
			fk_trigger->row				= true;
			fk_trigger->actions[0]		= 'i';
			fk_trigger->actions[1]		= 'u';
			fk_trigger->actions[2]		= '\0';
			fk_trigger->lang			= NULL;
			fk_trigger->text			= NULL;
			fk_trigger->attr			= NIL;
			fk_trigger->when			= NULL;
			fk_trigger->isconstraint	= true;
			fk_trigger->deferrable		= fkconstraint->deferrable;
			fk_trigger->initdeferred	= fkconstraint->initdeferred;
			fk_trigger->constrrelname	= fkconstraint->pktable_name;

			fk_trigger->args		= NIL;
			fk_trigger->args = lappend(fk_trigger->args,
										fkconstraint->constr_name);
			fk_trigger->args = lappend(fk_trigger->args,
										stmt->relname);
			fk_trigger->args = lappend(fk_trigger->args,
										fkconstraint->pktable_name);
			fk_trigger->args = lappend(fk_trigger->args,
										fkconstraint->match_type);
			fk_attr = fkconstraint->fk_attrs;
			pk_attr = fkconstraint->pk_attrs;
			if (length(fk_attr) != length(pk_attr))
			{
				elog(NOTICE, "Illegal FOREIGN KEY definition REFERENCES \"%s\"",
							fkconstraint->pktable_name);
				elog(ERROR, "number of key attributes in referenced table must be equal to foreign key");
			}
			while (fk_attr != NIL)
			{
				id = (Ident *)lfirst(fk_attr);
				fk_trigger->args = lappend(fk_trigger->args, id->name);

				id = (Ident *)lfirst(pk_attr);
				fk_trigger->args = lappend(fk_trigger->args, id->name);

				fk_attr = lnext(fk_attr);
				pk_attr = lnext(pk_attr);
			}

			extras_after = lappend(extras_after, (Node *)fk_trigger);

1018
			/*
1019
			 * Build a CREATE CONSTRAINT TRIGGER statement for the
1020 1021 1022 1023 1024 1025 1026 1027
			 * ON DELETE action fired on the PK table !!!
			 *
			 */
			fk_trigger = (CreateTrigStmt *)makeNode(CreateTrigStmt);
			fk_trigger->trigname		= fkconstraint->constr_name;
			fk_trigger->relname			= fkconstraint->pktable_name;
			switch ((fkconstraint->actions & FKCONSTR_ON_DELETE_MASK)
							>> FKCONSTR_ON_DELETE_SHIFT)
Jan Wieck's avatar
Jan Wieck committed
1028
			{
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059
				case FKCONSTR_ON_KEY_NOACTION:
					fk_trigger->funcname = "RI_FKey_noaction_del";
					break;
				case FKCONSTR_ON_KEY_RESTRICT:
					fk_trigger->funcname = "RI_FKey_restrict_del";
					break;
				case FKCONSTR_ON_KEY_CASCADE:
					fk_trigger->funcname = "RI_FKey_cascade_del";
					break;
				case FKCONSTR_ON_KEY_SETNULL:
					fk_trigger->funcname = "RI_FKey_setnull_del";
					break;
				case FKCONSTR_ON_KEY_SETDEFAULT:
					fk_trigger->funcname = "RI_FKey_setdefault_del";
					break;
				default:
					elog(ERROR, "Only one ON DELETE action can be specified for FOREIGN KEY constraint");
					break;
			}
			fk_trigger->before			= false;
			fk_trigger->row				= true;
			fk_trigger->actions[0]		= 'd';
			fk_trigger->actions[1]		= '\0';
			fk_trigger->lang			= NULL;
			fk_trigger->text			= NULL;
			fk_trigger->attr			= NIL;
			fk_trigger->when			= NULL;
			fk_trigger->isconstraint	= true;
			fk_trigger->deferrable		= fkconstraint->deferrable;
			fk_trigger->initdeferred	= fkconstraint->initdeferred;
			fk_trigger->constrrelname	= stmt->relname;
Jan Wieck's avatar
Jan Wieck committed
1060

1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
			fk_trigger->args		= NIL;
			fk_trigger->args = lappend(fk_trigger->args,
										fkconstraint->constr_name);
			fk_trigger->args = lappend(fk_trigger->args,
										stmt->relname);
			fk_trigger->args = lappend(fk_trigger->args,
										fkconstraint->pktable_name);
			fk_trigger->args = lappend(fk_trigger->args,
										fkconstraint->match_type);
			fk_attr = fkconstraint->fk_attrs;
			pk_attr = fkconstraint->pk_attrs;
			while (fk_attr != NIL)
			{
				id = (Ident *)lfirst(fk_attr);
				fk_trigger->args = lappend(fk_trigger->args, id->name);
Jan Wieck's avatar
Jan Wieck committed
1076

1077 1078
				id = (Ident *)lfirst(pk_attr);
				fk_trigger->args = lappend(fk_trigger->args, id->name);
Jan Wieck's avatar
Jan Wieck committed
1079

1080 1081
				fk_attr = lnext(fk_attr);
				pk_attr = lnext(pk_attr);
Jan Wieck's avatar
Jan Wieck committed
1082 1083
			}

1084 1085 1086
			extras_after = lappend(extras_after, (Node *)fk_trigger);

			/*
1087
			 * Build a CREATE CONSTRAINT TRIGGER statement for the
1088 1089 1090 1091 1092 1093 1094 1095
			 * ON UPDATE action fired on the PK table !!!
			 *
			 */
			fk_trigger = (CreateTrigStmt *)makeNode(CreateTrigStmt);
			fk_trigger->trigname		= fkconstraint->constr_name;
			fk_trigger->relname			= fkconstraint->pktable_name;
			switch ((fkconstraint->actions & FKCONSTR_ON_UPDATE_MASK)
							>> FKCONSTR_ON_UPDATE_SHIFT)
Jan Wieck's avatar
Jan Wieck committed
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
				case FKCONSTR_ON_KEY_NOACTION:
					fk_trigger->funcname = "RI_FKey_noaction_upd";
					break;
				case FKCONSTR_ON_KEY_RESTRICT:
					fk_trigger->funcname = "RI_FKey_restrict_upd";
					break;
				case FKCONSTR_ON_KEY_CASCADE:
					fk_trigger->funcname = "RI_FKey_cascade_upd";
					break;
				case FKCONSTR_ON_KEY_SETNULL:
					fk_trigger->funcname = "RI_FKey_setnull_upd";
					break;
				case FKCONSTR_ON_KEY_SETDEFAULT:
					fk_trigger->funcname = "RI_FKey_setdefault_upd";
					break;
				default:
					elog(ERROR, "Only one ON UPDATE action can be specified for FOREIGN KEY constraint");
					break;
			}
			fk_trigger->before			= false;
			fk_trigger->row				= true;
			fk_trigger->actions[0]		= 'u';
			fk_trigger->actions[1]		= '\0';
			fk_trigger->lang			= NULL;
			fk_trigger->text			= NULL;
			fk_trigger->attr			= NIL;
			fk_trigger->when			= NULL;
			fk_trigger->isconstraint	= true;
			fk_trigger->deferrable		= fkconstraint->deferrable;
			fk_trigger->initdeferred	= fkconstraint->initdeferred;
			fk_trigger->constrrelname	= stmt->relname;
Jan Wieck's avatar
Jan Wieck committed
1128

1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
			fk_trigger->args		= NIL;
			fk_trigger->args = lappend(fk_trigger->args,
										fkconstraint->constr_name);
			fk_trigger->args = lappend(fk_trigger->args,
										stmt->relname);
			fk_trigger->args = lappend(fk_trigger->args,
										fkconstraint->pktable_name);
			fk_trigger->args = lappend(fk_trigger->args,
										fkconstraint->match_type);
			fk_attr = fkconstraint->fk_attrs;
			pk_attr = fkconstraint->pk_attrs;
			while (fk_attr != NIL)
			{
				id = (Ident *)lfirst(fk_attr);
				fk_trigger->args = lappend(fk_trigger->args, id->name);
Jan Wieck's avatar
Jan Wieck committed
1144

1145 1146
				id = (Ident *)lfirst(pk_attr);
				fk_trigger->args = lappend(fk_trigger->args, id->name);
Jan Wieck's avatar
Jan Wieck committed
1147

1148 1149
				fk_attr = lnext(fk_attr);
				pk_attr = lnext(pk_attr);
Jan Wieck's avatar
Jan Wieck committed
1150
			}
1151 1152

			extras_after = lappend(extras_after, (Node *)fk_trigger);
Jan Wieck's avatar
Jan Wieck committed
1153 1154 1155
		}
	}

1156
	return q;
Bruce Momjian's avatar
Bruce Momjian committed
1157
}	/* transformCreateStmt() */
1158

Jan Wieck's avatar
Jan Wieck committed
1159

1160 1161
/*
 * transformIndexStmt -
1162
 *	  transforms the qualification of the index statement
1163
 */
1164
static Query *
1165
transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
1166
{
Bruce Momjian's avatar
Bruce Momjian committed
1167
	Query	   *qry;
1168

Bruce Momjian's avatar
Bruce Momjian committed
1169 1170
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
1171

1172
	/* take care of the where clause */
1173
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause, NULL);
Bruce Momjian's avatar
Bruce Momjian committed
1174
	qry->hasSubLinks = pstate->p_hasSubLinks;
1175

1176
	stmt->rangetable = pstate->p_rtable;
1177

Bruce Momjian's avatar
Bruce Momjian committed
1178
	qry->utilityStmt = (Node *) stmt;
1179

Bruce Momjian's avatar
Bruce Momjian committed
1180
	return qry;
1181 1182 1183 1184
}

/*
 * transformExtendStmt -
1185
 *	  transform the qualifications of the Extend Index Statement
1186 1187
 *
 */
1188
static Query *
1189
transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
1190
{
Bruce Momjian's avatar
Bruce Momjian committed
1191
	Query	   *qry;
1192

Bruce Momjian's avatar
Bruce Momjian committed
1193 1194
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
1195

1196
	/* take care of the where clause */
1197
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause, NULL);
Bruce Momjian's avatar
Bruce Momjian committed
1198 1199
	qry->hasSubLinks = pstate->p_hasSubLinks;

1200
	stmt->rangetable = pstate->p_rtable;
1201

Bruce Momjian's avatar
Bruce Momjian committed
1202 1203
	qry->utilityStmt = (Node *) stmt;
	return qry;
1204 1205 1206 1207
}

/*
 * transformRuleStmt -
1208 1209
 *	  transform a Create Rule Statement. The actions is a list of parse
 *	  trees which is transformed into a list of query trees.
1210
 */
1211
static Query *
1212
transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
1213
{
Bruce Momjian's avatar
Bruce Momjian committed
1214
	Query	   *qry;
1215
	Query	   *action;
1216
	List	   *actions;
1217

Bruce Momjian's avatar
Bruce Momjian committed
1218 1219
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
1220

1221
	/*
1222 1223 1224 1225 1226
	 * '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.
1227
	 */
1228 1229 1230 1231
	if (stmt->actions == NIL)
	{
		Query	   *nothing_qry = makeNode(Query);

1232 1233 1234
		nothing_qry->commandType = CMD_NOTHING;

		addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
1235
						   FALSE, FALSE, FALSE);
1236
		addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
1237
						   FALSE, FALSE, FALSE);
1238 1239 1240 1241 1242 1243

		nothing_qry->rtable = pstate->p_rtable;

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

1244 1245
	actions = stmt->actions;

1246
	/*
1247
	 * transform each statment, like parse_analyze()
1248
	 */
1249 1250
	while (actions != NIL)
	{
1251

1252 1253 1254 1255 1256
		/*
		 * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
		 * equal to 2.
		 */
		addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
1257
						   FALSE, FALSE, FALSE);
1258
		addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
1259
						   FALSE, FALSE, FALSE);
1260 1261 1262

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

1265
		action = (Query *) lfirst(actions);
1266 1267
		if (action->commandType != CMD_NOTHING)
			lfirst(actions) = transformStmt(pstate, lfirst(actions));
1268 1269
		actions = lnext(actions);
	}
1270

1271
	/* take care of the where clause */
1272
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause, NULL);
Bruce Momjian's avatar
Bruce Momjian committed
1273
	qry->hasSubLinks = pstate->p_hasSubLinks;
1274

Bruce Momjian's avatar
Bruce Momjian committed
1275 1276
	qry->utilityStmt = (Node *) stmt;
	return qry;
1277 1278 1279 1280 1281
}


/*
 * transformSelectStmt -
1282
 *	  transforms a Select Statement
1283 1284
 *
 */
1285
static Query *
Bruce Momjian's avatar
Bruce Momjian committed
1286
transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
1287
{
1288
	Query	   *qry = makeNode(Query);
1289
	Node	   *fromQual;
1290 1291

	qry->commandType = CMD_SELECT;
1292

1293
	/* set up a range table */
1294
	makeRangeTable(pstate, stmt->fromClause, &fromQual);
1295

1296
	qry->uniqueFlag = stmt->unique;
1297

1298
	qry->into = stmt->into;
1299
	qry->isTemp = stmt->istemp;
1300
	qry->isPortal = FALSE;
1301

1302
	qry->targetList = transformTargetList(pstate, stmt->targetList);
1303

1304
	qry->qual = transformWhereClause(pstate, stmt->whereClause, fromQual);
1305

1306 1307
	/* Initial processing of HAVING clause is just like WHERE clause.
	 * Additional work will be done in optimizer/plan/planner.c.
1308
	 */
1309
	qry->havingQual = transformWhereClause(pstate, stmt->havingClause, NULL);
1310

1311 1312 1313
	qry->groupClause = transformGroupClause(pstate,
											stmt->groupClause,
											qry->targetList);
1314

1315 1316 1317 1318
	qry->sortClause = transformSortClause(pstate,
										  stmt->sortClause,
										  qry->targetList,
										  qry->uniqueFlag);
1319

1320
	qry->hasSubLinks = pstate->p_hasSubLinks;
Bruce Momjian's avatar
Bruce Momjian committed
1321
	qry->hasAggs = pstate->p_hasAggs;
1322
	if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
Bruce Momjian's avatar
Bruce Momjian committed
1323
		parseCheckAggregates(pstate, qry);
1324

1325 1326 1327
	/*
	 * The INSERT INTO ... SELECT ... could have a UNION in child, so
	 * unionClause may be false
1328 1329
	 */
	qry->unionall = stmt->unionall;
Bruce Momjian's avatar
Hi!  
Bruce Momjian committed
1330

Bruce Momjian's avatar
Bruce Momjian committed
1331 1332 1333 1334 1335 1336
	/*
	 * 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;
1337

1338
	qry->rtable = pstate->p_rtable;
1339

1340 1341 1342
	if (stmt->forUpdate != NULL)
		transformForUpdate(qry, stmt->forUpdate);

1343
	return (Query *) qry;
1344 1345 1346 1347
}

/*
 * transformUpdateStmt -
1348
 *	  transforms an update statement
1349 1350
 *
 */
1351
static Query *
Bruce Momjian's avatar
Bruce Momjian committed
1352
transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
1353
{
1354
	Query	   *qry = makeNode(Query);
1355 1356
	List	   *origTargetList;
	List	   *tl;
1357 1358 1359

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

1361 1362 1363 1364
	/*
	 * 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.
	 */
1365 1366
	makeRangeTable(pstate, stmt->fromClause, NULL);
	setTargetTable(pstate, stmt->relname);
1367

1368
	qry->targetList = transformTargetList(pstate, stmt->targetList);
1369

1370
	qry->qual = transformWhereClause(pstate, stmt->whereClause, NULL);
1371

Bruce Momjian's avatar
Bruce Momjian committed
1372
	qry->hasSubLinks = pstate->p_hasSubLinks;
1373

1374
	qry->rtable = pstate->p_rtable;
1375
	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
1376

Bruce Momjian's avatar
Bruce Momjian committed
1377
	qry->hasAggs = pstate->p_hasAggs;
1378
	if (pstate->p_hasAggs)
1379
		parseCheckAggregates(pstate, qry);
1380

1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410
	/*
	 * Now we are done with SELECT-like processing, and can get on with
	 * transforming the target list to match the UPDATE target columns.
	 */

	/* Prepare to assign non-conflicting resnos to resjunk attributes */
	if (pstate->p_last_resno <= pstate->p_target_relation->rd_rel->relnatts)
		pstate->p_last_resno = pstate->p_target_relation->rd_rel->relnatts + 1;

	/* Prepare non-junk columns for assignment to target table */
	origTargetList = stmt->targetList;
	foreach(tl, qry->targetList)
	{
		TargetEntry *tle = (TargetEntry *) lfirst(tl);
		Resdom	   *resnode = tle->resdom;
		ResTarget  *origTarget;

		if (resnode->resjunk)
		{
			/* Resjunk nodes need no additional processing, but be sure they
			 * have names and resnos that do not match any target columns;
			 * else rewriter or planner might get confused.
			 */
			resnode->resname = "?resjunk?";
			resnode->resno = (AttrNumber) pstate->p_last_resno++;
			continue;
		}
		if (origTargetList == NIL)
			elog(ERROR, "UPDATE target count mismatch --- internal error");
		origTarget = (ResTarget *) lfirst(origTargetList);
1411 1412 1413 1414
		updateTargetListEntry(pstate, tle, origTarget->name,
							  attnameAttNum(pstate->p_target_relation,
											origTarget->name),
							  origTarget->indirection);
1415 1416 1417 1418 1419
		origTargetList = lnext(origTargetList);
	}
	if (origTargetList != NIL)
		elog(ERROR, "UPDATE target count mismatch --- internal error");

1420
	return (Query *) qry;
1421 1422 1423 1424
}

/*
 * transformCursorStmt -
1425
 *	  transform a Create Cursor Statement
1426 1427
 *
 */
1428
static Query *
1429
transformCursorStmt(ParseState *pstate, SelectStmt *stmt)
1430
{
1431
	Query	   *qry;
1432

1433
	qry = transformSelectStmt(pstate, stmt);
1434

1435
	qry->into = stmt->portalname;
1436
	qry->isTemp = stmt->istemp;
1437 1438
	qry->isPortal = TRUE;
	qry->isBinary = stmt->binary;		/* internal portal */
1439

1440
	return qry;
1441
}
Bruce Momjian's avatar
Hi!  
Bruce Momjian committed
1442 1443 1444 1445 1446 1447 1448

/* 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' */
Bruce Momjian's avatar
Bruce Momjian committed
1449
void
Bruce Momjian's avatar
Hi!  
Bruce Momjian committed
1450 1451
create_select_list(Node *ptr, List **select_list, bool *unionall_present)
{
Bruce Momjian's avatar
Bruce Momjian committed
1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463
	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);
Bruce Momjian's avatar
Hi!  
Bruce Momjian committed
1464 1465 1466
}

/* Changes the A_Expr Nodes to Expr Nodes and exchanges ANDs and ORs.
Bruce Momjian's avatar
Bruce Momjian committed
1467
 * The reason for the exchange is easy: We implement INTERSECTs and EXCEPTs
Bruce Momjian's avatar
Hi!  
Bruce Momjian committed
1468
 * by rewriting these queries to semantically equivalent queries that use
Bruce Momjian's avatar
Bruce Momjian committed
1469 1470
 * IN and NOT IN subselects. To be able to use all three operations
 * (UNIONs INTERSECTs and EXCEPTs) in one complex query we have to
Bruce Momjian's avatar
Hi!  
Bruce Momjian committed
1471 1472 1473 1474 1475 1476
 * 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
Bruce Momjian's avatar
Bruce Momjian committed
1477 1478 1479
 * hands back 'true' */
Node *
A_Expr_to_Expr(Node *ptr, bool *intersect_present)
Bruce Momjian's avatar
Hi!  
Bruce Momjian committed
1480
{
Bruce Momjian's avatar
Bruce Momjian committed
1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531
	Node	   *result = NULL;

	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:
1532
			result = ptr;
Bruce Momjian's avatar
Bruce Momjian committed
1533 1534
	}
	return result;
Bruce Momjian's avatar
Hi!  
Bruce Momjian committed
1535
}
1536

1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549
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");
}

1550 1551 1552 1553
static void
transformForUpdate(Query *qry, List *forUpdate)
{
	List	   *rowMark = NULL;
Bruce Momjian's avatar
Bruce Momjian committed
1554
	RowMark    *newrm;
1555 1556 1557
	List	   *l;
	Index		i;

1558 1559
	CheckSelectForUpdate(qry);

1560 1561 1562
	if (lfirst(forUpdate) == NULL)		/* all tables */
	{
		i = 1;
Bruce Momjian's avatar
Bruce Momjian committed
1563
		foreach(l, qry->rtable)
1564 1565 1566
		{
			newrm = makeNode(RowMark);
			newrm->rti = i++;
Bruce Momjian's avatar
Bruce Momjian committed
1567
			newrm->info = ROW_MARK_FOR_UPDATE | ROW_ACL_FOR_UPDATE;
1568 1569 1570 1571 1572 1573
			rowMark = lappend(rowMark, newrm);
		}
		qry->rowMark = nconc(qry->rowMark, rowMark);
		return;
	}

Bruce Momjian's avatar
Bruce Momjian committed
1574
	foreach(l, forUpdate)
1575
	{
Bruce Momjian's avatar
Bruce Momjian committed
1576 1577
		List	   *l2;
		List	   *l3;
1578 1579

		i = 1;
Bruce Momjian's avatar
Bruce Momjian committed
1580
		foreach(l2, qry->rtable)
1581
		{
Bruce Momjian's avatar
Bruce Momjian committed
1582
			if (strcmp(((RangeTblEntry *) lfirst(l2))->refname, lfirst(l)) == 0)
1583
			{
Bruce Momjian's avatar
Bruce Momjian committed
1584
				foreach(l3, rowMark)
1585
				{
Bruce Momjian's avatar
Bruce Momjian committed
1586
					if (((RowMark *) lfirst(l3))->rti == i)		/* duplicate */
1587 1588 1589 1590 1591 1592
						break;
				}
				if (l3 == NULL)
				{
					newrm = makeNode(RowMark);
					newrm->rti = i;
Bruce Momjian's avatar
Bruce Momjian committed
1593
					newrm->info = ROW_MARK_FOR_UPDATE | ROW_ACL_FOR_UPDATE;
1594 1595 1596 1597 1598 1599 1600
					rowMark = lappend(rowMark, newrm);
				}
				break;
			}
			i++;
		}
		if (l2 == NULL)
1601
			elog(ERROR, "FOR UPDATE: relation %s not found in FROM clause", strVal(lfirst(l)));
1602 1603 1604 1605 1606
	}

	qry->rowMark = rowMark;
	return;
}
Jan Wieck's avatar
Jan Wieck committed
1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681


/*
 * transformFkeyGetPrimaryKey -
 *
 *	Try to find the primary key attributes of a referenced table if
 *	the column list in the REFERENCES specification was omitted.
 *
 */
static void
transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
{
	Relation			pkrel;
	Form_pg_attribute  *pkrel_attrs;
	Relation			indexRd;
	HeapScanDesc		indexSd;
	ScanKeyData			key;
	HeapTuple			indexTup;
	Form_pg_index		indexStruct = NULL;
	Ident			   *pkattr;
	int					pkattno;
	int					i;

	/* ----------
	 * Open the referenced table and get the attributes list
	 * ----------
	 */
	pkrel = heap_openr(fkconstraint->pktable_name, AccessShareLock);
	if (pkrel == NULL)
		elog(ERROR, "referenced table \"%s\" not found",
						fkconstraint->pktable_name);
	pkrel_attrs = pkrel->rd_att->attrs;

	/* ----------
	 * Open pg_index and begin a scan for all indices defined on
	 * the referenced table
	 * ----------
	 */
	indexRd = heap_openr(IndexRelationName, AccessShareLock);
	ScanKeyEntryInitialize(&key, 0, Anum_pg_index_indrelid,
								F_OIDEQ,
								ObjectIdGetDatum(pkrel->rd_id));
    indexSd = heap_beginscan(indexRd,   /* scan desc */
								false,     /* scan backward flag */
								SnapshotNow,       /* NOW snapshot */
								1, /* number scan keys */
								&key);     /* scan keys */

	/* ----------
	 * Fetch the index with indisprimary == true
	 * ----------
	 */
	while (HeapTupleIsValid(indexTup = heap_getnext(indexSd, 0)))
	{
		indexStruct = (Form_pg_index) GETSTRUCT(indexTup);

		if (indexStruct->indisprimary)
		{
			break;
		}
	}

	/* ----------
	 * Check that we found it
	 * ----------
	 */
	if (!HeapTupleIsValid(indexTup))
		elog(ERROR, "PRIMARY KEY for referenced table \"%s\" not found",
					fkconstraint->pktable_name);

	/* ----------
	 * Now build the list of PK attributes from the indkey definition
	 * using the attribute names of the PK relation descriptor
	 * ----------
	 */
1682
	for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
Jan Wieck's avatar
Jan Wieck committed
1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702
	{
		pkattno = indexStruct->indkey[i];
		pkattr = (Ident *)makeNode(Ident);
		pkattr->name = nameout(&(pkrel_attrs[pkattno - 1]->attname));
		pkattr->indirection = NIL;
		pkattr->isRel = false;

		fkconstraint->pk_attrs = lappend(fkconstraint->pk_attrs, pkattr);
	}

	/* ----------
	 * End index scan and close relations
	 * ----------
	 */
	heap_endscan(indexSd);
	heap_close(indexRd, AccessShareLock);
	heap_close(pkrel, AccessShareLock);
}