lsyscache.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,698 行 · 第 1/5 页
C
2,698 行
/*------------------------------------------------------------------------- * * lsyscache.c * Convenience routines for common queries in the system catalog cache. * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.155 2008/01/01 19:45:53 momjian Exp $ * * NOTES * Eventually, the index information should go through here, too. *------------------------------------------------------------------------- */#include "postgres.h"#include "access/hash.h"#include "access/nbtree.h"#include "bootstrap/bootstrap.h"#include "catalog/pg_amop.h"#include "catalog/pg_amproc.h"#include "catalog/pg_constraint.h"#include "catalog/pg_namespace.h"#include "catalog/pg_opclass.h"#include "catalog/pg_operator.h"#include "catalog/pg_proc.h"#include "catalog/pg_statistic.h"#include "catalog/pg_type.h"#include "miscadmin.h"#include "nodes/makefuncs.h"#include "utils/array.h"#include "utils/builtins.h"#include "utils/datum.h"#include "utils/lsyscache.h"#include "utils/syscache.h"/* ---------- AMOP CACHES ---------- *//* * op_in_opfamily * * Return t iff operator 'opno' is in operator family 'opfamily'. */boolop_in_opfamily(Oid opno, Oid opfamily){ return SearchSysCacheExists(AMOPOPID, ObjectIdGetDatum(opno), ObjectIdGetDatum(opfamily), 0, 0);}/* * get_op_opfamily_strategy * * Get the operator's strategy number within the specified opfamily, * or 0 if it's not a member of the opfamily. */intget_op_opfamily_strategy(Oid opno, Oid opfamily){ HeapTuple tp; Form_pg_amop amop_tup; int result; tp = SearchSysCache(AMOPOPID, ObjectIdGetDatum(opno), ObjectIdGetDatum(opfamily), 0, 0); if (!HeapTupleIsValid(tp)) return 0; amop_tup = (Form_pg_amop) GETSTRUCT(tp); result = amop_tup->amopstrategy; ReleaseSysCache(tp); return result;}/* * get_op_opfamily_properties * * 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 opfamily, * therefore we raise an error if the tuple is not found. */voidget_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(opfamily), 0, 0); if (!HeapTupleIsValid(tp)) elog(ERROR, "operator %u is not a member of opfamily %u", opno, opfamily); amop_tup = (Form_pg_amop) GETSTRUCT(tp); *strategy = amop_tup->amopstrategy; *lefttype = amop_tup->amoplefttype; *righttype = amop_tup->amoprighttype; *recheck = amop_tup->amopreqcheck; ReleaseSysCache(tp);}/* * get_opfamily_member * Get the OID of the operator that implements the specified strategy * with the specified datatypes for the specified opfamily. * * Returns InvalidOid if there is no pg_amop entry for the given keys. */Oidget_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy){ HeapTuple tp; Form_pg_amop amop_tup; Oid result; tp = SearchSysCache(AMOPSTRATEGY, ObjectIdGetDatum(opfamily), ObjectIdGetDatum(lefttype), ObjectIdGetDatum(righttype), Int16GetDatum(strategy)); if (!HeapTupleIsValid(tp)) return InvalidOid; amop_tup = (Form_pg_amop) GETSTRUCT(tp); result = amop_tup->amopopr; ReleaseSysCache(tp); return result;}/* * get_ordering_op_properties * Given the OID of an ordering operator (a btree "<" or ">" operator), * determine its opfamily, its declared input datatype, and its * strategy number (BTLessStrategyNumber or BTGreaterStrategyNumber). * * Returns TRUE if successful, FALSE if no matching pg_amop entry exists. * (This indicates that the operator is not a valid ordering operator.) * * Note: the operator could be registered in multiple families, for example * if someone were to build a "reverse sort" opfamily. This would result in * uncertainty as to whether "ORDER BY USING op" would default to NULLS FIRST * or NULLS LAST, as well as inefficient planning due to failure to match up * pathkeys that should be the same. So we want a determinate result here. * Because of the way the syscache search works, we'll use the interpretation * associated with the opfamily with smallest OID, which is probably * determinate enough. Since there is no longer any particularly good reason * to build reverse-sort opfamilies, it doesn't seem worth expending any * additional effort on ensuring consistency. */boolget_ordering_op_properties(Oid opno, Oid *opfamily, Oid *opcintype, int16 *strategy){ bool result = false; CatCList *catlist; int i; /* ensure outputs are initialized on failure */ *opfamily = InvalidOid; *opcintype = InvalidOid; *strategy = 0; /* * Search pg_amop to see if the target operator is registered as the "<" * or ">" operator of any btree opfamily. */ catlist = SearchSysCacheList(AMOPOPID, 1, ObjectIdGetDatum(opno), 0, 0, 0); for (i = 0; i < catlist->n_members; i++) { HeapTuple tuple = &catlist->members[i]->tuple; Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple); /* must be btree */ if (aform->amopmethod != BTREE_AM_OID) continue; if (aform->amopstrategy == BTLessStrategyNumber || aform->amopstrategy == BTGreaterStrategyNumber) { /* Found it ... should have consistent input types */ if (aform->amoplefttype == aform->amoprighttype) { /* Found a suitable opfamily, return info */ *opfamily = aform->amopfamily; *opcintype = aform->amoplefttype; *strategy = aform->amopstrategy; result = true; break; } } } ReleaseSysCacheList(catlist); return result;}/* * get_compare_function_for_ordering_op * Get the OID of the datatype-specific btree comparison function * associated with an ordering operator (a "<" or ">" operator). * * *cmpfunc receives the comparison function OID. * *reverse is set FALSE if the operator is "<", TRUE if it's ">" * (indicating the comparison result must be negated before use). * * Returns TRUE if successful, FALSE if no btree function can be found. * (This indicates that the operator is not a valid ordering operator.) */boolget_compare_function_for_ordering_op(Oid opno, Oid *cmpfunc, bool *reverse){ Oid opfamily; Oid opcintype; int16 strategy; /* Find the operator in pg_amop */ if (get_ordering_op_properties(opno, &opfamily, &opcintype, &strategy)) { /* Found a suitable opfamily, get matching support function */ *cmpfunc = get_opfamily_proc(opfamily, opcintype, opcintype, BTORDER_PROC); if (!OidIsValid(*cmpfunc)) /* should not happen */ elog(ERROR, "missing support function %d(%u,%u) in opfamily %u", BTORDER_PROC, opcintype, opcintype, opfamily); *reverse = (strategy == BTGreaterStrategyNumber); return true; } /* ensure outputs are set on failure */ *cmpfunc = InvalidOid; *reverse = false; return false;}/* * get_equality_op_for_ordering_op * Get the OID of the datatype-specific btree equality operator * associated with an ordering operator (a "<" or ">" operator). * * Returns InvalidOid if no matching equality operator can be found. * (This indicates that the operator is not a valid ordering operator.) */Oidget_equality_op_for_ordering_op(Oid opno){ Oid result = InvalidOid; Oid opfamily; Oid opcintype; int16 strategy; /* Find the operator in pg_amop */ if (get_ordering_op_properties(opno, &opfamily, &opcintype, &strategy)) { /* Found a suitable opfamily, get matching equality operator */ result = get_opfamily_member(opfamily, opcintype, opcintype, BTEqualStrategyNumber); } return result;}/* * get_ordering_op_for_equality_op * Get the OID of a datatype-specific btree ordering operator * associated with an equality operator. (If there are multiple * possibilities, assume any one will do.) * * This function is used when we have to sort data before unique-ifying, * and don't much care which sorting op is used as long as it's compatible * with the intended equality operator. Since we need a sorting operator, * it should be single-data-type even if the given operator is cross-type. * The caller specifies whether to find an op for the LHS or RHS data type. * * Returns InvalidOid if no matching ordering operator can be found. */Oidget_ordering_op_for_equality_op(Oid opno, bool use_lhs_type){ Oid result = InvalidOid; CatCList *catlist; int i; /* * Search pg_amop to see if the target operator is registered as the "=" * operator of any btree opfamily. */ catlist = SearchSysCacheList(AMOPOPID, 1, ObjectIdGetDatum(opno), 0, 0, 0); for (i = 0; i < catlist->n_members; i++) { HeapTuple tuple = &catlist->members[i]->tuple; Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple); /* must be btree */ if (aform->amopmethod != BTREE_AM_OID) continue; if (aform->amopstrategy == BTEqualStrategyNumber) { /* Found a suitable opfamily, get matching ordering operator */ Oid typid; typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype; result = get_opfamily_member(aform->amopfamily, typid, typid, BTLessStrategyNumber); if (OidIsValid(result)) break; /* failure probably shouldn't happen, but keep looking if so */ } } ReleaseSysCacheList(catlist); return result;}/* * get_mergejoin_opfamilies * Given a putatively mergejoinable operator, return a list of the OIDs * of the btree opfamilies in which it represents equality. * * It is possible (though at present unusual) for an operator to be equality * in more than one opfamily, hence the result is a list. This also lets us * return NIL if the operator is not found in any opfamilies. * * The planner currently uses simple equal() tests to compare the lists * returned by this function, which makes the list order relevant, though * strictly speaking it should not be. Because of the way syscache list * searches are handled, in normal operation the result will be sorted by OID * so everything works fine. If running with system index usage disabled, * the result ordering is unspecified and hence the planner might fail to * recognize optimization opportunities ... but that's hardly a scenario in * which performance is good anyway, so there's no point in expending code * or cycles here to guarantee the ordering in that case. */List *get_mergejoin_opfamilies(Oid opno){ List *result = NIL; CatCList *catlist; int i; /* * Search pg_amop to see if the target operator is registered as the "=" * operator of any btree opfamily. */ catlist = SearchSysCacheList(AMOPOPID, 1, ObjectIdGetDatum(opno), 0, 0, 0); for (i = 0; i < catlist->n_members; i++) { HeapTuple tuple = &catlist->members[i]->tuple; Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple); /* must be btree equality */ if (aform->amopmethod == BTREE_AM_OID && aform->amopstrategy == BTEqualStrategyNumber) result = lappend_oid(result, aform->amopfamily); } ReleaseSysCacheList(catlist); return result;}/* * get_compatible_hash_operators * Get the OID(s) of hash equality operator(s) compatible with the given * operator, but operating on its LHS and/or RHS datatype. * * An operator for the LHS type is sought and returned into *lhs_opno if * lhs_opno isn't NULL. Similarly, an operator for the RHS type is sought * and returned into *rhs_opno if rhs_opno isn't NULL. * * If the given operator is not cross-type, the results should be the same * operator, but in cross-type situations they will be different. * * Returns true if able to find the requested operator(s), false if not. * (This indicates that the operator should not have been marked oprcanhash.) */boolget_compatible_hash_operators(Oid opno, Oid *lhs_opno, Oid *rhs_opno){ bool result = false; CatCList *catlist; int i; /* Ensure output args are initialized on failure */ if (lhs_opno) *lhs_opno = InvalidOid; if (rhs_opno) *rhs_opno = InvalidOid; /* * Search pg_amop to see if the target operator is registered as the "=" * operator of any hash opfamily. If the operator is registered in * multiple opfamilies, assume we can use any one. */ catlist = SearchSysCacheList(AMOPOPID, 1, ObjectIdGetDatum(opno), 0, 0, 0); for (i = 0; i < catlist->n_members; i++) { HeapTuple tuple = &catlist->members[i]->tuple; Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple); if (aform->amopmethod == HASH_AM_OID && aform->amopstrategy == HTEqualStrategyNumber) { /* No extra lookup needed if given operator is single-type */ if (aform->amoplefttype == aform->amoprighttype) { if (lhs_opno) *lhs_opno = opno; if (rhs_opno) *rhs_opno = opno; result = true; break; } /* * Get the matching single-type operator(s). Failure probably * shouldn't happen --- it implies a bogus opfamily --- but * continue looking if so. */ if (lhs_opno) { *lhs_opno = get_opfamily_member(aform->amopfamily, aform->amoplefttype, aform->amoplefttype, HTEqualStrategyNumber); if (!OidIsValid(*lhs_opno)) continue; /* Matching LHS found, done if caller doesn't want RHS */ if (!rhs_opno) { result = true; break; } } if (rhs_opno) { *rhs_opno = get_opfamily_member(aform->amopfamily, aform->amoprighttype, aform->amoprighttype, HTEqualStrategyNumber); if (!OidIsValid(*rhs_opno)) { /* Forget any LHS operator from this opfamily */ if (lhs_opno) *lhs_opno = InvalidOid; continue; } /* Matching RHS found, so done */ result = true; break; } } } ReleaseSysCacheList(catlist); return result;}/* * get_op_hash_functions * Get the OID(s) of hash support function(s) compatible with the given * operator, operating on its LHS and/or RHS datatype as required. * * A function for the LHS type is sought and returned into *lhs_procno if * lhs_procno isn't NULL. Similarly, a function for the RHS type is sought * and returned into *rhs_procno if rhs_procno isn't NULL. * * If the given operator is not cross-type, the results should be the same * function, but in cross-type situations they will be different. * * Returns true if able to find the requested function(s), false if not. * (This indicates that the operator should not have been marked oprcanhash.) */boolget_op_hash_functions(Oid opno, RegProcedure *lhs_procno, RegProcedure *rhs_procno){ bool result = false; CatCList *catlist; int i; /* Ensure output args are initialized on failure */ if (lhs_procno) *lhs_procno = InvalidOid; if (rhs_procno) *rhs_procno = InvalidOid; /* * Search pg_amop to see if the target operator is registered as the "=" * operator of any hash opfamily. If the operator is registered in * multiple opfamilies, assume we can use any one. */ catlist = SearchSysCacheList(AMOPOPID, 1, ObjectIdGetDatum(opno), 0, 0, 0); for (i = 0; i < catlist->n_members; i++) { HeapTuple tuple = &catlist->members[i]->tuple; Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple); if (aform->amopmethod == HASH_AM_OID && aform->amopstrategy == HTEqualStrategyNumber) { /*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?