mirror of
https://github.com/postgres/postgres.git
synced 2025-07-02 09:02:37 +03:00
Restructure operator classes to allow improved handling of cross-data-type
cases. Operator classes now exist within "operator families". While most families are equivalent to a single class, related classes can be grouped into one family to represent the fact that they are semantically compatible. Cross-type operators are now naturally adjunct parts of a family, without having to wedge them into a particular opclass as we had done originally. This commit restructures the catalogs and cleans up enough of the fallout so that everything still works at least as well as before, but most of the work needed to actually improve the planner's behavior will come later. Also, there are not yet CREATE/DROP/ALTER OPERATOR FAMILY commands; the only way to create a new family right now is to allow CREATE OPERATOR CLASS to make one by default. I owe some more documentation work, too. But that can all be done in smaller pieces once this infrastructure is in place.
This commit is contained in:
20
src/backend/utils/cache/catcache.c
vendored
20
src/backend/utils/cache/catcache.c
vendored
@ -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;
|
||||
|
413
src/backend/utils/cache/lsyscache.c
vendored
413
src/backend/utils/cache/lsyscache.c
vendored
@ -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);
|
||||
@ -132,11 +137,161 @@ get_opclass_member(Oid opclass, Oid subtype, int16 strategy)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,57 +317,43 @@ 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.
|
||||
*/
|
||||
@ -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,17 +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)
|
||||
Oid
|
||||
get_opclass_family(Oid opclass)
|
||||
{
|
||||
HeapTuple tp;
|
||||
Form_pg_opclass cla_tup;
|
||||
bool result;
|
||||
Oid result;
|
||||
|
||||
tp = SearchSysCache(CLAOID,
|
||||
ObjectIdGetDatum(opclass),
|
||||
@ -496,57 +631,7 @@ opclass_is_btree(Oid opclass)
|
||||
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)
|
||||
{
|
||||
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->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)
|
||||
|
181
src/backend/utils/cache/relcache.c
vendored
181
src/backend/utils/cache/relcache.c
vendored
@ -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;
|
||||
@ -947,18 +950,6 @@ RelationInitIndexAccessInfo(Relation relation)
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
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
|
||||
*/
|
||||
@ -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;
|
||||
|
||||
@ -1176,23 +1186,55 @@ LookupOpclassInfo(Oid operatorClassOid,
|
||||
(operatorClassOid != OID_BTREE_OPS_OID &&
|
||||
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(InvalidOid));
|
||||
ObjectIdGetDatum(opcentry->opcintype));
|
||||
ScanKeyInit(&skey[2],
|
||||
Anum_pg_amop_amoprighttype,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
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)),
|
||||
|
64
src/backend/utils/cache/syscache.c
vendored
64
src/backend/utils/cache/syscache.c
vendored
@ -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,
|
||||
|
78
src/backend/utils/cache/typcache.c
vendored
78
src/backend/utils/cache/typcache.c
vendored
@ -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);
|
||||
/* Only care about hash opclass if no btree opclass... */
|
||||
if (typentry->btree_opc == InvalidOid)
|
||||
Oid opclass;
|
||||
|
||||
opclass = GetDefaultOpClass(type_id, BTREE_AM_OID);
|
||||
if (OidIsValid(opclass))
|
||||
{
|
||||
if (typentry->hash_opc == InvalidOid)
|
||||
typentry->hash_opc = GetDefaultOpClass(type_id,
|
||||
HASH_AM_OID);
|
||||
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_opf == InvalidOid)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user