plancat.c 21.1 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * plancat.c
4
 *	   routines for accessing the system catalogs
5 6
 *
 *
P
 
PostgreSQL Daemon 已提交
7
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
8
 * Portions Copyright (c) 1994, Regents of the University of California
9 10 11
 *
 *
 * IDENTIFICATION
12
 *	  $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.116 2006/01/05 10:07:45 petere Exp $
13 14 15
 *
 *-------------------------------------------------------------------------
 */
16
#include "postgres.h"
17

18 19
#include <math.h>

B
Bruce Momjian 已提交
20 21
#include "access/genam.h"
#include "access/heapam.h"
22 23
#include "catalog/pg_amop.h"
#include "catalog/pg_inherits.h"
B
Bruce Momjian 已提交
24
#include "catalog/pg_index.h"
25
#include "nodes/makefuncs.h"
26
#include "optimizer/clauses.h"
27
#include "optimizer/plancat.h"
28
#include "optimizer/prep.h"
29
#include "optimizer/tlist.h"
30
#include "parser/parsetree.h"
31
#include "parser/parse_expr.h"
32
#include "parser/parse_relation.h"
33
#include "rewrite/rewriteManip.h"
34 35
#include "utils/builtins.h"
#include "utils/fmgroids.h"
36
#include "utils/lsyscache.h"
37
#include "utils/relcache.h"
38
#include "utils/syscache.h"
H
Hiroshi Inoue 已提交
39 40
#include "catalog/catalog.h"
#include "miscadmin.h"
41 42


43
static void estimate_rel_size(Relation rel, int32 *attr_widths,
B
Bruce Momjian 已提交
44
				  BlockNumber *pages, double *tuples);
45 46


47
/*
48
 * get_relation_info -
49
 *	  Retrieves catalog information for a given relation.
50 51 52 53
 *
 * Given the Oid of the relation, return the following info into fields
 * of the RelOptInfo struct:
 *
54 55
 *	min_attr	lowest valid AttrNumber
 *	max_attr	highest valid AttrNumber
56 57 58
 *	indexlist	list of IndexOptInfos for relation's indexes
 *	pages		number of pages
 *	tuples		number of tuples
59 60 61 62
 *
 * Also, initialize the attr_needed[] and attr_widths[] arrays.  In most
 * cases these are left as zeroes, but sometimes we need to compute attr
 * widths here, and we may as well cache the results for costsize.c.
63 64
 */
void
65
get_relation_info(Oid relationObjectId, RelOptInfo *rel)
66
{
67
	Index		varno = rel->relid;
68
	Relation	relation;
69 70
	bool		hasindex;
	List	   *indexinfos = NIL;
71

72 73
	/*
	 * Normally, we can assume the rewriter already acquired at least
B
Bruce Momjian 已提交
74 75 76 77 78
	 * AccessShareLock on each relation used in the query.	However this will
	 * not be the case for relations added to the query because they are
	 * inheritance children of some relation mentioned explicitly. For them,
	 * this is the first access during the parse/rewrite/plan pipeline, and so
	 * we need to obtain and keep a suitable lock.
79
	 *
B
Bruce Momjian 已提交
80 81 82 83 84 85
	 * XXX really, a suitable lock is RowShareLock if the relation is an
	 * UPDATE/DELETE target, and AccessShareLock otherwise.  However we cannot
	 * easily tell here which to get, so for the moment just get
	 * AccessShareLock always.	The executor will get the right lock when it
	 * runs, which means there is a very small chance of deadlock trying to
	 * upgrade our lock.
86 87 88 89 90
	 */
	if (rel->reloptkind == RELOPT_BASEREL)
		relation = heap_open(relationObjectId, NoLock);
	else
		relation = heap_open(relationObjectId, AccessShareLock);
91

92 93
	rel->min_attr = FirstLowInvalidHeapAttributeNumber + 1;
	rel->max_attr = RelationGetNumberOfAttributes(relation);
94

95 96 97 98 99 100 101 102 103 104 105 106
	Assert(rel->max_attr >= rel->min_attr);
	rel->attr_needed = (Relids *)
		palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(Relids));
	rel->attr_widths = (int32 *)
		palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(int32));

	/*
	 * Estimate relation size.
	 */
	estimate_rel_size(relation, rel->attr_widths - rel->min_attr,
					  &rel->pages, &rel->tuples);

