selfuncs.c 25.3 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * selfuncs.c
4
 *	  Selectivity functions for system catalogs and builtin types
5
 *
6 7
 *	  These routines are registered in the operator catalog in the
 *	  "oprrest" and "oprjoin" attributes.
8 9 10 11 12
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
13
 *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.39 1999/08/21 00:56:18 tgl Exp $
14 15 16 17
 *
 *-------------------------------------------------------------------------
 */

18 19
#include "postgres.h"

B
Bruce Momjian 已提交
20
#include "access/heapam.h"
21
#include "catalog/catname.h"
22
#include "catalog/pg_operator.h"
23
#include "catalog/pg_proc.h"
24
#include "catalog/pg_statistic.h"
25
#include "catalog/pg_type.h"
26
#include "parser/parse_func.h"
27
#include "parser/parse_oper.h"
B
Bruce Momjian 已提交
28
#include "utils/builtins.h"
29
#include "utils/int8.h"
B
Bruce Momjian 已提交
30 31
#include "utils/lsyscache.h"
#include "utils/syscache.h"
32 33

/* N is not a valid var/constant or relation id */
34
#define NONVALUE(N)		((N) == -1)
35

36 37
/* are we looking at a functional index selectivity request? */
#define FunctionalSelectivity(nIndKeys,attNum) ((attNum)==InvalidAttrNumber)
38

39 40 41
/* default selectivity estimate for inequalities such as "A < b" */
#define DEFAULT_INEQ_SEL  (1.0 / 3.0)

42 43
static bool convert_to_scale(Datum value, Oid typid,
							 double *scaleval);
44 45 46 47 48 49 50 51 52 53 54 55
static void getattproperties(Oid relid, AttrNumber attnum,
							 Oid *typid,
							 int *typlen,
							 bool *typbyval,
							 int32 *typmod);
static bool getattstatistics(Oid relid, AttrNumber attnum,
							 Oid typid, int32 typmod,
							 double *nullfrac,
							 double *commonfrac,
							 Datum *commonval,
							 Datum *loval,
							 Datum *hival);
56 57 58


/*
59
 *		eqsel			- Selectivity of "=" for any data types.
60 61 62 63 64 65
 *
 * Note: this routine is also used to estimate selectivity for some
 * operators that are not "=" but have comparable selectivity behavior,
 * such as "~~" (text LIKE).  Even for "=" we must keep in mind that
 * the left and right datatypes may differ, so the type of the given
 * constant "value" may be different from the type of the attribute.
66 67 68
 */
float64
eqsel(Oid opid,
69 70
	  Oid relid,
	  AttrNumber attno,
71
	  Datum value,
72
	  int32 flag)
