analyze.c 88.7 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * analyze.c
4
 *	  transform the parse tree into a query tree
5
 *
6
 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
Bruce Momjian's avatar
Add:  
Bruce Momjian committed
7
 * Portions Copyright (c) 1994, Regents of the University of California
8
 *
9
 *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.215 2002/02/26 22:47:08 tgl Exp $
10 11 12
 *
 *-------------------------------------------------------------------------
 */
13

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

16
#include "access/heapam.h"
Jan Wieck's avatar
Jan Wieck committed
17
#include "catalog/catname.h"
18
#include "catalog/heap.h"
Jan Wieck's avatar
Jan Wieck committed
19
#include "catalog/pg_index.h"
Bruce Momjian's avatar
Bruce Momjian committed
20
#include "catalog/pg_type.h"
21 22
#include "nodes/makefuncs.h"
#include "parser/analyze.h"
23
#include "parser/parse.h"
24
#include "parser/parsetree.h"
25
#include "parser/parse_agg.h"
Bruce Momjian's avatar
Bruce Momjian committed
26
#include "parser/parse_clause.h"
27
#include "parser/parse_coerce.h"
28 29
#include "parser/parse_expr.h"
#include "parser/parse_oper.h"
30 31
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
32
#include "parser/parse_type.h"
33
#include "parser/parse_expr.h"
34
#include "rewrite/rewriteManip.h"
35
#include "utils/builtins.h"
36
#include "utils/fmgroids.h"
37 38
#include "utils/relcache.h"
#include "utils/syscache.h"
39
#include "utils/temprel.h"
40

41 42 43 44
#ifdef MULTIBYTE
#include "mb/pg_wchar.h"
#endif

45 46 47 48 49 50 51 52

/* State shared by transformCreateStmt and its subroutines */
typedef struct
{
	const char *stmtType;		/* "CREATE TABLE" or "ALTER TABLE" */
	char	   *relname;		/* name of relation */
	List	   *inhRelnames;	/* names of relations to inherit from */
	bool		istemp;			/* is it to be a temp relation? */
53
	bool		hasoids;		/* does relation have an OID column? */
54 55 56 57 58 59 60 61 62 63 64 65 66
	Oid			relOid;			/* OID of table, if ALTER TABLE case */
	List	   *columns;		/* ColumnDef items */
	List	   *ckconstraints;	/* CHECK constraints */
	List	   *fkconstraints;	/* FOREIGN KEY constraints */
	List	   *ixconstraints;	/* index-creating constraints */
	List	   *blist;			/* "before list" of things to do before
								 * creating the table */
	List	   *alist;			/* "after list" of things to do after
								 * creating the table */
	IndexStmt  *pkey;			/* PRIMARY KEY index, if any */
} CreateStmtContext;


67 68
static Query *transformStmt(ParseState *pstate, Node *stmt,
						List **extras_before, List **extras_after);
69
static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
70 71
static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
						List **extras_before, List **extras_after);
72
static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);
73 74
static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt,
						List **extras_before, List **extras_after);
Bruce Momjian's avatar
Bruce Momjian committed
75
static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);
76 77
static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);
static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt);
Bruce Momjian's avatar
Bruce Momjian committed
78
static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
79 80 81 82
static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt,
						List **extras_before, List **extras_after);
static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
						List **extras_before, List **extras_after);
83
static void transformColumnDefinition(ParseState *pstate,
84 85
						  CreateStmtContext *cxt,
						  ColumnDef *column);
86
static void transformTableConstraint(ParseState *pstate,
87 88
						 CreateStmtContext *cxt,
						 Constraint *constraint);
89
static void transformIndexConstraints(ParseState *pstate,
90
						  CreateStmtContext *cxt);
91
static void transformFKConstraints(ParseState *pstate,
92
					   CreateStmtContext *cxt);
93
static Node *transformTypeRefs(ParseState *pstate, Node *stmt);
94

95
static void applyColumnNames(List *dst, List *src);
96 97
static void transformTypeRefsList(ParseState *pstate, List *l);
static void transformTypeRef(ParseState *pstate, TypeName *tn);
98
static List *getSetColTypes(ParseState *pstate, Node *node);
Bruce Momjian's avatar
Bruce Momjian committed
99
static void transformForUpdate(Query *qry, List *forUpdate);
100
static void transformConstraintAttrs(List *constraintList);
101
static void transformColumnType(ParseState *pstate, ColumnDef *column);
102
static void transformFkeyCheckAttrs(FkConstraint *fkconstraint, Oid *pktypoid);
103 104
static void transformFkeyGetPrimaryKey(FkConstraint *fkconstraint, Oid *pktypoid);
static bool relationHasPrimaryKey(char *relname);
105
static Oid	transformFkeyGetColType(CreateStmtContext *cxt, char *colname);
106
static void release_pstate_resources(ParseState *pstate);
107
static FromExpr *makeFromExpr(List *fromlist, Node *quals);
108

109

Bruce Momjian's avatar
Bruce Momjian committed
110

111 112
/*
 * parse_analyze -
113
 *	  analyze a raw parse tree and transform it to Query form.
114
 *
115 116 117 118
 * The result is a List of Query nodes (we need a list since some commands
 * produce multiple Queries).  Optimizable statements require considerable
 * transformation, while many utility-type statements are simply hung off
 * a dummy CMD_UTILITY Query node.
119
 */
120
List *
121
parse_analyze(Node *parseTree, ParseState *parentParseState)
122
{
Bruce Momjian's avatar
Bruce Momjian committed
123
	List	   *result = NIL;
124
	ParseState *pstate = make_parsestate(parentParseState);
125
	/* Lists to return extra commands from transformation */
126 127 128 129
	List	   *extras_before = NIL;
	List	   *extras_after = NIL;
	Query	   *query;
	List	   *listscan;
130

131
	query = transformStmt(pstate, parseTree, &extras_before, &extras_after);
132
	release_pstate_resources(pstate);
133

134 135
	while (extras_before != NIL)
	{
136
		result = nconc(result, parse_analyze(lfirst(extras_before), pstate));
137 138
		extras_before = lnext(extras_before);
	}
Bruce Momjian's avatar
Bruce Momjian committed
139

140
	result = lappend(result, query);
Bruce Momjian's avatar
Bruce Momjian committed
141

142 143
	while (extras_after != NIL)
	{
144
		result = nconc(result, parse_analyze(lfirst(extras_after), pstate));
145
		extras_after = lnext(extras_after);
146 147
	}

148 149 150 151 152 153 154 155 156 157 158 159
	/*
	 * Make sure that only the original query is marked original.
	 * We have to do this explicitly since recursive calls of parse_analyze
	 * will have set originalQuery in some of the added-on queries.
	 */
	foreach(listscan, result)
	{
		Query  *q = lfirst(listscan);

		q->originalQuery = (q == query);
	}

160 161
	pfree(pstate);

162
	return result;
163 164
}

165 166 167 168
static void
release_pstate_resources(ParseState *pstate)
{
	if (pstate->p_target_relation != NULL)
169
		heap_close(pstate->p_target_relation, NoLock);
170 171 172 173
	pstate->p_target_relation = NULL;
	pstate->p_target_rangetblentry = NULL;
}

174 175
/*
 * transformStmt -
176
 *	  transform a Parse tree into a Query tree.
177
 */
178
static Query *
179 180
transformStmt(ParseState *pstate, Node *parseTree,
			  List **extras_before,	List **extras_after)
181
{
182
	Query	   *result = NULL;
183 184 185

	switch (nodeTag(parseTree))
	{
186 187
			/*
			 * Non-optimizable statements
188
			 */
189
		case T_CreateStmt:
190 191
			result = transformCreateStmt(pstate, (CreateStmt *) parseTree,
									extras_before, extras_after);
192 193
			break;

194 195 196
		case T_IndexStmt:
			result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
			break;
197

198
		case T_RuleStmt:
199 200
			result = transformRuleStmt(pstate, (RuleStmt *) parseTree,
									extras_before, extras_after);
201
			break;
202

203 204 205
		case T_ViewStmt:
			{
				ViewStmt   *n = (ViewStmt *) parseTree;
206

207 208
				n->query = transformStmt(pstate, (Node *) n->query,
									extras_before, extras_after);
209

210 211 212 213
				/*
				 * If a list of column names was given, run through and
				 * insert these into the actual query tree. - thomas
				 * 2000-03-08
214
				 *
215 216
				 * Outer loop is over targetlist to make it easier to skip
				 * junk targetlist entries.
217 218 219
				 */
				if (n->aliases != NIL)
				{
220 221
					List	   *aliaslist = n->aliases;
					List	   *targetList;
222

223
					foreach(targetList, n->query->targetList)
224
					{
225
						TargetEntry *te = (TargetEntry *) lfirst(targetList);
226
						Resdom	   *rd;
227
						Ident	   *id;
228

229
						Assert(IsA(te, TargetEntry));
230
						rd = te->resdom;
231
						Assert(IsA(rd, Resdom));
232 233
						if (rd->resjunk)		/* junk columns don't get
												 * aliases */
234 235 236
							continue;
						id = (Ident *) lfirst(aliaslist);
						Assert(IsA(id, Ident));
237
						rd->resname = pstrdup(id->name);
238 239
						aliaslist = lnext(aliaslist);
						if (aliaslist == NIL)
240
							break;		/* done assigning aliases */
241
					}
242 243 244

					if (aliaslist != NIL)
						elog(ERROR, "CREATE VIEW specifies more column names than columns");
245
				}
246 247 248 249 250
				result = makeNode(Query);
				result->commandType = CMD_UTILITY;
				result->utilityStmt = (Node *) n;
			}
			break;
251

252 253 254
		case T_ExplainStmt:
			{
				ExplainStmt *n = (ExplainStmt *) parseTree;
255

256 257
				result = makeNode(Query);
				result->commandType = CMD_UTILITY;
258 259
				n->query = transformStmt(pstate, (Node *) n->query,
								extras_before, extras_after);
260 261 262
				result->utilityStmt = (Node *) parseTree;
			}
			break;
263

264
		case T_AlterTableStmt:
265 266
			result = transformAlterTableStmt(pstate, (AlterTableStmt *) parseTree,
										extras_before, extras_after);
267 268
			break;

269 270
			/*
			 * Optimizable statements
271
			 */
Bruce Momjian's avatar
Bruce Momjian committed
272
		case T_InsertStmt:
273 274
			result = transformInsertStmt(pstate, (InsertStmt *) parseTree,
										extras_before, extras_after);
275
			break;
276

277 278 279
		case T_DeleteStmt:
			result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
			break;
280

Bruce Momjian's avatar
Bruce Momjian committed
281 282
		case T_UpdateStmt:
			result = transformUpdateStmt(pstate, (UpdateStmt *) parseTree);
283
			break;
284

Bruce Momjian's avatar
Bruce Momjian committed
285
		case T_SelectStmt:
286 287 288 289 290
			if (((SelectStmt *) parseTree)->op == SETOP_NONE)
				result = transformSelectStmt(pstate,
											 (SelectStmt *) parseTree);
			else
				result = transformSetOperationStmt(pstate,
291
											   (SelectStmt *) parseTree);
292
			break;
293

294 295 296 297 298 299 300 301 302 303 304
			/*
			 * Convert use of %TYPE in statements where it is permitted.
			 */
		case T_ProcedureStmt:
		case T_CommentStmt:
		case T_RemoveFuncStmt:
		case T_DefineStmt:
			result = makeNode(Query);
			result->commandType = CMD_UTILITY;
			result->utilityStmt = transformTypeRefs(pstate, parseTree);
			break;
305

306
		default:
307

308
			/*
309
			 * other statements don't require any transformation-- just
Bruce Momjian's avatar
Bruce Momjian committed
310
			 * return the original parsetree, yea!
311 312 313 314 315
			 */
			result = makeNode(Query);
			result->commandType = CMD_UTILITY;
			result->utilityStmt = (Node *) parseTree;
			break;
316 317
	}
	return result;
318 319 320 321
}

/*
 * transformDeleteStmt -
322
 *	  transforms a Delete Statement
323
 */
324
static Query *
325
transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
326
{
327
	Query	   *qry = makeNode(Query);
328
	Node	   *qual;
329

330
	qry->commandType = CMD_DELETE;
331

332 333 334 335
	/* set up range table with just the result rel */
	qry->resultRelation = setTargetTable(pstate, stmt->relname,
										 interpretInhOption(stmt->inhOpt),
										 true);
336

337
	qry->distinctClause = NIL;
338

339
	/* fix where clause */
340
	qual = transformWhereClause(pstate, stmt->whereClause);
341

342
	/* done building the range table and jointree */
343
	qry->rtable = pstate->p_rtable;
344
	qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
345

346
	qry->hasSubLinks = pstate->p_hasSubLinks;
Bruce Momjian's avatar
Bruce Momjian committed
347
	qry->hasAggs = pstate->p_hasAggs;
348
	if (pstate->p_hasAggs)
349
		parseCheckAggregates(pstate, qry, qual);
350

351
	return qry;
352 353 354 355
}

/*
 * transformInsertStmt -
356
 *	  transform an Insert Statement
357
 */
358
static Query *
359 360
transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
					List **extras_before, List **extras_after)