107
	/*
B
Bruce Momjian 已提交
108
	 * Make list of indexes.  Ignore indexes on system catalogs if told to.
109
	 */
110
	if (IgnoreSystemIndexes && IsSystemClass(relation->rd_rel))
111 112 113
		hasindex = false;
	else
		hasindex = relation->rd_rel->relhasindex;
114

115
	if (hasindex)
116
	{
117 118
		List	   *indexoidlist;
		ListCell   *l;
119

120
		indexoidlist = RelationGetIndexList(relation);
121

122
		foreach(l, indexoidlist)
123
		{
124
			Oid			indexoid = lfirst_oid(l);
125 126 127
			Relation	indexRelation;
			Form_pg_index index;
			IndexOptInfo *info;
128
			int			ncolumns;
129 130 131
			int			i;
			int16		amorderstrategy;

132 133 134
			/*
			 * Extract info from the relation descriptor for the index.
			 *
135 136 137 138
			 * Note that we take no lock on the index; we assume our lock on
			 * the parent table will protect the index's schema information.
			 * When and if the executor actually uses the index, it will take
			 * a lock as needed to protect the access to the index contents.
139
			 */
140
			indexRelation = index_open(indexoid);
141
			index = indexRelation->rd_index;
142 143 144 145

			info = makeNode(IndexOptInfo);

			info->indexoid = index->indexrelid;
146
			info->rel = rel;
147
			info->ncolumns = ncolumns = index->indnatts;
148

149
			/*
B
Bruce Momjian 已提交
150 151
			 * Need to make classlist and ordering arrays large enough to put
			 * a terminating 0 at the end of each one.
152 153 154 155
			 */
			info->indexkeys = (int *) palloc(sizeof(int) * ncolumns);
			info->classlist = (Oid *) palloc0(sizeof(Oid) * (ncolumns + 1));
			info->ordering = (Oid *) palloc0(sizeof(Oid) * (ncolumns + 1));
156

157
			for (i = 0; i < ncolumns; i++)
158
			{
159 160
				info->classlist[i] = indexRelation->rd_indclass->values[i];
				info->indexkeys[i] = index->indkey.values[i];
161 162 163
			}

			info->relam = indexRelation->rd_rel->relam;
164 165
			info->amcostestimate = indexRelation->rd_am->amcostestimate;
			info->amoptionalkey = indexRelation->rd_am->amoptionalkey;
166 167

			/*
B
Bruce Momjian 已提交
168
			 * Fetch the ordering operators associated with the index, if any.
169
			 */
170
			amorderstrategy = indexRelation->rd_am->amorderstrategy;
171 172 173 174
			if (amorderstrategy != 0)
			{
				int			oprindex = amorderstrategy - 1;

175
				for (i = 0; i < ncolumns; i++)
176 177 178 179 180
				{
					info->ordering[i] = indexRelation->rd_operator[oprindex];
					oprindex += indexRelation->rd_am->amstrategies;
				}
			}
181

182 183 184
			/*
			 * Fetch the index expressions and predicate, if any.  We must
			 * modify the copies we obtain from the relcache to have the
B
Bruce Momjian 已提交
185 186
			 * correct varno for the parent relation, so that they match up
			 * correctly against qual clauses.
187 188 189 190 191 192 193
			 */
			info->indexprs = RelationGetIndexExpressions(indexRelation);
			info->indpred = RelationGetIndexPredicate(indexRelation);
			if (info->indexprs && varno != 1)
				ChangeVarNodes((Node *) info->indexprs, 1, varno, 0);
			if (info->indpred && varno != 1)
				ChangeVarNodes((Node *) info->indpred, 1, varno, 0);
B
Bruce Momjian 已提交
194
			info->predOK = false;		/* set later in indxpath.c */
195 196
			info->unique = index->indisunique;

197
			/*
B
Bruce Momjian 已提交
198 199 200 201 202
			 * Estimate the index size.  If it's not a partial index, we lock
			 * the number-of-tuples estimate to equal the parent table; if it
			 * is partial then we have to use the same methods as we would for
			 * a table, except we can be sure that the index is not larger
			 * than the table.
203 204 205 206 207 208 209 210 211 212 213 214 215 216
			 */
			if (info->indpred == NIL)
			{
				info->pages = RelationGetNumberOfBlocks(indexRelation);
				info->tuples = rel->tuples;
			}
			else
			{
				estimate_rel_size(indexRelation, NULL,
								  &info->pages, &info->tuples);
				if (info->tuples > rel->tuples)
					info->tuples = rel->tuples;
			}

217 218 219 220 221
			index_close(indexRelation);

			indexinfos = lcons(info, indexinfos);
		}

222
		list_free(indexoidlist);
223
	}
