plancat.c 8.7 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * plancat.c
4
 *	   routines for accessing the system catalogs
5 6 7 8 9 10
 *
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
11
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.45 2000/01/22 23:50:17 tgl Exp $
12 13 14
 *
 *-------------------------------------------------------------------------
 */
B
Bruce Momjian 已提交
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 24
#include "catalog/catname.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_inherits.h"
25
#include "optimizer/clauses.h"
26
#include "optimizer/internal.h"
27
#include "optimizer/paths.h"
28
#include "optimizer/plancat.h"
B
Bruce Momjian 已提交
29
#include "parser/parsetree.h"
30 31 32 33
#include "utils/syscache.h"


/*
34
 * relation_info -
35 36
 *	  Retrieves catalog information for a given relation.
 *	  Given the rangetable index of the relation, return the following info:
37 38 39
 *				whether the relation has secondary indices
 *				number of pages
 *				number of tuples
40 41
 */
void
42
relation_info(Query *root, Index relid,
43
			  bool *hasindex, long *pages, double *tuples)
44
{
45
	Oid			relationObjectId = getrelid(relid, root->rtable);
46 47
	HeapTuple	relationTuple;
	Form_pg_class relation;
48 49

	relationTuple = SearchSysCacheTuple(RELOID,
50
										ObjectIdGetDatum(relationObjectId),
51
										0, 0, 0);
52
	if (!HeapTupleIsValid(relationTuple))
53
		elog(ERROR, "relation_info: Relation %u not found",
54
			 relationObjectId);
55 56 57 58 59
	relation = (Form_pg_class) GETSTRUCT(relationTuple);

	*hasindex = (relation->relhasindex) ? true : false;
	*pages = relation->relpages;
	*tuples = relation->reltuples;
60 61
}

62
/*
63
 * find_secondary_indexes
64
 *	  Creates a list of IndexOptInfo nodes containing information for each
65
 *	  secondary index defined on the given relation.
66
 *
67
 * 'relid' is the RT index of the relation for which indices are being located
68
 *
69
 * Returns a list of new IndexOptInfo nodes.
70
 */
