heap.c 59.3 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * heap.c
4
 *	  code to create and destroy POSTGRES heap relations
5
 *
B
Add:  
Bruce Momjian 已提交
6 7
 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
 * Portions Copyright (c) 1994, Regents of the University of California
8 9 10
 *
 *
 * IDENTIFICATION
11
 *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.123 2000/03/14 23:06:06 thomas Exp $
12
 *
13 14
 *
 * INTERFACE ROUTINES
15
 *		heap_create()			- Create an uncataloged heap relation
16
 *		heap_create_with_catalog() - Create a cataloged relation
17
 *		heap_drop_with_catalog() - Removes named relation from catalogs
18 19
 *
 * NOTES
20
 *	  this code taken from access/heap/create.c, which contains
21
 *	  the old heap_create_with_catalog, amcreate, and amdestroy.
22 23
 *	  those routines will soon call these routines using the function
 *	  manager,
24 25 26
 *	  just like the poorly named "NewXXX" routines do.	The
 *	  "New" routines are all going to die soon, once and for all!
 *		-cim 1/13/91
27 28 29
 *
 *-------------------------------------------------------------------------
 */
B
Bruce Momjian 已提交
30 31 32
#include "postgres.h"

#include "access/heapam.h"
33
#include "access/genam.h"
34
#include "access/xact.h"
B
Bruce Momjian 已提交
35 36 37 38 39 40
#include "catalog/catalog.h"
#include "catalog/catname.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/pg_attrdef.h"
41
#include "catalog/pg_description.h"
B
Bruce Momjian 已提交
42 43 44
#include "catalog/pg_index.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_ipl.h"
45
#include "catalog/pg_proc.h"
B
Bruce Momjian 已提交
46
#include "catalog/pg_relcheck.h"
47
#include "catalog/pg_statistic.h"
48
#include "catalog/pg_type.h"
B
Hello.  
Bruce Momjian 已提交
49
#include "commands/comment.h"
B
Bruce Momjian 已提交
50
#include "commands/trigger.h"
51
#include "miscadmin.h"
52 53
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
B
Bruce Momjian 已提交
54
#include "optimizer/tlist.h"
55
#include "optimizer/var.h"
56
#include "nodes/makefuncs.h"
57
#include "parser/parse_clause.h"
B
Bruce Momjian 已提交
58
#include "parser/parse_expr.h"
59
#include "parser/parse_relation.h"
60
#include "parser/parse_target.h"
B
Bruce Momjian 已提交
61 62 63 64
#include "rewrite/rewriteRemove.h"
#include "storage/smgr.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
65
#include "utils/portal.h"
B
Bruce Momjian 已提交
66
#include "utils/relcache.h"
67
#include "utils/syscache.h"
68
#include "utils/temprel.h"
B
Bruce Momjian 已提交
69

70

71
static void AddNewRelationTuple(Relation pg_class_desc,
72 73 74
								Relation new_rel_desc, Oid new_rel_oid,
								int natts,
								char relkind, char *temp_relname);
75
static void AddToNoNameRelList(Relation r);
76

77 78 79
static void DeleteAttributeTuples(Relation rel);
static void DeleteRelationTuple(Relation rel);
static void DeleteTypeTuple(Relation rel);
80 81
static void RelationRemoveIndexes(Relation relation);
static void RelationRemoveInheritance(Relation relation);
82 83
static void RemoveFromNoNameRelList(Relation r);
static void AddNewRelationType(char *typeName, Oid new_rel_oid);
84 85 86
static void StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin,
							 bool updatePgAttribute);
static void StoreRelCheck(Relation rel, char *ccname, char *ccbin);
87 88
static void StoreConstraints(Relation rel);
static void RemoveConstraints(Relation rel);
89
static void RemoveStatistics(Relation rel);
90 91


92
/* ----------------------------------------------------------------
93
 *				XXX UGLY HARD CODED BADNESS FOLLOWS XXX
94
 *
95 96
 *		these should all be moved to someplace in the lib/catalog
 *		module, if not obliterated first.
97 98 99 100 101 102
 * ----------------------------------------------------------------
 */


/*
 * Note:
103 104 105 106
 *		Should the executor special case these attributes in the future?
 *		Advantage:	consume 1/2 the space in the ATTRIBUTE relation.
 *		Disadvantage:  having rules to compute values in these tuples may
 *				be more difficult if not impossible.
107 108
 */

109
static FormData_pg_attribute a1 = {
110
	0xffffffff, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData),
111
	SelfItemPointerAttributeNumber, 0, -1, -1, '\0', 'p', '\0', 'i', '\0', '\0'
112 113
};

114
static FormData_pg_attribute a2 = {
115
	0xffffffff, {"oid"}, OIDOID, 0, sizeof(Oid),
116
	ObjectIdAttributeNumber, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'
117 118
};

119
static FormData_pg_attribute a3 = {
120
	0xffffffff, {"xmin"}, XIDOID, 0, sizeof(TransactionId),
121
	MinTransactionIdAttributeNumber, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'
122 123
};

124
static FormData_pg_attribute a4 = {
125
	0xffffffff, {"cmin"}, CIDOID, 0, sizeof(CommandId),
126
	MinCommandIdAttributeNumber, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'
127 128
};

129
static FormData_pg_attribute a5 = {
130
	0xffffffff, {"xmax"}, XIDOID, 0, sizeof(TransactionId),
131
	MaxTransactionIdAttributeNumber, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'
132 133
};

134
static FormData_pg_attribute a6 = {
135
	0xffffffff, {"cmax"}, CIDOID, 0, sizeof(CommandId),
136
	MaxCommandIdAttributeNumber, 0, -1, -1, '\001', 'p', '\0', 'i', '\0', '\0'
137 138
};

139
static Form_pg_attribute HeapAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6};
140 141

/* ----------------------------------------------------------------
142
 *				XXX END OF UGLY HARD CODED BADNESS XXX
143 144 145 146 147 148 149
 * ----------------------------------------------------------------
 */

/* the tempRelList holds
   the list of temporary uncatalogued relations that are created.
   these relations should be destroyed at the end of transactions
*/
150 151
typedef struct tempRelList
{
152 153 154
	Relation   *rels;			/* array of relation descriptors */
	int			num;			/* number of temporary relations */
	int			size;			/* size of space allocated for the rels
155
								 * array */
156
} TempRelList;
157

158
#define NONAME_REL_LIST_SIZE	32
159

160
static TempRelList *tempRels = NULL;
161 162 163


/* ----------------------------------------------------------------
164
 *		heap_create		- Create an uncataloged heap relation
165
 *
166
 *		Fields relpages, reltuples, reltuples, relkeys, relhistory,
167
 *		relisindexed, and relkind of rel->rd_rel are initialized
168
 *		to all zeros, as are rd_last and rd_hook.  Rd_refcnt is set to 1.
169
 *
170 171 172 173
 *		Remove the system relation specific code to elsewhere eventually.
 *
 *		Eventually, must place information about this temporary relation
 *		into the transaction context block.
174 175
 *
 *
176
 * if heap_create is called with "" as the name, then heap_create will create
177
 * a temporary name "pg_noname.$PID.$SEQUENCE" for the relation
178 179 180
 * ----------------------------------------------------------------
 */
Relation
181 182 183
heap_create(char *relname,
			TupleDesc tupDesc,
			bool isnoname,
184 185
			bool istemp,
			bool storage_create)
186
{
187
	unsigned	i;
188
	Oid			relid;
189
	Relation	rel;
190 191 192
	int			len;
	bool		nailme = false;
	int			natts = tupDesc->natts;
193
	static unsigned int uniqueId = 0;
B
Bruce Momjian 已提交
194

195
	extern GlobalMemory CacheCxt;
196
	MemoryContext oldcxt;
197

198

199 200 201 202 203 204
	/* ----------------
	 *	sanity checks
	 * ----------------
	 */
	AssertArg(natts > 0);

205 206
	if (relname && !allowSystemTableMods &&
		IsSystemRelationName(relname) && IsNormalProcessingMode())
207
	{
T
Thomas G. Lockhart 已提交
208 209
		elog(ERROR, "Illegal class name '%s'"
			 "\n\tThe 'pg_' name prefix is reserved for system catalogs",
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
			 relname);
	}

	/* ----------------
	 *	switch to the cache context so that we don't lose
	 *	allocations at the end of this transaction, I guess.
	 *	-cim 6/14/90
	 * ----------------
	 */
	if (!CacheCxt)
		CacheCxt = CreateGlobalMemory("Cache");

	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);

	/* ----------------
	 *	real ugly stuff to assign the proper relid in the relation
	 *	descriptor follows.
	 * ----------------
	 */
229
	if (relname && !strcmp(RelationRelationName, relname))
230 231 232
	{
		relid = RelOid_pg_class;
		nailme = true;
233
	}
234
	else if (relname && !strcmp(AttributeRelationName, relname))
235
	{
236 237
		relid = RelOid_pg_attribute;
		nailme = true;
238
	}
239
	else if (relname && !strcmp(ProcedureRelationName, relname))
240
	{
241 242
		relid = RelOid_pg_proc;
		nailme = true;
243
	}
244
	else if (relname && !strcmp(TypeRelationName, relname))
245
	{
246 247
		relid = RelOid_pg_type;
		nailme = true;
248
	}
249 250 251
	else
		relid = newoid();

252 253 254 255 256
	if (isnoname)
	{
		Assert(!relname);
		relname = palloc(NAMEDATALEN);
		snprintf(relname, NAMEDATALEN, "pg_noname.%d.%u",
B
Bruce Momjian 已提交
257
				 (int) MyProcPid, uniqueId++);
258 259 260 261 262
	}

	if (istemp)
	{
		/* replace relname of caller */
263
		snprintf(relname, NAMEDATALEN, "pg_temp.%d.%u", MyProcPid, uniqueId++);
264
	}
265 266 267 268 269 270 271

	/* ----------------
	 *	allocate a new relation descriptor.
	 * ----------------
	 */
	len = sizeof(RelationData);

272 273
	rel = (Relation) palloc(len);
	MemSet((char *) rel, 0, len);
274 275
	rel->rd_fd = -1;		/* table is not open */
	rel->rd_unlinked = TRUE;	/* table is not created yet */
276 277
	/*
	 * create a new tuple descriptor from the one passed in
B
Bruce Momjian 已提交
278
	 */
