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 + -
显示快捷键?