aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils')
-rw-r--r--src/backend/utils/adt/ruleutils.c27
-rw-r--r--src/backend/utils/adt/selfuncs.c148
-rw-r--r--src/backend/utils/cache/catcache.c20
-rw-r--r--src/backend/utils/cache/lsyscache.c413
-rw-r--r--src/backend/utils/cache/relcache.c181
-rw-r--r--src/backend/utils/cache/syscache.c64
-rw-r--r--src/backend/utils/cache/typcache.c76
-rw-r--r--src/backend/utils/sort/tuplesort.c37
8 files changed, 551 insertions, 415 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index a99942010b6..b2ff95f457b 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -2,7 +2,7 @@
* ruleutils.c - Functions to convert stored expressions/querytrees
* back to source text
*
- * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.236 2006/12/21 16:05:15 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.237 2006/12/23 00:43:11 tgl Exp $
**********************************************************************/
#include "postgres.h"
@@ -19,6 +19,7 @@
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_trigger.h"
+#include "commands/defrem.h"
#include "executor/spi.h"
#include "funcapi.h"
#include "nodes/makefuncs.h"
@@ -4717,11 +4718,6 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
Form_pg_opclass opcrec;
char *opcname;
char *nspname;
- bool isvisible;
-
- /* Domains use their base type's default opclass */
- if (OidIsValid(actual_datatype))
- actual_datatype = getBaseType(actual_datatype);
ht_opc = SearchSysCache(CLAOID,
ObjectIdGetDatum(opclass),
@@ -4730,25 +4726,12 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
elog(ERROR, "cache lookup failed for opclass %u", opclass);
opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
- /*
- * Special case for ARRAY_OPS: pretend it is default for any array type
- */
- if (OidIsValid(actual_datatype))
- {
- if (opcrec->opcintype == ANYARRAYOID &&
- OidIsValid(get_element_type(actual_datatype)))
- actual_datatype = opcrec->opcintype;
- }
-
- /* Must force use of opclass name if not in search path */
- isvisible = OpclassIsVisible(opclass);
-
- if (actual_datatype != opcrec->opcintype || !opcrec->opcdefault ||
- !isvisible)
+ if (!OidIsValid(actual_datatype) ||
+ GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
{
/* Okay, we need the opclass name. Do we need to qualify it? */
opcname = NameStr(opcrec->opcname);
- if (isvisible)
+ if (OpclassIsVisible(opclass))
appendStringInfo(buf, " %s", quote_identifier(opcname));
else
{
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 230ce549f3b..73e82cd5e01 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.215 2006/12/15 18:42:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.216 2006/12/23 00:43:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -76,7 +76,7 @@
#include <ctype.h>
#include <math.h>
-#include "catalog/pg_opclass.h"
+#include "catalog/pg_opfamily.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
#include "mb/pg_wchar.h"
@@ -128,7 +128,7 @@ static double convert_timevalue_to_scalar(Datum value, Oid typid);
static bool get_variable_maximum(PlannerInfo *root, VariableStatData *vardata,
Oid sortop, Datum *max);
static Selectivity prefix_selectivity(VariableStatData *vardata,
- Oid opclass, Const *prefixcon);
+ Oid vartype, Oid opfamily, Const *prefixcon);
static Selectivity pattern_selectivity(Const *patt, Pattern_Type ptype);
static Datum string_to_datum(const char *str, Oid datatype);
static Const *string_to_const(const char *str, Oid datatype);
@@ -911,7 +911,7 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
Datum constval;
Oid consttype;
Oid vartype;
- Oid opclass;
+ Oid opfamily;
Pattern_Prefix_Status pstatus;
Const *patt = NULL;
Const *prefix = NULL;
@@ -960,9 +960,9 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
* Similarly, the exposed type of the left-hand side should be one of
* those we know. (Do not look at vardata.atttype, which might be
* something binary-compatible but different.) We can use it to choose
- * the index opclass from which we must draw the comparison operators.
+ * the index opfamily from which we must draw the comparison operators.
*
- * NOTE: It would be more correct to use the PATTERN opclasses than the
+ * NOTE: It would be more correct to use the PATTERN opfamilies than the
* simple ones, but at the moment ANALYZE will not generate statistics for
* the PATTERN operators. But our results are so approximate anyway that
* it probably hardly matters.
@@ -972,19 +972,16 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
switch (vartype)
{
case TEXTOID:
- opclass = TEXT_BTREE_OPS_OID;
- break;
- case VARCHAROID:
- opclass = VARCHAR_BTREE_OPS_OID;
+ opfamily = TEXT_BTREE_FAM_OID;
break;
case BPCHAROID:
- opclass = BPCHAR_BTREE_OPS_OID;
+ opfamily = BPCHAR_BTREE_FAM_OID;
break;
case NAMEOID:
- opclass = NAME_BTREE_OPS_OID;
+ opfamily = NAME_BTREE_FAM_OID;
break;
case BYTEAOID:
- opclass = BYTEA_BTREE_OPS_OID;
+ opfamily = BYTEA_BTREE_FAM_OID;
break;
default:
ReleaseVariableStats(vardata);
@@ -1028,12 +1025,12 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
/*
* Pattern specifies an exact match, so pretend operator is '='
*/
- Oid eqopr = get_opclass_member(opclass, InvalidOid,
- BTEqualStrategyNumber);
+ Oid eqopr = get_opfamily_member(opfamily, vartype, vartype,
+ BTEqualStrategyNumber);
List *eqargs;
if (eqopr == InvalidOid)
- elog(ERROR, "no = operator for opclass %u", opclass);
+ elog(ERROR, "no = operator for opfamily %u", opfamily);
eqargs = list_make2(variable, prefix);
result = DatumGetFloat8(DirectFunctionCall4(eqsel,
PointerGetDatum(root),
@@ -1074,7 +1071,8 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
Selectivity restsel;
if (pstatus == Pattern_Prefix_Partial)
- prefixsel = prefix_selectivity(&vardata, opclass, prefix);
+ prefixsel = prefix_selectivity(&vardata, vartype,
+ opfamily, prefix);
else
prefixsel = 1.0;
restsel = pattern_selectivity(rest, ptype);
@@ -2114,7 +2112,8 @@ icnlikejoinsel(PG_FUNCTION_ARGS)
* we can estimate how much of the input will actually be read. This
* can have a considerable impact on the cost when using indexscans.
*
- * clause should be a clause already known to be mergejoinable.
+ * clause should be a clause already known to be mergejoinable. opfamily and
+ * strategy specify the sort ordering being used.
*
* *leftscan is set to the fraction of the left-hand variable expected
* to be scanned (0 to 1), and similarly *rightscan for the right-hand
@@ -2122,6 +2121,7 @@ icnlikejoinsel(PG_FUNCTION_ARGS)
*/
void
mergejoinscansel(PlannerInfo *root, Node *clause,
+ Oid opfamily, int strategy,
Selectivity *leftscan,
Selectivity *rightscan)
{
@@ -2129,15 +2129,14 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
*right;
VariableStatData leftvar,
rightvar;
- Oid lefttype,
- righttype;
+ int op_strategy;
+ Oid op_lefttype;
+ Oid op_righttype;
+ bool op_recheck;
Oid opno,
lsortop,
rsortop,
- ltop,
- gtop,
leop,
- revgtop,
revleop;
Datum leftmax,
rightmax;
@@ -2159,15 +2158,51 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
examine_variable(root, left, 0, &leftvar);
examine_variable(root, right, 0, &rightvar);
- /* Get the direct input types of the operator */
- lefttype = exprType(left);
- righttype = exprType(right);
+ /* Extract the operator's declared left/right datatypes */
+ get_op_opfamily_properties(opno, opfamily,
+ &op_strategy,
+ &op_lefttype,
+ &op_righttype,
+ &op_recheck);
+ Assert(op_strategy == BTEqualStrategyNumber);
+ Assert(!op_recheck);
+
+ /*
+ * Look up the various operators we need. If we don't find them all,
+ * it probably means the opfamily is broken, but we cope anyway.
+ */
+ switch (strategy)
+ {
+ case BTLessStrategyNumber:
+ lsortop = get_opfamily_member(opfamily, op_lefttype, op_lefttype,
+ BTLessStrategyNumber);
+ rsortop = get_opfamily_member(opfamily, op_righttype, op_righttype,
+ BTLessStrategyNumber);
+ leop = get_opfamily_member(opfamily, op_lefttype, op_righttype,
+ BTLessEqualStrategyNumber);
+ revleop = get_opfamily_member(opfamily, op_righttype, op_lefttype,
+ BTLessEqualStrategyNumber);
+ break;
+ case BTGreaterStrategyNumber:
+ /* descending-order case */
+ lsortop = get_opfamily_member(opfamily, op_lefttype, op_lefttype,
+ BTGreaterStrategyNumber);
+ rsortop = get_opfamily_member(opfamily, op_righttype, op_righttype,
+ BTGreaterStrategyNumber);
+ leop = get_opfamily_member(opfamily, op_lefttype, op_righttype,
+ BTGreaterEqualStrategyNumber);
+ revleop = get_opfamily_member(opfamily, op_righttype, op_lefttype,
+ BTGreaterEqualStrategyNumber);
+ break;
+ default:
+ goto fail; /* shouldn't get here */
+ }
- /* Verify mergejoinability and get left and right "<" operators */
- if (!op_mergejoinable(opno,
- &lsortop,
- &rsortop))
- goto fail; /* shouldn't happen */
+ if (!OidIsValid(lsortop) ||
+ !OidIsValid(rsortop) ||
+ !OidIsValid(leop) ||
+ !OidIsValid(revleop))
+ goto fail; /* insufficient info in catalogs */
/* Try to get maximum values of both inputs */
if (!get_variable_maximum(root, &leftvar, lsortop, &leftmax))
@@ -2176,37 +2211,19 @@ mergejoinscansel(PlannerInfo *root, Node *clause,
if (!get_variable_maximum(root, &rightvar, rsortop, &rightmax))
goto fail; /* no max available from stats */
- /* Look up the "left < right" and "left > right" operators */
- op_mergejoin_crossops(opno, &ltop, &gtop, NULL, NULL);
-
- /* Look up the "left <= right" operator */
- leop = get_negator(gtop);
- if (!OidIsValid(leop))
- goto fail; /* insufficient info in catalogs */
-
- /* Look up the "right > left" operator */
- revgtop = get_commutator(ltop);
- if (!OidIsValid(revgtop))
- goto fail; /* insufficient info in catalogs */
-
- /* Look up the "right <= left" operator */
- revleop = get_negator(revgtop);
- if (!OidIsValid(revleop))
- goto fail; /* insufficient info in catalogs */
-
/*
* Now, the fraction of the left variable that will be scanned is the
* fraction that's <= the right-side maximum value. But only believe
* non-default estimates, else stick with our 1.0.
*/
selec = scalarineqsel(root, leop, false, &leftvar,
- rightmax, righttype);
+ rightmax, op_righttype);
if (selec != DEFAULT_INEQ_SEL)
*leftscan = selec;
/* And similarly for the right variable. */
selec = scalarineqsel(root, revleop, false, &rightvar,
- leftmax, lefttype);
+ leftmax, op_lefttype);
if (selec != DEFAULT_INEQ_SEL)
*rightscan = selec;
@@ -3486,7 +3503,7 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
* statistics.
*
* XXX it's conceivable that there are multiple matches with different
- * index opclasses; if so, we need to pick one that matches the
+ * index opfamilies; if so, we need to pick one that matches the
* operator we are estimating for. FIXME later.
*/
ListCell *ilist;
@@ -4100,7 +4117,7 @@ pattern_fixed_prefix(Const *patt, Pattern_Type ptype,
* population represented by the histogram --- the caller must fold this
* together with info about MCVs and NULLs.
*
- * We use the >= and < operators from the specified btree opclass to do the
+ * We use the >= and < operators from the specified btree opfamily to do the
* estimation. The given variable and Const must be of the associated
* datatype.
*
@@ -4110,17 +4127,18 @@ pattern_fixed_prefix(Const *patt, Pattern_Type ptype,
* more useful to use the upper-bound code than not.
*/
static Selectivity
-prefix_selectivity(VariableStatData *vardata, Oid opclass, Const *prefixcon)
+prefix_selectivity(VariableStatData *vardata,
+ Oid vartype, Oid opfamily, Const *prefixcon)
{
Selectivity prefixsel;
Oid cmpopr;
FmgrInfo opproc;
Const *greaterstrcon;
- cmpopr = get_opclass_member(opclass, InvalidOid,
- BTGreaterEqualStrategyNumber);
+ cmpopr = get_opfamily_member(opfamily, vartype, vartype,
+ BTGreaterEqualStrategyNumber);
if (cmpopr == InvalidOid)
- elog(ERROR, "no >= operator for opclass %u", opclass);
+ elog(ERROR, "no >= operator for opfamily %u", opfamily);
fmgr_info(get_opcode(cmpopr), &opproc);
prefixsel = ineq_histogram_selectivity(vardata, &opproc, true,
@@ -4143,10 +4161,10 @@ prefix_selectivity(VariableStatData *vardata, Oid opclass, Const *prefixcon)
{
Selectivity topsel;
- cmpopr = get_opclass_member(opclass, InvalidOid,
- BTLessStrategyNumber);
+ cmpopr = get_opfamily_member(opfamily, vartype, vartype,
+ BTLessStrategyNumber);
if (cmpopr == InvalidOid)
- elog(ERROR, "no < operator for opclass %u", opclass);
+ elog(ERROR, "no < operator for opfamily %u", opfamily);
fmgr_info(get_opcode(cmpopr), &opproc);
topsel = ineq_histogram_selectivity(vardata, &opproc, false,
@@ -4921,7 +4939,7 @@ btcostestimate(PG_FUNCTION_ARGS)
}
else if (match_index_to_operand(rightop, indexcol, index))
{
- /* Must flip operator to get the opclass member */
+ /* Must flip operator to get the opfamily member */
clause_op = get_commutator(clause_op);
}
else
@@ -4937,7 +4955,7 @@ btcostestimate(PG_FUNCTION_ARGS)
}
else if (match_index_to_operand(rightop, indexcol, index))
{
- /* Must flip operator to get the opclass member */
+ /* Must flip operator to get the opfamily member */
clause_op = get_commutator(clause_op);
}
else
@@ -4946,9 +4964,9 @@ btcostestimate(PG_FUNCTION_ARGS)
break;
}
}
- op_strategy = get_op_opclass_strategy(clause_op,
- index->classlist[indexcol]);
- Assert(op_strategy != 0); /* not a member of opclass?? */
+ op_strategy = get_op_opfamily_strategy(clause_op,
+ index->opfamily[indexcol]);
+ Assert(op_strategy != 0); /* not a member of opfamily?? */
if (op_strategy == BTEqualStrategyNumber)
eqQualHere = true;
/* count up number of SA scans induced by indexBoundQuals only */
diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index 55b9d5baf07..1a1d19f399a 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/catcache.c,v 1.134 2006/10/06 18:23:35 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/catcache.c,v 1.135 2006/12/23 00:43:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1033,9 +1033,10 @@ IndexScanOK(CatCache *cache, ScanKey cur_skey)
if (cache->id == INDEXRELID)
{
/*
- * Since the OIDs of indexes aren't hardwired, it's painful to figure
- * out which is which. Just force all pg_index searches to be heap
- * scans while building the relcaches.
+ * Rather than tracking exactly which indexes have to be loaded
+ * before we can use indexscans (which changes from time to time),
+ * just force all pg_index searches to be heap scans until we've
+ * built the critical relcaches.
*/
if (!criticalRelcachesBuilt)
return false;
@@ -1051,17 +1052,6 @@ IndexScanOK(CatCache *cache, ScanKey cur_skey)
*/
return false;
}
- else if (cache->id == OPEROID)
- {
- if (!criticalRelcachesBuilt)
- {
- /* Looking for an OID comparison function? */
- Oid lookup_oid = DatumGetObjectId(cur_skey[0].sk_argument);
-
- if (lookup_oid >= MIN_OIDCMP && lookup_oid <= MAX_OIDCMP)
- return false;
- }
- }
/* Normal case, allow index scan */
return true;
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index fdc31e0d977..824ef4a1efe 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.138 2006/10/04 00:30:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.139 2006/12/23 00:43:11 tgl Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
@@ -37,27 +37,27 @@
/* ---------- AMOP CACHES ---------- */
/*
- * op_in_opclass
+ * op_in_opfamily
*
- * Return t iff operator 'opno' is in operator class 'opclass'.
+ * Return t iff operator 'opno' is in operator family 'opfamily'.
*/
bool
-op_in_opclass(Oid opno, Oid opclass)
+op_in_opfamily(Oid opno, Oid opfamily)
{
return SearchSysCacheExists(AMOPOPID,
ObjectIdGetDatum(opno),
- ObjectIdGetDatum(opclass),
+ ObjectIdGetDatum(opfamily),
0, 0);
}
/*
- * get_op_opclass_strategy
+ * get_op_opfamily_strategy
*
- * Get the operator's strategy number within the specified opclass,
- * or 0 if it's not a member of the opclass.
+ * Get the operator's strategy number within the specified opfamily,
+ * or 0 if it's not a member of the opfamily.
*/
int
-get_op_opclass_strategy(Oid opno, Oid opclass)
+get_op_opfamily_strategy(Oid opno, Oid opfamily)
{
HeapTuple tp;
Form_pg_amop amop_tup;
@@ -65,7 +65,7 @@ get_op_opclass_strategy(Oid opno, Oid opclass)
tp = SearchSysCache(AMOPOPID,
ObjectIdGetDatum(opno),
- ObjectIdGetDatum(opclass),
+ ObjectIdGetDatum(opfamily),
0, 0);
if (!HeapTupleIsValid(tp))
return 0;
@@ -76,54 +76,59 @@ get_op_opclass_strategy(Oid opno, Oid opclass)
}
/*
- * get_op_opclass_properties
+ * get_op_opfamily_properties
*
- * Get the operator's strategy number, subtype, and recheck (lossy) flag
- * within the specified opclass.
+ * Get the operator's strategy number, input types, and recheck (lossy)
+ * flag within the specified opfamily.
*
- * Caller should already have verified that opno is a member of opclass,
+ * Caller should already have verified that opno is a member of opfamily,
* therefore we raise an error if the tuple is not found.
*/
void
-get_op_opclass_properties(Oid opno, Oid opclass,
- int *strategy, Oid *subtype, bool *recheck)
+get_op_opfamily_properties(Oid opno, Oid opfamily,
+ int *strategy,
+ Oid *lefttype,
+ Oid *righttype,
+ bool *recheck)
{
HeapTuple tp;
Form_pg_amop amop_tup;
tp = SearchSysCache(AMOPOPID,
ObjectIdGetDatum(opno),
- ObjectIdGetDatum(opclass),
+ ObjectIdGetDatum(opfamily),
0, 0);
if (!HeapTupleIsValid(tp))
- elog(ERROR, "operator %u is not a member of opclass %u",
- opno, opclass);
+ elog(ERROR, "operator %u is not a member of opfamily %u",
+ opno, opfamily);
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
*strategy = amop_tup->amopstrategy;
- *subtype = amop_tup->amopsubtype;
+ *lefttype = amop_tup->amoplefttype;
+ *righttype = amop_tup->amoprighttype;
*recheck = amop_tup->amopreqcheck;
ReleaseSysCache(tp);
}
/*
- * get_opclass_member
+ * get_opfamily_member
* Get the OID of the operator that implements the specified strategy
- * with the specified subtype for the specified opclass.
+ * with the specified datatypes for the specified opfamily.
*
* Returns InvalidOid if there is no pg_amop entry for the given keys.
*/
Oid
-get_opclass_member(Oid opclass, Oid subtype, int16 strategy)
+get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
+ int16 strategy)
{
HeapTuple tp;
Form_pg_amop amop_tup;
Oid result;
tp = SearchSysCache(AMOPSTRATEGY,
- ObjectIdGetDatum(opclass),
- ObjectIdGetDatum(subtype),
- Int16GetDatum(strategy),
- 0);
+ ObjectIdGetDatum(opfamily),
+ ObjectIdGetDatum(lefttype),
+ ObjectIdGetDatum(righttype),
+ Int16GetDatum(strategy));
if (!HeapTupleIsValid(tp))
return InvalidOid;
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
@@ -133,10 +138,160 @@ get_opclass_member(Oid opclass, Oid subtype, int16 strategy)
}
/*
+ * get_op_mergejoin_info
+ * Given the OIDs of a (putatively) mergejoinable equality operator
+ * and a sortop defining the sort ordering of the lefthand input of
+ * the merge clause, determine whether this sort ordering is actually
+ * usable for merging. If so, return the required sort ordering op
+ * for the righthand input, as well as the btree opfamily OID containing
+ * these operators and the operator strategy number of the two sortops
+ * (either BTLessStrategyNumber or BTGreaterStrategyNumber).
+ *
+ * We can mergejoin if we find the two operators in the same opfamily as
+ * equality and either less-than or greater-than respectively. If there
+ * are multiple such opfamilies, assume we can use any one.
+ */
+#ifdef NOT_YET
+/* eventually should look like this */
+bool
+get_op_mergejoin_info(Oid eq_op, Oid left_sortop,
+ Oid *right_sortop, Oid *opfamily, int *opstrategy)
+{
+ bool result = false;
+ Oid lefttype;
+ Oid righttype;
+ CatCList *catlist;
+ int i;
+
+ /* Make sure output args are initialized even on failure */
+ *right_sortop = InvalidOid;
+ *opfamily = InvalidOid;
+ *opstrategy = 0;
+
+ /* Need the righthand input datatype */
+ op_input_types(eq_op, &lefttype, &righttype);
+
+ /*
+ * Search through all the pg_amop entries containing the equality operator
+ */
+ catlist = SearchSysCacheList(AMOPOPID, 1,
+ ObjectIdGetDatum(eq_op),
+ 0, 0, 0);
+
+ for (i = 0; i < catlist->n_members; i++)
+ {
+ HeapTuple op_tuple = &catlist->members[i]->tuple;
+ Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
+ Oid opfamily_id;
+ StrategyNumber op_strategy;
+
+ /* must be btree */
+ if (op_form->amopmethod != BTREE_AM_OID)
+ continue;
+ /* must use the operator as equality */
+ if (op_form->amopstrategy != BTEqualStrategyNumber)
+ continue;
+
+ /* See if sort operator is also in this opclass with OK semantics */
+ opfamily_id = op_form->amopfamily;
+ op_strategy = get_op_opfamily_strategy(left_sortop, opfamily_id);
+ if (op_strategy == BTLessStrategyNumber ||
+ op_strategy == BTGreaterStrategyNumber)
+ {
+ /* Yes, so find the corresponding righthand sortop */
+ *right_sortop = get_opfamily_member(opfamily_id,
+ righttype,
+ righttype,
+ op_strategy);
+ if (OidIsValid(*right_sortop))
+ {
+ /* Found a workable mergejoin semantics */
+ *opfamily = opfamily_id;
+ *opstrategy = op_strategy;
+ result = true;
+ break;
+ }
+ }
+ }
+
+ ReleaseSysCacheList(catlist);
+
+ return result;
+}
+#else
+/* temp implementation until planner gets smarter: left_sortop is output */
+bool
+get_op_mergejoin_info(Oid eq_op, Oid *left_sortop,
+ Oid *right_sortop, Oid *opfamily)
+{
+ bool result = false;
+ Oid lefttype;
+ Oid righttype;
+ CatCList *catlist;
+ int i;
+
+ /* Make sure output args are initialized even on failure */
+ *left_sortop = InvalidOid;
+ *right_sortop = InvalidOid;
+ *opfamily = InvalidOid;
+
+ /* Need the input datatypes */
+ op_input_types(eq_op, &lefttype, &righttype);
+
+ /*
+ * Search through all the pg_amop entries containing the equality operator
+ */
+ catlist = SearchSysCacheList(AMOPOPID, 1,
+ ObjectIdGetDatum(eq_op),
+ 0, 0, 0);
+
+ for (i = 0; i < catlist->n_members; i++)
+ {
+ HeapTuple op_tuple = &catlist->members[i]->tuple;
+ Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
+ Oid opfamily_id;
+
+ /* must be btree */
+ if (op_form->amopmethod != BTREE_AM_OID)
+ continue;
+ /* must use the operator as equality */
+ if (op_form->amopstrategy != BTEqualStrategyNumber)
+ continue;
+
+ opfamily_id = op_form->amopfamily;
+
+ /* Find the matching sortops */
+ *left_sortop = get_opfamily_member(opfamily_id,
+ lefttype,
+ lefttype,
+ BTLessStrategyNumber);
+ *right_sortop = get_opfamily_member(opfamily_id,
+ righttype,
+ righttype,
+ BTLessStrategyNumber);
+ if (OidIsValid(*left_sortop) && OidIsValid(*right_sortop))
+ {
+ /* Found a workable mergejoin semantics */
+ *opfamily = opfamily_id;
+ result = true;
+ break;
+ }
+ }
+
+ ReleaseSysCacheList(catlist);
+
+ return result;
+}
+#endif
+
+/*
* get_op_hash_function
* Get the OID of the datatype-specific hash function associated with
* a hashable equality operator.
*
+ * XXX API needs to be generalized for the case of different left and right
+ * datatypes.
+ *
* Returns InvalidOid if no hash function can be found. (This indicates
* that the operator should not have been marked oprcanhash.)
*/
@@ -145,12 +300,12 @@ get_op_hash_function(Oid opno)
{
CatCList *catlist;
int i;
- Oid opclass = InvalidOid;
+ Oid result = InvalidOid;
/*
* Search pg_amop to see if the target operator is registered as the "="
- * operator of any hash opclass. If the operator is registered in
- * multiple opclasses, assume we can use the associated hash function from
+ * operator of any hash opfamily. If the operator is registered in
+ * multiple opfamilies, assume we can use the associated hash function from
* any one.
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
@@ -162,58 +317,44 @@ get_op_hash_function(Oid opno)
HeapTuple tuple = &catlist->members[i]->tuple;
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
- if (aform->amopstrategy == HTEqualStrategyNumber &&
- opclass_is_hash(aform->amopclaid))
+ if (aform->amopmethod == HASH_AM_OID &&
+ aform->amopstrategy == HTEqualStrategyNumber)
{
- opclass = aform->amopclaid;
+ /* Found a suitable opfamily, get matching hash support function */
+ result = get_opfamily_proc(aform->amopfamily,
+ aform->amoplefttype,
+ aform->amoprighttype,
+ HASHPROC);
break;
}
}
ReleaseSysCacheList(catlist);
- if (OidIsValid(opclass))
- {
- /* Found a suitable opclass, get its default hash support function */
- return get_opclass_proc(opclass, InvalidOid, HASHPROC);
- }
-
- /* Didn't find a match... */
- return InvalidOid;
+ return result;
}
/*
* get_op_btree_interpretation
- * Given an operator's OID, find out which btree opclasses it belongs to,
+ * Given an operator's OID, find out which btree opfamilies it belongs to,
* and what strategy number it has within each one. The results are
* returned as an OID list and a parallel integer list.
*
* In addition to the normal btree operators, we consider a <> operator to be
- * a "member" of an opclass if its negator is the opclass' equality operator.
- * ROWCOMPARE_NE is returned as the strategy number for this case.
+ * a "member" of an opfamily if its negator is an equality operator of the
+ * opfamily. ROWCOMPARE_NE is returned as the strategy number for this case.
*/
void
-get_op_btree_interpretation(Oid opno, List **opclasses, List **opstrats)
+get_op_btree_interpretation(Oid opno, List **opfamilies, List **opstrats)
{
- Oid lefttype,
- righttype;
CatCList *catlist;
bool op_negated;
int i;
- *opclasses = NIL;
+ *opfamilies = NIL;
*opstrats = NIL;
/*
- * Get the nominal left-hand input type of the operator; we will ignore
- * opclasses that don't have that as the expected input datatype. This is
- * a kluge to avoid being confused by binary-compatible opclasses (such as
- * text_ops and varchar_ops, which share the same operators).
- */
- op_input_types(opno, &lefttype, &righttype);
- Assert(OidIsValid(lefttype));
-
- /*
* Find all the pg_amop entries containing the operator.
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
@@ -221,8 +362,8 @@ get_op_btree_interpretation(Oid opno, List **opclasses, List **opstrats)
0, 0, 0);
/*
- * If we can't find any opclass containing the op, perhaps it is a <>
- * operator. See if it has a negator that is in an opclass.
+ * If we can't find any opfamily containing the op, perhaps it is a <>
+ * operator. See if it has a negator that is in an opfamily.
*/
op_negated = false;
if (catlist->n_members == 0)
@@ -239,25 +380,20 @@ get_op_btree_interpretation(Oid opno, List **opclasses, List **opstrats)
}
}
- /* Now search the opclasses */
+ /* Now search the opfamilies */
for (i = 0; i < catlist->n_members; i++)
{
HeapTuple op_tuple = &catlist->members[i]->tuple;
Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
- Oid opclass_id;
+ Oid opfamily_id;
StrategyNumber op_strategy;
- opclass_id = op_form->amopclaid;
-
/* must be btree */
- if (!opclass_is_btree(opclass_id))
- continue;
-
- /* must match operator input type exactly */
- if (get_opclass_input_type(opclass_id) != lefttype)
+ if (op_form->amopmethod != BTREE_AM_OID)
continue;
/* Get the operator's btree strategy number */
+ opfamily_id = op_form->amopfamily;
op_strategy = (StrategyNumber) op_form->amopstrategy;
Assert(op_strategy >= 1 && op_strategy <= 5);
@@ -269,7 +405,7 @@ get_op_btree_interpretation(Oid opno, List **opclasses, List **opstrats)
op_strategy = ROWCOMPARE_NE;
}
- *opclasses = lappend_oid(*opclasses, opclass_id);
+ *opfamilies = lappend_oid(*opfamilies, opfamily_id);
*opstrats = lappend_int(*opstrats, op_strategy);
}
@@ -280,24 +416,24 @@ get_op_btree_interpretation(Oid opno, List **opclasses, List **opstrats)
/* ---------- AMPROC CACHES ---------- */
/*
- * get_opclass_proc
+ * get_opfamily_proc
* Get the OID of the specified support function
- * for the specified opclass and subtype.
+ * for the specified opfamily and datatypes.
*
* Returns InvalidOid if there is no pg_amproc entry for the given keys.
*/
Oid
-get_opclass_proc(Oid opclass, Oid subtype, int16 procnum)
+get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
{
HeapTuple tp;
Form_pg_amproc amproc_tup;
RegProcedure result;
tp = SearchSysCache(AMPROCNUM,
- ObjectIdGetDatum(opclass),
- ObjectIdGetDatum(subtype),
- Int16GetDatum(procnum),
- 0);
+ ObjectIdGetDatum(opfamily),
+ ObjectIdGetDatum(lefttype),
+ ObjectIdGetDatum(righttype),
+ Int16GetDatum(procnum));
if (!HeapTupleIsValid(tp))
return InvalidOid;
amproc_tup = (Form_pg_amproc) GETSTRUCT(tp);
@@ -477,67 +613,16 @@ get_atttypetypmod(Oid relid, AttrNumber attnum,
/* ---------- OPCLASS CACHE ---------- */
/*
- * opclass_is_btree
+ * get_opclass_family
*
- * Returns TRUE iff the specified opclass is associated with the
- * btree index access method.
+ * Returns the OID of the operator family the opclass belongs to.
*/
-bool
-opclass_is_btree(Oid opclass)
-{
- HeapTuple tp;
- Form_pg_opclass cla_tup;
- bool result;
-
- tp = SearchSysCache(CLAOID,
- ObjectIdGetDatum(opclass),
- 0, 0, 0);
- if (!HeapTupleIsValid(tp))
- elog(ERROR, "cache lookup failed for opclass %u", opclass);
- cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
-
- result = (cla_tup->opcamid == BTREE_AM_OID);
- ReleaseSysCache(tp);
- return result;
-}
-
-/*
- * opclass_is_hash
- *
- * Returns TRUE iff the specified opclass is associated with the
- * hash index access method.
- */
-bool
-opclass_is_hash(Oid opclass)
-{
- HeapTuple tp;
- Form_pg_opclass cla_tup;
- bool result;
-
- tp = SearchSysCache(CLAOID,
- ObjectIdGetDatum(opclass),
- 0, 0, 0);
- if (!HeapTupleIsValid(tp))
- elog(ERROR, "cache lookup failed for opclass %u", opclass);
- cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
-
- result = (cla_tup->opcamid == HASH_AM_OID);
- ReleaseSysCache(tp);
- return result;
-}
-
-/*
- * opclass_is_default
- *
- * Returns TRUE iff the specified opclass is the default for its
- * index access method and input data type.
- */
-bool
-opclass_is_default(Oid opclass)
+Oid
+get_opclass_family(Oid opclass)
{
HeapTuple tp;
Form_pg_opclass cla_tup;
- bool result;
+ Oid result;
tp = SearchSysCache(CLAOID,
ObjectIdGetDatum(opclass),
@@ -546,7 +631,7 @@ opclass_is_default(Oid opclass)
elog(ERROR, "cache lookup failed for opclass %u", opclass);
cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
- result = cla_tup->opcdefault;
+ result = cla_tup->opcfamily;
ReleaseSysCache(tp);
return result;
}
@@ -657,11 +742,13 @@ op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
/*
* op_mergejoinable
*
- * Returns the left and right sort operators corresponding to a
- * mergejoinable operator, or false if the operator is not mergejoinable.
+ * Returns true if the operator is potentially mergejoinable. (The planner
+ * will fail to find any mergejoin plans unless there are suitable btree
+ * opfamily entries for this operator and associated sortops. The pg_operator
+ * flag is just a hint to tell the planner whether to bother looking.)
*/
bool
-op_mergejoinable(Oid opno, Oid *leftOp, Oid *rightOp)
+op_mergejoinable(Oid opno)
{
HeapTuple tp;
bool result = false;
@@ -673,65 +760,17 @@ op_mergejoinable(Oid opno, Oid *leftOp, Oid *rightOp)
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
- if (optup->oprlsortop &&
- optup->oprrsortop)
- {
- *leftOp = optup->oprlsortop;
- *rightOp = optup->oprrsortop;
- result = true;
- }
+ result = optup->oprcanmerge;
ReleaseSysCache(tp);
}
return result;
}
/*
- * op_mergejoin_crossops
- *
- * Returns the cross-type comparison operators (ltype "<" rtype and
- * ltype ">" rtype) for an operator previously determined to be
- * mergejoinable. Optionally, fetches the regproc ids of these
- * operators, as well as their operator OIDs.
- */
-void
-op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
- RegProcedure *ltproc, RegProcedure *gtproc)
-{
- HeapTuple tp;
- Form_pg_operator optup;
-
- /*
- * Get the declared comparison operators of the operator.
- */
- tp = SearchSysCache(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
- if (!HeapTupleIsValid(tp)) /* shouldn't happen */
- elog(ERROR, "cache lookup failed for operator %u", opno);
- optup = (Form_pg_operator) GETSTRUCT(tp);
- *ltop = optup->oprltcmpop;
- *gtop = optup->oprgtcmpop;
- ReleaseSysCache(tp);
-
- /* Check < op provided */
- if (!OidIsValid(*ltop))
- elog(ERROR, "mergejoin operator %u has no matching < operator",
- opno);
- if (ltproc)
- *ltproc = get_opcode(*ltop);
-
- /* Check > op provided */
- if (!OidIsValid(*gtop))
- elog(ERROR, "mergejoin operator %u has no matching > operator",
- opno);
- if (gtproc)
- *gtproc = get_opcode(*gtop);
-}
-
-/*
* op_hashjoinable
*
- * Returns true if the operator is hashjoinable.
+ * Returns true if the operator is hashjoinable. (There must be a suitable
+ * hash opfamily entry for this operator if it is so marked.)
*/
bool
op_hashjoinable(Oid opno)
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 65cd1e72907..be5fb60dc8e 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.250 2006/11/05 23:40:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.251 2006/12/23 00:43:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -69,7 +69,7 @@
*/
#define RELCACHE_INIT_FILENAME "pg_internal.init"
-#define RELCACHE_INIT_FILEMAGIC 0x573263 /* version ID value */
+#define RELCACHE_INIT_FILEMAGIC 0x573264 /* version ID value */
/*
* hardcoded tuple descriptors. see include/catalog/pg_attribute.h
@@ -159,7 +159,8 @@ do { \
/*
* Special cache for opclass-related information
*
- * Note: only default-subtype operators and support procs get cached
+ * Note: only default operators and support procs get cached, ie, those with
+ * lefttype = righttype = opcintype.
*/
typedef struct opclasscacheent
{
@@ -167,6 +168,8 @@ typedef struct opclasscacheent
bool valid; /* set TRUE after successful fill-in */
StrategyNumber numStrats; /* max # of strategies (from pg_am) */
StrategyNumber numSupport; /* max # of support procs (from pg_am) */
+ Oid opcfamily; /* OID of opclass's family */
+ Oid opcintype; /* OID of opclass's declared input type */
Oid *operatorOids; /* strategy operators' OIDs */
RegProcedure *supportProcs; /* support procs */
} OpClassCacheEnt;
@@ -201,6 +204,8 @@ static List *insert_ordered_oid(List *list, Oid datum);
static void IndexSupportInitialize(oidvector *indclass,
Oid *indexOperator,
RegProcedure *indexSupport,
+ Oid *opFamily,
+ Oid *opcInType,
StrategyNumber maxStrategyNumber,
StrategyNumber maxSupportNumber,
AttrNumber maxAttributeNumber);
@@ -921,11 +926,9 @@ RelationInitIndexAccessInfo(Relation relation)
Form_pg_am aform;
Datum indclassDatum;
bool isnull;
+ oidvector *indclass;
MemoryContext indexcxt;
MemoryContext oldcontext;
- Oid *operator;
- RegProcedure *support;
- FmgrInfo *supportinfo;
int natts;
uint16 amstrategies;
uint16 amsupport;
@@ -948,18 +951,6 @@ RelationInitIndexAccessInfo(Relation relation)
ReleaseSysCache(tuple);
/*
- * indclass cannot be referenced directly through the C struct, because it
- * is after the variable-width indkey field. Therefore we extract the
- * datum the hard way and provide a direct link in the relcache.
- */
- indclassDatum = fastgetattr(relation->rd_indextuple,
- Anum_pg_index_indclass,
- GetPgIndexDescriptor(),
- &isnull);
- Assert(!isnull);
- relation->rd_indclass = (oidvector *) DatumGetPointer(indclassDatum);
-
- /*
* Make a copy of the pg_am entry for the index's access method
*/
tuple = SearchSysCache(AMOID,
@@ -1001,38 +992,53 @@ RelationInitIndexAccessInfo(Relation relation)
relation->rd_aminfo = (RelationAmInfo *)
MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
+ relation->rd_opfamily = (Oid *)
+ MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));
+ relation->rd_opcintype = (Oid *)
+ MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));
+
if (amstrategies > 0)
- operator = (Oid *)
+ relation->rd_operator = (Oid *)
MemoryContextAllocZero(indexcxt,
natts * amstrategies * sizeof(Oid));
else
- operator = NULL;
+ relation->rd_operator = NULL;
if (amsupport > 0)
{
int nsupport = natts * amsupport;
- support = (RegProcedure *)
+ relation->rd_support = (RegProcedure *)
MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));
- supportinfo = (FmgrInfo *)
+ relation->rd_supportinfo = (FmgrInfo *)
MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
}
else
{
- support = NULL;
- supportinfo = NULL;
+ relation->rd_support = NULL;
+ relation->rd_supportinfo = NULL;
}
- relation->rd_operator = operator;
- relation->rd_support = support;
- relation->rd_supportinfo = supportinfo;
+ /*
+ * indclass cannot be referenced directly through the C struct, because it
+ * comes after the variable-width indkey field. Must extract the
+ * datum the hard way...
+ */
+ indclassDatum = fastgetattr(relation->rd_indextuple,
+ Anum_pg_index_indclass,
+ GetPgIndexDescriptor(),
+ &isnull);
+ Assert(!isnull);
+ indclass = (oidvector *) DatumGetPointer(indclassDatum);
/*
- * Fill the operator and support procedure OID arrays. (aminfo and
+ * Fill the operator and support procedure OID arrays, as well as the
+ * info about opfamilies and opclass input types. (aminfo and
* supportinfo are left as zeroes, and are filled on-the-fly when used)
*/
- IndexSupportInitialize(relation->rd_indclass,
- operator, support,
+ IndexSupportInitialize(indclass,
+ relation->rd_operator, relation->rd_support,
+ relation->rd_opfamily, relation->rd_opcintype,
amstrategies, amsupport, natts);
/*
@@ -1048,8 +1054,8 @@ RelationInitIndexAccessInfo(Relation relation)
* Initializes an index's cached opclass information,
* given the index's pg_index.indclass entry.
*
- * Data is returned into *indexOperator and *indexSupport, which are arrays
- * allocated by the caller.
+ * Data is returned into *indexOperator, *indexSupport, *opFamily, and
+ * *opcInType, which are arrays allocated by the caller.
*
* The caller also passes maxStrategyNumber, maxSupportNumber, and
* maxAttributeNumber, since these indicate the size of the arrays
@@ -1061,6 +1067,8 @@ static void
IndexSupportInitialize(oidvector *indclass,
Oid *indexOperator,
RegProcedure *indexSupport,
+ Oid *opFamily,
+ Oid *opcInType,
StrategyNumber maxStrategyNumber,
StrategyNumber maxSupportNumber,
AttrNumber maxAttributeNumber)
@@ -1080,6 +1088,8 @@ IndexSupportInitialize(oidvector *indclass,
maxSupportNumber);
/* copy cached data into relcache entry */
+ opFamily[attIndex] = opcentry->opcfamily;
+ opcInType[attIndex] = opcentry->opcintype;
if (maxStrategyNumber > 0)
memcpy(&indexOperator[attIndex * maxStrategyNumber],
opcentry->operatorOids,
@@ -1116,7 +1126,7 @@ LookupOpclassInfo(Oid operatorClassOid,
bool found;
Relation rel;
SysScanDesc scan;
- ScanKeyData skey[2];
+ ScanKeyData skey[3];
HeapTuple htup;
bool indexOK;
@@ -1177,22 +1187,54 @@ LookupOpclassInfo(Oid operatorClassOid,
operatorClassOid != INT2_BTREE_OPS_OID);
/*
+ * We have to fetch the pg_opclass row to determine its opfamily and
+ * opcintype, which are needed to look up the operators and functions.
+ * It'd be convenient to use the syscache here, but that probably doesn't
+ * work while bootstrapping.
+ */
+ ScanKeyInit(&skey[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(operatorClassOid));
+ rel = heap_open(OperatorClassRelationId, AccessShareLock);
+ scan = systable_beginscan(rel, OpclassOidIndexId, indexOK,
+ SnapshotNow, 1, skey);
+
+ if (HeapTupleIsValid(htup = systable_getnext(scan)))
+ {
+ Form_pg_opclass opclassform = (Form_pg_opclass) GETSTRUCT(htup);
+
+ opcentry->opcfamily = opclassform->opcfamily;
+ opcentry->opcintype = opclassform->opcintype;
+ }
+ else
+ elog(ERROR, "could not find tuple for opclass %u", operatorClassOid);
+
+ systable_endscan(scan);
+ heap_close(rel, AccessShareLock);
+
+
+ /*
* Scan pg_amop to obtain operators for the opclass. We only fetch the
- * default ones (those with subtype zero).
+ * default ones (those with lefttype = righttype = opcintype).
*/
if (numStrats > 0)
{
ScanKeyInit(&skey[0],
- Anum_pg_amop_amopclaid,
+ Anum_pg_amop_amopfamily,
BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(operatorClassOid));
+ ObjectIdGetDatum(opcentry->opcfamily));
ScanKeyInit(&skey[1],
- Anum_pg_amop_amopsubtype,
+ Anum_pg_amop_amoplefttype,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(opcentry->opcintype));
+ ScanKeyInit(&skey[2],
+ Anum_pg_amop_amoprighttype,
BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(InvalidOid));
+ ObjectIdGetDatum(opcentry->opcintype));
rel = heap_open(AccessMethodOperatorRelationId, AccessShareLock);
scan = systable_beginscan(rel, AccessMethodStrategyIndexId, indexOK,
- SnapshotNow, 2, skey);
+ SnapshotNow, 3, skey);
while (HeapTupleIsValid(htup = systable_getnext(scan)))
{
@@ -1212,21 +1254,25 @@ LookupOpclassInfo(Oid operatorClassOid,
/*
* Scan pg_amproc to obtain support procs for the opclass. We only fetch
- * the default ones (those with subtype zero).
+ * the default ones (those with lefttype = righttype = opcintype).
*/
if (numSupport > 0)
{
ScanKeyInit(&skey[0],
- Anum_pg_amproc_amopclaid,
+ Anum_pg_amproc_amprocfamily,
BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(operatorClassOid));
+ ObjectIdGetDatum(opcentry->opcfamily));
ScanKeyInit(&skey[1],
- Anum_pg_amproc_amprocsubtype,
+ Anum_pg_amproc_amproclefttype,
BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(InvalidOid));
+ ObjectIdGetDatum(opcentry->opcintype));
+ ScanKeyInit(&skey[2],
+ Anum_pg_amproc_amprocrighttype,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(opcentry->opcintype));
rel = heap_open(AccessMethodProcedureRelationId, AccessShareLock);
scan = systable_beginscan(rel, AccessMethodProcedureIndexId, indexOK,
- SnapshotNow, 2, skey);
+ SnapshotNow, 3, skey);
while (HeapTupleIsValid(htup = systable_getnext(scan)))
{
@@ -3097,8 +3143,6 @@ load_relcache_init_file(void)
Relation rel;
Form_pg_class relform;
bool has_not_null;
- Datum indclassDatum;
- bool isnull;
/* first read the relation descriptor length */
if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
@@ -3187,6 +3231,8 @@ load_relcache_init_file(void)
{
Form_pg_am am;
MemoryContext indexcxt;
+ Oid *opfamily;
+ Oid *opcintype;
Oid *operator;
RegProcedure *support;
int nsupport;
@@ -3207,14 +3253,6 @@ load_relcache_init_file(void)
rel->rd_indextuple->t_data = (HeapTupleHeader) ((char *) rel->rd_indextuple + HEAPTUPLESIZE);
rel->rd_index = (Form_pg_index) GETSTRUCT(rel->rd_indextuple);
- /* fix up indclass pointer too */
- indclassDatum = fastgetattr(rel->rd_indextuple,
- Anum_pg_index_indclass,
- GetPgIndexDescriptor(),
- &isnull);
- Assert(!isnull);
- rel->rd_indclass = (oidvector *) DatumGetPointer(indclassDatum);
-
/* next, read the access method tuple form */
if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
goto read_failed;
@@ -3235,6 +3273,26 @@ load_relcache_init_file(void)
ALLOCSET_SMALL_MAXSIZE);
rel->rd_indexcxt = indexcxt;
+ /* next, read the vector of opfamily OIDs */
+ if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
+ goto read_failed;
+
+ opfamily = (Oid *) MemoryContextAlloc(indexcxt, len);
+ if ((nread = fread(opfamily, 1, len, fp)) != len)
+ goto read_failed;
+
+ rel->rd_opfamily = opfamily;
+
+ /* next, read the vector of opcintype OIDs */
+ if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
+ goto read_failed;
+
+ opcintype = (Oid *) MemoryContextAlloc(indexcxt, len);
+ if ((nread = fread(opcintype, 1, len, fp)) != len)
+ goto read_failed;
+
+ rel->rd_opcintype = opcintype;
+
/* next, read the vector of operator OIDs */
if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len))
goto read_failed;
@@ -3269,10 +3327,11 @@ load_relcache_init_file(void)
Assert(rel->rd_index == NULL);
Assert(rel->rd_indextuple == NULL);
- Assert(rel->rd_indclass == NULL);
Assert(rel->rd_am == NULL);
Assert(rel->rd_indexcxt == NULL);
Assert(rel->rd_aminfo == NULL);
+ Assert(rel->rd_opfamily == NULL);
+ Assert(rel->rd_opcintype == NULL);
Assert(rel->rd_operator == NULL);
Assert(rel->rd_support == NULL);
Assert(rel->rd_supportinfo == NULL);
@@ -3450,6 +3509,16 @@ write_relcache_init_file(void)
/* next, write the access method tuple form */
write_item(am, sizeof(FormData_pg_am), fp);
+ /* next, write the vector of opfamily OIDs */
+ write_item(rel->rd_opfamily,
+ relform->relnatts * sizeof(Oid),
+ fp);
+
+ /* next, write the vector of opcintype OIDs */
+ write_item(rel->rd_opcintype,
+ relform->relnatts * sizeof(Oid),
+ fp);
+
/* next, write the vector of operator OIDs */
write_item(rel->rd_operator,
relform->relnatts * (am->amstrategies * sizeof(Oid)),
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index e19fba05840..f2fb0796cbb 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.108 2006/10/06 18:23:35 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.109 2006/12/23 00:43:11 tgl Exp $
*
* NOTES
* These routines allow the parser/planner/executor to perform
@@ -30,11 +30,11 @@
#include "catalog/pg_cast.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
-#include "catalog/pg_inherits.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
+#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_statistic.h"
@@ -135,7 +135,7 @@ static const struct cachedesc cacheinfo[] = {
2,
{
Anum_pg_amop_amopopr,
- Anum_pg_amop_amopclaid,
+ Anum_pg_amop_amopfamily,
0,
0
},
@@ -144,24 +144,24 @@ static const struct cachedesc cacheinfo[] = {
{AccessMethodOperatorRelationId, /* AMOPSTRATEGY */
AccessMethodStrategyIndexId,
0,
- 3,
+ 4,
{
- Anum_pg_amop_amopclaid,
- Anum_pg_amop_amopsubtype,
- Anum_pg_amop_amopstrategy,
- 0
+ Anum_pg_amop_amopfamily,
+ Anum_pg_amop_amoplefttype,
+ Anum_pg_amop_amoprighttype,
+ Anum_pg_amop_amopstrategy
},
64
},
{AccessMethodProcedureRelationId, /* AMPROCNUM */
AccessMethodProcedureIndexId,
0,
- 3,
+ 4,
{
- Anum_pg_amproc_amopclaid,
- Anum_pg_amproc_amprocsubtype,
- Anum_pg_amproc_amprocnum,
- 0
+ Anum_pg_amproc_amprocfamily,
+ Anum_pg_amproc_amproclefttype,
+ Anum_pg_amproc_amprocrighttype,
+ Anum_pg_amproc_amprocnum
},
64
},
@@ -255,7 +255,7 @@ static const struct cachedesc cacheinfo[] = {
0,
3,
{
- Anum_pg_opclass_opcamid,
+ Anum_pg_opclass_opcmethod,
Anum_pg_opclass_opcname,
Anum_pg_opclass_opcnamespace,
0
@@ -334,18 +334,6 @@ static const struct cachedesc cacheinfo[] = {
},
1024
},
- {InheritsRelationId, /* INHRELID */
- InheritsRelidSeqnoIndexId,
- Anum_pg_inherits_inhrelid,
- 2,
- {
- Anum_pg_inherits_inhrelid,
- Anum_pg_inherits_inhseqno,
- 0,
- 0
- },
- 256
- },
{LanguageRelationId, /* LANGNAME */
LanguageNameIndexId,
0,
@@ -418,6 +406,30 @@ static const struct cachedesc cacheinfo[] = {
},
1024
},
+ {OperatorFamilyRelationId, /* OPFAMILYAMNAMENSP */
+ OpfamilyAmNameNspIndexId,
+ 0,
+ 3,
+ {
+ Anum_pg_opfamily_opfmethod,
+ Anum_pg_opfamily_opfname,
+ Anum_pg_opfamily_opfnamespace,
+ 0
+ },
+ 64
+ },
+ {OperatorFamilyRelationId, /* OPFAMILYOID */
+ OpfamilyOidIndexId,
+ 0,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 64
+ },
{ProcedureRelationId, /* PROCNAMEARGSNSP */
ProcedureNameArgsNspIndexId,
0,
diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c
index c5a0272414d..192675c95ee 100644
--- a/src/backend/utils/cache/typcache.c
+++ b/src/backend/utils/cache/typcache.c
@@ -36,7 +36,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.22 2006/10/04 00:30:01 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.23 2006/12/23 00:43:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -165,17 +165,30 @@ lookup_type_cache(Oid type_id, int flags)
/* If we haven't already found the opclass, try to do so */
if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_LT_OPR | TYPECACHE_GT_OPR |
TYPECACHE_CMP_PROC |
- TYPECACHE_EQ_OPR_FINFO | TYPECACHE_CMP_PROC_FINFO)) &&
- typentry->btree_opc == InvalidOid)
+ TYPECACHE_EQ_OPR_FINFO | TYPECACHE_CMP_PROC_FINFO |
+ TYPECACHE_BTREE_OPFAMILY)) &&
+ typentry->btree_opf == InvalidOid)
{
- typentry->btree_opc = GetDefaultOpClass(type_id,
- BTREE_AM_OID);
+ Oid opclass;
+
+ opclass = GetDefaultOpClass(type_id, BTREE_AM_OID);
+ if (OidIsValid(opclass))
+ {
+ typentry->btree_opf = get_opclass_family(opclass);
+ typentry->btree_opintype = get_opclass_input_type(opclass);
+ }
/* Only care about hash opclass if no btree opclass... */
- if (typentry->btree_opc == InvalidOid)
+ if (typentry->btree_opf == InvalidOid)
{
- if (typentry->hash_opc == InvalidOid)
- typentry->hash_opc = GetDefaultOpClass(type_id,
- HASH_AM_OID);
+ if (typentry->hash_opf == InvalidOid)
+ {
+ opclass = GetDefaultOpClass(type_id, HASH_AM_OID);
+ if (OidIsValid(opclass))
+ {
+ typentry->hash_opf = get_opclass_family(opclass);
+ typentry->hash_opintype = get_opclass_input_type(opclass);
+ }
+ }
}
else
{
@@ -193,37 +206,42 @@ lookup_type_cache(Oid type_id, int flags)
if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) &&
typentry->eq_opr == InvalidOid)
{
- if (typentry->btree_opc != InvalidOid)
- typentry->eq_opr = get_opclass_member(typentry->btree_opc,
- InvalidOid,
- BTEqualStrategyNumber);
+ if (typentry->btree_opf != InvalidOid)
+ typentry->eq_opr = get_opfamily_member(typentry->btree_opf,
+ typentry->btree_opintype,
+ typentry->btree_opintype,
+ BTEqualStrategyNumber);
if (typentry->eq_opr == InvalidOid &&
- typentry->hash_opc != InvalidOid)
- typentry->eq_opr = get_opclass_member(typentry->hash_opc,
- InvalidOid,
- HTEqualStrategyNumber);
+ typentry->hash_opf != InvalidOid)
+ typentry->eq_opr = get_opfamily_member(typentry->hash_opf,
+ typentry->hash_opintype,
+ typentry->hash_opintype,
+ HTEqualStrategyNumber);
}
if ((flags & TYPECACHE_LT_OPR) && typentry->lt_opr == InvalidOid)
{
- if (typentry->btree_opc != InvalidOid)
- typentry->lt_opr = get_opclass_member(typentry->btree_opc,
- InvalidOid,
- BTLessStrategyNumber);
+ if (typentry->btree_opf != InvalidOid)
+ typentry->lt_opr = get_opfamily_member(typentry->btree_opf,
+ typentry->btree_opintype,
+ typentry->btree_opintype,
+ BTLessStrategyNumber);
}
if ((flags & TYPECACHE_GT_OPR) && typentry->gt_opr == InvalidOid)
{
- if (typentry->btree_opc != InvalidOid)
- typentry->gt_opr = get_opclass_member(typentry->btree_opc,
- InvalidOid,
- BTGreaterStrategyNumber);
+ if (typentry->btree_opf != InvalidOid)
+ typentry->gt_opr = get_opfamily_member(typentry->btree_opf,
+ typentry->btree_opintype,
+ typentry->btree_opintype,
+ BTGreaterStrategyNumber);
}
if ((flags & (TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO)) &&
typentry->cmp_proc == InvalidOid)
{
- if (typentry->btree_opc != InvalidOid)
- typentry->cmp_proc = get_opclass_proc(typentry->btree_opc,
- InvalidOid,
- BTORDER_PROC);
+ if (typentry->btree_opf != InvalidOid)
+ typentry->cmp_proc = get_opfamily_proc(typentry->btree_opf,
+ typentry->btree_opintype,
+ typentry->btree_opintype,
+ BTORDER_PROC);
}
/*
diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c
index 652f9a2ff44..dceaf5a6556 100644
--- a/src/backend/utils/sort/tuplesort.c
+++ b/src/backend/utils/sort/tuplesort.c
@@ -91,7 +91,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/sort/tuplesort.c,v 1.70 2006/10/04 00:30:04 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/sort/tuplesort.c,v 1.71 2006/12/23 00:43:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2104,15 +2104,16 @@ SelectSortFunction(Oid sortOperator,
int i;
HeapTuple tuple;
Form_pg_operator optup;
- Oid opclass = InvalidOid;
+ Oid opfamily = InvalidOid;
+ Oid opinputtype = InvalidOid;
/*
- * Search pg_amop to see if the target operator is registered as the "<"
- * or ">" operator of any btree opclass. It's possible that it might be
+ * Search pg_amop to see if the target operator is registered as a "<"
+ * or ">" operator of any btree opfamily. It's possible that it might be
* registered both ways (eg, if someone were to build a "reverse sort"
- * opclass for some reason); prefer the "<" case if so. If the operator is
- * registered the same way in multiple opclasses, assume we can use the
- * associated comparator function from any one.
+ * opfamily); prefer the "<" case if so. If the operator is registered the
+ * same way in multiple opfamilies, assume we can use the associated
+ * comparator function from any one.
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(sortOperator),
@@ -2125,21 +2126,24 @@ SelectSortFunction(Oid sortOperator,
tuple = &catlist->members[i]->tuple;
aform = (Form_pg_amop) GETSTRUCT(tuple);
- if (!opclass_is_btree(aform->amopclaid))
+ /* must be btree */
+ if (aform->amopmethod != BTREE_AM_OID)
continue;
- /* must be of default subtype, too */
- if (aform->amopsubtype != InvalidOid)
+ /* mustn't be cross-datatype, either */
+ if (aform->amoplefttype != aform->amoprighttype)
continue;
if (aform->amopstrategy == BTLessStrategyNumber)
{
- opclass = aform->amopclaid;
+ opfamily = aform->amopfamily;
+ opinputtype = aform->amoplefttype;
*kind = SORTFUNC_CMP;
break; /* done looking */
}
else if (aform->amopstrategy == BTGreaterStrategyNumber)
{
- opclass = aform->amopclaid;
+ opfamily = aform->amopfamily;
+ opinputtype = aform->amoplefttype;
*kind = SORTFUNC_REVCMP;
/* keep scanning in hopes of finding a BTLess entry */
}
@@ -2147,10 +2151,13 @@ SelectSortFunction(Oid sortOperator,
ReleaseSysCacheList(catlist);
- if (OidIsValid(opclass))
+ if (OidIsValid(opfamily))
{
- /* Found a suitable opclass, get its default comparator function */
- *sortFunction = get_opclass_proc(opclass, InvalidOid, BTORDER_PROC);
+ /* Found a suitable opfamily, get the matching comparator function */
+ *sortFunction = get_opfamily_proc(opfamily,
+ opinputtype,
+ opinputtype,
+ BTORDER_PROC);
Assert(RegProcedureIsValid(*sortFunction));
return;
}