279
	rel->rd_att = CreateTupleDescCopyConstr(tupDesc);
280 281 282 283 284 285 286 287

	/* ----------------
	 *	nail the reldesc if this is a bootstrap create reln and
	 *	we may need it in the cache later on in the bootstrap
	 *	process so we don't ever want it kicked out.  e.g. pg_attribute!!!
	 * ----------------
	 */
	if (nailme)
288
		rel->rd_isnailed = true;
289

290
	RelationSetReferenceCount(rel, 1);
291

292
	rel->rd_rel = (Form_pg_class) palloc(sizeof *rel->rd_rel);
293

294 295 296 297 298
	/* ----------------
	 *	initialize the fields of our new relation descriptor
	 * ----------------
	 */
	MemSet((char *) rel->rd_rel, 0, sizeof *rel->rd_rel);
299
	strcpy(RelationGetPhysicalRelationName(rel), relname);
300 301
	rel->rd_rel->relkind = RELKIND_UNCATALOGED;
	rel->rd_rel->relnatts = natts;
302
	if (tupDesc->constr)
303
		rel->rd_rel->relchecks = tupDesc->constr->num_check;
304 305

	for (i = 0; i < natts; i++)
306
		rel->rd_att->attrs[i]->attrelid = relid;
307

308
	RelationGetRelid(rel) = relid;
309 310 311 312

	if (nailme)
	{
		/* for system relations, set the reltype field here */
313
		rel->rd_rel->reltype = relid;
314 315 316
	}

	/* ----------------
317
	 *	remember if this is a noname relation
318 319
	 * ----------------
	 */
320
	rel->rd_isnoname = isnoname;
321 322 323 324 325 326

	/* ----------------
	 *	have the storage manager create the relation.
	 * ----------------
	 */

327 328 329
	/* smgrcreate() is moved to heap_storage_create() */
	if (storage_create)
		heap_storage_create(rel);
330

331
	RelationRegisterRelation(rel);
332 333 334 335

	MemoryContextSwitchTo(oldcxt);

	/*
336
	 * add all noname relations to the tempRels list so they can be
337 338
	 * properly disposed of at the end of transaction
	 */
339 340
	if (isnoname)
		AddToNoNameRelList(rel);
341

342
	return rel;
343 344
}

345 346 347 348 349 350 351 352 353 354 355 356 357
bool
heap_storage_create(Relation rel)
{
	bool smgrcall = false;

	if (rel->rd_unlinked)
	{
		rel->rd_fd = (File) smgrcreate(DEFAULT_SMGR, rel);
		rel->rd_unlinked = FALSE;
		smgrcall = true;
	}
	return smgrcall;
}
358 359

/* ----------------------------------------------------------------
360
 *		heap_create_with_catalog		- Create a cataloged relation
361
 *
362
 *		this is done in 6 steps:
363
 *
364 365
 *		1) CheckAttributeNames() is used to make certain the tuple
 *		   descriptor contains a valid set of attribute names
366
 *
367
 *		2) pg_class is opened and RelationFindRelid()
368
 *		   performs a scan to ensure that no relation with the
369
 *		   same name already exists.
370
 *
371
 *		3) heap_create_with_catalog() is called to create the new relation
372
 *		   on disk.
373
 *
374 375
 *		4) TypeDefine() is called to define a new type corresponding
 *		   to the new relation.
376
 *
377 378
 *		5) AddNewAttributeTuples() is called to register the
 *		   new relation's schema in pg_attribute.
379
 *
380
 *		6) AddNewRelationTuple() is called to register the
381
 *		   relation itself in the catalogs.
382
 *
383 384 385 386
 *		7) StoreConstraints is called ()		- vadim 08/22/97
 *
 *		8) the relations are closed and the new relation's oid
 *		   is returned.
387 388
 *
 * old comments:
389 390 391 392 393 394 395 396 397 398 399 400 401 402
 *		A new relation is inserted into the RELATION relation
 *		with the specified attribute(s) (newly inserted into
 *		the ATTRIBUTE relation).  How does concurrency control
 *		work?  Is it automatic now?  Expects the caller to have
 *		attname, atttypid, atttyparg, attproc, and attlen domains filled.
 *		Create fills the attnum domains sequentually from zero,
 *		fills the attdisbursion domains with zeros, and fills the
 *		attrelid fields with the relid.
 *
 *		scan relation catalog for name conflict
 *		scan type catalog for typids (if not arg)
 *		create and insert attribute(s) into attribute catalog
 *		create new relation
 *		insert new relation into attribute catalog
403
 *
404
 *		Should coordinate with heap_create_with_catalog(). Either
405
 *		it should not be called or there should be a way to prevent
406 407 408 409
 *		the relation from being removed at the end of the
 *		transaction if it is successful ('u'/'r' may be enough).
 *		Also, if the transaction does not commit, then the
 *		relation should be removed.
410
 *
411 412
 *		XXX amcreate ignores "off" when inserting (for now).
 *		XXX amcreate (like the other utilities) needs to understand indexes.
413 414 415 416 417
 *
 * ----------------------------------------------------------------
 */

/* --------------------------------
418
 *		CheckAttributeNames
419
 *
420 421
 *		this is used to make certain the tuple descriptor contains a
 *		valid set of attribute names.  a problem simply generates
B
Bruce Momjian 已提交
422
 *		elog(ERROR) which aborts the current transaction.
423 424 425 426 427
 * --------------------------------
 */
static void
CheckAttributeNames(TupleDesc tupdesc)
{
428 429 430
	unsigned	i;
	unsigned	j;
	int			natts = tupdesc->natts;
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446

	/* ----------------
	 *	first check for collision with system attribute names
	 * ----------------
	 *
	 *	 also, warn user if attribute to be created has
	 *	 an unknown typid  (usually as a result of a 'retrieve into'
	 *	  - jolly
	 */
	for (i = 0; i < natts; i += 1)
	{
		for (j = 0; j < sizeof HeapAtt / sizeof HeapAtt[0]; j += 1)
		{
			if (nameeq(&(HeapAtt[j]->attname),
					   &(tupdesc->attrs[i]->attname)))
			{
T
Thomas G. Lockhart 已提交
447 448
				elog(ERROR, "Attribute '%s' has a name conflict"
					 "\n\tName matches an existing system attribute",
449
					 NameStr(HeapAtt[j]->attname));
450 451 452 453
			}
		}
		if (tupdesc->attrs[i]->atttypid == UNKNOWNOID)
		{
T
Thomas G. Lockhart 已提交
454 455
			elog(NOTICE, "Attribute '%s' has an unknown type"
				 "\n\tRelation created; continue",
456
				 NameStr(tupdesc->attrs[i]->attname));
457
		}
458
	}
459 460 461 462 463 464 465 466 467 468 469 470

	/* ----------------
	 *	next check for repeated attribute names
	 * ----------------
	 */
	for (i = 1; i < natts; i += 1)
	{
		for (j = 0; j < i; j += 1)
		{
			if (nameeq(&(tupdesc->attrs[j]->attname),
					   &(tupdesc->attrs[i]->attname)))
			{
T
Thomas G. Lockhart 已提交
471
				elog(ERROR, "Attribute '%s' is repeated",
472
					 NameStr(tupdesc->attrs[j]->attname));
473 474
			}
		}
475 476 477 478
	}
}

/* --------------------------------
479
 *		RelnameFindRelid
480
 *
481
 *		Find any existing relation of the given name.
482 483
 * --------------------------------
 */
484
Oid
485
RelnameFindRelid(const char *relname)
486
{
487 488
	HeapTuple	tuple;
	Oid			relid;
489 490 491 492 493 494 495

	/*
	 * If this is not bootstrap (initdb) time, use the catalog index on
	 * pg_class.
	 */
	if (!IsBootstrapProcessingMode())
	{
496
		tuple = SearchSysCacheTuple(RELNAME,
B
Bruce Momjian 已提交
497 498
									PointerGetDatum(relname),
									0, 0, 0);
499 500
		if (HeapTupleIsValid(tuple))
			relid = tuple->t_data->t_oid;
501
		else
502
			relid = InvalidOid;
503
	}
504 505
	else
	{
B
Bruce Momjian 已提交
506
		Relation	pg_class_desc;
507 508
		ScanKeyData key;
		HeapScanDesc pg_class_scan;
B
Bruce Momjian 已提交
509

510
		pg_class_desc = heap_openr(RelationRelationName, AccessShareLock);
511 512 513 514 515 516 517 518 519 520 521

		/* ----------------
		 *	At bootstrap time, we have to do this the hard way.  Form the
		 *	scan key.
		 * ----------------
		 */
		ScanKeyEntryInitialize(&key,
							   0,
							   (AttrNumber) Anum_pg_class_relname,
							   (RegProcedure) F_NAMEEQ,
							   (Datum) relname);
B
Bruce Momjian 已提交
522

523 524 525 526 527 528 529 530 531
		/* ----------------
		 *	begin the scan
		 * ----------------
		 */
		pg_class_scan = heap_beginscan(pg_class_desc,
									   0,
									   SnapshotNow,
									   1,
									   &key);
B
Bruce Momjian 已提交
532

533 534 535 536 537 538
		/* ----------------
		 *	get a tuple.  if the tuple is NULL then it means we
		 *	didn't find an existing relation.
		 * ----------------
		 */
		tuple = heap_getnext(pg_class_scan, 0);
B
Bruce Momjian 已提交
539

540 541 542 543
		if (HeapTupleIsValid(tuple))
			relid = tuple->t_data->t_oid;
		else
			relid = InvalidOid;
544

545
		heap_endscan(pg_class_scan);
546

547
		heap_close(pg_class_desc, AccessShareLock);
548 549
	}
	return relid;
550 551 552
}

/* --------------------------------
553
 *		AddNewAttributeTuples
554
 *
555 556
 *		this registers the new relation's schema by adding
 *		tuples to pg_attribute.
557 558 559 560
 * --------------------------------
 */
static void
AddNewAttributeTuples(Oid new_rel_oid,
561
					  TupleDesc tupdesc)
