diff options
Diffstat (limited to 'src/backend/utils')
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 27 | ||||
-rw-r--r-- | src/backend/utils/adt/selfuncs.c | 148 | ||||
-rw-r--r-- | src/backend/utils/cache/catcache.c | 20 | ||||
-rw-r--r-- | src/backend/utils/cache/lsyscache.c | 413 | ||||
-rw-r--r-- | src/backend/utils/cache/relcache.c | 181 | ||||
-rw-r--r-- | src/backend/utils/cache/syscache.c | 64 | ||||
-rw-r--r-- | src/backend/utils/cache/typcache.c | 76 | ||||
-rw-r--r-- | src/backend/utils/sort/tuplesort.c | 37 |
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, <op, >op, 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; } |