73
{
74
	float64		result;
75 76 77 78 79

	result = (float64) palloc(sizeof(float64data));
	if (NONVALUE(attno) || NONVALUE(relid))
		*result = 0.1;
	else
80 81 82 83 84 85 86 87 88 89 90 91 92 93
	{
		Oid			typid;
		int			typlen;
		bool		typbyval;
		int32		typmod;
		double		nullfrac;
		double		commonfrac;
		Datum		commonval;
		double		selec;

		/* get info about the attribute */
		getattproperties(relid, attno,
						 &typid, &typlen, &typbyval, &typmod);

94
		/* get stats for the attribute, if available */
95 96 97 98 99 100
		if (getattstatistics(relid, attno, typid, typmod,
							 &nullfrac, &commonfrac, &commonval,
							 NULL, NULL))
		{
			if (flag & SEL_CONSTANT)
			{
101 102 103 104 105 106
				/* Is the constant "=" to the column's most common value?
				 * (Although the operator may not really be "=",
				 * we will assume that seeing whether it returns TRUE
				 * for the most common value is useful information.
				 * If you don't like it, maybe you shouldn't be using
				 * eqsel for your operator...)
107
				 */
108 109
				RegProcedure	eqproc = get_opcode(opid);
				bool			mostcommon;
110

111 112 113 114 115 116 117 118 119 120 121
				if (eqproc == (RegProcedure) NULL)
					elog(ERROR, "eqsel: no procedure for operator %u",
						 opid);

				/* be careful to apply operator right way 'round */
				if (flag & SEL_RIGHT)
					mostcommon = (bool)
						DatumGetUInt8(fmgr(eqproc, commonval, value));
				else
					mostcommon = (bool)
						DatumGetUInt8(fmgr(eqproc, value, commonval));
122 123 124

				if (mostcommon)
				{
125
					/* Constant is "=" to the most common value.  We know
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
					 * selectivity exactly (or as exactly as VACUUM could
					 * calculate it, anyway).
					 */
					selec = commonfrac;
				}
				else
				{
					/* Comparison is against a constant that is neither the
					 * most common value nor null.  Its selectivity cannot
					 * be more than this:
					 */
					selec = 1.0 - commonfrac - nullfrac;
					if (selec > commonfrac)
						selec = commonfrac;
					/* and in fact it's probably less, so apply a fudge
					 * factor.
					 */
					selec *= 0.5;
				}
			}
			else
			{
				/* Search is for a value that we do not know a priori,
				 * but we will assume it is not NULL.  Selectivity
				 * cannot be more than this:
				 */
				selec = 1.0 - nullfrac;
				if (selec > commonfrac)
					selec = commonfrac;
				/* and in fact it's probably less, so apply a fudge
				 * factor.
				 */
				selec *= 0.5;
			}

			/* result should be in range, but make sure... */
			if (selec < 0.0)
				selec = 0.0;
			else if (selec > 1.0)
				selec = 1.0;

			if (! typbyval)
				pfree(DatumGetPointer(commonval));
		}
		else
		{
			/* No VACUUM ANALYZE stats available, so make a guess using
			 * the disbursion stat (if we have that, which is unlikely...)
			 */
175
			selec = get_attdisbursion(relid, attno, 0.01);
176 177 178 179
		}

		*result = (float64data) selec;
	}
180
	return result;
181 182 183
}

/*
184
 *		neqsel			- Selectivity of "!=" for any data types.
185 186 187 188
 *
 * This routine is also used for some operators that are not "!="
 * but have comparable selectivity behavior.  See above comments
 * for eqsel().
189 190 191
 */
float64
neqsel(Oid opid,
192 193
	   Oid relid,
	   AttrNumber attno,
194
	   Datum value,
195
	   int32 flag)
196
{
197
	float64		result;
198 199 200

	result = eqsel(opid, relid, attno, value, flag);
	*result = 1.0 - *result;
201
	return result;
202 203 204
}

/*
205
 *		intltsel		- Selectivity of "<" (also "<=") for integers.
206 207 208 209 210
 *
 * Actually, this works and is used for all numeric types, so it should
 * be renamed.  In fact, it is also currently called for all manner of
 * non-numeric types, for which it is NOT very helpful.  That needs
 * to be fixed.
211 212 213
 */
float64
intltsel(Oid opid,
214 215
		 Oid relid,
		 AttrNumber attno,
216
		 Datum value,
217
		 int32 flag)