562
{
563
	Form_pg_attribute *dpp;
564 565
	unsigned	i;
	HeapTuple	tup;
566
	Relation	rel;
567 568 569
	bool		hasindex;
	Relation	idescs[Num_pg_attr_indices];
	int			natts = tupdesc->natts;
570 571 572 573 574

	/* ----------------
	 *	open pg_attribute
	 * ----------------
	 */
575
	rel = heap_openr(AttributeRelationName, RowExclusiveLock);
576 577 578 579 580

	/* -----------------
	 * Check if we have any indices defined on pg_attribute.
	 * -----------------
	 */
581
	hasindex = RelationGetForm(rel)->relhasindex;
582
	if (hasindex)
583 584 585
		CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);

	/* ----------------
586
	 *	initialize tuple descriptor.
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604
	 * ----------------
	 */
	fillatt(tupdesc);

	/* ----------------
	 *	first we add the user attributes..
	 * ----------------
	 */
	dpp = tupdesc->attrs;
	for (i = 0; i < natts; i++)
	{
		(*dpp)->attrelid = new_rel_oid;
		(*dpp)->attdisbursion = 0;

		tup = heap_addheader(Natts_pg_attribute,
							 ATTRIBUTE_TUPLE_SIZE,
							 (char *) *dpp);

605
		heap_insert(rel, tup);
B
Bruce Momjian 已提交
606

607
		if (hasindex)
608
			CatalogIndexInsert(idescs, Num_pg_attr_indices, rel, tup);
609

610
		heap_freetuple(tup);
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
		dpp++;
	}

	/* ----------------
	 *	next we add the system attributes..
	 * ----------------
	 */
	dpp = HeapAtt;
	for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++)
	{
		(*dpp)->attrelid = new_rel_oid;
		/* (*dpp)->attdisbursion = 0;	   unneeded */

		tup = heap_addheader(Natts_pg_attribute,
							 ATTRIBUTE_TUPLE_SIZE,
							 (char *) *dpp);

628
		heap_insert(rel, tup);
629 630

		if (hasindex)
631
			CatalogIndexInsert(idescs, Num_pg_attr_indices, rel, tup);
632

633
		heap_freetuple(tup);
634 635 636
		dpp++;
	}

637
	heap_close(rel, RowExclusiveLock);
638 639 640 641

	/*
	 * close pg_attribute indices
	 */
642
	if (hasindex)
643
		CatalogCloseIndices(Num_pg_attr_indices, idescs);
644 645 646
}

/* --------------------------------
647
 *		AddNewRelationTuple
648
 *
649 650
 *		this registers the new relation in the catalogs by
 *		adding a tuple to pg_class.
651 652
 * --------------------------------
 */
653
static void
654
AddNewRelationTuple(Relation pg_class_desc,
B
Bruce Momjian 已提交
655 656
					Relation new_rel_desc,
					Oid new_rel_oid,
657
					int natts,
B
Bruce Momjian 已提交
658 659
					char relkind,
					char *temp_relname)
660
{
661 662 663
	Form_pg_class new_rel_reltup;
	HeapTuple	tup;
	Relation	idescs[Num_pg_class_indices];
664 665 666 667 668 669 670 671

	/* ----------------
	 *	first we munge some of the information in our
	 *	uncataloged relation's relation descriptor.
	 * ----------------
	 */
	new_rel_reltup = new_rel_desc->rd_rel;

672 673 674 675 676 677 678 679 680 681 682 683 684
	/* ----------------
	 * Here we insert bogus estimates of the size of the new relation.
	 * In reality, of course, the new relation has 0 tuples and pages,
	 * and if we were tracking these statistics accurately then we'd
	 * set the fields that way.  But at present the stats will be updated
	 * only by VACUUM or CREATE INDEX, and the user might insert a lot of
	 * tuples before he gets around to doing either of those.  So, instead
	 * of saying the relation is empty, we insert guesstimates.  The point
	 * is to keep the optimizer from making really stupid choices on
	 * never-yet-vacuumed tables; so the estimates need only be large
	 * enough to discourage the optimizer from using nested-loop plans.
	 * With this hack, nested-loop plans will be preferred only after
	 * the table has been proven to be small by VACUUM or CREATE INDEX.
685 686 687 688
	 * Maintaining the stats on-the-fly would solve the problem more cleanly,
	 * but the overhead of that would likely cost more than it'd save.
	 * (NOTE: CREATE INDEX inserts the same bogus estimates if it finds the
	 * relation has 0 rows and pages. See index.c.)
689 690
	 * ----------------
	 */
B
Bruce Momjian 已提交
691
	new_rel_reltup->relpages = 10;		/* bogus estimates */
692
	new_rel_reltup->reltuples = 1000;
693 694

	new_rel_reltup->relowner = GetUserId();
695
	new_rel_reltup->relkind = relkind;
696 697 698 699 700 701 702 703 704 705
	new_rel_reltup->relnatts = natts;

	/* ----------------
	 *	now form a tuple to add to pg_class
	 *	XXX Natts_pg_class_fixed is a hack - see pg_class.h
	 * ----------------
	 */
	tup = heap_addheader(Natts_pg_class_fixed,
						 CLASS_TUPLE_SIZE,
						 (char *) new_rel_reltup);
706
	tup->t_data->t_oid = new_rel_oid;
707

708 709
	/*
	 * finally insert the new tuple and free it.
710 711 712
	 */
	heap_insert(pg_class_desc, tup);

713 714
	if (temp_relname)
		create_temp_relation(temp_relname, tup);
B
Bruce Momjian 已提交
715

H
Hiroshi Inoue 已提交
716
	if (!IsIgnoringSystemIndexes())
717 718 719 720 721 722 723 724 725
	{
		/*
		 * First, open the catalog indices and insert index tuples for the
		 * new relation.
		 */
		CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
		CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class_desc, tup);
		CatalogCloseIndices(Num_pg_class_indices, idescs);
	}
B
Bruce Momjian 已提交
726

727
	heap_freetuple(tup);
728 729 730 731
}


/* --------------------------------
732
 *		AddNewRelationType -
733
 *
734
 *		define a complex type corresponding to the new relation
735 736
 * --------------------------------
 */
737
static void
738
AddNewRelationType(char *typeName, Oid new_rel_oid)
739
{
740
	Oid			new_type_oid;
741 742 743 744 745 746 747 748 749 750 751 752 753

	/*
	 * The sizes are set to oid size because it makes implementing sets
	 * MUCH easier, and no one (we hope) uses these fields to figure out
	 * how much space to allocate for the type. An oid is the type used
	 * for a set definition.  When a user requests a set, what they
	 * actually get is the oid of a tuple in the pg_proc catalog, so the
	 * size of the "set" is the size of an oid. Similarly, byval being
	 * true makes sets much easier, and it isn't used by anything else.
	 * Note the assumption that OIDs are the same size as int4s.
	 */
	new_type_oid = TypeCreate(typeName, /* type name */
							  new_rel_oid,		/* relation oid */
754 755
							  typeLen(typeidType(OIDOID)),		/* internal size */
							  typeLen(typeidType(OIDOID)),		/* external size */
756 757
							  'c',		/* type-type (catalog) */
							  ',',		/* default array delimiter */
758 759 760 761
							  "int4in", /* input procedure */
							  "int4out",		/* output procedure */
							  "int4in", /* receive procedure */
							  "int4out",		/* send procedure */
762 763 764 765
							  NULL,		/* array element type - irrelevent */
							  "-",		/* default type value */
							  (bool) 1, /* passed by value */
							  'i');		/* default alignment */
766 767 768
}

/* --------------------------------
769
 *		heap_create_with_catalog
770
 *
771
 *		creates a new cataloged relation.  see comments above.
772 773 774
 * --------------------------------
 */
Oid
775 776
heap_create_with_catalog(char *relname,
						 TupleDesc tupdesc,
777 778
						 char relkind,
						 bool istemp)
779
{
780 781 782 783
	Relation	pg_class_desc;
	Relation	new_rel_desc;
	Oid			new_rel_oid;
	int			natts = tupdesc->natts;
B
Bruce Momjian 已提交
784 785
	char	   *temp_relname = NULL;

786 787 788 789
	/* ----------------
	 *	sanity checks
	 * ----------------
	 */
790
	Assert(IsNormalProcessingMode() || IsBootstrapProcessingMode());
791
	if (natts <= 0 || natts > MaxHeapAttributeNumber)
T
Thomas G. Lockhart 已提交
792 793 794
		elog(ERROR, "Number of attributes is out of range"
			 "\n\tFrom 1 to %d attributes may be specified",
			 MaxHeapAttributeNumber);
795 796 797

	CheckAttributeNames(tupdesc);

798 799
	/* temp tables can mask non-temp tables */
	if ((!istemp && RelnameFindRelid(relname)) ||
800
		(istemp && get_temp_rel_by_username(relname) != NULL))
T
Thomas G. Lockhart 已提交
801
		elog(ERROR, "Relation '%s' already exists", relname);
802

803 804 805
	/* save user relation name because heap_create changes it */
	if (istemp)
	{
B
Bruce Momjian 已提交
806
		temp_relname = pstrdup(relname);		/* save original value */
807
		relname = palloc(NAMEDATALEN);
B
Bruce Momjian 已提交
808
		strcpy(relname, temp_relname);	/* heap_create will change this */
809
	}
B
Bruce Momjian 已提交
810

811
	/* ----------------
812
	 *	get_temp_rel_by_username() couldn't check the simultaneous
813 814 815 816 817 818 819 820 821 822 823
	 *	creation. Uniqueness will be really checked by unique
	 *	indexes of system tables but we couldn't check it here.
	 *	We have to pospone to create the disk file for this
	 *	relation.
	 *	Another boolean parameter "storage_create" was added
	 *	to heap_create() function. If the parameter is false
	 *	heap_create() only registers an uncataloged relation
	 *	to relation cache and heap_storage_create() should be
	 *	called later.
	 *	We could pull its relation oid from the newly formed
	 *	relation descriptor.
824
	 *
825 826 827 828
	 *	Note: The call to heap_create() changes relname for
	 *	noname and temp tables.
	 *	The call to heap_storage_create() does all the "real"
	 *	work of creating the disk file for the relation.
829 830
	 * ----------------
	 */
831
	new_rel_desc = heap_create(relname, tupdesc, false, istemp, false);
832

833 834 835 836 837 838 839
	new_rel_oid = new_rel_desc->rd_att->attrs[0]->attrelid;

	/* ----------------
	 *	since defining a relation also defines a complex type,
	 *	we add a new system type corresponding to the new relation.
	 * ----------------
	 */
840
	AddNewRelationType(relname, new_rel_oid);
841 842 843 844 845 846 847 848 849 850 851 852

	/* ----------------
	 *	now add tuples to pg_attribute for the attributes in
	 *	our new relation.
	 * ----------------
	 */
	AddNewAttributeTuples(new_rel_oid, tupdesc);

	/* ----------------
	 *	now update the information in pg_class.
	 * ----------------
	 */
853
	pg_class_desc = heap_openr(RelationRelationName, RowExclusiveLock);
854 855

	AddNewRelationTuple(pg_class_desc,
B
Bruce Momjian 已提交
856 857 858 859 860
						new_rel_desc,
						new_rel_oid,
						natts,
						relkind,
						temp_relname);
861 862 863

	StoreConstraints(new_rel_desc);

864 865 866 867 868 869
	if (istemp)
	{
		pfree(relname);
		pfree(temp_relname);
	}

870 871 872 873
	/*
	 * We create the disk file for this relation here
	 */
	heap_storage_create(new_rel_desc);
874 875 876 877 878 879 880
	/* ----------------
	 *	ok, the relation has been cataloged, so close our relations
	 *	and return the oid of the newly created relation.
	 *
	 *	SOMEDAY: fill the STATISTIC relation properly.
	 * ----------------
	 */
881 882
	heap_close(new_rel_desc, NoLock); /* do not unlock till end of xact */
	heap_close(pg_class_desc, RowExclusiveLock);
883 884

	return new_rel_oid;
885 886 887 888
}