361
{
362
	Query	   *qry = makeNode(Query);
363 364
	List	   *sub_rtable;
	List	   *sub_namespace;
365
	List	   *icolumns;
366 367
	List	   *attrnos;
	List	   *attnos;
368
	List	   *tl;
369

370 371
	qry->commandType = CMD_INSERT;
	pstate->p_is_insert = true;
372

373
	/*
374 375
	 * If a non-nil rangetable/namespace was passed in, and we are doing
	 * INSERT/SELECT, arrange to pass the rangetable/namespace down to the
376 377
	 * SELECT.	This can only happen if we are inside a CREATE RULE, and
	 * in that case we want the rule's OLD and NEW rtable entries to
378
	 * appear as part of the SELECT's rtable, not as outer references for
379 380
	 * it.	(Kluge!)  The SELECT's joinlist is not affected however. We
	 * must do this before adding the target table to the INSERT's rtable.
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
	 */
	if (stmt->selectStmt)
	{
		sub_rtable = pstate->p_rtable;
		pstate->p_rtable = NIL;
		sub_namespace = pstate->p_namespace;
		pstate->p_namespace = NIL;
	}
	else
	{
		sub_rtable = NIL;		/* not used, but keep compiler quiet */
		sub_namespace = NIL;
	}

	/*
	 * Must get write lock on INSERT target table before scanning SELECT,
397
	 * else we will grab the wrong kind of initial lock if the target
398
	 * table is also mentioned in the SELECT part.	Note that the target
399
	 * table is not added to the joinlist or namespace.
400
	 */
401 402
	qry->resultRelation = setTargetTable(pstate, stmt->relname,
										 false, false);
403

404
	/*
405
	 * Is it INSERT ... SELECT or INSERT ... VALUES?
Bruce Momjian's avatar
Bruce Momjian committed
406
	 */
407 408
	if (stmt->selectStmt)
	{
409
		ParseState *sub_pstate = make_parsestate(pstate->parentParseState);
410
		Query	   *selectQuery;
411 412
		RangeTblEntry *rte;
		RangeTblRef *rtr;
Bruce Momjian's avatar
Bruce Momjian committed
413

414 415 416
		/*
		 * Process the source SELECT.
		 *
417 418 419 420
		 * It is important that this be handled just like a standalone
		 * SELECT; 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...)
421
		 */
422 423 424
		sub_pstate->p_rtable = sub_rtable;
		sub_pstate->p_namespace = sub_namespace;

425 426 427 428 429 430
		/*
		 * Note: we are not expecting that extras_before and extras_after
		 * are going to be used by the transformation of the SELECT statement.
 		 */
		selectQuery = transformStmt(sub_pstate, stmt->selectStmt,
								extras_before, extras_after);
431

432 433
		release_pstate_resources(sub_pstate);
		pfree(sub_pstate);
434 435 436 437 438

		Assert(IsA(selectQuery, Query));
		Assert(selectQuery->commandType == CMD_SELECT);
		if (selectQuery->into || selectQuery->isPortal)
			elog(ERROR, "INSERT ... SELECT may not specify INTO");
439

440
		/*
441 442
		 * Make the source be a subquery in the INSERT's rangetable, and
		 * add it to the INSERT's joinlist.
443 444 445 446 447 448 449 450 451 452
		 */
		rte = addRangeTableEntryForSubquery(pstate,
											selectQuery,
											makeAttr("*SELECT*", NULL),
											true);
		rtr = makeNode(RangeTblRef);
		/* assume new rte is at end */
		rtr->rtindex = length(pstate->p_rtable);
		Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable));
		pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);
453

454
		/*
455 456 457 458
		 * Generate a targetlist for the INSERT that selects all the
		 * non-resjunk columns from the subquery.  (We need this to be
		 * separate from the subquery's tlist because we may add columns,
		 * insert datatype coercions, etc.)
459 460
		 *
		 * HACK: constants in the INSERT's targetlist are copied up as-is
461 462 463 464 465
		 * rather than being referenced as subquery outputs.  This is
		 * mainly to ensure that when we try to coerce them to the target
		 * column's datatype, the right things happen for UNKNOWN
		 * constants. Otherwise this fails: INSERT INTO foo SELECT 'bar',
		 * ... FROM baz
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
		 */
		qry->targetList = NIL;
		foreach(tl, selectQuery->targetList)
		{
			TargetEntry *tle = (TargetEntry *) lfirst(tl);
			Resdom	   *resnode = tle->resdom;
			Node	   *expr;

			if (resnode->resjunk)
				continue;
			if (tle->expr && IsA(tle->expr, Const))
				expr = tle->expr;
			else
				expr = (Node *) makeVar(rtr->rtindex,
										resnode->resno,
										resnode->restype,
										resnode->restypmod,
										0);
			resnode = copyObject(resnode);
			resnode->resno = (AttrNumber) pstate->p_last_resno++;
			qry->targetList = lappend(qry->targetList,
									  makeTargetEntry(resnode, expr));
		}
	}
	else
	{
		/*
493 494
		 * For INSERT ... VALUES, transform the given list of values to
		 * form a targetlist for the INSERT.
495 496 497
		 */
		qry->targetList = transformTargetList(pstate, stmt->targetList);
	}
498

499
	/*
500 501 502 503 504 505 506 507 508
	 * Now we are done with SELECT-like processing, and can get on with
	 * transforming the target list to match the INSERT 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;

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

511 512 513
	/*
	 * Prepare columns for assignment to target table.
	 */
514
	attnos = attrnos;
515 516 517 518 519
	foreach(tl, qry->targetList)
	{
		TargetEntry *tle = (TargetEntry *) lfirst(tl);
		Ident	   *id;

520
		Assert(!tle->resdom->resjunk);
521
		if (icolumns == NIL || attnos == NIL)
522 523
			elog(ERROR, "INSERT has more expressions than target columns");
		id = (Ident *) lfirst(icolumns);
524 525
		updateTargetListEntry(pstate, tle, id->name, lfirsti(attnos),
							  id->indirection);
526
		icolumns = lnext(icolumns);
527
		attnos = lnext(attnos);
528 529
	}

530
	/*
531 532
	 * XXX It is possible that the targetlist has fewer entries than were
	 * in the columns list.  We do not consider this an error.	Perhaps we
533
	 * should, if the columns list was explicitly given?
534
	 */
535

536 537 538
	/* done building the range table and jointree */
	qry->rtable = pstate->p_rtable;
	qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
539

540
	qry->hasSubLinks = pstate->p_hasSubLinks;
541 542 543
	qry->hasAggs = pstate->p_hasAggs;
	if (pstate->p_hasAggs)
		parseCheckAggregates(pstate, qry, NULL);
544

545
	return qry;
546 547
}

Bruce Momjian's avatar
Bruce Momjian committed
548
/*
549 550 551 552 553
 *	makeObjectName()
 *
 *	Create a name for an implicitly created index, sequence, constraint, etc.
 *
 *	The parameters are: the original table name, the original field name, and
554
 *	a "type" string (such as "seq" or "pkey").	The field name and/or type
555 556 557 558 559 560 561
 *	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
562
 *	both names if necessary to make a short-enough string.	The type part
563 564 565 566
 *	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
567
 *	from the truncated characters.	Currently it seems best to keep it simple,
568
 *	so that the generated names are easily predictable by a person.
569
 */
570
char *
571
makeObjectName(char *name1, char *name2, char *typename)
572
{
573
	char	   *name;
574 575 576 577 578 579 580 581
	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)
582
	{
583 584 585 586 587 588 589
		name2chars = strlen(name2);
		overhead++;				/* allow for separating underscore */
	}
	else
		name2chars = 0;
	if (typename)
		overhead += strlen(typename) + 1;
590

591
	availchars = NAMEDATALEN - 1 - overhead;
592

593 594 595
	/*
	 * If we must truncate,  preferentially truncate the longer name. This
	 * logic could be expressed without a loop, but it's simple and
596 597 598 599 600 601 602 603
	 * obvious as a loop.
	 */
	while (name1chars + name2chars > availchars)
	{
		if (name1chars > name2chars)
			name1chars--;
		else
			name2chars--;
604 605
	}

606 607 608 609 610 611 612
#ifdef MULTIBYTE
	if (name1)
		name1chars = pg_mbcliplen(name1, name1chars, name1chars);
	if (name2)
		name2chars = pg_mbcliplen(name2, name2chars, name2chars);
#endif

613 614 615 616 617 618 619
	/* Now construct the string using the chosen lengths */
	name = palloc(name1chars + name2chars + overhead + 1);
	strncpy(name, name1, name1chars);
	ndx = name1chars;
	if (name2)
	{
		name[ndx++] = '_';
620
		strncpy(name + ndx, name2, name2chars);
621 622 623 624 625
		ndx += name2chars;
	}
	if (typename)
	{
		name[ndx++] = '_';
626
		strcpy(name + ndx, typename);
627 628 629
	}
	else
		name[ndx] = '\0';
630

631
	return name;
Bruce Momjian's avatar
Bruce Momjian committed
632
}
633

Bruce Momjian's avatar
Bruce Momjian committed
634
static char *
635 636
CreateIndexName(char *table_name, char *column_name,
				char *label, List *indices)
637 638 639 640
{
	int			pass = 0;
	char	   *iname = NULL;
	List	   *ilist;
641 642
	char		typename[NAMEDATALEN];

643 644
	/*
	 * The type name for makeObjectName is label, or labelN if that's
645 646
	 * necessary to prevent collisions among multiple indexes for the same
	 * table.  Note there is no check for collisions with already-existing
647 648
	 * indexes, only among the indexes we're about to create now; this
	 * ought to be improved someday.
649 650
	 */
	strcpy(typename, label);
651

652
	for (;;)
653
	{
654
		iname = makeObjectName(table_name, column_name, typename);
655

656
		foreach(ilist, indices)
657
		{
658
			IndexStmt  *index = lfirst(ilist);
659

660 661
			if (index->idxname != NULL &&
				strcmp(iname, index->idxname) == 0)
662 663 664 665 666 667
				break;
		}
		/* ran through entire list? then no name conflict found so done */
		if (ilist == NIL)
			break;

668
		/* found a conflict, so try a new name component */
669
		pfree(iname);
670
		sprintf(typename, "%s%d", label, ++pass);
671 672
	}

673
	return iname;
Bruce Momjian's avatar
Bruce Momjian committed
674
}
675

676 677 678 679 680 681 682 683 684 685
/*
 * 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 *
686 687
transformCreateStmt(ParseState *pstate, CreateStmt *stmt,
					List **extras_before, List **extras_after)
688
{
689
	CreateStmtContext cxt;
690 691
	Query	   *q;
	List	   *elements;
692

693 694 695 696
	cxt.stmtType = "CREATE TABLE";
	cxt.relname = stmt->relname;
	cxt.inhRelnames = stmt->inhRelnames;
	cxt.istemp = stmt->istemp;
697
	cxt.hasoids = stmt->hasoids;
698 699 700 701 702 703 704 705
	cxt.relOid = InvalidOid;
	cxt.columns = NIL;
	cxt.ckconstraints = NIL;
	cxt.fkconstraints = NIL;
	cxt.ixconstraints = NIL;
	cxt.blist = NIL;
	cxt.alist = NIL;
	cxt.pkey = NULL;
706

707
	/*
708 709
	 * Run through each primary element in the table creation clause.
	 * Separate column defs from constraints, and do preliminary analysis.
710
	 */
711
	foreach(elements, stmt->tableElts)
712
	{
713 714
		Node	   *element = lfirst(elements);

715 716 717
		switch (nodeTag(element))
		{
			case T_ColumnDef:
718 719 720
				transformColumnDefinition(pstate, &cxt,
										  (ColumnDef *) element);
				break;
721

722 723 724 725
			case T_Constraint:
				transformTableConstraint(pstate, &cxt,
										 (Constraint *) element);
				break;
726

727 728 729 730
			case T_FkConstraint:
				/* No pre-transformation needed */
				cxt.fkconstraints = lappend(cxt.fkconstraints, element);
				break;
731

732 733 734 735
			default:
				elog(ERROR, "parser: unrecognized node (internal error)");
		}
	}
736

737
	Assert(stmt->constraints == NIL);
738

739 740 741 742
	/*
	 * Postprocess constraints that give rise to index definitions.
	 */
	transformIndexConstraints(pstate, &cxt);
743

744 745 746 747 748 749 750 751 752 753 754 755 756
	/*
	 * Postprocess foreign-key constraints.
	 */
	transformFKConstraints(pstate, &cxt);

	/*
	 * Output results.
	 */
	q = makeNode(Query);
	q->commandType = CMD_UTILITY;
	q->utilityStmt = (Node *) stmt;
	stmt->tableElts = cxt.columns;
	stmt->constraints = cxt.ckconstraints;
757 758
	*extras_before = nconc (*extras_before, cxt.blist);
	*extras_after = nconc (cxt.alist, *extras_after);
759

760 761
	return q;
}
762