224

225 226
	rel->indexlist = indexinfos;

227 228
	/* close rel, but keep lock if any */
	heap_close(relation, NoLock);
229 230
}

231 232 233 234 235 236 237 238 239 240 241
/*
 * estimate_rel_size - estimate # pages and # tuples in a table or index
 *
 * If attr_widths isn't NULL, it points to the zero-index entry of the
 * relation's attr_width[] cache; we fill this in if we have need to compute
 * the attribute widths for estimation purposes.
 */
static void
estimate_rel_size(Relation rel, int32 *attr_widths,
				  BlockNumber *pages, double *tuples)
{
B
Bruce Momjian 已提交
242 243
	BlockNumber curpages;
	BlockNumber relpages;
244 245 246 247 248 249 250 251 252
	double		reltuples;
	double		density;

	switch (rel->rd_rel->relkind)
	{
		case RELKIND_RELATION:
		case RELKIND_INDEX:
		case RELKIND_TOASTVALUE:
			/* it has storage, ok to call the smgr */
253 254 255 256
			curpages = RelationGetNumberOfBlocks(rel);

			/*
			 * HACK: if the relation has never yet been vacuumed, use a
B
Bruce Momjian 已提交
257 258 259 260 261 262 263 264 265 266
			 * minimum estimate of 10 pages.  This emulates a desirable aspect
			 * of pre-8.0 behavior, which is that we wouldn't assume a newly
			 * created relation is really small, which saves us from making
			 * really bad plans during initial data loading.  (The plans are
			 * not wrong when they are made, but if they are cached and used
			 * again after the table has grown a lot, they are bad.) It would
			 * be better to force replanning if the table size has changed a
			 * lot since the plan was made ... but we don't currently have any
			 * infrastructure for redoing cached plans at all, so we have to
			 * kluge things here instead.
267
			 *
268 269 270 271 272
			 * We approximate "never vacuumed" by "has relpages = 0", which
			 * means this will also fire on genuinely empty relations.	Not
			 * great, but fortunately that's a seldom-seen case in the real
			 * world, and it shouldn't degrade the quality of the plan too
			 * much anyway to err in this direction.
273 274 275 276 277 278
			 */
			if (curpages < 10 && rel->rd_rel->relpages == 0)
				curpages = 10;

			/* report estimated # pages */
			*pages = curpages;
279 280 281 282 283 284 285 286 287
			/* quick exit if rel is clearly empty */
			if (curpages == 0)
			{
				*tuples = 0;
				break;
			}
			/* coerce values in pg_class to more desirable types */
			relpages = (BlockNumber) rel->rd_rel->relpages;
			reltuples = (double) rel->rd_rel->reltuples;
B
Bruce Momjian 已提交
288

289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
			/*
			 * If it's an index, discount the metapage.  This is a kluge
			 * because it assumes more than it ought to about index contents;
			 * it's reasonably OK for btrees but a bit suspect otherwise.
			 */
			if (rel->rd_rel->relkind == RELKIND_INDEX &&
				relpages > 0)
			{
				curpages--;
				relpages--;
			}
			/* estimate number of tuples from previous tuple density */
			if (relpages > 0)
				density = reltuples / (double) relpages;
			else
			{
				/*
				 * When we have no data because the relation was truncated,
				 * estimate tuple width from attribute datatypes.  We assume
				 * here that the pages are completely full, which is OK for
B
Bruce Momjian 已提交
309 310
				 * tables (since they've presumably not been VACUUMed yet) but
				 * is probably an overestimate for indexes.  Fortunately
311 312
				 * get_relation_info() can clamp the overestimate to the
				 * parent table's size.
313 314
				 *
				 * Note: this code intentionally disregards alignment
B
Bruce Momjian 已提交
315 316 317 318
				 * considerations, because (a) that would be gilding the lily
				 * considering how crude the estimate is, and (b) it creates
				 * platform dependencies in the default plans which are kind
				 * of a headache for regression testing.
319
				 */
B
Bruce Momjian 已提交
320 321
				int32		tuple_width = 0;
				int			i;
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341

				for (i = 1; i <= RelationGetNumberOfAttributes(rel); i++)
				{
					Form_pg_attribute att = rel->rd_att->attrs[i - 1];
					int32		item_width;

					if (att->attisdropped)
						continue;
					/* This should match set_rel_width() in costsize.c */
					item_width = get_attavgwidth(RelationGetRelid(rel), i);
					if (item_width <= 0)
					{
						item_width = get_typavgwidth(att->atttypid,
													 att->atttypmod);
						Assert(item_width > 0);
					}
					if (attr_widths != NULL)
						attr_widths[i] = item_width;
					tuple_width += item_width;
				}
342
				tuple_width += sizeof(HeapTupleHeaderData);
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
				tuple_width += sizeof(ItemPointerData);
				/* note: integer division is intentional here */
				density = (BLCKSZ - sizeof(PageHeaderData)) / tuple_width;
			}
			*tuples = rint(density * (double) curpages);
			break;
		case RELKIND_SEQUENCE:
			/* Sequences always have a known size */
			*pages = 1;
			*tuples = 1;
			break;
		default:
			/* else it has no disk storage; probably shouldn't get here? */
			*pages = 0;
			*tuples = 0;
			break;
	}
}