/* ----------------------------------------------------------------
889
 *		heap_drop_with_catalog	- removes all record of named relation from catalogs
890
 *
891 892 893 894
 *		1)	open relation, check for existence, etc.
 *		2)	remove inheritance information
 *		3)	remove indexes
 *		4)	remove pg_class tuple
895 896 897 898 899
 *		5)	remove pg_attribute tuples and related descriptions
 *              6)      remove pg_description tuples
 *		7)	remove pg_type tuples
 *		8)	RemoveConstraints ()
 *		9)	unlink relation
900 901
 *
 * old comments
902 903 904
 *		Except for vital relations, removes relation from
 *		relation catalog, and related attributes from
 *		attribute catalog (needed?).  (Anything else?)
905
 *
906 907 908 909 910 911
 *		get proper relation from relation catalog (if not arg)
 *		check if relation is vital (strcmp()/reltype?)
 *		scan attribute catalog deleting attributes of reldesc
 *				(necessary?)
 *		delete relation from relation catalog
 *		(How are the tuples of the relation discarded?)
912
 *
913 914 915 916
 *		XXX Must fix to work with indexes.
 *		There may be a better order for doing things.
 *		Problems with destroying a deleted database--cannot create
 *		a struct reldesc without having an open file descriptor.
917 918 919 920
 * ----------------------------------------------------------------
 */

/* --------------------------------
921
 *		RelationRemoveInheritance
922
 *
923 924 925 926
 *		Note: for now, we cause an exception if relation is a
 *		superclass.  Someday, we may want to allow this and merge
 *		the type info into subclass procedures....	this seems like
 *		lots of work.
927 928
 * --------------------------------
 */
929
static void
930 931
RelationRemoveInheritance(Relation relation)
{
932 933 934 935
	Relation	catalogRelation;
	HeapTuple	tuple;
	HeapScanDesc scan;
	ScanKeyData entry;
936
	bool		found = false;
937

938 939 940 941
	/* ----------------
	 *	open pg_inherits
	 * ----------------
	 */
942
	catalogRelation = heap_openr(InheritsRelationName, RowExclusiveLock);
943 944 945 946 947 948 949

	/* ----------------
	 *	form a scan key for the subclasses of this class
	 *	and begin scanning
	 * ----------------
	 */
	ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_inherits_inhparent,
B
Bruce Momjian 已提交
950
						   F_OIDEQ,
951
						   ObjectIdGetDatum(RelationGetRelid(relation)));
952 953 954

	scan = heap_beginscan(catalogRelation,
						  false,
955
						  SnapshotNow,
956 957 958 959 960 961 962
						  1,
						  &entry);

	/* ----------------
	 *	if any subclasses exist, then we disallow the deletion.
	 * ----------------
	 */
963
	tuple = heap_getnext(scan, 0);
964 965
	if (HeapTupleIsValid(tuple))
	{
966
		Oid		subclass = ((Form_pg_inherits) GETSTRUCT(tuple))->inhrelid;
967

968
		heap_endscan(scan);
969
		heap_close(catalogRelation, RowExclusiveLock);
970

971
		elog(ERROR, "Relation '%u' inherits '%s'",
972
			 subclass, RelationGetRelationName(relation));
973
	}
974
	heap_endscan(scan);
975 976 977 978 979 980

	/* ----------------
	 *	If we get here, it means the relation has no subclasses
	 *	so we can trash it.  First we remove dead INHERITS tuples.
	 * ----------------
	 */
981
	entry.sk_attno = Anum_pg_inherits_inhrelid;
982 983 984

	scan = heap_beginscan(catalogRelation,
						  false,
985
						  SnapshotNow,
986 987 988
						  1,
						  &entry);

989
	while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
990
	{
V
Vadim B. Mikheev 已提交
991
		heap_delete(catalogRelation, &tuple->t_self, NULL);
992
		found = true;
993 994
	}

995
	heap_endscan(scan);
996
	heap_close(catalogRelation, RowExclusiveLock);
997 998 999 1000 1001

	/* ----------------
	 *	now remove dead IPL tuples
	 * ----------------
	 */
1002 1003
	catalogRelation = heap_openr(InheritancePrecidenceListRelationName,
								 RowExclusiveLock);
1004

1005
	entry.sk_attno = Anum_pg_ipl_iplrelid;
1006 1007 1008

	scan = heap_beginscan(catalogRelation,
						  false,
1009
						  SnapshotNow,
1010 1011 1012
						  1,
						  &entry);

1013
	while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
V
Vadim B. Mikheev 已提交
1014
		heap_delete(catalogRelation, &tuple->t_self, NULL);
1015 1016

	heap_endscan(scan);
1017
	heap_close(catalogRelation, RowExclusiveLock);
1018 1019 1020
}

/* --------------------------------
1021 1022
 *		RelationRemoveIndexes
 *
1023 1024
 * --------------------------------
 */
1025
static void
1026 1027
RelationRemoveIndexes(Relation relation)
{
1028 1029 1030 1031
	Relation	indexRelation;
	HeapTuple	tuple;
	HeapScanDesc scan;
	ScanKeyData entry;
1032

1033
	indexRelation = heap_openr(IndexRelationName, RowExclusiveLock);
1034

1035
	ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_index_indrelid,
B
Bruce Momjian 已提交
1036
						   F_OIDEQ,
1037
						   ObjectIdGetDatum(RelationGetRelid(relation)));
1038 1039 1040

	scan = heap_beginscan(indexRelation,
						  false,
1041
						  SnapshotNow,
1042 1043 1044
						  1,
						  &entry);

1045
	while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
1046
		index_drop(((Form_pg_index) GETSTRUCT(tuple))->indexrelid);
1047 1048

	heap_endscan(scan);
1049
	heap_close(indexRelation, RowExclusiveLock);
1050 1051 1052
}

/* --------------------------------
1053
 *		DeleteRelationTuple
1054 1055 1056
 *
 * --------------------------------
 */
1057
static void
1058
DeleteRelationTuple(Relation rel)
1059
{
1060 1061
	Relation	pg_class_desc;
	HeapTuple	tup;
1062 1063 1064 1065 1066

	/* ----------------
	 *	open pg_class
	 * ----------------
	 */
1067
	pg_class_desc = heap_openr(RelationRelationName, RowExclusiveLock);
1068

1069
	tup = SearchSysCacheTupleCopy(RELOID,
1070
								  ObjectIdGetDatum(rel->rd_id),
1071
								  0, 0, 0);
1072
	if (!HeapTupleIsValid(tup))
1073
	{
1074
		heap_close(pg_class_desc, RowExclusiveLock);
T
Thomas G. Lockhart 已提交
1075
		elog(ERROR, "Relation '%s' does not exist",
1076
					RelationGetRelationName(rel));
1077 1078 1079 1080 1081 1082
	}

	/* ----------------
	 *	delete the relation tuple from pg_class, and finish up.
	 * ----------------
	 */
V
Vadim B. Mikheev 已提交
1083
	heap_delete(pg_class_desc, &tup->t_self, NULL);
1084
	heap_freetuple(tup);
1085

1086
	heap_close(pg_class_desc, RowExclusiveLock);
1087 1088
}

1089 1090 1091 1092 1093 1094
/* --------------------------------
 * RelationTruncateIndexes - This routine is used to truncate all
 * indices associated with the heap relation to zero tuples.
 * The routine will truncate and then reconstruct the indices on
 * the relation specified by the heapRelation parameter.
 * --------------------------------
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
 */