218
{
219
	float64		result;
220 221

	result = (float64) palloc(sizeof(float64data));
222 223
	if (! (flag & SEL_CONSTANT) || NONVALUE(attno) || NONVALUE(relid))
		*result = DEFAULT_INEQ_SEL;
224 225
	else
	{
226 227 228 229 230 231 232 233 234
		HeapTuple	oprtuple;
		Oid			ltype,
					rtype;
		Oid			typid;
		int			typlen;
		bool		typbyval;
		int32		typmod;
		Datum		hival,
					loval;
235
		double		val,
236 237 238 239 240
					high,
					low,
					numerator,
					denominator;

241 242 243
		/* Get left and right datatypes of the operator so we know
		 * what type the constant is.
		 */
244 245 246 247 248 249
		oprtuple = get_operator_tuple(opid);
		if (! HeapTupleIsValid(oprtuple))
			elog(ERROR, "intltsel: no tuple for operator %u", opid);
		ltype = ((Form_pg_operator) GETSTRUCT(oprtuple))->oprleft;
		rtype = ((Form_pg_operator) GETSTRUCT(oprtuple))->oprright;

250 251 252 253
		/* Convert the constant to a uniform comparison scale. */
		if (! convert_to_scale(value, 
							   ((flag & SEL_RIGHT) ? rtype : ltype),
							   &val))
254
		{
255 256 257 258 259 260
			/* Ideally we'd produce an error here, on the grounds that
			 * the given operator shouldn't have intltsel registered as its
			 * selectivity func unless we can deal with its operand types.
			 * But currently, all manner of stuff is invoking intltsel,
			 * so give a default estimate until that can be fixed.
			 */
261
			*result = DEFAULT_INEQ_SEL;
262
			return result;
263
		}
264

265
		/* Now get info and stats about the attribute */
266 267 268 269 270 271 272
		getattproperties(relid, attno,
						 &typid, &typlen, &typbyval, &typmod);

		if (! getattstatistics(relid, attno, typid, typmod,
							   NULL, NULL, NULL,
							   &loval, &hival))
		{
273
			/* no stats available, so default result */
274 275 276
			*result = DEFAULT_INEQ_SEL;
			return result;
		}
277 278 279 280

		/* Convert the attribute's loval/hival to common scale. */
		if (! convert_to_scale(loval, typid, &low) ||
			! convert_to_scale(hival, typid, &high))
281
		{
282 283 284 285 286 287 288 289 290
			/* See above comments... */
			if (! typbyval)
			{
				pfree(DatumGetPointer(hival));
				pfree(DatumGetPointer(loval));
			}

			*result = DEFAULT_INEQ_SEL;
			return result;
291
		}
292 293 294

		/* release temp storage if needed */
		if (! typbyval)
295
		{
296 297 298 299 300 301 302 303 304 305
			pfree(DatumGetPointer(hival));
			pfree(DatumGetPointer(loval));
		}

		if (high <= low)
		{
			/* If we trusted the stats fully, we could return a small or
			 * large selec depending on which side of the single data point
			 * the constant is on.  But it seems better to assume that the
			 * stats are out of date and return a default...
306 307
			 */
			*result = DEFAULT_INEQ_SEL;
308 309 310 311 312 313 314 315 316 317 318
        }
		else if (val <= low || val >= high)
		{
			/* If given value is outside the statistical range, return a
			 * small or large value; but not 0.0/1.0 since there is a chance
			 * the stats are out of date.
			 */
			if (flag & SEL_RIGHT)
				*result = (val <= low) ? 0.01 : 0.99;
			else
				*result = (val <= low) ? 0.99 : 0.01;
319 320 321
		}
		else
		{
322
			denominator = high - low;
323
			if (flag & SEL_RIGHT)
324
				numerator = val - low;
325
			else
326
				numerator = high - val;
327
			*result = numerator / denominator;
328
		}
329
	}
330
	return result;
331 332 333
}

/*
334
 *		intgtsel		- Selectivity of ">" (also ">=") for integers.
335 336
 *
 * See above comments for intltsel.
337 338 339
 */
float64
intgtsel(Oid opid,
340 341
		 Oid relid,
		 AttrNumber attno,
342
		 Datum value,
343
		 int32 flag)
344
{
345
	float64		result;
346

347 348 349 350 351 352
	/* Compute selectivity of "<", then invert --- but only if we
	 * were able to produce a non-default estimate.
	 */
	result = intltsel(opid, relid, attno, value, flag);
	if (*result != DEFAULT_INEQ_SEL)
		*result = 1.0 - *result;
353
	return result;
354 355 356
}

/*
357
 *		eqjoinsel		- Join selectivity of "="
358 359 360
 */
float64
eqjoinsel(Oid opid,
361 362 363 364
		  Oid relid1,
		  AttrNumber attno1,
		  Oid relid2,
		  AttrNumber attno2)
365
{
366
	float64		result;
367
	float64data num1,
368 369
				num2,
				max;
370 371 372 373 374

	result = (float64) palloc(sizeof(float64data));
	if (NONVALUE(attno1) || NONVALUE(relid1) ||
		NONVALUE(attno2) || NONVALUE(relid2))
		*result = 0.1;
375
	else
376
	{
377 378
		num1 = get_attdisbursion(relid1, attno1, 0.01);
		num2 = get_attdisbursion(relid2, attno2, 0.01);
379
		max = (num1 > num2) ? num1 : num2;
380
		if (max <= 0)
381 382
			*result = 1.0;
		else
383
			*result = max;
384
	}
385
	return result;
386 387 388
}

/*
389
 *		neqjoinsel		- Join selectivity of "!="
390 391 392
 */