71 72
List *
find_secondary_indexes(Query *root, Index relid)
73
{
74 75 76 77 78 79
	List	   *indexes = NIL;
	Oid			indrelid = getrelid(relid, root->rtable);
	Relation	relation;
	HeapScanDesc scan;
	ScanKeyData	indexKey;
	HeapTuple	indexTuple;
80

81 82
	/* Scan pg_index for tuples describing indexes of this rel */
	relation = heap_openr(IndexRelationName, AccessShareLock);
83

84 85 86 87
	ScanKeyEntryInitialize(&indexKey, 0,
						   Anum_pg_index_indrelid,
						   F_OIDEQ,
						   ObjectIdGetDatum(indrelid));
88

89 90 91 92
	scan = heap_beginscan(relation, 0, SnapshotNow,
						  1, &indexKey);

	while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
93
	{
94
		Form_pg_index	index = (Form_pg_index) GETSTRUCT(indexTuple);
95
		IndexOptInfo   *info = makeNode(IndexOptInfo);
96 97 98 99
		int				i;
		Relation		indexRelation;
		uint16			amstrategy;
		Oid				relam;
100 101

		/*
102 103
		 * Need to make these arrays large enough to be sure there is a
		 * terminating 0 at the end of each one.
104
		 */
105 106 107 108 109
		info->classlist = (Oid *) palloc(sizeof(Oid) * (INDEX_MAX_KEYS+1));
		info->indexkeys = (int *) palloc(sizeof(int) * (INDEX_MAX_KEYS+1));
		info->ordering = (Oid *) palloc(sizeof(Oid) * (INDEX_MAX_KEYS+1));

		/* Extract info from the pg_index tuple */
110
		info->indexoid = index->indexrelid;
111 112 113 114 115 116 117 118 119
		info->indproc = index->indproc;		/* functional index ?? */
		if (VARSIZE(&index->indpred) != 0)	/* partial index ?? */
		{
			char	   *predString = fmgr(F_TEXTOUT, &index->indpred);
			info->indpred = (List *) stringToNode(predString);
			pfree(predString);
		}
		else
			info->indpred = NIL;
120

121 122
		for (i = 0; i < INDEX_MAX_KEYS; i++)
			info->indexkeys[i] = index->indkey[i];
123
		info->indexkeys[INDEX_MAX_KEYS] = 0;
124 125
		for (i = 0; i < INDEX_MAX_KEYS; i++)
			info->classlist[i] = index->indclass[i];
126
		info->classlist[INDEX_MAX_KEYS] = (Oid) 0;
127

128 129
		/* Extract info from the relation descriptor for the index */
		indexRelation = index_open(index->indexrelid);
130
#ifdef notdef
131 132
		/* XXX should iterate through strategies -- but how?  use #1 for now */
		amstrategy = indexRelation->rd_am->amstrategies;
133
#endif	 /* notdef */
134 135 136 137 138
		amstrategy = 1;
		relam = indexRelation->rd_rel->relam;
		info->relam = relam;
		info->pages = indexRelation->rd_rel->relpages;
		info->tuples = indexRelation->rd_rel->reltuples;
139
		info->amcostestimate = index_cost_estimator(indexRelation);
140 141 142 143 144 145 146 147 148 149 150 151 152
		index_close(indexRelation);

		/*
		 * Fetch the ordering operators associated with the index.
		 *
		 * XXX what if it's a hash or other unordered index?
		 */
		MemSet(info->ordering, 0, sizeof(Oid) * (INDEX_MAX_KEYS+1));
		for (i = 0; i < INDEX_MAX_KEYS && index->indclass[i]; i++)
		{
			HeapTuple		amopTuple;

			amopTuple = SearchSysCacheTuple(AMOPSTRATEGY,
153
										ObjectIdGetDatum(relam),
154
										ObjectIdGetDatum(index->indclass[i]),
155 156
										UInt16GetDatum(amstrategy),
										0);
157 158 159 160 161 162 163
			if (!HeapTupleIsValid(amopTuple))
				elog(ERROR, "find_secondary_indexes: no amop %u %u %d",
					 relam, index->indclass[i], amstrategy);
			info->ordering[i] = ((Form_pg_amop) GETSTRUCT(amopTuple))->amopopr;
		}

		indexes = lcons(info, indexes);
164
	}
165 166 167 168 169

	heap_endscan(scan);
	heap_close(relation, AccessShareLock);

	return indexes;
170 171 172
}

/*
173
 * restriction_selectivity
174 175 176 177 178 179
 *
 * Returns the selectivity of a specified operator.
 * This code executes registered procedures stored in the
 * operator relation, by calling the function manager.
 *
 * XXX The assumption in the selectivity procedures is that if the
180
 *		relation OIDs or attribute numbers are 0, then the clause
181
 *		isn't of the form (op var const).
182
 */
183
Selectivity
184
restriction_selectivity(Oid functionObjectId,
185 186 187
						Oid operatorObjectId,
						Oid relationObjectId,
						AttrNumber attributeNumber,
188 189
						Datum constValue,
						int constFlag)
190
{
191
	float64		result;
192 193 194 195 196 197 198 199 200

	result = (float64) fmgr(functionObjectId,
							(char *) operatorObjectId,
							(char *) relationObjectId,
							(char *) (int) attributeNumber,
							(char *) constValue,
							(char *) constFlag,
							NULL);
	if (!PointerIsValid(result))
201
		elog(ERROR, "restriction_selectivity: bad pointer");
202 203

	if (*result < 0.0 || *result > 1.0)
204
		elog(ERROR, "restriction_selectivity: bad value %f", *result);
205

206
	return (Selectivity) *result;
207 208 209
}

/*
210
 * join_selectivity
211
 *
212 213
 * Returns the selectivity of an operator, given the join clause
 * information.
214 215
 *
 * XXX The assumption in the selectivity procedures is that if the
216
 *		relation OIDs or attribute numbers are 0, then the clause
217
 *		isn't of the form (op var var).
218
 */