static void
RelationTruncateIndexes(Relation heapRelation)
{
	Relation indexRelation, currentIndex;
	ScanKeyData entry;
	HeapScanDesc scan;
	HeapTuple indexTuple, procTuple, classTuple;
	Form_pg_index index;
	Oid heapId, indexId, procId, accessMethodId;
	Node *oldPred = NULL;
	PredInfo *predInfo;
	List *cnfPred = NULL;
	AttrNumber *attributeNumberA;
	FuncIndexInfo fInfo, *funcInfo = NULL;
	int i, numberOfAttributes;
	char *predString;

	heapId = RelationGetRelid(heapRelation);

	/* Scan pg_index to find indexes on heapRelation */

	indexRelation = heap_openr(IndexRelationName, AccessShareLock);
	ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid, F_OIDEQ,
						   ObjectIdGetDatum(heapId));
	scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
	while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
	{
		/*
		 * For each index, fetch index attributes so we can apply index_build
		 */
		index = (Form_pg_index) GETSTRUCT(indexTuple);
		indexId = index->indexrelid;
		procId = index->indproc;

		for (i = 0; i < INDEX_MAX_KEYS; i++)
		{
			if (index->indkey[i] == InvalidAttrNumber)
				break;
		}
		numberOfAttributes = i;

		/* If a valid where predicate, compute predicate Node */
		if (VARSIZE(&index->indpred) != 0)
		{
			predString = fmgr(F_TEXTOUT, &index->indpred);
			oldPred = stringToNode(predString);
			pfree(predString);
		}
		predInfo = (PredInfo *) palloc(sizeof(PredInfo));
		predInfo->pred = (Node *) cnfPred;
		predInfo->oldPred = oldPred;

		/* Assign Index keys to attributes array */
		attributeNumberA = (AttrNumber *) palloc(numberOfAttributes *
												 sizeof(AttrNumber));
		for (i = 0; i < numberOfAttributes; i++)
			attributeNumberA[i] = index->indkey[i];

		/* If this is a procedural index, initialize our FuncIndexInfo */
		if (procId != InvalidOid)
		{
			funcInfo = &fInfo;
			FIsetnArgs(funcInfo, numberOfAttributes);
1159
			procTuple = SearchSysCacheTuple(PROCOID, ObjectIdGetDatum(procId),
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181
											0, 0, 0);
			if (!HeapTupleIsValid(procTuple))
				elog(ERROR, "RelationTruncateIndexes: index procedure not found");
			namecpy(&(funcInfo->funcName),
					&(((Form_pg_proc) GETSTRUCT(procTuple))->proname));
			FIsetProcOid(funcInfo, procTuple->t_data->t_oid);
		}

		/* Fetch the classTuple associated with this index */
		classTuple = SearchSysCacheTupleCopy(RELOID, ObjectIdGetDatum(indexId),
											 0, 0, 0);
		if (!HeapTupleIsValid(classTuple))
			elog(ERROR, "RelationTruncateIndexes: index access method not found");
		accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;

		/* Open our index relation */
		currentIndex = index_open(indexId);
		if (currentIndex == NULL)
			elog(ERROR, "RelationTruncateIndexes: can't open index relation");

		/* Obtain exclusive lock on it, just to be sure */
		LockRelation(currentIndex, AccessExclusiveLock);
1182

1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209
		/*
		 * Release any buffers associated with this index.  If they're dirty,
		 * they're just dropped without bothering to flush to disk.
		 */
		ReleaseRelationBuffers(currentIndex);
		if (FlushRelationBuffers(currentIndex, (BlockNumber) 0, false) < 0)
			elog(ERROR, "RelationTruncateIndexes: unable to flush index from buffer pool");

		/* Now truncate the actual data and set blocks to zero */
		smgrtruncate(DEFAULT_SMGR, currentIndex, 0);
		currentIndex->rd_nblocks = 0;

		/* Initialize the index and rebuild */
		InitIndexStrategy(numberOfAttributes, currentIndex, accessMethodId);
		index_build(heapRelation, currentIndex, numberOfAttributes,
					attributeNumberA, 0, NULL, funcInfo, predInfo);

		/*
		 * index_build will close both the heap and index relations
		 * (but not give up the locks we hold on them).  That's fine
		 * for the index, but we need to open the heap again.  We need
		 * no new lock, since this backend still has the exclusive lock
		 * grabbed by heap_truncate.
		 */
		heapRelation = heap_open(heapId, NoLock);
		Assert(heapRelation != NULL);
	}
1210

1211 1212 1213
	/* Complete the scan and close pg_index */
    heap_endscan(scan);
	heap_close(indexRelation, AccessShareLock);
1214 1215 1216 1217 1218
}

/* ----------------------------
 *   heap_truncate
 *
1219 1220 1221
 *   This routine is used to truncate the data from the
 *   storage manager of any data within the relation handed
 *   to this routine.
1222 1223 1224
 * ----------------------------
 */

1225 1226 1227 1228 1229 1230 1231 1232 1233
void
heap_truncate(char *relname)
{
	Relation rel;
	Oid rid;

	/* Open relation for processing, and grab exclusive access on it. */

	rel = heap_openr(relname, AccessExclusiveLock);
1234
	rid = RelationGetRelid(rel);
1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258

	/* ----------------
	 *	TRUNCATE TABLE within a transaction block is dangerous, because
	 *	if the transaction is later rolled back we have no way to
	 *	undo truncation of the relation's physical file.  For now, allow it
	 *	but emit a warning message.
	 *	Someday we might want to consider postponing the physical truncate
	 *	until transaction commit, but that's a lot of work...
	 *	The only case that actually works right is for relations created
	 *	in the current transaction, since the post-abort state would be that
	 *	they don't exist anyway.  So, no warning in that case.
	 * ----------------
	 */
	if (IsTransactionBlock() && ! rel->rd_myxactonly)
		elog(NOTICE, "Caution: TRUNCATE TABLE cannot be rolled back, so don't abort now");

	/*
	 * Release any buffers associated with this relation.  If they're dirty,
	 * they're just dropped without bothering to flush to disk.
	 */

	ReleaseRelationBuffers(rel);
	if (FlushRelationBuffers(rel, (BlockNumber) 0, false) < 0)
		elog(ERROR, "heap_truncate: unable to flush relation from buffer pool");
1259

1260 1261 1262 1263 1264 1265
	/* Now truncate the actual data and set blocks to zero */

	smgrtruncate(DEFAULT_SMGR, rel, 0);
	rel->rd_nblocks = 0;

	/* If this relation has indexes, truncate the indexes too */
H
Hiroshi Inoue 已提交
1266
	RelationTruncateIndexes(rel);
1267 1268 1269 1270 1271 1272 1273 1274 1275 1276

	/*
	 * Close the relation, but keep exclusive lock on it until commit.
	 */
	heap_close(rel, NoLock);

	/*
	 * Is this really necessary?
	 */
	RelationForgetRelation(rid);
1277 1278 1279
}


1280
/* --------------------------------
1281
 *		DeleteAttributeTuples
1282 1283 1284
 *
 * --------------------------------
 */
1285
static void
1286
DeleteAttributeTuples(Relation rel)
1287
{
1288 1289
	Relation	pg_attribute_desc;
	HeapTuple	tup;
1290
	int2		attnum;
1291

1292 1293 1294 1295
	/* ----------------
	 *	open pg_attribute
	 * ----------------
	 */
1296
	pg_attribute_desc = heap_openr(AttributeRelationName, RowExclusiveLock);
1297

B
Bruce Momjian 已提交
1298
	for (attnum = FirstLowInvalidHeapAttributeNumber + 1;
1299 1300
		 attnum <= rel->rd_att->natts;
		 attnum++)
1301
	{
B
Bruce Momjian 已提交
1302
		if (HeapTupleIsValid(tup = SearchSysCacheTupleCopy(ATTNUM,
1303 1304
								   ObjectIdGetDatum(RelationGetRelid(rel)),
								   Int16GetDatum(attnum),
1305
														   0, 0)))
B
Bruce Momjian 已提交
1306
		{
B
Hello.  
Bruce Momjian 已提交
1307 1308
		  
		  /*** Delete any comments associated with this attribute ***/
1309

B
Hello.  
Bruce Momjian 已提交
1310
		  DeleteComments(tup->t_data->t_oid);
1311

B
Hello.  
Bruce Momjian 已提交
1312
		  heap_delete(pg_attribute_desc, &tup->t_self, NULL);
1313
		  heap_freetuple(tup);
1314

B
Hello.  
Bruce Momjian 已提交
1315 1316
		}
	}
1317

B
Hello.  
Bruce Momjian 已提交
1318
	heap_close(pg_attribute_desc, RowExclusiveLock);
1319 1320
}

1321
/* --------------------------------
1322
 *		DeleteTypeTuple
1323
 *
1324 1325 1326 1327
 *		If the user attempts to destroy a relation and there
 *		exists attributes in other relations of type
 *		"relation we are deleting", then we have to do something
 *		special.  presently we disallow the destroy.
1328 1329
 * --------------------------------
 */
1330
static void
1331
DeleteTypeTuple(Relation rel)
1332
{
1333 1334 1335 1336 1337 1338 1339 1340 1341
	Relation	pg_type_desc;
	HeapScanDesc pg_type_scan;
	Relation	pg_attribute_desc;
	HeapScanDesc pg_attribute_scan;
	ScanKeyData key;
	ScanKeyData attkey;
	HeapTuple	tup;
	HeapTuple	atttup;
	Oid			typoid;
1342 1343 1344 1345 1346

	/* ----------------
	 *	open pg_type
	 * ----------------
	 */
1347
	pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
1348 1349 1350 1351 1352 1353

	/* ----------------
	 *	create a scan key to locate the type tuple corresponding
	 *	to this relation.
	 * ----------------
	 */
B
Bruce Momjian 已提交
1354
	ScanKeyEntryInitialize(&key, 0,
1355 1356 1357
						   Anum_pg_type_typrelid,
						   F_OIDEQ,
						   ObjectIdGetDatum(RelationGetRelid(rel)));
1358 1359 1360

	pg_type_scan = heap_beginscan(pg_type_desc,
								  0,
1361
								  SnapshotNow,
1362 1363 1364 1365 1366 1367 1368 1369
								  1,
								  &key);

	/* ----------------
	 *	use heap_getnext() to fetch the pg_type tuple.	If this
	 *	tuple is not valid then something's wrong.
	 * ----------------
	 */
1370
	tup = heap_getnext(pg_type_scan, 0);
1371

1372
	if (!HeapTupleIsValid(tup))
1373 1374
	{
		heap_endscan(pg_type_scan);
1375
		heap_close(pg_type_desc, RowExclusiveLock);
1376
		elog(ERROR, "DeleteTypeTuple: %s type nonexistent",
1377
			 RelationGetRelationName(rel));
1378 1379 1380 1381 1382 1383 1384 1385 1386
	}

	/* ----------------
	 *	now scan pg_attribute.	if any other relations have
	 *	attributes of the type of the relation we are deleteing
	 *	then we have to disallow the deletion.	should talk to
	 *	stonebraker about this.  -cim 6/19/90
	 * ----------------
	 */
1387
	typoid = tup->t_data->t_oid;
1388

1389
	pg_attribute_desc = heap_openr(AttributeRelationName, RowExclusiveLock);
1390 1391

	ScanKeyEntryInitialize(&attkey,
B
Bruce Momjian 已提交
1392 1393 1394
						   0,
						   Anum_pg_attribute_atttypid,
						   F_OIDEQ,
1395 1396 1397 1398
						   typoid);

	pg_attribute_scan = heap_beginscan(pg_attribute_desc,
									   0,
1399
									   SnapshotNow,
1400 1401 1402 1403 1404
									   1,
									   &attkey);

	/* ----------------
	 *	try and get a pg_attribute tuple.  if we succeed it means
B
Bruce Momjian 已提交
1405
	 *	we can't delete the relation because something depends on
1406 1407 1408
	 *	the schema.
	 * ----------------
	 */
1409
	atttup = heap_getnext(pg_attribute_scan, 0);
1410

B
Bruce Momjian 已提交
1411
	if (HeapTupleIsValid(atttup))
1412
	{
1413
		Oid			relid = ((Form_pg_attribute) GETSTRUCT(atttup))->attrelid;
1414 1415

		heap_endscan(pg_attribute_scan);
1416 1417 1418
		heap_close(pg_attribute_desc, RowExclusiveLock);
		heap_endscan(pg_type_scan);
		heap_close(pg_type_desc, RowExclusiveLock);
1419

1420
		elog(ERROR, "DeleteTypeTuple: att of type %s exists in relation %u",
1421
			 RelationGetRelationName(rel), relid);
1422
	}
M
Marc G. Fournier 已提交
1423
	heap_endscan(pg_attribute_scan);
1424
	heap_close(pg_attribute_desc, RowExclusiveLock);
1425 1426 1427 1428 1429 1430 1431

	/* ----------------
	 *	Ok, it's safe so we delete the relation tuple
	 *	from pg_type and finish up.  But first end the scan so that
	 *	we release the read lock on pg_type.  -mer 13 Aug 1991
	 * ----------------
	 */
B
Hello.  
Bruce Momjian 已提交
1432
	
V
Vadim B. Mikheev 已提交
1433
	heap_delete(pg_type_desc, &tup->t_self, NULL);
1434

1435
	heap_endscan(pg_type_scan);
1436
	heap_close(pg_type_desc, RowExclusiveLock);
M
Marc G. Fournier 已提交
1437 1438 1439
}