763 764 765 766 767 768 769 770 771
static void
transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
						  ColumnDef *column)
{
	bool		is_serial;
	bool		saw_nullable;
	Constraint *constraint;
	List	   *clist;
	Ident	   *key;
772

773
	cxt->columns = lappend(cxt->columns, column);
774

775 776 777 778 779 780 781 782 783 784 785 786 787 788
	/* Check for SERIAL pseudo-types */
	is_serial = false;
	if (strcmp(column->typename->name, "serial") == 0 ||
		strcmp(column->typename->name, "serial4") == 0)
	{
		is_serial = true;
		column->typename->name = pstrdup("int4");
	}
	else if (strcmp(column->typename->name, "bigserial") == 0 ||
			 strcmp(column->typename->name, "serial8") == 0)
	{
		is_serial = true;
		column->typename->name = pstrdup("int8");
	}
789

790 791
	/* Do necessary work on the column type declaration */
	transformColumnType(pstate, column);
Jan Wieck's avatar
Jan Wieck committed
792

793 794 795 796 797 798 799 800
	/* Special actions for SERIAL pseudo-types */
	if (is_serial)
	{
		char	   *sname;
		char	   *qstring;
		A_Const    *snamenode;
		FuncCall   *funccallnode;
		CreateSeqStmt *sequence;
801

802
		/*
803 804 805 806
		 * Create appropriate constraints for SERIAL.  We do this in full,
		 * rather than shortcutting, so that we will detect any
		 * conflicting constraints the user wrote (like a different
		 * DEFAULT).
807 808
		 */
		sname = makeObjectName(cxt->relname, column->colname, "seq");
Jan Wieck's avatar
Jan Wieck committed
809

810
		/*
811 812
		 * Create an expression tree representing the function call
		 * nextval('"sequencename"')
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
		 */
		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 = makeList1(snamenode);
		funccallnode->agg_star = false;
		funccallnode->agg_distinct = false;

		constraint = makeNode(Constraint);
		constraint->contype = CONSTR_DEFAULT;
		constraint->name = sname;
		constraint->raw_expr = (Node *) funccallnode;
		constraint->cooked_expr = NULL;
		constraint->keys = NIL;
		column->constraints = lappend(column->constraints, constraint);

		constraint = makeNode(Constraint);
		constraint->contype = CONSTR_UNIQUE;
835
		constraint->name = NULL;	/* assign later */
836 837 838 839 840
		column->constraints = lappend(column->constraints, constraint);

		constraint = makeNode(Constraint);
		constraint->contype = CONSTR_NOTNULL;
		column->constraints = lappend(column->constraints, constraint);
841

842
		/*
843 844 845
		 * Build a CREATE SEQUENCE command to create the sequence object,
		 * and add it to the list of things to be done before this
		 * CREATE/ALTER TABLE.
846 847 848 849 850
		 */
		sequence = makeNode(CreateSeqStmt);
		sequence->seqname = pstrdup(sname);
		sequence->istemp = cxt->istemp;
		sequence->options = NIL;
Jan Wieck's avatar
Jan Wieck committed
851

852
		elog(NOTICE, "%s will create implicit sequence '%s' for SERIAL column '%s.%s'",
853
		cxt->stmtType, sequence->seqname, cxt->relname, column->colname);
854

855 856
		cxt->blist = lappend(cxt->blist, sequence);
	}
857

858 859
	/* Process column constraints, if any... */
	transformConstraintAttrs(column->constraints);
860

861
	saw_nullable = false;
862

863 864 865
	foreach(clist, column->constraints)
	{
		constraint = lfirst(clist);
866

867
		/*
868 869 870
		 * 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.
871 872 873 874 875
		 */
		if (IsA(constraint, FkConstraint))
		{
			FkConstraint *fkconstraint = (FkConstraint *) constraint;
			Ident	   *id = makeNode(Ident);
876

877 878 879
			id->name = column->colname;
			id->indirection = NIL;
			id->isRel = false;
880

881
			fkconstraint->fk_attrs = makeList1(id);
882

883 884 885
			cxt->fkconstraints = lappend(cxt->fkconstraints, fkconstraint);
			continue;
		}
886

887
		Assert(IsA(constraint, Constraint));
888

889 890 891 892 893 894 895 896 897
		switch (constraint->contype)
		{
			case CONSTR_NULL:
				if (saw_nullable && column->is_not_null)
					elog(ERROR, "%s/(NOT) NULL conflicting declaration for '%s.%s'",
						 cxt->stmtType, cxt->relname, column->colname);
				column->is_not_null = FALSE;
				saw_nullable = true;
				break;
898

899 900 901 902 903 904 905
			case CONSTR_NOTNULL:
				if (saw_nullable && !column->is_not_null)
					elog(ERROR, "%s/(NOT) NULL conflicting declaration for '%s.%s'",
						 cxt->stmtType, cxt->relname, column->colname);
				column->is_not_null = TRUE;
				saw_nullable = true;
				break;
906

907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924
			case CONSTR_DEFAULT:
				if (column->raw_default != NULL)
					elog(ERROR, "%s/DEFAULT multiple values specified for '%s.%s'",
						 cxt->stmtType, cxt->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(cxt->relname,
													  NULL,
													  "pkey");
				if (constraint->keys == NIL)
				{
					key = makeNode(Ident);
					key->name = pstrdup(column->colname);
					constraint->keys = makeList1(key);
925
				}
926
				cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
927 928
				break;

929 930 931 932 933 934 935 936 937 938 939 940 941
			case CONSTR_UNIQUE:
				if (constraint->name == NULL)
					constraint->name = makeObjectName(cxt->relname,
													  column->colname,
													  "key");
				if (constraint->keys == NIL)
				{
					key = makeNode(Ident);
					key->name = pstrdup(column->colname);
					constraint->keys = makeList1(key);
				}
				cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
				break;
942

943 944 945 946 947 948 949 950 951 952 953 954 955
			case CONSTR_CHECK:
				if (constraint->name == NULL)
					constraint->name = makeObjectName(cxt->relname,
													  column->colname,
													  NULL);
				cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
				break;

			case CONSTR_ATTR_DEFERRABLE:
			case CONSTR_ATTR_NOT_DEFERRABLE:
			case CONSTR_ATTR_DEFERRED:
			case CONSTR_ATTR_IMMEDIATE:
				/* transformConstraintAttrs took care of these */
Jan Wieck's avatar
Jan Wieck committed
956 957
				break;

958
			default:
959 960
				elog(ERROR, "parser: unrecognized constraint (internal error)");
				break;
961 962
		}
	}
963
}
964

965 966 967 968 969 970 971 972 973 974 975 976 977
static void
transformTableConstraint(ParseState *pstate, CreateStmtContext *cxt,
						 Constraint *constraint)
{
	switch (constraint->contype)
	{
		case CONSTR_PRIMARY:
			if (constraint->name == NULL)
				constraint->name = makeObjectName(cxt->relname,
												  NULL,
												  "pkey");
			cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
			break;
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
		case CONSTR_UNIQUE:
			cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
			break;

		case CONSTR_CHECK:
			cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
			break;

		case CONSTR_NULL:
		case CONSTR_NOTNULL:
		case CONSTR_DEFAULT:
		case CONSTR_ATTR_DEFERRABLE:
		case CONSTR_ATTR_NOT_DEFERRABLE:
		case CONSTR_ATTR_DEFERRED:
		case CONSTR_ATTR_IMMEDIATE:
			elog(ERROR, "parser: illegal context for constraint (internal error)");
			break;

		default:
			elog(ERROR, "parser: unrecognized constraint (internal error)");
			break;
	}
}

static void
transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
{
	List	   *listptr;
	List	   *keys;
	IndexStmt  *index;
	IndexElem  *iparam;
	ColumnDef  *column;
	List	   *columns;
	List	   *indexlist = NIL;

	/*
1015 1016 1017
	 * Run through the constraints that need to generate an index. For
	 * PRIMARY KEY, mark each column as NOT NULL and create an index. For
	 * UNIQUE, create an index as for PRIMARY KEY, but do not insist on
1018 1019 1020
	 * NOT NULL.
	 */
	foreach(listptr, cxt->ixconstraints)
1021
	{
1022 1023
		Constraint *constraint = lfirst(listptr);

1024
		Assert(IsA(constraint, Constraint));
1025
		Assert((constraint->contype == CONSTR_PRIMARY)
Bruce Momjian's avatar
Bruce Momjian committed
1026
			   || (constraint->contype == CONSTR_UNIQUE));
1027

1028 1029
		index = makeNode(IndexStmt);

1030 1031
		index->unique = true;
		index->primary = (constraint->contype == CONSTR_PRIMARY);
1032
		if (index->primary)
1033
		{
1034 1035 1036 1037
			/* In ALTER TABLE case, a primary index might already exist */
			if (cxt->pkey != NULL ||
				(OidIsValid(cxt->relOid) &&
				 relationHasPrimaryKey(cxt->relname)))
1038
				elog(ERROR, "%s / PRIMARY KEY multiple primary keys"
1039 1040 1041
					 " for table '%s' are not allowed",
					 cxt->stmtType, cxt->relname);
			cxt->pkey = index;
1042
		}
1043

1044
		if (constraint->name != NULL)
1045
			index->idxname = pstrdup(constraint->name);
1046
		else if (constraint->contype == CONSTR_PRIMARY)
1047
			index->idxname = makeObjectName(cxt->relname, NULL, "pkey");
1048
		else
1049
			index->idxname = NULL;		/* will set it later */
1050

1051
		index->relname = cxt->relname;
1052 1053 1054
		index->accessMethod = "btree";
		index->indexParams = NIL;
		index->whereClause = NULL;
1055

1056
		/*
1057 1058
		 * Make sure referenced keys exist.  If we are making a PRIMARY
		 * KEY index, also make sure they are NOT NULL.
1059
		 */
1060
		foreach(keys, constraint->keys)
1061
		{
1062
			Ident	   *key = (Ident *) lfirst(keys);
1063
			bool		found = false;
1064

1065
			Assert(IsA(key, Ident));
1066
			column = NULL;
1067
			foreach(columns, cxt->columns)
1068 1069
			{
				column = lfirst(columns);
1070 1071
				Assert(IsA(column, ColumnDef));
				if (strcmp(column->colname, key->name) == 0)
1072 1073
				{
					found = true;
1074
					break;
1075
				}
1076
			}
1077 1078 1079 1080 1081 1082
			if (found)
			{
				/* found column in the new table; force it to be NOT NULL */
				if (constraint->contype == CONSTR_PRIMARY)
					column->is_not_null = TRUE;
			}
1083 1084 1085
			else if (SystemAttributeByName(key->name, cxt->hasoids) != NULL)
			{
				/*
1086 1087 1088
				 * column will be a system column in the new table, so
				 * accept it.  System columns can't ever be null, so no
				 * need to worry about PRIMARY/NOT NULL constraint.
1089 1090 1091
				 */
				found = true;
			}
1092
			else if (cxt->inhRelnames)
1093 1094
			{
				/* try inherited tables */
1095
				List	   *inher;
1096

1097
				foreach(inher, cxt->inhRelnames)
1098
				{
1099 1100 1101
					Value	   *inh = lfirst(inher);
					Relation	rel;
					int			count;
1102 1103

					Assert(IsA(inh, String));
1104
					rel = heap_openr(strVal(inh), AccessShareLock);
1105 1106
					if (rel->rd_rel->relkind != RELKIND_RELATION)
						elog(ERROR, "inherited table \"%s\" is not a relation",
1107
							 strVal(inh));
1108 1109 1110
					for (count = 0; count < rel->rd_att->natts; count++)
					{
						Form_pg_attribute inhattr = rel->rd_att->attrs[count];
1111
						char	   *inhname = NameStr(inhattr->attname);
1112 1113 1114 1115

						if (strcmp(key->name, inhname) == 0)
						{
							found = true;
1116

1117
							/*
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129
							 * If the column is inherited, we currently
							 * have no easy way to force it to be NOT
							 * NULL. Only way I can see to fix this would
							 * be to convert the inherited-column info to
							 * ColumnDef nodes before we reach this point,
							 * and then create the table from those nodes
							 * rather than referencing the parent tables
							 * later.  That would likely be cleaner, but
							 * too much work to contemplate right now.
							 * Instead, raise an error if the inherited
							 * column won't be NOT NULL. (Would a NOTICE
							 * be more reasonable?)
1130
							 */
1131
							if (constraint->contype == CONSTR_PRIMARY &&
1132
								!inhattr->attnotnull)
1133 1134
								elog(ERROR, "inherited attribute \"%s\" cannot be a PRIMARY KEY because it is not marked NOT NULL",
									 inhname);
1135 1136 1137 1138 1139 1140 1141 1142
							break;
						}
					}
					heap_close(rel, NoLock);
					if (found)
						break;
				}
			}
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154
			else if (OidIsValid(cxt->relOid))
			{
				/* ALTER TABLE case: does column already exist? */
				HeapTuple	atttuple;

				atttuple = SearchSysCache(ATTNAME,
										  ObjectIdGetDatum(cxt->relOid),
										  PointerGetDatum(key->name),
										  0, 0);
				if (HeapTupleIsValid(atttuple))
				{
					found = true;
1155

1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
					/*
					 * We require pre-existing column to be already marked
					 * NOT NULL.
					 */
					if (constraint->contype == CONSTR_PRIMARY &&
						!((Form_pg_attribute) GETSTRUCT(atttuple))->attnotnull)
						elog(ERROR, "Existing attribute \"%s\" cannot be a PRIMARY KEY because it is not marked NOT NULL",
							 key->name);
					ReleaseSysCache(atttuple);
				}
			}
1167 1168

			if (!found)
1169 1170
				elog(ERROR, "%s: column \"%s\" named in key does not exist",
					 cxt->stmtType, key->name);
1171

1172 1173 1174 1175 1176
			/* Check for PRIMARY KEY(foo, foo) */
			foreach(columns, index->indexParams)
			{
				iparam = (IndexElem *) lfirst(columns);
				if (strcmp(key->name, iparam->name) == 0)
1177 1178
					elog(ERROR, "%s: column \"%s\" appears twice in %s constraint",
						 cxt->stmtType, key->name,
1179 1180 1181 1182
						 index->primary ? "PRIMARY KEY" : "UNIQUE");
			}

			/* OK, add it to the index definition */
1183
			iparam = makeNode(IndexElem);
1184
			iparam->name = pstrdup(key->name);
1185 1186 1187 1188 1189
			iparam->args = NIL;
			iparam->class = NULL;
			index->indexParams = lappend(index->indexParams, iparam);
		}

1190
		indexlist = lappend(indexlist, index);
1191 1192
	}

1193 1194
	/*
	 * Scan the index list and remove any redundant index specifications.
1195 1196 1197 1198
	 * This can happen if, for instance, the user writes SERIAL PRIMARY
	 * KEY or SERIAL UNIQUE.  A strict reading of SQL92 would suggest
	 * raising an error instead, but that strikes me as too
	 * anal-retentive. - tgl 2001-02-14
1199 1200 1201
	 *
	 * XXX in ALTER TABLE case, it'd be nice to look for duplicate
	 * pre-existing indexes, too.
1202
	 */
1203 1204
	cxt->alist = NIL;
	if (cxt->pkey != NULL)
1205
	{
1206
		/* Make sure we keep the PKEY index in preference to others... */
1207
		cxt->alist = makeList1(cxt->pkey);
1208
	}
1209
	while (indexlist != NIL)
1210
	{
1211
		index = lfirst(indexlist);
1212

1213 1214
		/* if it's pkey, it's already in cxt->alist */
		if (index != cxt->pkey)
1215 1216 1217
		{
			bool		keep = true;
			List	   *priorlist;
1218

1219
			foreach(priorlist, cxt->alist)
1220
			{
1221
				IndexStmt  *priorindex = lfirst(priorlist);
Bruce Momjian's avatar
Bruce Momjian committed
1222

1223 1224 1225 1226
				if (equal(index->indexParams, priorindex->indexParams))
				{
					/*
					 * If the prior index is as yet unnamed, and this one
1227 1228 1229 1230
					 * is named, then transfer the name to the prior
					 * index. This ensures that if we have named and
					 * unnamed constraints, we'll use (at least one of)
					 * the names for the index.
1231 1232 1233 1234 1235
					 */
					if (priorindex->idxname == NULL)
						priorindex->idxname = index->idxname;
					keep = false;
					break;
1236
				}
1237 1238 1239
			}

			if (keep)
1240
				cxt->alist = lappend(cxt->alist, index);
1241
		}
1242

1243
		indexlist = lnext(indexlist);
1244 1245
	}

1246 1247 1248
	/*
	 * Finally, select unique names for all not-previously-named indices,
	 * and display notice messages.
1249
	 *
1250 1251
	 * XXX in ALTER TABLE case, we fail to consider name collisions against
	 * pre-existing indexes.
1252
	 */
1253
	foreach(indexlist, cxt->alist)
1254
	{
1255
		index = lfirst(indexlist);
1256 1257 1258 1259

		if (index->idxname == NULL && index->indexParams != NIL)
		{
			iparam = lfirst(index->indexParams);
1260 1261
			index->idxname = CreateIndexName(cxt->relname, iparam->name,
											 "key", cxt->alist);
1262 1263
		}
		if (index->idxname == NULL)		/* should not happen */
1264 1265
			elog(ERROR, "%s: failed to make implicit index name",
				 cxt->stmtType);
1266

1267 1268
		elog(NOTICE, "%s / %s%s will create implicit index '%s' for table '%s'",
			 cxt->stmtType,
1269
			 (strcmp(cxt->stmtType, "ALTER TABLE") == 0) ? "ADD " : "",
1270
			 (index->primary ? "PRIMARY KEY" : "UNIQUE"),
1271
			 index->idxname, cxt->relname);
1272
	}
1273
}
1274

1275 1276 1277 1278 1279 1280 1281 1282 1283
static void
transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
{
	CreateTrigStmt *fk_trigger;
	List	   *fkactions = NIL;
	List	   *fkclist;
	List	   *fk_attr;
	List	   *pk_attr;
	Ident	   *id;
1284 1285 1286
	Oid			pktypoid[INDEX_MAX_KEYS];
	Oid			fktypoid[INDEX_MAX_KEYS];
	int			i;
1287 1288 1289

	if (cxt->fkconstraints == NIL)
		return;
1290

1291 1292 1293 1294
	elog(NOTICE, "%s will create implicit trigger(s) for FOREIGN KEY check(s)",
		 cxt->stmtType);

	foreach(fkclist, cxt->fkconstraints)
Jan Wieck's avatar
Jan Wieck committed
1295
	{
1296
		FkConstraint *fkconstraint = (FkConstraint *) lfirst(fkclist);
1297
		int			attnum;
1298
		List	   *fkattrs;
Jan Wieck's avatar
Jan Wieck committed
1299

1300 1301 1302 1303 1304
		/*
		 * If the constraint has no name, set it to <unnamed>
		 */
		if (fkconstraint->constr_name == NULL)
			fkconstraint->constr_name = "<unnamed>";
Jan Wieck's avatar
Jan Wieck committed
1305

1306
		for (attnum = 0; attnum < INDEX_MAX_KEYS; attnum++)
1307 1308 1309
			pktypoid[attnum] = fktypoid[attnum] = InvalidOid;

		/*
1310 1311
		 * Look up the referencing attributes to make sure they exist (or
		 * will exist) in this table, and remember their type OIDs.
1312 1313 1314
		 */
		attnum = 0;
		foreach(fkattrs, fkconstraint->fk_attrs)
Jan Wieck's avatar
Jan Wieck committed
1315
		{
1316
			Ident	   *fkattr = lfirst(fkattrs);
Jan Wieck's avatar
Jan Wieck committed
1317

1318 1319 1320 1321 1322 1323
			if (attnum >= INDEX_MAX_KEYS)
				elog(ERROR, "Can only have %d keys in a foreign key",
					 INDEX_MAX_KEYS);
			fktypoid[attnum++] = transformFkeyGetColType(cxt,
														 fkattr->name);
		}
Jan Wieck's avatar
Jan Wieck committed
1324

1325 1326 1327 1328 1329 1330 1331 1332 1333
		/*
		 * If the attribute list for the referenced table was omitted,
		 * lookup the definition of the primary key.
		 */
		if (fkconstraint->pk_attrs == NIL)
		{
			if (strcmp(fkconstraint->pktable_name, cxt->relname) != 0)
				transformFkeyGetPrimaryKey(fkconstraint, pktypoid);
			else if (cxt->pkey != NULL)
1334
			{
1335 1336
				/* Use the to-be-created primary key */
				List	   *attr;
1337

1338
				attnum = 0;
1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352
				foreach(attr, cxt->pkey->indexParams)
				{
					IndexElem  *ielem = lfirst(attr);
					Ident	   *pkattr = (Ident *) makeNode(Ident);

					pkattr->name = pstrdup(ielem->name);
					pkattr->indirection = NIL;
					pkattr->isRel = false;
					fkconstraint->pk_attrs = lappend(fkconstraint->pk_attrs,
													 pkattr);
					if (attnum >= INDEX_MAX_KEYS)
						elog(ERROR, "Can only have %d keys in a foreign key",
							 INDEX_MAX_KEYS);
					pktypoid[attnum++] = transformFkeyGetColType(cxt,
1353
															ielem->name);
1354
				}
1355
			}
1356
			else
1357
			{
1358 1359
				/* In ALTER TABLE case, primary key may already exist */
				if (OidIsValid(cxt->relOid))
1360
					transformFkeyGetPrimaryKey(fkconstraint, pktypoid);
1361
				else
1362
					elog(ERROR, "PRIMARY KEY for referenced table \"%s\" not found",
1363
						 fkconstraint->pktable_name);
1364
			}
1365 1366 1367 1368 1369 1370
		}
		else
		{
			/* Validate the specified referenced key list */
			if (strcmp(fkconstraint->pktable_name, cxt->relname) != 0)
				transformFkeyCheckAttrs(fkconstraint, pktypoid);
1371 1372
			else
			{
1373 1374 1375 1376 1377
				/* Look for a matching new unique/primary constraint */
				List	   *index;
				bool		found = false;

				foreach(index, cxt->alist)
1378
				{
1379 1380
					IndexStmt  *ind = lfirst(index);
					List	   *pkattrs;
1381

1382 1383 1384 1385 1386
					if (!ind->unique)
						continue;
					if (length(ind->indexParams) !=
						length(fkconstraint->pk_attrs))
						continue;
1387
					attnum = 0;
1388
					foreach(pkattrs, fkconstraint->pk_attrs)
1389
					{
1390
						Ident	   *pkattr = lfirst(pkattrs);
1391 1392
						List	   *indparms;

1393 1394
						found = false;
						foreach(indparms, ind->indexParams)
1395
						{
1396 1397 1398
							IndexElem  *indparm = lfirst(indparms);

							if (strcmp(indparm->name, pkattr->name) == 0)
1399
							{
1400 1401
								found = true;
								break;
1402 1403
							}
						}
1404
						if (!found)
1405
							break;
1406 1407 1408 1409
						if (attnum >= INDEX_MAX_KEYS)
							elog(ERROR, "Can only have %d keys in a foreign key",
								 INDEX_MAX_KEYS);
						pktypoid[attnum++] = transformFkeyGetColType(cxt,
1410
														   pkattr->name);
1411
					}
1412 1413 1414 1415 1416
					if (found)
						break;
				}
				if (!found)
				{
1417 1418 1419 1420
					/*
					 * In ALTER TABLE case, such an index may already
					 * exist
					 */
1421 1422 1423
					if (OidIsValid(cxt->relOid))
						transformFkeyCheckAttrs(fkconstraint, pktypoid);
					else
1424 1425 1426 1427
						elog(ERROR, "UNIQUE constraint matching given keys for referenced table \"%s\" not found",
							 fkconstraint->pktable_name);
				}
			}
1428
		}
1429

1430 1431 1432
		/* Be sure referencing and referenced column types are comparable */
		for (i = 0; i < INDEX_MAX_KEYS && fktypoid[i] != 0; i++)
		{
Jan Wieck's avatar
Jan Wieck committed
1433
			/*
1434 1435 1436 1437
			 * fktypoid[i] is the foreign key table's i'th element's type
			 * oid pktypoid[i] is the primary key table's i'th element's
			 * type oid We let oper() do our work for us, including
			 * elog(ERROR) if the types don't compare with =
Jan Wieck's avatar
Jan Wieck committed
1438
			 */
1439 1440
			Operator	o = oper("=", fktypoid[i], pktypoid[i], false);

1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472
			ReleaseSysCache(o);
		}

		/*
		 * Build a CREATE CONSTRAINT TRIGGER statement for the CHECK
		 * action.
		 */
		fk_trigger = (CreateTrigStmt *) makeNode(CreateTrigStmt);
		fk_trigger->trigname = fkconstraint->constr_name;
		fk_trigger->relname = cxt->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,
								   makeString(fkconstraint->constr_name));
		fk_trigger->args = lappend(fk_trigger->args,
								   makeString(cxt->relname));
		fk_trigger->args = lappend(fk_trigger->args,
1473
								 makeString(fkconstraint->pktable_name));
1474
		fk_trigger->args = lappend(fk_trigger->args,
1475
								   makeString(fkconstraint->match_type));
1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487
		fk_attr = fkconstraint->fk_attrs;
		pk_attr = fkconstraint->pk_attrs;
		if (length(fk_attr) != length(pk_attr))
			elog(ERROR, "number of key attributes in referenced table must be equal to foreign key"
				 "\n\tIllegal FOREIGN KEY definition references \"%s\"",
				 fkconstraint->pktable_name);

		while (fk_attr != NIL)
		{
			id = (Ident *) lfirst(fk_attr);
			fk_trigger->args = lappend(fk_trigger->args,
									   makeString(id->name));
Jan Wieck's avatar
Jan Wieck committed
1488

1489 1490 1491
			id = (Ident *) lfirst(pk_attr);
			fk_trigger->args = lappend(fk_trigger->args,
									   makeString(id->name));
Jan Wieck's avatar
Jan Wieck committed
1492

1493 1494 1495
			fk_attr = lnext(fk_attr);
			pk_attr = lnext(pk_attr);
		}
Jan Wieck's avatar
Jan Wieck committed
1496

1497
		fkactions = lappend(fkactions, (Node *) fk_trigger);
Jan Wieck's avatar
Jan Wieck committed
1498

1499
		/*
1500 1501
		 * Build a CREATE CONSTRAINT TRIGGER statement for the ON DELETE
		 * action fired on the PK table !!!
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 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542
		 */
		fk_trigger = (CreateTrigStmt *) makeNode(CreateTrigStmt);
		fk_trigger->trigname = fkconstraint->constr_name;
		fk_trigger->relname = fkconstraint->pktable_name;
		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 = cxt->relname;
		switch ((fkconstraint->actions & FKCONSTR_ON_DELETE_MASK)
				>> FKCONSTR_ON_DELETE_SHIFT)
		{
			case FKCONSTR_ON_KEY_NOACTION:
				fk_trigger->funcname = "RI_FKey_noaction_del";
				break;
			case FKCONSTR_ON_KEY_RESTRICT:
				fk_trigger->deferrable = false;
				fk_trigger->initdeferred = false;
				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;
		}
Jan Wieck's avatar
Jan Wieck committed
1543

1544 1545 1546 1547 1548 1549
		fk_trigger->args = NIL;
		fk_trigger->args = lappend(fk_trigger->args,
								   makeString(fkconstraint->constr_name));
		fk_trigger->args = lappend(fk_trigger->args,
								   makeString(cxt->relname));
		fk_trigger->args = lappend(fk_trigger->args,
1550
								 makeString(fkconstraint->pktable_name));
1551
		fk_trigger->args = lappend(fk_trigger->args,
1552
								   makeString(fkconstraint->match_type));
1553 1554 1555 1556 1557 1558 1559
		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,
									   makeString(id->name));
Jan Wieck's avatar
Jan Wieck committed
1560

1561 1562 1563
			id = (Ident *) lfirst(pk_attr);
			fk_trigger->args = lappend(fk_trigger->args,
									   makeString(id->name));
Jan Wieck's avatar
Jan Wieck committed
1564

1565 1566 1567
			fk_attr = lnext(fk_attr);
			pk_attr = lnext(pk_attr);
		}