float64
neqjoinsel(Oid opid,
393 394 395 396
		   Oid relid1,
		   AttrNumber attno1,
		   Oid relid2,
		   AttrNumber attno2)
397
{
398
	float64		result;
399 400 401

	result = eqjoinsel(opid, relid1, attno1, relid2, attno2);
	*result = 1.0 - *result;
402
	return result;
403 404 405
}

/*
406
 *		intltjoinsel	- Join selectivity of "<" and "<="
407 408 409
 */
float64
intltjoinsel(Oid opid,
410 411 412 413
			 Oid relid1,
			 AttrNumber attno1,
			 Oid relid2,
			 AttrNumber attno2)
414
{
415
	float64		result;
416 417

	result = (float64) palloc(sizeof(float64data));
418
	*result = DEFAULT_INEQ_SEL;
419
	return result;
420 421 422
}

/*
423
 *		intgtjoinsel	- Join selectivity of ">" and ">="
424 425 426
 */
float64
intgtjoinsel(Oid opid,
427 428 429 430
			 Oid relid1,
			 AttrNumber attno1,
			 Oid relid2,
			 AttrNumber attno2)
431
{
432
	float64		result;
433 434

	result = (float64) palloc(sizeof(float64data));
435
	*result = DEFAULT_INEQ_SEL;
436
	return result;
437 438
}

439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
/*
 * convert_to_scale
 *	  Convert a given value of the indicated type to the comparison
 *	  scale needed by intltsel().  Returns "true" if successful.
 *
 * All numeric datatypes are simply converted to their equivalent
 * "double" values.
 * Future extension: convert string-like types to some suitable scale.
 */
static bool
convert_to_scale(Datum value, Oid typid,
				 double *scaleval)
{
	/* Fast-path conversions for some built-in types */
	switch (typid)
	{
		case BOOLOID:
			*scaleval = (double) DatumGetUInt8(value);
			return true;
		case INT2OID:
			*scaleval = (double) DatumGetInt16(value);
			return true;
		case INT4OID:
			*scaleval = (double) DatumGetInt32(value);
			return true;
464 465 466
		case INT8OID:
			*scaleval = (double) (* i8tod((int64 *) DatumGetPointer(value)));
			return true;
467 468 469 470 471 472
		case FLOAT4OID:
			*scaleval = (double) (* DatumGetFloat32(value));
			return true;
		case FLOAT8OID:
			*scaleval = (double) (* DatumGetFloat64(value));
			return true;
473 474 475
		case NUMERICOID:
			*scaleval = (double) (* numeric_float8((Numeric) DatumGetPointer(value)));
			return true;
476 477 478 479 480
		case OIDOID:
		case REGPROCOID:
			/* we can treat OIDs as integers... */
			*scaleval = (double) DatumGetObjectId(value);
			return true;
481 482 483 484 485 486 487 488
		case TEXTOID:
			/*
			 * Eventually this should get handled by somehow scaling as a
			 * string value.  For now, we need to call it out to avoid
			 * falling into the default case, because there is a float8(text)
			 * function declared in pg_proc that will do the wrong thing :-(
			 */
			break;
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
		default:
		{
			/* See whether there is a registered type-conversion function,
			 * namely a procedure named "float8" with the right signature.
			 */
			Oid			oid_array[MAXFARGS];
			HeapTuple	ftup;

			MemSet(oid_array, 0, MAXFARGS * sizeof(Oid));
			oid_array[0] = typid;
			ftup = SearchSysCacheTuple(PRONAME,
									   PointerGetDatum("float8"),
									   Int32GetDatum(1),
									   PointerGetDatum(oid_array),
									   0);
			if (HeapTupleIsValid(ftup) &&
				((Form_pg_proc) GETSTRUCT(ftup))->prorettype == FLOAT8OID)
			{
				RegProcedure convertproc = (RegProcedure) ftup->t_data->t_oid;
				Datum converted = (Datum) fmgr(convertproc, value);
				*scaleval = (double) (* DatumGetFloat64(converted));
				return true;
			}
			break;
		}
	}
	/* Don't know how to convert */
	return false;
}

519
/*
520 521 522
 * getattproperties
 *	  Retrieve pg_attribute properties for an attribute,
 *	  including type OID, type len, type byval flag, typmod.
523
 */
524 525 526
static void
getattproperties(Oid relid, AttrNumber attnum,
				 Oid *typid, int *typlen, bool *typbyval, int32 *typmod)