/* --------------------------------
1440
 *		heap_drop_with_catalog
M
Marc G. Fournier 已提交
1441 1442 1443 1444
 *
 * --------------------------------
 */
void
1445
heap_drop_with_catalog(const char *relname)
M
Marc G. Fournier 已提交
1446
{
1447
	Relation	rel;
1448
	Oid			rid;
1449
	bool		istemp = (get_temp_rel_by_username(relname) != NULL);
1450 1451

	/* ----------------
1452
	 *	Open and lock the relation.
1453 1454
	 * ----------------
	 */
1455
	rel = heap_openr(relname, AccessExclusiveLock);
1456
	rid = RelationGetRelid(rel);
1457 1458 1459 1460 1461

	/* ----------------
	 *	prevent deletion of system relations
	 * ----------------
	 */
1462
	/* allow temp of pg_class? Guess so. */
1463
	if (!istemp && !allowSystemTableMods &&
1464
		IsSystemRelationName(RelationGetRelationName(rel)))
T
Thomas G. Lockhart 已提交
1465
		elog(ERROR, "System relation '%s' cannot be destroyed",
1466
			 RelationGetRelationName(rel));
1467

1468
	/* ----------------
1469 1470 1471 1472 1473 1474 1475 1476 1477
	 *	DROP TABLE within a transaction block is dangerous, because
	 *	if the transaction is later rolled back there will be no way to
	 *	undo the unlink of the relation's physical file.  For now, allow it
	 *	but emit a warning message.
	 *	Someday we might want to consider postponing the physical unlink
	 *	until transaction commit, but that's a lot of work...
	 *	The only case that actually works right is for relations created
	 *	in the current transaction, since the post-abort state would be that
	 *	they don't exist anyway.  So, no warning in that case.
1478 1479 1480
	 * ----------------
	 */
	if (IsTransactionBlock() && ! rel->rd_myxactonly)
1481
		elog(NOTICE, "Caution: DROP TABLE cannot be rolled back, so don't abort now");
1482

1483 1484 1485 1486
	/* ----------------
	 *	remove inheritance information
	 * ----------------
	 */
1487
	RelationRemoveInheritance(rel);
1488 1489 1490 1491 1492

	/* ----------------
	 *	remove indexes if necessary
	 * ----------------
	 */
H
Hiroshi Inoue 已提交
1493 1494
	/* should ignore relhasindex */
	RelationRemoveIndexes(rel);
1495 1496 1497 1498 1499

	/* ----------------
	 *	remove rules if necessary
	 * ----------------
	 */
1500
	if (rel->rd_rules != NULL)
1501 1502 1503
		RelationRemoveRules(rid);

	/* triggers */
1504
	RelationRemoveTriggers(rel);
1505 1506 1507 1508 1509

	/* ----------------
	 *	delete attribute tuples
	 * ----------------
	 */
1510
	DeleteAttributeTuples(rel);
1511

1512
	/* ----------------
1513
	 *	delete comments, statistics, and constraints
1514 1515
	 * ----------------
	 */
1516 1517
	DeleteComments(RelationGetRelid(rel));

1518 1519
	RemoveStatistics(rel);

1520 1521
	RemoveConstraints(rel);

1522
	/* ----------------
1523
	 *	delete type tuple
1524 1525
	 * ----------------
	 */
1526
	DeleteTypeTuple(rel);
1527 1528 1529 1530 1531

	/* ----------------
	 *	delete relation tuple
	 * ----------------
	 */
1532
	DeleteRelationTuple(rel);
1533 1534 1535 1536

	/*
	 * release dirty buffers of this relation
	 */
1537
	ReleaseRelationBuffers(rel);
1538 1539

	/* ----------------
1540
	 *	unlink the relation's physical file and finish up.
1541 1542
	 * ----------------
	 */
1543
	if (!(rel->rd_isnoname) || !(rel->rd_unlinked))
1544
		smgrunlink(DEFAULT_SMGR, rel);
1545

1546
	rel->rd_unlinked = TRUE;
1547

1548 1549 1550 1551 1552 1553
	/*
	 * Close relcache entry, but *keep* AccessExclusiveLock on the
	 * relation until transaction commit.  This ensures no one else
	 * will try to do something with the doomed relation.
	 */
	heap_close(rel, NoLock);
1554

1555 1556 1557 1558
	/* ----------------
	 *	flush the relation from the relcache
	 * ----------------
	 */
1559
	RelationForgetRelation(rid);
1560 1561 1562

	if (istemp)
		remove_temp_relation(rid);
M
Marc G. Fournier 已提交
1563 1564 1565
}

/*
1566
 * heap_drop
1567
 *	  destroy and close temporary relations
M
Marc G. Fournier 已提交
1568 1569 1570
 *
 */

1571
void
1572
heap_drop(Relation rel)
M
Marc G. Fournier 已提交
1573
{
1574
	ReleaseRelationBuffers(rel);
1575
	if (!(rel->rd_isnoname) || !(rel->rd_unlinked))
1576
		smgrunlink(DEFAULT_SMGR, rel);
1577
	rel->rd_unlinked = TRUE;
1578
	heap_close(rel, NoLock);
1579
	RemoveFromNoNameRelList(rel);
M
Marc G. Fournier 已提交
1580 1581 1582 1583
}


/**************************************************************
1584
  functions to deal with the list of temporary relations
M
Marc G. Fournier 已提交
1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599
**************************************************************/

/* --------------
   InitTempRellist():

   initialize temporary relations list
   the tempRelList is a list of temporary relations that
   are created in the course of the transactions
   they need to be destroyed properly at the end of the transactions

   MODIFIES the global variable tempRels

 >> NOTE <<

   malloc is used instead of palloc because we KNOW when we are
1600
   going to free these things.	Keeps us away from the memory context
M
Marc G. Fournier 已提交
1601 1602 1603 1604
   hairyness

*/
void
1605
InitNoNameRelList(void)
M
Marc G. Fournier 已提交
1606
{
1607 1608 1609 1610 1611
	if (tempRels)
	{
		free(tempRels->rels);
		free(tempRels);
	}
M
Marc G. Fournier 已提交
1612

1613
	tempRels = (TempRelList *) malloc(sizeof(TempRelList));
1614
	tempRels->size = NONAME_REL_LIST_SIZE;
1615
	tempRels->rels = (Relation *) malloc(sizeof(Relation) * tempRels->size);
B
Bruce Momjian 已提交
1616
	MemSet(tempRels->rels, 0, sizeof(Relation) * tempRels->size);
1617
	tempRels->num = 0;
M
Marc G. Fournier 已提交
1618 1619 1620 1621 1622 1623
}

/*
   removes a relation from the TempRelList

   MODIFIES the global variable tempRels
1624
	  we don't really remove it, just mark it as NULL
1625
	  and DropNoNameRels will look for NULLs
M
Marc G. Fournier 已提交
1626
*/
1627
static void
1628
RemoveFromNoNameRelList(Relation r)
M
Marc G. Fournier 已提交
1629
{
1630
	int			i;
M
Marc G. Fournier 已提交
1631

1632 1633
	if (!tempRels)
		return;
M
Marc G. Fournier 已提交
1634

1635 1636 1637 1638 1639 1640 1641
	for (i = 0; i < tempRels->num; i++)
	{
		if (tempRels->rels[i] == r)
		{
			tempRels->rels[i] = NULL;
			break;
		}
M
Marc G. Fournier 已提交
1642 1643 1644 1645 1646 1647 1648 1649
	}
}

/*
   add a temporary relation to the TempRelList

   MODIFIES the global variable tempRels
*/
1650
static void
1651
AddToNoNameRelList(Relation r)
M
Marc G. Fournier 已提交
1652
{
1653 1654
	if (!tempRels)
		return;
M
Marc G. Fournier 已提交
1655

1656 1657
	if (tempRels->num == tempRels->size)
	{
1658
		tempRels->size += NONAME_REL_LIST_SIZE;
1659 1660 1661 1662 1663
		tempRels->rels = realloc(tempRels->rels,
								 sizeof(Relation) * tempRels->size);
	}
	tempRels->rels[tempRels->num] = r;
	tempRels->num++;
M
Marc G. Fournier 已提交
1664 1665 1666 1667 1668 1669
}