Jan Wieck's avatar
Jan Wieck committed
1568

1569
		fkactions = lappend(fkactions, (Node *) fk_trigger);
1570

1571
		/*
1572 1573
		 * Build a CREATE CONSTRAINT TRIGGER statement for the ON UPDATE
		 * action fired on the PK table !!!
1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614
		 */
		fk_trigger = (CreateTrigStmt *) makeNode(CreateTrigStmt);
		fk_trigger->trigname = fkconstraint->constr_name;
		fk_trigger->relname = fkconstraint->pktable_name;
		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 = cxt->relname;
		switch ((fkconstraint->actions & FKCONSTR_ON_UPDATE_MASK)
				>> FKCONSTR_ON_UPDATE_SHIFT)
		{
			case FKCONSTR_ON_KEY_NOACTION:
				fk_trigger->funcname = "RI_FKey_noaction_upd";
				break;
			case FKCONSTR_ON_KEY_RESTRICT:
				fk_trigger->deferrable = false;
				fk_trigger->initdeferred = false;
				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;
		}
Jan Wieck's avatar
Jan Wieck committed
1615

1616 1617 1618 1619 1620 1621
		fk_trigger->args = NIL;
		fk_trigger->args = lappend(fk_trigger->args,
								   makeString(fkconstraint->constr_name));
		fk_trigger->args = lappend(fk_trigger->args,
								   makeString(cxt->relname));
		fk_trigger->args = lappend(fk_trigger->args,
1622
								 makeString(fkconstraint->pktable_name));
1623
		fk_trigger->args = lappend(fk_trigger->args,
1624
								   makeString(fkconstraint->match_type));
1625 1626 1627 1628 1629 1630 1631
		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,
									   makeString(id->name));
Jan Wieck's avatar
Jan Wieck committed
1632

1633 1634 1635
			id = (Ident *) lfirst(pk_attr);
			fk_trigger->args = lappend(fk_trigger->args,
									   makeString(id->name));
1636

1637 1638
			fk_attr = lnext(fk_attr);
			pk_attr = lnext(pk_attr);
Jan Wieck's avatar
Jan Wieck committed
1639 1640
		}

1641 1642
		fkactions = lappend(fkactions, (Node *) fk_trigger);
	}
1643

1644
	/*
1645 1646 1647
	 * Attach completed list of extra actions to cxt->alist.  We cannot do
	 * this earlier, because we assume above that cxt->alist still holds
	 * only IndexStmts.
1648 1649 1650
	 */
	cxt->alist = nconc(cxt->alist, fkactions);
}
Jan Wieck's avatar
Jan Wieck committed
1651

1652 1653
/*
 * transformIndexStmt -
1654
 *	  transforms the qualification of the index statement
1655
 */