362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392

/*
 * get_relation_constraints
 *
 * Retrieve the CHECK constraint expressions of the given relation.
 *
 * Returns a List (possibly empty) of constraint expressions.  Each one
 * has been canonicalized, and its Vars are changed to have the varno
 * indicated by rel->relid.  This allows the expressions to be easily
 * compared to expressions taken from WHERE.
 *
 * Note: at present this is invoked at most once per relation per planner
 * run, and in many cases it won't be invoked at all, so there seems no
 * point in caching the data in RelOptInfo.
 */
List *
get_relation_constraints(Oid relationObjectId, RelOptInfo *rel)
{
	List	   *result = NIL;
	Index		varno = rel->relid;
	Relation	relation;
	TupleConstr *constr;

	/*
	 * We assume the relation has already been safely locked.
	 */
	relation = heap_open(relationObjectId, NoLock);

	constr = relation->rd_att->constr;
	if (constr != NULL)
	{
B
Bruce Momjian 已提交
393 394
		int			num_check = constr->num_check;
		int			i;
395 396 397

		for (i = 0; i < num_check; i++)
		{
B
Bruce Momjian 已提交
398
			Node	   *cexpr;
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426

			cexpr = stringToNode(constr->check[i].ccbin);

			/*
			 * Run each expression through const-simplification and
			 * canonicalization.  This is not just an optimization, but is
			 * necessary, because we will be comparing it to
			 * similarly-processed qual clauses, and may fail to detect valid
			 * matches without this.  This must match the processing done to
			 * qual clauses in preprocess_expression()!  (We can skip the
			 * stuff involving subqueries, however, since we don't allow any
			 * in check constraints.)
			 */
			cexpr = eval_const_expressions(cexpr);

			cexpr = (Node *) canonicalize_qual((Expr *) cexpr);

			/*
			 * Also mark any coercion format fields as "don't care", so that
			 * we can match to both explicit and implicit coercions.
			 */
			set_coercionform_dontcare(cexpr);

			/* Fix Vars to have the desired varno */
			if (varno != 1)
				ChangeVarNodes(cexpr, 1, varno, 0);

			/*
B
Bruce Momjian 已提交
427 428
			 * Finally, convert to implicit-AND format (that is, a List) and
			 * append the resulting item(s) to our output list.
429 430 431 432 433 434 435 436 437 438 439 440
			 */
			result = list_concat(result,
								 make_ands_implicit((Expr *) cexpr));
		}
	}

	heap_close(relation, NoLock);

	return result;
}