219
Selectivity
220 221 222 223 224 225
join_selectivity(Oid functionObjectId,
				 Oid operatorObjectId,
				 Oid relationObjectId1,
				 AttrNumber attributeNumber1,
				 Oid relationObjectId2,
				 AttrNumber attributeNumber2)
226
{
227
	float64		result;
228 229 230 231 232 233 234 235 236

	result = (float64) fmgr(functionObjectId,
							(char *) operatorObjectId,
							(char *) relationObjectId1,
							(char *) (int) attributeNumber1,
							(char *) relationObjectId2,
							(char *) (int) attributeNumber2,
							NULL);
	if (!PointerIsValid(result))
237
		elog(ERROR, "join_selectivity: bad pointer");
238 239

	if (*result < 0.0 || *result > 1.0)
240
		elog(ERROR, "join_selectivity: bad value %f", *result);
241

242
	return (Selectivity) *result;
243 244 245
}

/*
246
 * find_inheritance_children
247
 *
248 249
 * Returns an integer list containing the OIDs of all relations which
 * inherit *directly* from the relation with OID 'inhparent'.
250
 */
251
List *
252 253
find_inheritance_children(Oid inhparent)
{
254 255 256 257
	static ScanKeyData key[1] = {
		{0, Anum_pg_inherits_inhparent, F_OIDEQ}
	};

258 259 260 261 262
	HeapTuple	inheritsTuple;
	Relation	relation;
	HeapScanDesc scan;
	List	   *list = NIL;
	Oid			inhrelid;
263

264 265
	fmgr_info(F_OIDEQ, &key[0].sk_func);
	key[0].sk_nargs = key[0].sk_func.fn_nargs;
266
	key[0].sk_argument = ObjectIdGetDatum(inhparent);
267

268
	relation = heap_openr(InheritsRelationName, AccessShareLock);
269
	scan = heap_beginscan(relation, 0, SnapshotNow, 1, key);
270
	while (HeapTupleIsValid(inheritsTuple = heap_getnext(scan, 0)))
271
	{
272
		inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid;
273 274 275
		list = lappendi(list, inhrelid);
	}
	heap_endscan(scan);
276
	heap_close(relation, AccessShareLock);
277
	return list;
278 279
}

280
#ifdef NOT_USED
281
/*
282
 * VersionGetParents
283 284 285 286
 *
 * Returns a LISP list containing the OIDs of all relations which are
 * base relations of the relation with OID 'verrelid'.
 */
287
List *
288 289
VersionGetParents(Oid verrelid)
{
290 291 292 293
	static ScanKeyData key[1] = {
		{0, Anum_pg_version_verrelid, F_OIDEQ}
	};

294 295 296 297 298
	HeapTuple	versionTuple;
	Relation	relation;
	HeapScanDesc scan;
	Oid			verbaseid;
	List	   *list = NIL;
299

300 301
	fmgr_info(F_OIDEQ, &key[0].sk_func);
	key[0].sk_nargs = key[0].sk_func.fn_nargs;
302
	key[0].sk_argument = ObjectIdGetDatum(verrelid);
303
	relation = heap_openr(VersionRelationName, AccessShareLock);
304
	scan = heap_beginscan(relation, 0, SnapshotNow, 1, key);
305
	while (HeapTupleIsValid(versionTuple = heap_getnext(scan, 0)))
306
	{
307
		verbaseid = ((Form_pg_version)
308 309 310 311 312 313 314 315
					 GETSTRUCT(versionTuple))->verbaseid;

		list = lconsi(verbaseid, list);

		key[0].sk_argument = ObjectIdGetDatum(verbaseid);
		heap_rescan(scan, 0, key);
	}
	heap_endscan(scan);
316
	heap_close(relation, AccessShareLock);
317
	return list;
318
}
B
Bruce Momjian 已提交
319

320
#endif