1656
static Query *
1657
transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
1658
{
Bruce Momjian's avatar
Bruce Momjian committed
1659
	Query	   *qry;
1660
	RangeTblEntry *rte;
1661

Bruce Momjian's avatar
Bruce Momjian committed
1662 1663
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
1664

1665
	/* take care of the where clause */
1666 1667 1668
	if (stmt->whereClause)
	{
		/*
1669 1670 1671 1672 1673
		 * Put the parent table into the rtable so that the WHERE clause
		 * can refer to its fields without qualification.  Note that this
		 * only works if the parent table already exists --- so we can't
		 * easily support predicates on indexes created implicitly by
		 * CREATE TABLE. Fortunately, that's not necessary.
1674 1675
		 */
		rte = addRangeTableEntry(pstate, stmt->relname, NULL, false, true);
1676

1677 1678
		/* no to join list, yes to namespace */
		addRTEtoQuery(pstate, rte, false, true);
1679

1680 1681
		stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
	}
1682

Bruce Momjian's avatar
Bruce Momjian committed
1683
	qry->hasSubLinks = pstate->p_hasSubLinks;
1684
	stmt->rangetable = pstate->p_rtable;
1685

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

Bruce Momjian's avatar
Bruce Momjian committed
1688
	return qry;
1689 1690 1691 1692
}

/*
 * transformRuleStmt -
1693 1694
 *	  transform a Create Rule Statement. The actions is a list of parse
 *	  trees which is transformed into a list of query trees.
1695
 */
1696
static Query *
1697 1698
transformRuleStmt(ParseState *pstate, RuleStmt *stmt,
				List **extras_before, List **extras_after)
1699
{
Bruce Momjian's avatar
Bruce Momjian committed
1700
	Query	   *qry;
1701 1702
	RangeTblEntry *oldrte;
	RangeTblEntry *newrte;
1703

Bruce Momjian's avatar
Bruce Momjian committed
1704 1705
	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
1706 1707
	qry->utilityStmt = (Node *) stmt;

1708 1709
	/*
	 * To avoid deadlock, make sure the first thing we do is grab
1710 1711 1712
	 * AccessExclusiveLock on the target relation.	This will be needed by
	 * DefineQueryRewrite(), and we don't want to grab a lesser lock
	 * beforehand.	We don't need to hold a refcount on the relcache
1713 1714 1715 1716 1717
	 * entry, however.
	 */
	heap_close(heap_openr(stmt->object->relname, AccessExclusiveLock),
			   NoLock);

1718
	/*
1719 1720 1721
	 * NOTE: 'OLD' must always have a varno equal to 1 and 'NEW' equal to
	 * 2.  Set up their RTEs in the main pstate for use in parsing the
	 * rule qualification.
1722 1723 1724 1725 1726 1727 1728 1729
	 */
	Assert(pstate->p_rtable == NIL);
	oldrte = addRangeTableEntry(pstate, stmt->object->relname,
								makeAttr("*OLD*", NULL),
								false, true);
	newrte = addRangeTableEntry(pstate, stmt->object->relname,
								makeAttr("*NEW*", NULL),
								false, true);
1730 1731 1732
	/* Must override addRangeTableEntry's default access-check flags */
	oldrte->checkForRead = false;
	newrte->checkForRead = false;
1733

1734
	/*
1735
	 * They must be in the namespace too for lookup purposes, but only add
1736 1737
	 * the one(s) that are relevant for the current kind of rule.  In an
	 * UPDATE rule, quals must refer to OLD.field or NEW.field to be
1738 1739 1740 1741
	 * unambiguous, but there's no need to be so picky for INSERT &
	 * DELETE. (Note we marked the RTEs "inFromCl = true" above to allow
	 * unqualified references to their fields.)  We do not add them to the
	 * joinlist.
1742 1743 1744 1745
	 */
	switch (stmt->event)
	{
		case CMD_SELECT:
1746
			addRTEtoQuery(pstate, oldrte, false, true);
1747 1748
			break;
		case CMD_UPDATE:
1749 1750
			addRTEtoQuery(pstate, oldrte, false, true);
			addRTEtoQuery(pstate, newrte, false, true);
1751 1752
			break;
		case CMD_INSERT:
1753
			addRTEtoQuery(pstate, newrte, false, true);
1754 1755
			break;
		case CMD_DELETE:
1756
			addRTEtoQuery(pstate, oldrte, false, true);
1757 1758 1759 1760 1761 1762 1763 1764 1765 1766
			break;
		default:
			elog(ERROR, "transformRuleStmt: unexpected event type %d",
				 (int) stmt->event);
			break;
	}

	/* take care of the where clause */
	stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);

1767
	if (length(pstate->p_rtable) != 2)	/* naughty, naughty... */
1768 1769 1770 1771
		elog(ERROR, "Rule WHERE condition may not contain references to other relations");

	/* save info about sublinks in where clause */
	qry->hasSubLinks = pstate->p_hasSubLinks;
1772

1773
	/*
1774
	 * 'instead nothing' rules with a qualification need a query
1775 1776
	 * rangetable so the rewrite handler can add the negated rule
	 * qualification to the original query. We create a query with the new
1777
	 * command type CMD_NOTHING here that is treated specially by the
1778
	 * rewrite system.
1779
	 */
1780 1781 1782 1783
	if (stmt->actions == NIL)
	{
		Query	   *nothing_qry = makeNode(Query);

1784 1785
		nothing_qry->commandType = CMD_NOTHING;
		nothing_qry->rtable = pstate->p_rtable;
1786
		nothing_qry->jointree = makeFromExpr(NIL, NULL);		/* no join wanted */
1787

1788
		stmt->actions = makeList1(nothing_qry);
1789
	}
1790
	else
1791
	{
1792 1793
		List	   *oldactions;
		List	   *newactions = NIL;
1794

1795
		/*
1796
		 * transform each statement, like parse_analyze()
1797
		 */
1798
		foreach(oldactions, stmt->actions)
1799
		{
1800
			Node	   *action = (Node *) lfirst(oldactions);
1801
			ParseState *sub_pstate = make_parsestate(pstate->parentParseState);
1802 1803
			Query	   *sub_qry,
					   *top_subqry;
1804 1805
			bool		has_old,
						has_new;
1806

1807
			/*
1808 1809 1810 1811 1812 1813
			 * Set up OLD/NEW in the rtable for this statement.  The
			 * entries are marked not inFromCl because we don't want them
			 * to be referred to by unqualified field names nor "*" in the
			 * rule actions.  We must add them to the namespace, however,
			 * or they won't be accessible at all.  We decide later
			 * whether to put them in the joinlist.
1814 1815 1816 1817 1818 1819 1820
			 */
			oldrte = addRangeTableEntry(sub_pstate, stmt->object->relname,
										makeAttr("*OLD*", NULL),
										false, false);
			newrte = addRangeTableEntry(sub_pstate, stmt->object->relname,
										makeAttr("*NEW*", NULL),
										false, false);
1821 1822
			oldrte->checkForRead = false;
			newrte->checkForRead = false;
1823 1824
			addRTEtoQuery(sub_pstate, oldrte, false, true);
			addRTEtoQuery(sub_pstate, newrte, false, true);
1825

1826
			/* Transform the rule action statement */
1827 1828
			top_subqry = transformStmt(sub_pstate, action,
								extras_before, extras_after);
1829 1830 1831

			/*
			 * We cannot support utility-statement actions (eg NOTIFY)
1832 1833
			 * with nonempty rule WHERE conditions, because there's no way
			 * to make the utility action execute conditionally.
1834 1835 1836 1837
			 */
			if (top_subqry->commandType == CMD_UTILITY &&
				stmt->whereClause != NULL)
				elog(ERROR, "Rules with WHERE conditions may only have SELECT, INSERT, UPDATE, or DELETE actions");
1838 1839 1840 1841

			/*
			 * If the action is INSERT...SELECT, OLD/NEW have been pushed
			 * down into the SELECT, and that's what we need to look at.
1842 1843
			 * (Ugly kluge ... try to fix this when we redesign
			 * querytrees.)
1844 1845
			 */
			sub_qry = getInsertSelectQuery(top_subqry, NULL);
1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882

			/*
			 * Validate action's use of OLD/NEW, qual too
			 */
			has_old =
				rangeTableEntry_used((Node *) sub_qry, PRS2_OLD_VARNO, 0) ||
				rangeTableEntry_used(stmt->whereClause, PRS2_OLD_VARNO, 0);
			has_new =
				rangeTableEntry_used((Node *) sub_qry, PRS2_NEW_VARNO, 0) ||
				rangeTableEntry_used(stmt->whereClause, PRS2_NEW_VARNO, 0);

			switch (stmt->event)
			{
				case CMD_SELECT:
					if (has_old)
						elog(ERROR, "ON SELECT rule may not use OLD");
					if (has_new)
						elog(ERROR, "ON SELECT rule may not use NEW");
					break;
				case CMD_UPDATE:
					/* both are OK */
					break;
				case CMD_INSERT:
					if (has_old)
						elog(ERROR, "ON INSERT rule may not use OLD");
					break;
				case CMD_DELETE:
					if (has_new)
						elog(ERROR, "ON DELETE rule may not use NEW");
					break;
				default:
					elog(ERROR, "transformRuleStmt: unexpected event type %d",
						 (int) stmt->event);
					break;
			}

			/*
1883 1884 1885
			 * For efficiency's sake, add OLD to the rule action's
			 * jointree only if it was actually referenced in the
			 * statement or qual.
1886 1887 1888 1889 1890 1891
			 *
			 * For INSERT, NEW is not really a relation (only a reference to
			 * the to-be-inserted tuple) and should never be added to the
			 * jointree.
			 *
			 * For UPDATE, we treat NEW as being another kind of reference to
1892 1893 1894 1895 1896 1897
			 * OLD, because it represents references to *transformed*
			 * tuples of the existing relation.  It would be wrong to
			 * enter NEW separately in the jointree, since that would
			 * cause a double join of the updated relation.  It's also
			 * wrong to fail to make a jointree entry if only NEW and not
			 * OLD is mentioned.
1898
			 */
1899
			if (has_old || (has_new && stmt->event == CMD_UPDATE))
1900
			{
1901
				/* hack so we can use addRTEtoQuery() */
1902 1903
				sub_pstate->p_rtable = sub_qry->rtable;
				sub_pstate->p_joinlist = sub_qry->jointree->fromlist;
1904
				addRTEtoQuery(sub_pstate, oldrte, true, false);
1905
				sub_qry->jointree->fromlist = sub_pstate->p_joinlist;
1906 1907
			}

1908
			newactions = lappend(newactions, top_subqry);
1909 1910 1911 1912

			release_pstate_resources(sub_pstate);
			pfree(sub_pstate);
		}
1913 1914

		stmt->actions = newactions;
1915
	}
1916

Bruce Momjian's avatar
Bruce Momjian committed
1917
	return qry;
1918 1919 1920 1921 1922
}


/*
 * transformSelectStmt -
1923
 *	  transforms a Select Statement
1924
 *
1925
 * Note: this is also used for DECLARE CURSOR statements.
1926
 */
1927
static Query *
Bruce Momjian's avatar
Bruce Momjian committed
1928
transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
1929
{
1930
	Query	   *qry = makeNode(Query);
1931
	Node	   *qual;
1932 1933

	qry->commandType = CMD_SELECT;
1934

1935 1936 1937 1938 1939 1940 1941 1942
	if (stmt->portalname)
	{
		/* DECLARE CURSOR */
		if (stmt->into)
			elog(ERROR, "DECLARE CURSOR must not specify INTO");
		if (stmt->forUpdate)
			elog(ERROR, "DECLARE/UPDATE is not supported"
				 "\n\tCursors must be READ ONLY");
1943

1944
		/*
1945
		 * 15 august 1991 -- since 3.0 postgres does locking right, we
1946 1947 1948
		 * discovered that portals were violating locking protocol. portal
		 * locks cannot span xacts. as a short-term fix, we installed the
		 * check here. -- mao
1949 1950 1951 1952 1953 1954 1955
		 */
		if (!IsTransactionBlock())
			elog(ERROR, "DECLARE CURSOR may only be used in begin/end transaction blocks");

		qry->into = stmt->portalname;
		qry->isTemp = stmt->istemp;
		qry->isPortal = TRUE;
1956
		qry->isBinary = stmt->binary;	/* internal portal */
1957 1958 1959 1960 1961 1962 1963 1964 1965 1966
	}
	else
	{
		/* SELECT */
		qry->into = stmt->into;
		qry->isTemp = stmt->istemp;
		qry->isPortal = FALSE;
		qry->isBinary = FALSE;
	}

1967 1968 1969
	/* make FOR UPDATE clause available to addRangeTableEntry */
	pstate->p_forUpdate = stmt->forUpdate;

1970 1971
	/* process the FROM clause */
	transformFromClause(pstate, stmt->fromClause);
1972

1973
	/* transform targetlist */
1974
	qry->targetList = transformTargetList(pstate, stmt->targetList);
1975

1976 1977 1978 1979
	if (stmt->intoColNames)
		applyColumnNames(qry->targetList, stmt->intoColNames);

	/* transform WHERE */
1980
	qual = transformWhereClause(pstate, stmt->whereClause);
1981

1982 1983
	/*
	 * Initial processing of HAVING clause is just like WHERE clause.
1984
	 * Additional work will be done in optimizer/plan/planner.c.
1985
	 */
1986
	qry->havingQual = transformWhereClause(pstate, stmt->havingClause);
1987

1988 1989 1990
	qry->groupClause = transformGroupClause(pstate,
											stmt->groupClause,
											qry->targetList);
1991

1992 1993
	qry->sortClause = transformSortClause(pstate,
										  stmt->sortClause,
1994 1995 1996 1997 1998
										  qry->targetList);

	qry->distinctClause = transformDistinctClause(pstate,
												  stmt->distinctClause,
												  qry->targetList,
1999
												  &qry->sortClause);
2000

2001 2002 2003
	qry->limitOffset = stmt->limitOffset;
	qry->limitCount = stmt->limitCount;

2004
	qry->hasSubLinks = pstate->p_hasSubLinks;
Bruce Momjian's avatar
Bruce Momjian committed
2005
	qry->hasAggs = pstate->p_hasAggs;
2006
	if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
2007
		parseCheckAggregates(pstate, qry, qual);
2008

2009 2010 2011
	qry->rtable = pstate->p_rtable;
	qry->jointree = makeFromExpr(pstate->p_joinlist, qual);

2012
	if (stmt->forUpdate != NIL)
2013 2014 2015 2016 2017 2018 2019
		transformForUpdate(qry, stmt->forUpdate);

	return qry;
}