527
{
528
	HeapTuple	atp;
529
	Form_pg_attribute att_tup;
530 531 532 533 534

	atp = SearchSysCacheTuple(ATTNUM,
							  ObjectIdGetDatum(relid),
							  Int16GetDatum(attnum),
							  0, 0);
535 536 537 538 539 540 541 542 543
	if (! HeapTupleIsValid(atp))
		elog(ERROR, "getattproperties: no attribute tuple %u %d",
			 relid, (int) attnum);
	att_tup = (Form_pg_attribute) GETSTRUCT(atp);

	*typid = att_tup->atttypid;
	*typlen = att_tup->attlen;
	*typbyval = att_tup->attbyval;
	*typmod = att_tup->atttypmod;
544 545 546
}

/*
547 548 549
 * getattstatistics
 *	  Retrieve the pg_statistic data for an attribute.
 *	  Returns 'false' if no stats are available.
550
 *
551 552 553 554
 * Inputs:
 * 'relid' and 'attnum' are the relation and attribute number.
 * 'typid' and 'typmod' are the type and typmod of the column,
 * which the caller must already have looked up.
555
 *
556 557 558 559 560 561 562 563 564 565 566
 * Outputs:
 * The available stats are nullfrac, commonfrac, commonval, loval, hival.
 * The caller need not retrieve all five --- pass NULL pointers for the
 * unwanted values.
 *
 * commonval, loval, hival are returned as Datums holding the internal
 * representation of the values.  (Note that these should be pfree'd
 * after use if the data type is not by-value.)
 *
 * XXX currently, this does a linear search of pg_statistic because there
 * is no index nor syscache for pg_statistic.  FIX THIS!
567
 */
568 569 570 571 572 573 574
static bool
getattstatistics(Oid relid, AttrNumber attnum, Oid typid, int32 typmod,
				 double *nullfrac,
				 double *commonfrac,
				 Datum *commonval,
				 Datum *loval,
				 Datum *hival)
575
{
576 577
	Relation	rel;
	HeapScanDesc scan;
578
	static ScanKeyData key[2] = {
B
Bruce Momjian 已提交
579
		{0, Anum_pg_statistic_starelid, F_OIDEQ, {0, 0, F_OIDEQ}},
580
		{0, Anum_pg_statistic_staattnum, F_INT2EQ, {0, 0, F_INT2EQ}}
581
	};
582 583
	bool		isnull;
	HeapTuple	tuple;
584 585
	HeapTuple	typeTuple;
	FmgrInfo	inputproc;
586

587
	rel = heap_openr(StatisticRelationName);
588 589 590

	key[0].sk_argument = ObjectIdGetDatum(relid);
	key[1].sk_argument = Int16GetDatum((int16) attnum);
591 592

	scan = heap_beginscan(rel, 0, SnapshotNow, 2, key);
593
	tuple = heap_getnext(scan, 0);
594 595
	if (!HeapTupleIsValid(tuple))
	{
596 597 598 599 600
		/* no such stats entry */
		heap_endscan(scan);
		heap_close(rel);
		return false;
	}
601

602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
	/* We assume that there will only be one entry in pg_statistic
	 * for the given rel/att.  Someday, VACUUM might store more than one...
	 */
	if (nullfrac)
		*nullfrac = ((Form_pg_statistic) GETSTRUCT(tuple))->stanullfrac;
	if (commonfrac)
		*commonfrac = ((Form_pg_statistic) GETSTRUCT(tuple))->stacommonfrac;

	/* Get the type input proc for the column datatype */
	typeTuple = SearchSysCacheTuple(TYPOID,
									ObjectIdGetDatum(typid),
									0, 0, 0);
	if (! HeapTupleIsValid(typeTuple))
		elog(ERROR, "getattstatistics: Cache lookup failed for type %u",
			 typid);
	fmgr_info(((Form_pg_type) GETSTRUCT(typeTuple))->typinput, &inputproc);

	/* Values are variable-length fields, so cannot access as struct fields.
	 * Must do it the hard way with heap_getattr.
	 */
	if (commonval)
	{
		text *val = (text *) heap_getattr(tuple,
										  Anum_pg_statistic_stacommonval,
										  RelationGetDescr(rel),
										  &isnull);
		if (isnull)
		{
			elog(DEBUG, "getattstatistics: stacommonval is null");
			*commonval = PointerGetDatum(NULL);
		}
		else
		{
			char *strval = textout(val);
			*commonval = (Datum)
				(*fmgr_faddr(&inputproc)) (strval, typid, typmod);
			pfree(strval);
		}
640
	}
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681

	if (loval)
	{
		text *val = (text *) heap_getattr(tuple,
										  Anum_pg_statistic_staloval,
										  RelationGetDescr(rel),
										  &isnull);
		if (isnull)
		{
			elog(DEBUG, "getattstatistics: staloval is null");
			*loval = PointerGetDatum(NULL);
		}
		else
		{
			char *strval = textout(val);
			*loval = (Datum)
				(*fmgr_faddr(&inputproc)) (strval, typid, typmod);
			pfree(strval);
		}
	}

	if (hival)
	{
		text *val = (text *) heap_getattr(tuple,
										  Anum_pg_statistic_stahival,
										  RelationGetDescr(rel),
										  &isnull);
		if (isnull)
		{
			elog(DEBUG, "getattstatistics: stahival is null");
			*hival = PointerGetDatum(NULL);
		}
		else
		{
			char *strval = textout(val);
			*hival = (Datum)
				(*fmgr_faddr(&inputproc)) (strval, typid, typmod);
			pfree(strval);
		}
	}

682 683
	heap_endscan(scan);
	heap_close(rel);
684 685 686
	return true;
}