441 442 443 444 445 446 447 448 449 450
/*
 * build_physical_tlist
 *
 * Build a targetlist consisting of exactly the relation's user attributes,
 * in order.  The executor can special-case such tlists to avoid a projection
 * step at runtime, so we use such tlists preferentially for scan nodes.
 *
 * Exception: if there are any dropped columns, we punt and return NIL.
 * Ideally we would like to handle the dropped-column case too.  However this
 * creates problems for ExecTypeFromTL, which may be asked to build a tupdesc
B
Bruce Momjian 已提交
451
 * for a tlist that includes vars of no-longer-existent types.	In theory we
452 453 454 455
 * could dig out the required info from the pg_attribute entries of the
 * relation, but that data is not readily available to ExecTypeFromTL.
 * For now, we don't apply the physical-tlist optimization when there are
 * dropped cols.
456
 *
457 458 459
 * We also support building a "physical" tlist for subqueries and functions,
 * since the same optimization can occur in SubqueryScan and FunctionScan
 * nodes.
460 461
 */
List *
462
build_physical_tlist(PlannerInfo *root, RelOptInfo *rel)
463
{
464
	List	   *tlist = NIL;
465
	Index		varno = rel->relid;
466
	RangeTblEntry *rte = rt_fetch(varno, root->parse->rtable);
467
	Relation	relation;
468 469 470
	Query	   *subquery;
	Var		   *var;
	ListCell   *l;
471 472
	int			attrno,
				numattrs;
473
	List	   *colvars;
474

475 476 477
	switch (rte->rtekind)
	{
		case RTE_RELATION:
478 479
			/* Assume we already have adequate lock */
			relation = heap_open(rte->relid, NoLock);
480

481 482 483 484
			numattrs = RelationGetNumberOfAttributes(relation);
			for (attrno = 1; attrno <= numattrs; attrno++)
			{
				Form_pg_attribute att_tup = relation->rd_att->attrs[attrno - 1];
485

486 487 488 489 490 491
				if (att_tup->attisdropped)
				{
					/* found a dropped col, so punt */
					tlist = NIL;
					break;
				}
492

493 494 495 496 497 498 499 500 501 502 503 504
				var = makeVar(varno,
							  attrno,
							  att_tup->atttypid,
							  att_tup->atttypmod,
							  0);

				tlist = lappend(tlist,
								makeTargetEntry((Expr *) var,
												attrno,
												NULL,
												false));
			}
505

506
			heap_close(relation, NoLock);
507 508
			break;

509 510 511 512 513 514
		case RTE_SUBQUERY:
			subquery = rte->subquery;
			foreach(l, subquery->targetList)
			{
				TargetEntry *tle = (TargetEntry *) lfirst(l);

515 516 517 518
				/*
				 * A resjunk column of the subquery can be reflected as
				 * resjunk in the physical tlist; we need not punt.
				 */
519 520 521 522 523 524 525 526 527 528 529 530 531
				var = makeVar(varno,
							  tle->resno,
							  exprType((Node *) tle->expr),
							  exprTypmod((Node *) tle->expr),
							  0);

				tlist = lappend(tlist,
								makeTargetEntry((Expr *) var,
												tle->resno,
												NULL,
												tle->resjunk));
			}
			break;
532

533
		case RTE_FUNCTION:
B
Bruce Momjian 已提交
534
			expandRTE(rte, varno, 0, true /* include dropped */ ,
535 536 537 538
					  NULL, &colvars);
			foreach(l, colvars)
			{
				var = (Var *) lfirst(l);
B
Bruce Momjian 已提交
539

540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
				/*
				 * A non-Var in expandRTE's output means a dropped column;
				 * must punt.
				 */
				if (!IsA(var, Var))
				{
					tlist = NIL;
					break;
				}

				tlist = lappend(tlist,
								makeTargetEntry((Expr *) var,
												var->varattno,
												NULL,
												false));
			}
			break;

558 559 560 561 562 563
		default:
			/* caller error */
			elog(ERROR, "unsupported RTE kind %d in build_physical_tlist",
				 (int) rte->rtekind);
			break;
	}
564

565
	return tlist;
566 567
}