/*
 * transformSetOperationsStmt -
2020
 *	  transforms a set-operations tree
2021
 *
2022
 * A set-operation tree is just a SELECT, but with UNION/INTERSECT/EXCEPT
2023 2024
 * structure to it.  We must transform each leaf SELECT and build up a top-
 * level Query that contains the leaf SELECTs as subqueries in its rangetable.
2025 2026
 * The tree of set operations is converted into the setOperations field of
 * the top-level Query.
2027
 */
2028 2029
static Query *
transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
2030 2031 2032
{
	Query	   *qry = makeNode(Query);
	SelectStmt *leftmostSelect;
2033
	int			leftmostRTI;
2034
	Query	   *leftmostQuery;
2035
	SetOperationStmt *sostmt;
2036
	char	   *into;
2037
	bool		istemp;
2038
	List	   *intoColNames;
2039 2040 2041 2042 2043 2044
	char	   *portalname;
	bool		binary;
	List	   *sortClause;
	Node	   *limitOffset;
	Node	   *limitCount;
	List	   *forUpdate;
2045
	Node	   *node;
2046
	List	   *lefttl,
2047 2048 2049 2050 2051
			   *dtlist,
			   *targetvars,
			   *targetnames,
			   *sv_namespace;
	JoinExpr   *jnode;
2052 2053 2054 2055
	int			tllen;

	qry->commandType = CMD_SELECT;

2056
	/*
2057 2058
	 * Find leftmost leaf SelectStmt; extract the one-time-only items from
	 * it and from the top-level node.
2059
	 */
2060 2061 2062 2063 2064
	leftmostSelect = stmt->larg;
	while (leftmostSelect && leftmostSelect->op != SETOP_NONE)
		leftmostSelect = leftmostSelect->larg;
	Assert(leftmostSelect && IsA(leftmostSelect, SelectStmt) &&
		   leftmostSelect->larg == NULL);
2065 2066
	into = leftmostSelect->into;
	istemp = leftmostSelect->istemp;
2067
	intoColNames = leftmostSelect->intoColNames;
2068 2069
	portalname = stmt->portalname;
	binary = stmt->binary;
2070 2071 2072 2073

	/* clear them to prevent complaints in transformSetOperationTree() */
	leftmostSelect->into = NULL;
	leftmostSelect->istemp = false;
2074
	leftmostSelect->intoColNames = NIL;
2075 2076
	stmt->portalname = NULL;
	stmt->binary = false;
2077

2078 2079
	/*
	 * These are not one-time, exactly, but we want to process them here
2080 2081
	 * and not let transformSetOperationTree() see them --- else it'll
	 * just recurse right back here!
2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093
	 */
	sortClause = stmt->sortClause;
	limitOffset = stmt->limitOffset;
	limitCount = stmt->limitCount;
	forUpdate = stmt->forUpdate;

	stmt->sortClause = NIL;
	stmt->limitOffset = NULL;
	stmt->limitCount = NULL;
	stmt->forUpdate = NIL;

	/* We don't support forUpdate with set ops at the moment. */
2094 2095
	if (forUpdate)
		elog(ERROR, "SELECT FOR UPDATE is not allowed with UNION/INTERSECT/EXCEPT");
Bruce Momjian's avatar
Hi!  
Bruce Momjian committed
2096

Bruce Momjian's avatar
Bruce Momjian committed
2097
	/*
2098
	 * Recursively transform the components of the tree.
Bruce Momjian's avatar
Bruce Momjian committed
2099
	 */
2100 2101 2102
	sostmt = (SetOperationStmt *) transformSetOperationTree(pstate, stmt);
	Assert(sostmt && IsA(sostmt, SetOperationStmt));
	qry->setOperations = (Node *) sostmt;
2103 2104 2105 2106

	/*
	 * Re-find leftmost SELECT (now it's a sub-query in rangetable)
	 */
2107
	node = sostmt->larg;
2108 2109 2110
	while (node && IsA(node, SetOperationStmt))
		node = ((SetOperationStmt *) node)->larg;
	Assert(node && IsA(node, RangeTblRef));
2111 2112
	leftmostRTI = ((RangeTblRef *) node)->rtindex;
	leftmostQuery = rt_fetch(leftmostRTI, pstate->p_rtable)->subquery;
2113
	Assert(leftmostQuery != NULL);
2114

2115 2116
	/*
	 * Generate dummy targetlist for outer query using column names of
2117 2118 2119
	 * leftmost select and common datatypes of topmost set operation. Also
	 * make lists of the dummy vars and their names for use in parsing
	 * ORDER BY.
2120 2121
	 */
	qry->targetList = NIL;
2122 2123
	targetvars = NIL;
	targetnames = NIL;
2124
	lefttl = leftmostQuery->targetList;
2125
	foreach(dtlist, sostmt->colTypes)
2126
	{
2127 2128 2129 2130 2131
		Oid			colType = (Oid) lfirsti(dtlist);
		Resdom	   *leftResdom = ((TargetEntry *) lfirst(lefttl))->resdom;
		char	   *colName = pstrdup(leftResdom->resname);
		Resdom	   *resdom;
		Node	   *expr;
2132 2133 2134 2135

		resdom = makeResdom((AttrNumber) pstate->p_last_resno++,
							colType,
							-1,
2136
							colName,
2137
							false);
2138 2139
		expr = (Node *) makeVar(leftmostRTI,
								leftResdom->resno,
2140 2141 2142 2143 2144
								colType,
								-1,
								0);
		qry->targetList = lappend(qry->targetList,
								  makeTargetEntry(resdom, expr));
2145 2146
		targetvars = lappend(targetvars, expr);
		targetnames = lappend(targetnames, makeString(colName));
2147 2148
		lefttl = lnext(lefttl);
	}
2149

2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162
	/*
	 * Insert one-time items into top-level query
	 *
	 * This needs to agree with transformSelectStmt!
	 */
	if (portalname)
	{
		/* DECLARE CURSOR */
		if (into)
			elog(ERROR, "DECLARE CURSOR must not specify INTO");
		if (forUpdate)
			elog(ERROR, "DECLARE/UPDATE is not supported"
				 "\n\tCursors must be READ ONLY");
2163

2164
		/*
2165
		 * 15 august 1991 -- since 3.0 postgres does locking right, we
2166 2167 2168
		 * discovered that portals were violating locking protocol. portal
		 * locks cannot span xacts. as a short-term fix, we installed the
		 * check here. -- mao
2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186
		 */
		if (!IsTransactionBlock())
			elog(ERROR, "DECLARE CURSOR may only be used in begin/end transaction blocks");

		qry->into = portalname;
		qry->isTemp = istemp;
		qry->isPortal = TRUE;
		qry->isBinary = binary; /* internal portal */
	}
	else
	{
		/* SELECT */
		qry->into = into;
		qry->isTemp = istemp;
		qry->isPortal = FALSE;
		qry->isBinary = FALSE;
	}

2187 2188 2189
	if (intoColNames)
		applyColumnNames(qry->targetList, intoColNames);

2190
	/*
2191 2192 2193 2194 2195
	 * As a first step towards supporting sort clauses that are
	 * expressions using the output columns, generate a namespace entry
	 * that makes the output columns visible.  A JoinExpr node is handy
	 * for this, since we can easily control the Vars generated upon
	 * matches.
2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207
	 *
	 * Note: we don't yet do anything useful with such cases, but at least
	 * "ORDER BY upper(foo)" will draw the right error message rather than
	 * "foo not found".
	 */
	jnode = makeNode(JoinExpr);
	jnode->colnames = targetnames;
	jnode->colvars = targetvars;

	sv_namespace = pstate->p_namespace;
	pstate->p_namespace = makeList1(jnode);

2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219
	/*
	 * For now, we don't support resjunk sort clauses on the output of a
	 * setOperation tree --- you can only use the SQL92-spec options of
	 * selecting an output column by name or number.  Enforce by checking
	 * that transformSortClause doesn't add any items to tlist.
	 */
	tllen = length(qry->targetList);

	qry->sortClause = transformSortClause(pstate,
										  sortClause,
										  qry->targetList);

2220 2221
	pstate->p_namespace = sv_namespace;

2222 2223 2224 2225 2226 2227 2228 2229 2230 2231
	if (tllen != length(qry->targetList))
		elog(ERROR, "ORDER BY on a UNION/INTERSECT/EXCEPT result must be on one of the result columns");

	qry->limitOffset = limitOffset;
	qry->limitCount = limitCount;

	qry->hasSubLinks = pstate->p_hasSubLinks;
	qry->hasAggs = pstate->p_hasAggs;
	if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
		parseCheckAggregates(pstate, qry, NULL);
2232

2233
	qry->rtable = pstate->p_rtable;
2234
	qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
2235

2236
	if (forUpdate != NIL)
2237
		transformForUpdate(qry, forUpdate);
2238

2239 2240 2241 2242 2243 2244 2245 2246
	return qry;
}

/*
 * transformSetOperationTree
 *		Recursively transform leaves and internal nodes of a set-op tree
 */
static Node *
2247
transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
2248
{
2249
	bool		isLeaf;
2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275

	Assert(stmt && IsA(stmt, SelectStmt));

	/*
	 * Validity-check both leaf and internal SELECTs for disallowed ops.
	 */
	if (stmt->into)
		elog(ERROR, "INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT");
	if (stmt->portalname)		/* should not happen */
		elog(ERROR, "Portal may not appear in UNION/INTERSECT/EXCEPT");
	/* We don't support forUpdate with set ops at the moment. */
	if (stmt->forUpdate)
		elog(ERROR, "SELECT FOR UPDATE is not allowed with UNION/INTERSECT/EXCEPT");

	/*
	 * If an internal node of a set-op tree has ORDER BY, UPDATE, or LIMIT
	 * clauses attached, we need to treat it like a leaf node to generate
	 * an independent sub-Query tree.  Otherwise, it can be represented by
	 * a SetOperationStmt node underneath the parent Query.
	 */
	if (stmt->op == SETOP_NONE)
	{
		Assert(stmt->larg == NULL && stmt->rarg == NULL);
		isLeaf = true;
	}
	else
2276
	{
2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287
		Assert(stmt->larg != NULL && stmt->rarg != NULL);
		if (stmt->sortClause || stmt->limitOffset || stmt->limitCount ||
			stmt->forUpdate)
			isLeaf = true;
		else
			isLeaf = false;
	}

	if (isLeaf)
	{
		/* Process leaf SELECT */
2288 2289 2290
		List	   *selectList;
		Query	   *selectQuery;
		char		selectName[32];
2291 2292 2293 2294
		RangeTblEntry *rte;
		RangeTblRef *rtr;

		/*
2295 2296 2297
		 * Transform SelectStmt into a Query.
		 *
		 * Note: previously transformed sub-queries don't affect the parsing
2298 2299
		 * of this sub-query, because they are not in the toplevel
		 * pstate's namespace list.
2300
		 */
2301
		selectList = parse_analyze((Node *) stmt, pstate);
2302 2303 2304

		Assert(length(selectList) == 1);
		selectQuery = (Query *) lfirst(selectList);
2305

2306 2307 2308 2309 2310 2311 2312 2313 2314
		/*
		 * Make the leaf query be a subquery in the top-level rangetable.
		 */
		sprintf(selectName, "*SELECT* %d", length(pstate->p_rtable) + 1);
		rte = addRangeTableEntryForSubquery(pstate,
											selectQuery,
											makeAttr(pstrdup(selectName),
													 NULL),
											false);
2315

2316
		/*
2317 2318
		 * Return a RangeTblRef to replace the SelectStmt in the set-op
		 * tree.
2319 2320 2321 2322 2323 2324 2325
		 */
		rtr = makeNode(RangeTblRef);
		/* assume new rte is at end */
		rtr->rtindex = length(pstate->p_rtable);
		Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable));
		return (Node *) rtr;
	}
2326
	else
2327
	{
2328 2329
		/* Process an internal node (set operation node) */
		SetOperationStmt *op = makeNode(SetOperationStmt);
2330 2331
		List	   *lcoltypes;
		List	   *rcoltypes;
2332 2333
		const char *context;

2334 2335
		context = (stmt->op == SETOP_UNION ? "UNION" :
				   (stmt->op == SETOP_INTERSECT ? "INTERSECT" :
2336
					"EXCEPT"));
2337 2338 2339 2340

		op->op = stmt->op;
		op->all = stmt->all;

2341 2342 2343
		/*
		 * Recursively transform the child nodes.
		 */
2344 2345
		op->larg = transformSetOperationTree(pstate, stmt->larg);
		op->rarg = transformSetOperationTree(pstate, stmt->rarg);
2346

2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358
		/*
		 * Verify that the two children have the same number of non-junk
		 * columns, and determine the types of the merged output columns.
		 */
		lcoltypes = getSetColTypes(pstate, op->larg);
		rcoltypes = getSetColTypes(pstate, op->rarg);
		if (length(lcoltypes) != length(rcoltypes))
			elog(ERROR, "Each %s query must have the same number of columns",
				 context);
		op->colTypes = NIL;
		while (lcoltypes != NIL)
		{
2359 2360 2361
			Oid			lcoltype = (Oid) lfirsti(lcoltypes);
			Oid			rcoltype = (Oid) lfirsti(rcoltypes);
			Oid			rescoltype;
2362 2363 2364 2365 2366 2367 2368

			rescoltype = select_common_type(makeListi2(lcoltype, rcoltype),
											context);
			op->colTypes = lappendi(op->colTypes, rescoltype);
			lcoltypes = lnext(lcoltypes);
			rcoltypes = lnext(rcoltypes);
		}
2369

2370 2371
		return (Node *) op;
	}
2372 2373
}

2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384
/*
 * getSetColTypes
 *		Get output column types of an (already transformed) set-op node
 */
static List *
getSetColTypes(ParseState *pstate, Node *node)
{
	if (IsA(node, RangeTblRef))
	{
		RangeTblRef *rtr = (RangeTblRef *) node;
		RangeTblEntry *rte = rt_fetch(rtr->rtindex, pstate->p_rtable);
2385 2386 2387
		Query	   *selectQuery = rte->subquery;
		List	   *result = NIL;
		List	   *tl;
2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417

		Assert(selectQuery != NULL);
		/* Get types of non-junk columns */
		foreach(tl, selectQuery->targetList)
		{
			TargetEntry *tle = (TargetEntry *) lfirst(tl);
			Resdom	   *resnode = tle->resdom;

			if (resnode->resjunk)
				continue;
			result = lappendi(result, resnode->restype);
		}
		return result;
	}
	else if (IsA(node, SetOperationStmt))
	{
		SetOperationStmt *op = (SetOperationStmt *) node;

		/* Result already computed during transformation of node */
		Assert(op->colTypes != NIL);
		return op->colTypes;
	}
	else
	{
		elog(ERROR, "getSetColTypes: unexpected node %d",
			 (int) nodeTag(node));
		return NIL;				/* keep compiler quiet */
	}
}