/*
   go through the tempRels list and destroy each of the relations
*/
void
1670
DropNoNameRels(void)
M
Marc G. Fournier 已提交
1671
{
1672
	int			i;
1673
	Relation	rel;
M
Marc G. Fournier 已提交
1674

1675 1676
	if (!tempRels)
		return;
M
Marc G. Fournier 已提交
1677

1678 1679
	for (i = 0; i < tempRels->num; i++)
	{
1680 1681 1682
		rel = tempRels->rels[i];
		/* rel may be NULL if it has been removed from the list already */
		if (rel)
1683
			heap_drop(rel);
1684 1685 1686 1687
	}
	free(tempRels->rels);
	free(tempRels);
	tempRels = NULL;
M
Marc G. Fournier 已提交
1688 1689
}

1690 1691 1692 1693 1694 1695
/*
 * Store a default expression for column attnum of relation rel.
 * The expression must be presented as a nodeToString() string.
 * If updatePgAttribute is true, update the pg_attribute entry
 * for the column to show that a default exists.
 */
1696
static void
1697 1698
StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin,
				 bool updatePgAttribute)
1699
{
1700
	Node	   *expr;
1701 1702
	RangeTblEntry *rte;
	char	   *adsrc;
1703 1704 1705 1706
	Relation	adrel;
	Relation	idescs[Num_pg_attrdef_indices];
	HeapTuple	tuple;
	Datum		values[4];
1707 1708 1709 1710 1711
	static char	nulls[4] = {' ', ' ', ' ', ' '};
	Relation	attrrel;
	Relation	attridescs[Num_pg_attr_indices];
	HeapTuple	atttup;
	Form_pg_attribute attStruct;
B
Bruce Momjian 已提交
1712

1713 1714 1715
	/*
	 * Need to construct source equivalent of given node-string.
	 */
1716 1717 1718 1719 1720
	expr = stringToNode(adbin);
	/*
	 * deparse_expression needs a RangeTblEntry list, so make one
	 */
	rte = makeNode(RangeTblEntry);
1721
	rte->relname = RelationGetRelationName(rel);
1722
#ifndef DISABLE_EREF
1723 1724
	rte->ref = makeNode(Attr);
	rte->ref->relname = RelationGetRelationName(rel);
1725
#endif
1726 1727 1728 1729 1730
	rte->relid = RelationGetRelid(rel);
	rte->inh = false;
	rte->inFromCl = true;
	rte->skipAcl = false;
	adsrc = deparse_expression(expr, lcons(lcons(rte, NIL), NIL), false);
1731

1732
	values[Anum_pg_attrdef_adrelid - 1] = RelationGetRelid(rel);
1733 1734 1735
	values[Anum_pg_attrdef_adnum - 1] = attnum;
	values[Anum_pg_attrdef_adbin - 1] = PointerGetDatum(textin(adbin));
	values[Anum_pg_attrdef_adsrc - 1] = PointerGetDatum(textin(adsrc));
1736
	adrel = heap_openr(AttrDefaultRelationName, RowExclusiveLock);
1737 1738
	tuple = heap_formtuple(adrel->rd_att, values, nulls);
	heap_insert(adrel, tuple);
1739 1740
	CatalogOpenIndices(Num_pg_attrdef_indices, Name_pg_attrdef_indices,
					   idescs);
1741 1742
	CatalogIndexInsert(idescs, Num_pg_attrdef_indices, adrel, tuple);
	CatalogCloseIndices(Num_pg_attrdef_indices, idescs);
1743
	heap_close(adrel, RowExclusiveLock);
1744 1745 1746

	pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1]));
	pfree(DatumGetPointer(values[Anum_pg_attrdef_adsrc - 1]));
1747
	heap_freetuple(tuple);
1748 1749 1750 1751 1752 1753 1754
	pfree(adsrc);

	if (! updatePgAttribute)
		return;					/* done if pg_attribute is OK */

	attrrel = heap_openr(AttributeRelationName, RowExclusiveLock);
	atttup = SearchSysCacheTupleCopy(ATTNUM,
1755
									 ObjectIdGetDatum(RelationGetRelid(rel)),
1756 1757 1758
									 (Datum) attnum, 0, 0);
	if (!HeapTupleIsValid(atttup))
		elog(ERROR, "cache lookup of attribute %d in relation %u failed",
1759
			 attnum, RelationGetRelid(rel));
1760 1761 1762 1763
	attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
	if (! attStruct->atthasdef)
	{
		attStruct->atthasdef = true;
1764
		heap_update(attrrel, &atttup->t_self, atttup, NULL);
1765 1766 1767 1768 1769 1770 1771
		/* keep catalog indices current */
		CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices,
						   attridescs);
		CatalogIndexInsert(attridescs, Num_pg_attr_indices, attrrel, atttup);
		CatalogCloseIndices(Num_pg_attr_indices, attridescs);
	}
	heap_close(attrrel, RowExclusiveLock);
1772
	heap_freetuple(atttup);
1773 1774
}

1775 1776 1777 1778 1779 1780 1781
/*
 * Store a constraint expression for the given relation.
 * The expression must be presented as a nodeToString() string.
 *
 * Caller is responsible for updating the count of constraints
 * in the pg_class entry for the relation.
 */
1782
static void
1783
StoreRelCheck(Relation rel, char *ccname, char *ccbin)
1784
{
1785 1786 1787
	Node	   *expr;
	RangeTblEntry *rte;
	char	   *ccsrc;
1788 1789 1790 1791
	Relation	rcrel;
	Relation	idescs[Num_pg_relcheck_indices];
	HeapTuple	tuple;
	Datum		values[4];
1792
	static char	nulls[4] = {' ', ' ', ' ', ' '};
1793

B
Bruce Momjian 已提交
1794
	/*
1795
	 * Convert condition to a normal boolean expression tree.
1796
	 */
1797 1798 1799 1800 1801 1802
	expr = stringToNode(ccbin);
	expr = (Node *) make_ands_explicit((List *) expr);
	/*
	 * deparse_expression needs a RangeTblEntry list, so make one
	 */
	rte = makeNode(RangeTblEntry);
1803
	rte->relname = RelationGetRelationName(rel);
1804
#ifndef DISABLE_EREF
1805 1806
	rte->ref = makeNode(Attr);
	rte->ref->relname = RelationGetRelationName(rel);
1807
#endif
1808 1809 1810 1811 1812
	rte->relid = RelationGetRelid(rel);
	rte->inh = false;
	rte->inFromCl = true;
	rte->skipAcl = false;
	ccsrc = deparse_expression(expr, lcons(lcons(rte, NIL), NIL), false);
1813

1814
	values[Anum_pg_relcheck_rcrelid - 1] = RelationGetRelid(rel);
1815 1816 1817
	values[Anum_pg_relcheck_rcname - 1] = PointerGetDatum(namein(ccname));
	values[Anum_pg_relcheck_rcbin - 1] = PointerGetDatum(textin(ccbin));
	values[Anum_pg_relcheck_rcsrc - 1] = PointerGetDatum(textin(ccsrc));
1818
	rcrel = heap_openr(RelCheckRelationName, RowExclusiveLock);
1819 1820
	tuple = heap_formtuple(rcrel->rd_att, values, nulls);
	heap_insert(rcrel, tuple);
1821 1822
	CatalogOpenIndices(Num_pg_relcheck_indices, Name_pg_relcheck_indices,
					   idescs);
1823 1824
	CatalogIndexInsert(idescs, Num_pg_relcheck_indices, rcrel, tuple);
	CatalogCloseIndices(Num_pg_relcheck_indices, idescs);
1825
	heap_close(rcrel, RowExclusiveLock);
1826 1827 1828 1829

	pfree(DatumGetPointer(values[Anum_pg_relcheck_rcname - 1]));
	pfree(DatumGetPointer(values[Anum_pg_relcheck_rcbin - 1]));
	pfree(DatumGetPointer(values[Anum_pg_relcheck_rcsrc - 1]));
1830
	heap_freetuple(tuple);
1831
	pfree(ccsrc);
1832 1833
}

1834 1835 1836 1837 1838 1839 1840 1841 1842 1843
/*
 * Store defaults and constraints passed in via the tuple constraint struct.
 *
 * NOTE: only pre-cooked expressions will be passed this way, which is to
 * say expressions inherited from an existing relation.  Newly parsed
 * expressions can be added later, by direct calls to StoreAttrDefault
 * and StoreRelCheck (see AddRelationRawConstraints()).  We assume that
 * pg_attribute and pg_class entries for the relation were already set
 * to reflect the existence of these defaults/constraints.
 */
1844 1845
static void
StoreConstraints(Relation rel)
1846
{
1847 1848
	TupleConstr *constr = rel->rd_att->constr;
	int			i;
1849 1850 1851 1852

	if (!constr)
		return;

1853 1854 1855 1856 1857 1858
	/* deparsing of constraint expressions will fail unless the just-created
	 * pg_attribute tuples for this relation are made visible.  So, bump
	 * the command counter.
	 */
	CommandCounterIncrement();

1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884
	for (i = 0; i < constr->num_defval; i++)
		StoreAttrDefault(rel, constr->defval[i].adnum,
						 constr->defval[i].adbin, false);

	for (i = 0; i < constr->num_check; i++)
		StoreRelCheck(rel, constr->check[i].ccname,
					  constr->check[i].ccbin);
}

/*
 * AddRelationRawConstraints
 *
 * Add raw (not-yet-transformed) column default expressions and/or constraint
 * check expressions to an existing relation.  This is defined to do both
 * for efficiency in DefineRelation, but of course you can do just one or
 * the other by passing empty lists.
 *
 * rel: relation to be modified
 * rawColDefaults: list of RawColumnDefault structures
 * rawConstraints: list of Constraint nodes
 *
 * All entries in rawColDefaults will be processed.  Entries in rawConstraints
 * will be processed only if they are CONSTR_CHECK type and contain a "raw"
 * expression.
 *
 * NB: caller should have opened rel with AccessExclusiveLock, and should
1885 1886 1887
 * hold that lock till end of transaction.  Also, we assume the caller has
 * done a CommandCounterIncrement if necessary to make the relation's catalog
 * tuples visible.
1888 1889 1890 1891 1892 1893
 */