568
/*
569
 * restriction_selectivity
570
 *
571
 * Returns the selectivity of a specified restriction operator clause.
572 573 574
 * This code executes registered procedures stored in the
 * operator relation, by calling the function manager.
 *
575
 * See clause_selectivity() for the meaning of the additional parameters.
576
 */
577
Selectivity
578
restriction_selectivity(PlannerInfo *root,
579 580 581
						Oid operator,
						List *args,
						int varRelid)
582
{
583
	RegProcedure oprrest = get_oprrest(operator);
584 585
	float8		result;

586
	/*
587 588
	 * if the oprrest procedure is missing for whatever reason, use a
	 * selectivity of 0.5
589 590 591 592 593 594 595 596 597
	 */
	if (!oprrest)
		return (Selectivity) 0.5;

	result = DatumGetFloat8(OidFunctionCall4(oprrest,
											 PointerGetDatum(root),
											 ObjectIdGetDatum(operator),
											 PointerGetDatum(args),
											 Int32GetDatum(varRelid)));
598 599

	if (result < 0.0 || result > 1.0)
600
		elog(ERROR, "invalid restriction selectivity: %f", result);
601 602

	return (Selectivity) result;
603 604 605
}

/*
606
 * join_selectivity
607
 *
608 609 610
 * Returns the selectivity of a specified join operator clause.
 * This code executes registered procedures stored in the
 * operator relation, by calling the function manager.
611
 */
612
Selectivity
613
join_selectivity(PlannerInfo *root,
614
				 Oid operator,
615 616
				 List *args,
				 JoinType jointype)
617
{
618
	RegProcedure oprjoin = get_oprjoin(operator);
619 620
	float8		result;

621
	/*
622 623
	 * if the oprjoin procedure is missing for whatever reason, use a
	 * selectivity of 0.5
624 625 626 627
	 */
	if (!oprjoin)
		return (Selectivity) 0.5;

628
	result = DatumGetFloat8(OidFunctionCall4(oprjoin,
629 630
											 PointerGetDatum(root),
											 ObjectIdGetDatum(operator),
631 632
											 PointerGetDatum(args),
											 Int16GetDatum(jointype)));
633 634

	if (result < 0.0 || result > 1.0)
635
		elog(ERROR, "invalid join selectivity: %f", result);
636 637

	return (Selectivity) result;
638 639 640
}