2418 2419 2420 2421 2422
/* Attach column names from a ColumnDef list to a TargetEntry list */
static void
applyColumnNames(List *dst, List *src)
{
	if (length(src) > length(dst))
2423
		elog(ERROR, "CREATE TABLE AS specifies too many column names");
2424 2425 2426 2427

	while (src != NIL && dst != NIL)
	{
		TargetEntry *d = (TargetEntry *) lfirst(dst);
2428
		ColumnDef  *s = (ColumnDef *) lfirst(src);
2429 2430 2431 2432 2433 2434 2435 2436 2437 2438

		Assert(d->resdom && !d->resdom->resjunk);

		d->resdom->resname = pstrdup(s->colname);

		dst = lnext(dst);
		src = lnext(src);
	}
}

2439

2440 2441
/*
 * transformUpdateStmt -
2442
 *	  transforms an update statement
2443
 */
2444
static Query *
Bruce Momjian's avatar
Bruce Momjian committed
2445
transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
2446
{
2447
	Query	   *qry = makeNode(Query);
2448
	Node	   *qual;
2449 2450
	List	   *origTargetList;
	List	   *tl;
2451 2452 2453

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

2455 2456 2457 2458
	qry->resultRelation = setTargetTable(pstate, stmt->relname,
										 interpretInhOption(stmt->inhOpt),
										 true);

2459 2460 2461 2462
	/*
	 * 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.
	 */
2463
	transformFromClause(pstate, stmt->fromClause);
2464

2465
	qry->targetList = transformTargetList(pstate, stmt->targetList);
2466

2467
	qual = transformWhereClause(pstate, stmt->whereClause);
2468

2469
	qry->rtable = pstate->p_rtable;
2470
	qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
2471

2472
	qry->hasSubLinks = pstate->p_hasSubLinks;
Bruce Momjian's avatar
Bruce Momjian committed
2473
	qry->hasAggs = pstate->p_hasAggs;
2474
	if (pstate->p_hasAggs)
2475
		parseCheckAggregates(pstate, qry, qual);
2476

2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495
	/*
	 * 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)
		{
2496 2497 2498 2499
			/*
			 * 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.
2500 2501 2502 2503 2504 2505 2506 2507
			 */
			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);
2508 2509 2510 2511
		updateTargetListEntry(pstate, tle, origTarget->name,
							  attnameAttNum(pstate->p_target_relation,
											origTarget->name),
							  origTarget->indirection);
2512 2513 2514 2515 2516
		origTargetList = lnext(origTargetList);
	}
	if (origTargetList != NIL)
		elog(ERROR, "UPDATE target count mismatch --- internal error");

2517
	return qry;
2518
}
Bruce Momjian's avatar
Hi!  
Bruce Momjian committed
2519

2520 2521
/*
 * tranformAlterTableStmt -
2522
 *	transform an Alter Table Statement
2523 2524
 */
static Query *
2525 2526
transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
						List **extras_before, List **extras_after)
2527
{
2528
	CreateStmtContext cxt;
2529 2530 2531
	Query	   *qry;

	/*
2532
	 * The only subtypes that currently require parse transformation
2533
	 * handling are 'A'dd column and Add 'C'onstraint.	These largely
2534
	 * re-use code from CREATE TABLE.
2535
	 */
2536 2537
	switch (stmt->subtype)
	{
2538
		case 'A':
2539 2540 2541 2542 2543 2544 2545
			cxt.stmtType = "ALTER TABLE";
			cxt.relname = stmt->relname;
			cxt.inhRelnames = NIL;
			cxt.istemp = is_temp_rel_name(stmt->relname);
			cxt.relOid = GetSysCacheOid(RELNAME,
										PointerGetDatum(stmt->relname),
										0, 0, 0);
2546
			cxt.hasoids = SearchSysCacheExists(ATTNUM,
2547 2548
											ObjectIdGetDatum(cxt.relOid),
								  Int16GetDatum(ObjectIdAttributeNumber),
2549
											   0, 0);
2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565
			cxt.columns = NIL;
			cxt.ckconstraints = NIL;
			cxt.fkconstraints = NIL;
			cxt.ixconstraints = NIL;
			cxt.blist = NIL;
			cxt.alist = NIL;
			cxt.pkey = NULL;

			Assert(IsA(stmt->def, ColumnDef));
			transformColumnDefinition(pstate, &cxt,
									  (ColumnDef *) stmt->def);

			transformIndexConstraints(pstate, &cxt);
			transformFKConstraints(pstate, &cxt);

			((ColumnDef *) stmt->def)->constraints = cxt.ckconstraints;
2566 2567
			*extras_before = nconc(*extras_before, cxt.blist);
			*extras_after = nconc(cxt.alist, *extras_after);
2568
			break;
2569

2570 2571 2572 2573 2574 2575 2576 2577
		case 'C':
			cxt.stmtType = "ALTER TABLE";
			cxt.relname = stmt->relname;
			cxt.inhRelnames = NIL;
			cxt.istemp = is_temp_rel_name(stmt->relname);
			cxt.relOid = GetSysCacheOid(RELNAME,
										PointerGetDatum(stmt->relname),
										0, 0, 0);
2578
			cxt.hasoids = SearchSysCacheExists(ATTNUM,
2579 2580
											ObjectIdGetDatum(cxt.relOid),
								  Int16GetDatum(ObjectIdAttributeNumber),
2581
											   0, 0);
2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596
			cxt.columns = NIL;
			cxt.ckconstraints = NIL;
			cxt.fkconstraints = NIL;
			cxt.ixconstraints = NIL;
			cxt.blist = NIL;
			cxt.alist = NIL;
			cxt.pkey = NULL;

			if (IsA(stmt->def, Constraint))
				transformTableConstraint(pstate, &cxt,
										 (Constraint *) stmt->def);
			else if (IsA(stmt->def, FkConstraint))
				cxt.fkconstraints = lappend(cxt.fkconstraints, stmt->def);
			else
				elog(ERROR, "Unexpected node type in ALTER TABLE ADD CONSTRAINT");
2597

2598 2599
			transformIndexConstraints(pstate, &cxt);
			transformFKConstraints(pstate, &cxt);
2600

2601 2602
			Assert(cxt.columns == NIL);
			stmt->def = (Node *) nconc(cxt.ckconstraints, cxt.fkconstraints);
2603 2604
			*extras_before = nconc(*extras_before, cxt.blist);
			*extras_after = nconc(cxt.alist, *extras_after);
2605
			break;
2606

2607 2608 2609
		default:
			break;
	}
2610 2611 2612

	qry = makeNode(Query);
	qry->commandType = CMD_UTILITY;
2613
	qry->utilityStmt = (Node *) stmt;
2614

2615 2616 2617
	return qry;
}

2618
/*
2619 2620 2621 2622 2623 2624 2625 2626
 * Transform uses of %TYPE in a statement.
 */
static Node *
transformTypeRefs(ParseState *pstate, Node *stmt)
{
	switch (nodeTag(stmt))
	{
		case T_ProcedureStmt:
2627 2628
			{
				ProcedureStmt *ps = (ProcedureStmt *) stmt;
2629

2630 2631 2632 2633 2634
				transformTypeRefsList(pstate, ps->argTypes);
				transformTypeRef(pstate, (TypeName *) ps->returnType);
				transformTypeRefsList(pstate, ps->withClause);
			}
			break;
2635 2636

		case T_CommentStmt:
2637 2638
			{
				CommentStmt *cs = (CommentStmt *) stmt;
2639

2640 2641 2642
				transformTypeRefsList(pstate, cs->objlist);
			}
			break;
2643 2644

		case T_RemoveFuncStmt:
2645 2646
			{
				RemoveFuncStmt *rs = (RemoveFuncStmt *) stmt;
2647

2648 2649 2650
				transformTypeRefsList(pstate, rs->args);
			}
			break;
2651 2652 2653

		case T_DefineStmt:
			{
2654 2655
				DefineStmt *ds = (DefineStmt *) stmt;
				List	   *ele;
2656

2657
				foreach(ele, ds->definition)
2658
				{
2659 2660 2661 2662 2663
					DefElem    *de = (DefElem *) lfirst(ele);

					if (de->arg != NULL
						&& IsA(de->arg, TypeName))
						transformTypeRef(pstate, (TypeName *) de->arg);
2664 2665
				}
			}
2666
			break;
2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686

		default:
			elog(ERROR, "Unsupported type %d in transformTypeRefs",
				 nodeTag(stmt));
			break;
	}

	return stmt;
}

/*
 * Transform uses of %TYPE in a list.
 */
static void
transformTypeRefsList(ParseState *pstate, List *l)
{
	List	   *ele;

	foreach(ele, l)
	{
2687
		Node	   *elem = lfirst(ele);
2688 2689 2690

		if (elem && IsA(elem, TypeName))
			transformTypeRef(pstate, (TypeName *) elem);
2691 2692 2693 2694 2695 2696 2697 2698 2699
	}
}

/*
 * Transform a TypeName to not use %TYPE.
 */
static void
transformTypeRef(ParseState *pstate, TypeName *tn)
{
2700 2701 2702 2703
	Attr	   *att;
	Node	   *n;
	Var		   *v;
	char	   *tyn;
2704 2705 2706 2707 2708

	if (tn->attrname == NULL)
		return;
	att = makeAttr(tn->name, tn->attrname);
	n = transformExpr(pstate, (Node *) att, EXPR_COLUMN_FIRST);
2709
	if (!IsA(n, Var))
2710 2711 2712 2713 2714 2715 2716 2717 2718
		elog(ERROR, "unsupported expression in %%TYPE");
	v = (Var *) n;
	tyn = typeidTypeName(v->vartype);
	elog(NOTICE, "%s.%s%%TYPE converted to %s", tn->name, tn->attrname, tyn);
	tn->name = tyn;
	tn->typmod = v->vartypmod;
	tn->attrname = NULL;
}

2719
/* exported so planner can check again after rewriting, query pullup, etc */
2720 2721 2722
void
CheckSelectForUpdate(Query *qry)
{
2723 2724
	if (qry->setOperations)
		elog(ERROR, "SELECT FOR UPDATE is not allowed with UNION/INTERSECT/EXCEPT");
2725
	if (qry->distinctClause != NIL)
2726
		elog(ERROR, "SELECT FOR UPDATE is not allowed with DISTINCT clause");
2727
	if (qry->groupClause != NIL)
2728 2729 2730 2731 2732
		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");
}

2733 2734 2735
static void
transformForUpdate(Query *qry, List *forUpdate)
{
2736
	List	   *rowMarks = qry->rowMarks;
2737
	List	   *l;
2738
	List	   *rt;
2739 2740
	Index		i;

2741 2742
	CheckSelectForUpdate(qry);

2743
	if (lfirst(forUpdate) == NULL)
2744
	{
2745 2746 2747
		/* all tables used in query */
		i = 0;
		foreach(rt, qry->rtable)
2748
		{
2749 2750 2751 2752 2753 2754 2755 2756 2757 2758
			RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);

			++i;
			if (rte->subquery)
			{
				/* FOR UPDATE of subquery is propagated to subquery's rels */
				transformForUpdate(rte->subquery, makeList1(NULL));
			}
			else
			{
2759
				if (!intMember(i, rowMarks))	/* avoid duplicates */
2760
					rowMarks = lappendi(rowMarks, i);
2761 2762
				rte->checkForWrite = true;
			}
2763 2764
		}
	}
2765
	else
2766
	{
2767 2768
		/* just the named tables */
		foreach(l, forUpdate)
2769
		{
2770
			char	   *relname = strVal(lfirst(l));
2771 2772 2773

			i = 0;
			foreach(rt, qry->rtable)
2774
			{
2775
				RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
2776

2777 2778
				++i;
				if (strcmp(rte->eref->relname, relname) == 0)
2779
				{
2780 2781 2782 2783 2784 2785 2786
					if (rte->subquery)
					{
						/* propagate to subquery */
						transformForUpdate(rte->subquery, makeList1(NULL));
					}
					else
					{
2787
						if (!intMember(i, rowMarks))	/* avoid duplicates */
2788 2789 2790 2791
							rowMarks = lappendi(rowMarks, i);
						rte->checkForWrite = true;
					}
					break;
2792 2793
				}
			}
2794 2795 2796
			if (rt == NIL)
				elog(ERROR, "FOR UPDATE: relation \"%s\" not found in FROM clause",
					 relname);
2797 2798 2799
		}
	}

2800
	qry->rowMarks = rowMarks;
2801
}
Jan Wieck's avatar
Jan Wieck committed
2802 2803


2804 2805 2806
/*
 * transformFkeyCheckAttrs -
 *
2807
 *	Make sure that the attributes of a referenced table
2808
 *		belong to a unique (or primary key) constraint.
2809
 */