687 688
float64
btreesel(Oid operatorObjectId,
689 690 691 692 693 694
		 Oid indrelid,
		 AttrNumber attributeNumber,
		 char *constValue,
		 int32 constFlag,
		 int32 nIndexKeys,
		 Oid indexrelid)
695
{
696
	float64		result;
697 698 699

	if (FunctionalSelectivity(nIndexKeys, attributeNumber))
	{
B
Bruce Momjian 已提交
700

701 702 703 704 705
		/*
		 * Need to call the functions selectivity function here.  For now
		 * simply assume it's 1/3 since functions don't currently have
		 * selectivity functions
		 */
706 707
		result = (float64) palloc(sizeof(float64data));
		*result = 1.0 / 3.0;
708 709 710
	}
	else
	{
711 712 713 714 715 716 717 718 719 720
		RegProcedure oprrest = get_oprrest(operatorObjectId);

		/*
		 * Operators used for indexes should have selectivity estimators.
		 * (An alternative is to default to 0.5, as the optimizer does in
		 * dealing with operators occurring in WHERE clauses, but if you
		 * are going to the trouble of making index support you probably
		 * don't want to miss the benefits of a good selectivity estimate.)
		 */
		if (!oprrest)
721 722 723 724 725 726 727 728 729 730
		{
#if 1
			/*
			 * XXX temporary fix for 6.5: rtree operators are missing their
			 * selectivity estimators, so return a default estimate instead.
			 * Ugh.
			 */
			result = (float64) palloc(sizeof(float64data));
			*result = 0.5;
#else
731
			elog(ERROR,
732
				 "Operator %u must have a restriction selectivity estimator to be used in an index",
733
				 operatorObjectId);
734 735 736 737 738 739 740 741 742 743
#endif
		}
		else
			result = (float64) fmgr(oprrest,
									(char *) operatorObjectId,
									(char *) indrelid,
									(char *) (int) attributeNumber,
									(char *) constValue,
									(char *) constFlag,
									NULL);
744 745 746
	}

	if (!PointerIsValid(result))
747
		elog(ERROR, "Btree Selectivity: bad pointer");
748
	if (*result < 0.0 || *result > 1.0)
749
		elog(ERROR, "Btree Selectivity: bad value %lf", *result);
750

751
	return result;
752 753 754 755
}

float64
btreenpage(Oid operatorObjectId,
756 757 758 759 760 761
		   Oid indrelid,
		   AttrNumber attributeNumber,
		   char *constValue,
		   int32 constFlag,
		   int32 nIndexKeys,
		   Oid indexrelid)