void
AddRelationRawConstraints(Relation rel,
						  List *rawColDefaults,
						  List *rawConstraints)
{
1894
	char	   *relname = RelationGetRelationName(rel);
1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927
	TupleDesc	tupleDesc;
	TupleConstr *oldconstr;
	int			numoldchecks;
	ConstrCheck *oldchecks;
	ParseState *pstate;
	int			numchecks;
	List	   *listptr;
	Relation	relrel;
	Relation	relidescs[Num_pg_class_indices];
	HeapTuple	reltup;
	Form_pg_class relStruct;

	/*
	 * Get info about existing constraints.
	 */
	tupleDesc = RelationGetDescr(rel);
	oldconstr = tupleDesc->constr;
	if (oldconstr)
	{
		numoldchecks = oldconstr->num_check;
		oldchecks = oldconstr->check;
	}
	else
	{
		numoldchecks = 0;
		oldchecks = NULL;
	}

	/*
	 * Create a dummy ParseState and insert the target relation as
	 * its sole rangetable entry.  We need a ParseState for transformExpr.
	 */
	pstate = make_parsestate(NULL);
1928 1929
	makeRangeTable(pstate, NULL);
	addRangeTableEntry(pstate, relname, makeAttr(relname, NULL), false, true, true);
1930 1931 1932 1933 1934

	/*
	 * Process column default expressions.
	 */
	foreach(listptr, rawColDefaults)
1935
	{
1936 1937
		RawColumnDefault *colDef = (RawColumnDefault *) lfirst(listptr);
		Node	   *expr;
1938
		Oid			type_id;
1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949

		Assert(colDef->raw_default != NULL);
		/*
		 * Transform raw parsetree to executable expression.
		 */
		expr = transformExpr(pstate, colDef->raw_default, EXPR_COLUMN_FIRST);
		/*
		 * Make sure default expr does not refer to any vars.
		 */
		if (contain_var_clause(expr))
			elog(ERROR, "Cannot use attribute(s) in DEFAULT clause");
1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967
		/*
		 * Check that it will be possible to coerce the expression
		 * to the column's type.  We store the expression without
		 * coercion, however, to avoid premature coercion in cases like
		 *
		 * CREATE TABLE tbl (fld datetime DEFAULT 'now');
		 *
		 * NB: this should match the code in updateTargetListEntry()
		 * that will actually do the coercion, to ensure we don't accept
		 * an unusable default expression.
		 */
		type_id = exprType(expr);
		if (type_id != InvalidOid)
		{
			Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1];

			if (type_id != atp->atttypid)
			{
1968 1969
				if (CoerceTargetExpr(NULL, expr, type_id,
									 atp->atttypid, atp->atttypmod) == NULL)
1970 1971 1972
					elog(ERROR, "Attribute '%s' is of type '%s'"
						 " but default expression is of type '%s'"
						 "\n\tYou will need to rewrite or cast the expression",
1973
						 NameStr(atp->attname),
1974 1975 1976 1977
						 typeidTypeName(atp->atttypid),
						 typeidTypeName(type_id));
			}
		}
1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989
		/*
		 * Might as well try to reduce any constant expressions.
		 */
		expr = eval_const_expressions(expr);
		/*
		 * Must fix opids, in case any operators remain...
		 */
		fix_opids(expr);
		/*
		 * OK, store it.
		 */
		StoreAttrDefault(rel, colDef->attnum, nodeToString(expr), true);
1990 1991
	}

1992 1993 1994 1995 1996
	/*
	 * Process constraint expressions.
	 */
	numchecks = numoldchecks;
	foreach(listptr, rawConstraints)
1997
	{
1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043
		Constraint *cdef = (Constraint *) lfirst(listptr);
		char	   *ccname;
		Node	   *expr;

		if (cdef->contype != CONSTR_CHECK || cdef->raw_expr == NULL)
			continue;
		Assert(cdef->cooked_expr == NULL);

		/* Check name uniqueness, or generate a new name */
		if (cdef->name != NULL)
		{
			int			i;
			List	   *listptr2;

			ccname = cdef->name;
			/* Check against old constraints */
			for (i = 0; i < numoldchecks; i++)
			{
				if (strcmp(oldchecks[i].ccname, ccname) == 0)
					elog(ERROR, "Duplicate CHECK constraint name: '%s'",
						 ccname);
			}
			/* Check against other new constraints */
			foreach(listptr2, rawConstraints)
			{
				Constraint *cdef2 = (Constraint *) lfirst(listptr2);

				if (cdef2 == cdef ||
					cdef2->contype != CONSTR_CHECK ||
					cdef2->raw_expr == NULL ||
					cdef2->name == NULL)
					continue;
				if (strcmp(cdef2->name, ccname) == 0)
					elog(ERROR, "Duplicate CHECK constraint name: '%s'",
						 ccname);
			}
		}
		else
		{
			ccname = (char *) palloc(NAMEDATALEN);
			snprintf(ccname, NAMEDATALEN, "$%d", numchecks + 1);
		}
		/*
		 * Transform raw parsetree to executable expression.
		 */
		expr = transformExpr(pstate, cdef->raw_expr, EXPR_COLUMN_FIRST);
2044 2045 2046 2047 2048 2049
		/*
		 * Make sure it yields a boolean result.
		 */
		if (exprType(expr) != BOOLOID)
			elog(ERROR, "CHECK '%s' does not yield boolean result",
				 ccname);
2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076
		/*
		 * Make sure no outside relations are referred to.
		 */
		if (length(pstate->p_rtable) != 1)
			elog(ERROR, "Only relation '%s' can be referenced in CHECK",
				 relname);
		/*
		 * Might as well try to reduce any constant expressions.
		 */
		expr = eval_const_expressions(expr);
		/*
		 * Constraints are evaluated with execQual, which expects an
		 * implicit-AND list, so convert expression to implicit-AND form.
		 * (We could go so far as to convert to CNF, but that's probably
		 * overkill...)
		 */
		expr = (Node *) make_ands_implicit((Expr *) expr);
		/*
		 * Must fix opids in operator clauses.
		 */
		fix_opids(expr);
		/*
		 * OK, store it.
		 */
		StoreRelCheck(rel, ccname, nodeToString(expr));

		numchecks++;
2077 2078
	}

2079 2080 2081 2082 2083 2084 2085 2086 2087 2088
	/*
	 * Update the count of constraints in the relation's pg_class tuple.
	 * We do this even if there was no change, in order to ensure that an
	 * SI update message is sent out for the pg_class tuple, which will
	 * force other backends to rebuild their relcache entries for the rel.
	 * (Of course, for a newly created rel there is no need for an SI message,
	 * but for ALTER TABLE ADD ATTRIBUTE this'd be important.)
	 */
	relrel = heap_openr(RelationRelationName, RowExclusiveLock);
	reltup = SearchSysCacheTupleCopy(RELOID,
2089
									 ObjectIdGetDatum(RelationGetRelid(rel)),
2090 2091
									 0, 0, 0);
	if (!HeapTupleIsValid(reltup))
2092
		elog(ERROR, "cache lookup of relation %u failed", RelationGetRelid(rel));
2093 2094 2095 2096
	relStruct = (Form_pg_class) GETSTRUCT(reltup);

	relStruct->relchecks = numchecks;

2097
	heap_update(relrel, &reltup->t_self, reltup, NULL);
2098 2099 2100 2101 2102 2103 2104 2105

	/* keep catalog indices current */
	CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
					   relidescs);
	CatalogIndexInsert(relidescs, Num_pg_class_indices, relrel, reltup);
	CatalogCloseIndices(Num_pg_class_indices, relidescs);

	heap_close(relrel, RowExclusiveLock);
2106
	heap_freetuple(reltup);
2107 2108
}

2109 2110
static void
RemoveAttrDefault(Relation rel)
2111
{
2112 2113 2114 2115
	Relation	adrel;
	HeapScanDesc adscan;
	ScanKeyData key;
	HeapTuple	tup;
2116

2117
	adrel = heap_openr(AttrDefaultRelationName, RowExclusiveLock);
2118 2119

	ScanKeyEntryInitialize(&key, 0, Anum_pg_attrdef_adrelid,
2120
						   F_OIDEQ, RelationGetRelid(rel));
2121

2122
	adscan = heap_beginscan(adrel, 0, SnapshotNow, 1, &key);
2123

2124
	while (HeapTupleIsValid(tup = heap_getnext(adscan, 0)))
V
Vadim B. Mikheev 已提交
2125
		heap_delete(adrel, &tup->t_self, NULL);
2126 2127

	heap_endscan(adscan);
2128
	heap_close(adrel, RowExclusiveLock);
2129 2130
}

2131 2132
static void
RemoveRelCheck(Relation rel)
2133
{
2134 2135 2136 2137
	Relation	rcrel;
	HeapScanDesc rcscan;
	ScanKeyData key;
	HeapTuple	tup;
2138

2139
	rcrel = heap_openr(RelCheckRelationName, RowExclusiveLock);
2140 2141

	ScanKeyEntryInitialize(&key, 0, Anum_pg_relcheck_rcrelid,
2142
						   F_OIDEQ, RelationGetRelid(rel));
2143

2144
	rcscan = heap_beginscan(rcrel, 0, SnapshotNow, 1, &key);
2145

2146
	while (HeapTupleIsValid(tup = heap_getnext(rcscan, 0)))
V
Vadim B. Mikheev 已提交
2147
		heap_delete(rcrel, &tup->t_self, NULL);
2148 2149

	heap_endscan(rcscan);
2150
	heap_close(rcrel, RowExclusiveLock);
2151
}
2152

2153 2154
static void
RemoveConstraints(Relation rel)
2155
{
2156
	TupleConstr *constr = rel->rd_att->constr;
2157 2158 2159 2160 2161 2162 2163 2164 2165

	if (!constr)
		return;

	if (constr->num_defval > 0)
		RemoveAttrDefault(rel);

	if (constr->num_check > 0)
		RemoveRelCheck(rel);
2166
}
2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188

static void
RemoveStatistics(Relation rel)
{
	Relation	pgstatistic;
	HeapScanDesc scan;
	ScanKeyData key;
	HeapTuple	tuple;

	pgstatistic = heap_openr(StatisticRelationName, RowExclusiveLock);

	ScanKeyEntryInitialize(&key, 0x0, Anum_pg_statistic_starelid,
						   F_OIDEQ,
						   ObjectIdGetDatum(RelationGetRelid(rel)));
	scan = heap_beginscan(pgstatistic, false, SnapshotNow, 1, &key);

	while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
		heap_delete(pgstatistic, &tuple->t_self, NULL);

	heap_endscan(scan);
	heap_close(pgstatistic, RowExclusiveLock);
}