2810
static void
2811
transformFkeyCheckAttrs(FkConstraint *fkconstraint, Oid *pktypoid)
2812 2813 2814 2815 2816
{
	Relation	pkrel;
	List	   *indexoidlist,
			   *indexoidscan;
	int			i;
2817
	bool		found = false;
2818

2819
	/*
2820
	 * Open the referenced table
2821 2822 2823
	 */
	pkrel = heap_openr(fkconstraint->pktable_name, AccessShareLock);

2824 2825 2826 2827
	if (pkrel->rd_rel->relkind != RELKIND_RELATION)
		elog(ERROR, "Referenced relation \"%s\" is not a table",
			 fkconstraint->pktable_name);

2828 2829 2830 2831
	/*
	 * Get the list of index OIDs for the table from the relcache, and
	 * look up each one in the pg_index syscache for each unique one, and
	 * then compare the attributes we were given to those defined.
2832 2833 2834 2835 2836
	 */
	indexoidlist = RelationGetIndexList(pkrel);

	foreach(indexoidscan, indexoidlist)
	{
2837
		Oid			indexoid = lfirsti(indexoidscan);
2838
		HeapTuple	indexTuple;
2839 2840
		Form_pg_index indexStruct;

2841
		found = false;
2842 2843 2844
		indexTuple = SearchSysCache(INDEXRELID,
									ObjectIdGetDatum(indexoid),
									0, 0, 0);
2845
		if (!HeapTupleIsValid(indexTuple))
2846
			elog(ERROR, "transformFkeyCheckAttrs: index %u not found",
2847 2848 2849
				 indexoid);
		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);

2850 2851
		if (indexStruct->indisunique)
		{
2852 2853
			for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
				;
2854
			if (i == length(fkconstraint->pk_attrs))
2855
			{
Tom Lane's avatar
Tom Lane committed
2856
				/* go through the fkconstraint->pk_attrs list */
2857
				List	   *attrl;
2858
				int			attnum = 0;
2859

Tom Lane's avatar
Tom Lane committed
2860
				foreach(attrl, fkconstraint->pk_attrs)
2861
				{
2862 2863
					Ident	   *attr = lfirst(attrl);

Tom Lane's avatar
Tom Lane committed
2864 2865
					found = false;
					for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
2866
					{
2867 2868
						int			pkattno = indexStruct->indkey[i];

2869 2870
						if (namestrcmp(attnumAttName(pkrel, pkattno),
									   attr->name) == 0)
2871
						{
2872 2873 2874
							pktypoid[attnum++] = attnumTypeId(pkrel, pkattno);
							found = true;
							break;
2875 2876
						}
					}
Tom Lane's avatar
Tom Lane committed
2877 2878
					if (!found)
						break;
2879 2880 2881
				}
			}
		}
2882
		ReleaseSysCache(indexTuple);
2883
		if (found)
2884
			break;
2885 2886 2887 2888 2889 2890 2891 2892 2893 2894
	}
	if (!found)
		elog(ERROR, "UNIQUE constraint matching given keys for referenced table \"%s\" not found",
			 fkconstraint->pktable_name);

	freeList(indexoidlist);
	heap_close(pkrel, AccessShareLock);
}


Jan Wieck's avatar
Jan Wieck committed
2895 2896 2897 2898 2899 2900 2901
/*
 * transformFkeyGetPrimaryKey -
 *
 *	Try to find the primary key attributes of a referenced table if
 *	the column list in the REFERENCES specification was omitted.
 */
static void
2902
transformFkeyGetPrimaryKey(FkConstraint *fkconstraint, Oid *pktypoid)
Jan Wieck's avatar
Jan Wieck committed
2903
{
2904
	Relation	pkrel;
2905 2906
	List	   *indexoidlist,
			   *indexoidscan;
2907
	HeapTuple	indexTuple = NULL;
2908 2909
	Form_pg_index indexStruct = NULL;
	int			i;
2910
	int			attnum = 0;
Jan Wieck's avatar
Jan Wieck committed
2911

2912
	/*
2913
	 * Open the referenced table
Jan Wieck's avatar
Jan Wieck committed
2914 2915 2916
	 */
	pkrel = heap_openr(fkconstraint->pktable_name, AccessShareLock);

2917 2918 2919 2920
	if (pkrel->rd_rel->relkind != RELKIND_RELATION)
		elog(ERROR, "Referenced relation \"%s\" is not a table",
			 fkconstraint->pktable_name);

2921 2922 2923 2924
	/*
	 * Get the list of index OIDs for the table from the relcache, and
	 * look up each one in the pg_index syscache until we find one marked
	 * primary key (hopefully there isn't more than one such).
Jan Wieck's avatar
Jan Wieck committed
2925
	 */
2926
	indexoidlist = RelationGetIndexList(pkrel);
Jan Wieck's avatar
Jan Wieck committed
2927

2928
	foreach(indexoidscan, indexoidlist)
Jan Wieck's avatar
Jan Wieck committed
2929
	{
2930
		Oid			indexoid = lfirsti(indexoidscan);
2931

2932 2933 2934
		indexTuple = SearchSysCache(INDEXRELID,
									ObjectIdGetDatum(indexoid),
									0, 0, 0);
2935 2936 2937 2938
		if (!HeapTupleIsValid(indexTuple))
			elog(ERROR, "transformFkeyGetPrimaryKey: index %u not found",
				 indexoid);
		indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
Jan Wieck's avatar
Jan Wieck committed
2939 2940
		if (indexStruct->indisprimary)
			break;
2941
		ReleaseSysCache(indexTuple);
2942
		indexStruct = NULL;
Jan Wieck's avatar
Jan Wieck committed
2943 2944
	}

2945 2946
	freeList(indexoidlist);

2947
	/*
Jan Wieck's avatar
Jan Wieck committed
2948 2949
	 * Check that we found it
	 */
2950
	if (indexStruct == NULL)
Jan Wieck's avatar
Jan Wieck committed
2951
		elog(ERROR, "PRIMARY KEY for referenced table \"%s\" not found",
2952
			 fkconstraint->pktable_name);
Jan Wieck's avatar
Jan Wieck committed
2953

2954
	/*
Jan Wieck's avatar
Jan Wieck committed
2955 2956 2957
	 * Now build the list of PK attributes from the indkey definition
	 * using the attribute names of the PK relation descriptor
	 */
2958
	for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
Jan Wieck's avatar
Jan Wieck committed
2959
	{
2960 2961 2962
		int			pkattno = indexStruct->indkey[i];
		Ident	   *pkattr = makeNode(Ident);

2963
		pkattr->name = pstrdup(NameStr(*attnumAttName(pkrel, pkattno)));
Jan Wieck's avatar
Jan Wieck committed
2964 2965
		pkattr->indirection = NIL;
		pkattr->isRel = false;
2966
		pktypoid[attnum++] = attnumTypeId(pkrel, pkattno);
Jan Wieck's avatar
Jan Wieck committed
2967 2968 2969 2970

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

2971 2972
	ReleaseSysCache(indexTuple);

Jan Wieck's avatar
Jan Wieck committed
2973 2974 2975
	heap_close(pkrel, AccessShareLock);
}

2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033
/*
 * relationHasPrimaryKey -
 *
 *	See whether an existing relation has a primary key.
 */
static bool
relationHasPrimaryKey(char *relname)
{
	bool		result = false;
	Relation	rel;
	List	   *indexoidlist,
			   *indexoidscan;

	rel = heap_openr(relname, AccessShareLock);

	/*
	 * Get the list of index OIDs for the table from the relcache, and
	 * look up each one in the pg_index syscache until we find one marked
	 * primary key (hopefully there isn't more than one such).
	 */
	indexoidlist = RelationGetIndexList(rel);

	foreach(indexoidscan, indexoidlist)
	{
		Oid			indexoid = lfirsti(indexoidscan);
		HeapTuple	indexTuple;

		indexTuple = SearchSysCache(INDEXRELID,
									ObjectIdGetDatum(indexoid),
									0, 0, 0);
		if (!HeapTupleIsValid(indexTuple))
			elog(ERROR, "relationHasPrimaryKey: index %u not found",
				 indexoid);
		result = ((Form_pg_index) GETSTRUCT(indexTuple))->indisprimary;
		ReleaseSysCache(indexTuple);
		if (result)
			break;
	}

	freeList(indexoidlist);

	heap_close(rel, AccessShareLock);

	return result;
}

/*
 * transformFkeyGetColType -
 *
 *	Find a referencing column by name, and return its type OID.
 *	Error if it can't be found.
 */
static Oid
transformFkeyGetColType(CreateStmtContext *cxt, char *colname)
{
	List	   *cols;
	List	   *inher;
	Oid			result;
3034
	Form_pg_attribute sysatt;
3035 3036 3037 3038 3039 3040 3041 3042

	/* First look for column among the newly-created columns */
	foreach(cols, cxt->columns)
	{
		ColumnDef  *col = lfirst(cols);

		if (strcmp(col->colname, colname) == 0)
		{
3043
			char	   *buff = TypeNameToInternalName(col->typename);
3044 3045 3046 3047 3048 3049 3050 3051

			result = typenameTypeId(buff);
			if (!OidIsValid(result))
				elog(ERROR, "Unable to lookup type %s",
					 col->typename->name);
			return result;
		}
	}
3052 3053 3054 3055
	/* Perhaps it's a system column name */
	sysatt = SystemAttributeByName(colname, cxt->hasoids);
	if (sysatt)
		return sysatt->atttypid;
3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104
	/* Look for column among inherited columns (if CREATE TABLE case) */
	foreach(inher, cxt->inhRelnames)
	{
		Value	   *inh = lfirst(inher);
		Relation	rel;
		int			count;

		Assert(IsA(inh, String));
		rel = heap_openr(strVal(inh), AccessShareLock);
		if (rel->rd_rel->relkind != RELKIND_RELATION)
			elog(ERROR, "inherited table \"%s\" is not a relation",
				 strVal(inh));
		for (count = 0; count < rel->rd_att->natts; count++)
		{
			char	   *name = NameStr(rel->rd_att->attrs[count]->attname);

			if (strcmp(name, colname) == 0)
			{
				result = rel->rd_att->attrs[count]->atttypid;

				heap_close(rel, NoLock);
				return result;
			}
		}
		heap_close(rel, NoLock);
	}
	/* Look for column among existing columns (if ALTER TABLE case) */
	if (OidIsValid(cxt->relOid))
	{
		HeapTuple	atttuple;

		atttuple = SearchSysCache(ATTNAME,
								  ObjectIdGetDatum(cxt->relOid),
								  PointerGetDatum(colname),
								  0, 0);
		if (HeapTupleIsValid(atttuple))
		{
			result = ((Form_pg_attribute) GETSTRUCT(atttuple))->atttypid;

			ReleaseSysCache(atttuple);
			return result;
		}
	}

	elog(ERROR, "%s: column \"%s\" referenced in foreign key constraint does not exist",
		 cxt->stmtType, colname);
	return InvalidOid;			/* keep compiler quiet */
}

3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122
/*
 * Preprocess a list of column constraint clauses
 * to attach constraint attributes to their primary constraint nodes
 * and detect inconsistent/misplaced constraint attributes.
 *
 * NOTE: currently, attributes are only supported for FOREIGN KEY primary
 * constraints, but someday they ought to be supported for other constraints.
 */
static void
transformConstraintAttrs(List *constraintList)
{
	Node	   *lastprimarynode = NULL;
	bool		saw_deferrability = false;
	bool		saw_initially = false;
	List	   *clist;

	foreach(clist, constraintList)
	{
3123
		Node	   *node = lfirst(clist);
3124

3125
		if (!IsA(node, Constraint))
3126 3127 3128 3129 3130 3131 3132 3133
		{
			lastprimarynode = node;
			/* reset flags for new primary node */
			saw_deferrability = false;
			saw_initially = false;
		}
		else
		{
3134
			Constraint *con = (Constraint *) node;
3135 3136 3137 3138 3139

			switch (con->contype)
			{
				case CONSTR_ATTR_DEFERRABLE:
					if (lastprimarynode == NULL ||
3140
						!IsA(lastprimarynode, FkConstraint))
3141 3142 3143 3144 3145 3146 3147 3148
						elog(ERROR, "Misplaced DEFERRABLE clause");
					if (saw_deferrability)
						elog(ERROR, "Multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed");
					saw_deferrability = true;
					((FkConstraint *) lastprimarynode)->deferrable = true;
					break;
				case CONSTR_ATTR_NOT_DEFERRABLE:
					if (lastprimarynode == NULL ||
3149
						!IsA(lastprimarynode, FkConstraint))
3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160
						elog(ERROR, "Misplaced NOT DEFERRABLE clause");
					if (saw_deferrability)
						elog(ERROR, "Multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed");
					saw_deferrability = true;
					((FkConstraint *) lastprimarynode)->deferrable = false;
					if (saw_initially &&
						((FkConstraint *) lastprimarynode)->initdeferred)
						elog(ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
					break;
				case CONSTR_ATTR_DEFERRED:
					if (lastprimarynode == NULL ||
3161
						!IsA(lastprimarynode, FkConstraint))
3162 3163 3164 3165 3166
						elog(ERROR, "Misplaced INITIALLY DEFERRED clause");
					if (saw_initially)
						elog(ERROR, "Multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed");
					saw_initially = true;
					((FkConstraint *) lastprimarynode)->initdeferred = true;
3167 3168 3169 3170 3171 3172

					/*
					 * If only INITIALLY DEFERRED appears, assume
					 * DEFERRABLE
					 */
					if (!saw_deferrability)
3173
						((FkConstraint *) lastprimarynode)->deferrable = true;
3174
					else if (!((FkConstraint *) lastprimarynode)->deferrable)
3175 3176 3177 3178
						elog(ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
					break;
				case CONSTR_ATTR_IMMEDIATE:
					if (lastprimarynode == NULL ||
3179
						!IsA(lastprimarynode, FkConstraint))
3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197
						elog(ERROR, "Misplaced INITIALLY IMMEDIATE clause");
					if (saw_initially)
						elog(ERROR, "Multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed");
					saw_initially = true;
					((FkConstraint *) lastprimarynode)->initdeferred = false;
					break;
				default:
					/* Otherwise it's not an attribute */
					lastprimarynode = node;
					/* reset flags for new primary node */
					saw_deferrability = false;
					saw_initially = false;
					break;
			}
		}
	}
}

3198 3199 3200 3201
/* Build a FromExpr node */
static FromExpr *
makeFromExpr(List *fromlist, Node *quals)
{
3202
	FromExpr   *f = makeNode(FromExpr);
3203 3204 3205 3206 3207 3208

	f->fromlist = fromlist;
	f->quals = quals;
	return f;
}

3209 3210 3211 3212 3213 3214
/*
 * Special handling of type definition for a column
 */
static void
transformColumnType(ParseState *pstate, ColumnDef *column)
{
3215
	TypeName   *typename = column->typename;
3216
	Type		ctype = typenameType(typename->name);
3217

3218
	/*
3219
	 * Is this the name of a complex type? If so, implement it as a set.
3220 3221 3222 3223
	 *
	 * XXX this is a hangover from ancient Berkeley code that probably
	 * doesn't work anymore anyway.
	 */
3224 3225 3226 3227 3228 3229 3230 3231 3232 3233
	if (typeTypeRelid(ctype) != InvalidOid)
	{
		/*
		 * (Eventually add in here that the set can only contain one
		 * element.)
		 */
		typename->setof = true;
	}

	ReleaseSysCache(ctype);
3234
}