762
{
763 764 765 766 767
	float64		temp,
				result;
	float64data tempData;
	HeapTuple	atp;
	int			npage;
768 769 770

	if (FunctionalSelectivity(nIndexKeys, attributeNumber))
	{
B
Bruce Momjian 已提交
771

772 773 774 775 776 777 778 779 780 781
		/*
		 * Need to call the functions selectivity function here.  For now
		 * simply assume it's 1/3 since functions don't currently have
		 * selectivity functions
		 */
		tempData = 1.0 / 3.0;
		temp = &tempData;
	}
	else
	{
782 783 784 785 786 787 788 789 790 791
		RegProcedure oprrest = get_oprrest(operatorObjectId);

		/*
		 * Operators used for indexes should have selectivity estimators.
		 * (An alternative is to default to 0.5, as the optimizer does in
		 * dealing with operators occurring in WHERE clauses, but if you
		 * are going to the trouble of making index support you probably
		 * don't want to miss the benefits of a good selectivity estimate.)
		 */
		if (!oprrest)
792 793 794 795 796 797 798 799 800 801
		{
#if 1
			/*
			 * XXX temporary fix for 6.5: rtree operators are missing their
			 * selectivity estimators, so return a default estimate instead.
			 * Ugh.
			 */
			tempData = 0.5;
			temp = &tempData;
#else
802
			elog(ERROR,
803
				 "Operator %u must have a restriction selectivity estimator to be used in an index",
804
				 operatorObjectId);
805 806 807 808 809 810 811 812 813 814
#endif
		}
		else
			temp = (float64) fmgr(oprrest,
								  (char *) operatorObjectId,
								  (char *) indrelid,
								  (char *) (int) attributeNumber,
								  (char *) constValue,
								  (char *) constFlag,
								  NULL);
815
	}
816

817 818 819 820 821
	atp = SearchSysCacheTuple(RELOID,
							  ObjectIdGetDatum(indexrelid),
							  0, 0, 0);
	if (!HeapTupleIsValid(atp))
	{
822
		elog(ERROR, "btreenpage: no index tuple %u", indexrelid);
823
		return 0;
824 825 826 827 828
	}

	npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
	result = (float64) palloc(sizeof(float64data));
	*result = *temp * npage;
829
	return result;
830 831 832 833
}

float64
hashsel(Oid operatorObjectId,
834 835 836 837 838 839
		Oid indrelid,
		AttrNumber attributeNumber,
		char *constValue,
		int32 constFlag,
		int32 nIndexKeys,
		Oid indexrelid)
840
{
841

842 843 844 845
	float64		result;
	float64data resultData;
	HeapTuple	atp;
	int			ntuples;
846 847 848 849 850 851 852 853 854 855

	if (FunctionalSelectivity(nIndexKeys, attributeNumber))
	{

		/*
		 * Need to call the functions selectivity function here.  For now
		 * simply use 1/Number of Tuples since functions don't currently
		 * have selectivity functions
		 */

856 857
		atp = SearchSysCacheTuple(RELOID,
								  ObjectIdGetDatum(indexrelid),
858 859 860
								  0, 0, 0);
		if (!HeapTupleIsValid(atp))
		{
861
			elog(ERROR, "hashsel: no index tuple %u", indexrelid);
862
			return 0;
863 864 865 866 867 868 869 870
		}
		ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
		if (ntuples > 0)
			resultData = 1.0 / (float64data) ntuples;
		else
			resultData = (float64data) (1.0 / 100.0);
		result = &resultData;

871
	}
872 873
	else
	{
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888
		RegProcedure oprrest = get_oprrest(operatorObjectId);

		/*
		 * Operators used for indexes should have selectivity estimators.
		 * (An alternative is to default to 0.5, as the optimizer does in
		 * dealing with operators occurring in WHERE clauses, but if you
		 * are going to the trouble of making index support you probably
		 * don't want to miss the benefits of a good selectivity estimate.)
		 */
		if (!oprrest)
			elog(ERROR,
				 "Operator %u must have a restriction selectivity estimator to be used in a hash index",
				 operatorObjectId);

		result = (float64) fmgr(oprrest,
889 890 891 892 893 894
								(char *) operatorObjectId,
								(char *) indrelid,
								(char *) (int) attributeNumber,
								(char *) constValue,
								(char *) constFlag,
								NULL);
895
	}
896 897

	if (!PointerIsValid(result))
898
		elog(ERROR, "Hash Table Selectivity: bad pointer");
899
	if (*result < 0.0 || *result > 1.0)
900
		elog(ERROR, "Hash Table Selectivity: bad value %lf", *result);
901

902
	return result;
903 904


905 906 907 908
}