/*
641
 * find_inheritance_children
642
 *
643
 * Returns a list containing the OIDs of all relations which
644
 * inherit *directly* from the relation with OID 'inhparent'.
645 646 647 648 649
 *
 * XXX might be a good idea to create an index on pg_inherits' inhparent
 * field, so that we can use an indexscan instead of sequential scan here.
 * However, in typical databases pg_inherits won't have enough entries to
 * justify an indexscan...
650
 */
651
List *
652 653
find_inheritance_children(Oid inhparent)
{
654
	List	   *list = NIL;
655 656
	Relation	relation;
	HeapScanDesc scan;
657
	HeapTuple	inheritsTuple;
658
	Oid			inhrelid;
B
Bruce Momjian 已提交
659
	ScanKeyData key[1];
660

661
	/*
B
Bruce Momjian 已提交
662 663
	 * Can skip the scan if pg_class shows the relation has never had a
	 * subclass.
664
	 */
B
Bruce Momjian 已提交
665
	if (!has_subclass(inhparent))
666 667
		return NIL;

668 669 670 671
	ScanKeyInit(&key[0],
				Anum_pg_inherits_inhparent,
				BTEqualStrategyNumber, F_OIDEQ,
				ObjectIdGetDatum(inhparent));
672
	relation = heap_open(InheritsRelationId, AccessShareLock);
673 674
	scan = heap_beginscan(relation, SnapshotNow, 1, key);
	while ((inheritsTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
675
	{
676
		inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid;
677
		list = lappend_oid(list, inhrelid);
678 679
	}
	heap_endscan(scan);
680
	heap_close(relation, AccessShareLock);
681
	return list;
682 683
}

684
/*
685 686
 * has_subclass
 *
B
Bruce Momjian 已提交
687
 * In the current implementation, has_subclass returns whether a
688 689
 * particular class *might* have a subclass. It will not return the
 * correct result if a class had a subclass which was later dropped.
690 691 692 693 694
 * This is because relhassubclass in pg_class is not updated when a
 * subclass is dropped, primarily because of concurrency concerns.
 *
 * Currently has_subclass is only used as an efficiency hack to skip
 * unnecessary inheritance searches, so this is OK.
695
 */
696 697
bool
has_subclass(Oid relationId)
698
{
699 700
	HeapTuple	tuple;
	bool		result;
701

702 703 704
	tuple = SearchSysCache(RELOID,
						   ObjectIdGetDatum(relationId),
						   0, 0, 0);
705
	if (!HeapTupleIsValid(tuple))
706
		elog(ERROR, "cache lookup failed for relation %u", relationId);
707 708 709 710

	result = ((Form_pg_class) GETSTRUCT(tuple))->relhassubclass;
	ReleaseSysCache(tuple);
	return result;
711
}
712 713 714 715 716 717 718 719 720 721 722

/*
 * has_unique_index
 *
 * Detect whether there is a unique index on the specified attribute
 * of the specified relation, thus allowing us to conclude that all
 * the (non-null) values of the attribute are distinct.
 */
bool
has_unique_index(RelOptInfo *rel, AttrNumber attno)
{
723
	ListCell   *ilist;
724 725 726 727 728 729

	foreach(ilist, rel->indexlist)
	{
		IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);

		/*
B
Bruce Momjian 已提交
730 731 732 733 734
		 * Note: ignore partial indexes, since they don't allow us to conclude
		 * that all attr values are distinct.  We don't take any interest in
		 * expressional indexes either. Also, a multicolumn unique index
		 * doesn't allow us to conclude that just the specified attr is
		 * unique.
735 736
		 */
		if (index->unique &&
737
			index->ncolumns == 1 &&
738
			index->indexkeys[0] == attno &&
739
			index->indpred == NIL)
740 741 742 743
			return true;
	}
	return false;
}