float64
hashnpage(Oid operatorObjectId,
909 910 911 912 913 914
		  Oid indrelid,
		  AttrNumber attributeNumber,
		  char *constValue,
		  int32 constFlag,
		  int32 nIndexKeys,
		  Oid indexrelid)
915
{
916 917 918 919 920 921
	float64		temp,
				result;
	float64data tempData;
	HeapTuple	atp;
	int			npage;
	int			ntuples;
922

923 924
	atp = SearchSysCacheTuple(RELOID,
							  ObjectIdGetDatum(indexrelid),
925 926 927
							  0, 0, 0);
	if (!HeapTupleIsValid(atp))
	{
928
		elog(ERROR, "hashsel: no index tuple %u", indexrelid);
929
		return 0;
930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948
	}


	if (FunctionalSelectivity(nIndexKeys, attributeNumber))
	{

		/*
		 * Need to call the functions selectivity function here.  For now,
		 * use 1/Number of Tuples since functions don't currently have
		 * selectivity functions
		 */

		ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
		if (ntuples > 0)
			tempData = 1.0 / (float64data) ntuples;
		else
			tempData = (float64data) (1.0 / 100.0);
		temp = &tempData;

949
	}
950 951
	else
	{
952 953 954 955 956 957 958 959 960 961 962 963 964 965 966
		RegProcedure oprrest = get_oprrest(operatorObjectId);

		/*
		 * Operators used for indexes should have selectivity estimators.
		 * (An alternative is to default to 0.5, as the optimizer does in
		 * dealing with operators occurring in WHERE clauses, but if you
		 * are going to the trouble of making index support you probably
		 * don't want to miss the benefits of a good selectivity estimate.)
		 */
		if (!oprrest)
			elog(ERROR,
				 "Operator %u must have a restriction selectivity estimator to be used in a hash index",
				 operatorObjectId);

		temp = (float64) fmgr(oprrest,
967 968 969 970 971 972
							  (char *) operatorObjectId,
							  (char *) indrelid,
							  (char *) (int) attributeNumber,
							  (char *) constValue,
							  (char *) constFlag,
							  NULL);
973
	}
974 975 976 977

	npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
	result = (float64) palloc(sizeof(float64data));
	*result = *temp * npage;
978
	return result;
979 980 981 982 983
}


float64
rtsel(Oid operatorObjectId,
984 985 986 987 988 989
	  Oid indrelid,
	  AttrNumber attributeNumber,
	  char *constValue,
	  int32 constFlag,
	  int32 nIndexKeys,
	  Oid indexrelid)
990
{
991 992
	return (btreesel(operatorObjectId, indrelid, attributeNumber,
					 constValue, constFlag, nIndexKeys, indexrelid));
993 994 995 996
}

float64
rtnpage(Oid operatorObjectId,
997 998 999 1000 1001 1002
		Oid indrelid,
		AttrNumber attributeNumber,
		char *constValue,
		int32 constFlag,
		int32 nIndexKeys,
		Oid indexrelid)
1003
{
1004 1005
	return (btreenpage(operatorObjectId, indrelid, attributeNumber,
					   constValue, constFlag, nIndexKeys, indexrelid));
1006
}
1007 1008 1009

float64
gistsel(Oid operatorObjectId,
1010 1011 1012 1013 1014 1015
		Oid indrelid,
		AttrNumber attributeNumber,
		char *constValue,
		int32 constFlag,
		int32 nIndexKeys,
		Oid indexrelid)
1016
{
1017 1018
	return (btreesel(operatorObjectId, indrelid, attributeNumber,
					 constValue, constFlag, nIndexKeys, indexrelid));
1019 1020 1021 1022
}

float64
gistnpage(Oid operatorObjectId,
1023 1024 1025 1026 1027 1028
		  Oid indrelid,
		  AttrNumber attributeNumber,
		  char *constValue,
		  int32 constFlag,
		  int32 nIndexKeys,
		  Oid indexrelid)
1029
{
1030 1031
	return (btreenpage(operatorObjectId, indrelid, attributeNumber,
					   constValue, constFlag, nIndexKeys, indexrelid));
1032
}