X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fbackend%2Futils%2Fcache%2Flsyscache.c;h=7a4306e93f5545764cbd02e6aa042120b385790c;hb=c6e3ac11b60ac4a8942ab964252d51c1c0bd8845;hp=d86a70521e3c2674b82c78b1fe0274805ba38581;hpb=bc8036fc666a8f846b1d4b2f935af7edd90eb5aa;p=postgresql diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index d86a70521e..7a4306e93f 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -3,11 +3,11 @@ * lsyscache.c * Convenience routines for common queries in the system catalog cache. * - * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2011, 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.152 2007/05/11 17:57:12 tgl Exp $ + * src/backend/utils/cache/lsyscache.c * * NOTES * Eventually, the index information should go through here, too. @@ -20,11 +20,13 @@ #include "bootstrap/bootstrap.h" #include "catalog/pg_amop.h" #include "catalog/pg_amproc.h" +#include "catalog/pg_collation.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_range.h" #include "catalog/pg_statistic.h" #include "catalog/pg_type.h" #include "miscadmin.h" @@ -32,8 +34,14 @@ #include "utils/array.h" #include "utils/builtins.h" #include "utils/datum.h" +#include "utils/fmgroids.h" #include "utils/lsyscache.h" +#include "utils/rel.h" #include "utils/syscache.h" +#include "utils/typcache.h" + +/* Hook for plugins to get control in get_attavgwidth() */ +get_attavgwidth_hook_type get_attavgwidth_hook = NULL; /* ---------- AMOP CACHES ---------- */ @@ -42,14 +50,16 @@ * op_in_opfamily * * Return t iff operator 'opno' is in operator family 'opfamily'. + * + * This function only considers search operators, not ordering operators. */ bool op_in_opfamily(Oid opno, Oid opfamily) { - return SearchSysCacheExists(AMOPOPID, - ObjectIdGetDatum(opno), - ObjectIdGetDatum(opfamily), - 0, 0); + return SearchSysCacheExists3(AMOPOPID, + ObjectIdGetDatum(opno), + CharGetDatum(AMOP_SEARCH), + ObjectIdGetDatum(opfamily)); } /* @@ -57,6 +67,8 @@ op_in_opfamily(Oid opno, Oid opfamily) * * Get the operator's strategy number within the specified opfamily, * or 0 if it's not a member of the opfamily. + * + * This function only considers search operators, not ordering operators. */ int get_op_opfamily_strategy(Oid opno, Oid opfamily) @@ -65,10 +77,10 @@ get_op_opfamily_strategy(Oid opno, Oid opfamily) Form_pg_amop amop_tup; int result; - tp = SearchSysCache(AMOPOPID, - ObjectIdGetDatum(opno), - ObjectIdGetDatum(opfamily), - 0, 0); + tp = SearchSysCache3(AMOPOPID, + ObjectIdGetDatum(opno), + CharGetDatum(AMOP_SEARCH), + ObjectIdGetDatum(opfamily)); if (!HeapTupleIsValid(tp)) return 0; amop_tup = (Form_pg_amop) GETSTRUCT(tp); @@ -77,29 +89,53 @@ get_op_opfamily_strategy(Oid opno, Oid opfamily) return result; } +/* + * get_op_opfamily_sortfamily + * + * If the operator is an ordering operator within the specified opfamily, + * return its amopsortfamily OID; else return InvalidOid. + */ +Oid +get_op_opfamily_sortfamily(Oid opno, Oid opfamily) +{ + HeapTuple tp; + Form_pg_amop amop_tup; + Oid result; + + tp = SearchSysCache3(AMOPOPID, + ObjectIdGetDatum(opno), + CharGetDatum(AMOP_ORDER), + ObjectIdGetDatum(opfamily)); + if (!HeapTupleIsValid(tp)) + return InvalidOid; + amop_tup = (Form_pg_amop) GETSTRUCT(tp); + result = amop_tup->amopsortfamily; + ReleaseSysCache(tp); + return result; +} + /* * get_op_opfamily_properties * - * Get the operator's strategy number, input types, and recheck (lossy) - * flag within the specified opfamily. + * Get the operator's strategy number and declared input data types + * 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. */ void -get_op_opfamily_properties(Oid opno, Oid opfamily, +get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op, int *strategy, Oid *lefttype, - Oid *righttype, - bool *recheck) + Oid *righttype) { HeapTuple tp; Form_pg_amop amop_tup; - tp = SearchSysCache(AMOPOPID, - ObjectIdGetDatum(opno), - ObjectIdGetDatum(opfamily), - 0, 0); + tp = SearchSysCache3(AMOPOPID, + ObjectIdGetDatum(opno), + CharGetDatum(ordering_op ? AMOP_ORDER : AMOP_SEARCH), + ObjectIdGetDatum(opfamily)); if (!HeapTupleIsValid(tp)) elog(ERROR, "operator %u is not a member of opfamily %u", opno, opfamily); @@ -107,7 +143,6 @@ get_op_opfamily_properties(Oid opno, Oid opfamily, *strategy = amop_tup->amopstrategy; *lefttype = amop_tup->amoplefttype; *righttype = amop_tup->amoprighttype; - *recheck = amop_tup->amopreqcheck; ReleaseSysCache(tp); } @@ -126,11 +161,11 @@ get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, Form_pg_amop amop_tup; Oid result; - tp = SearchSysCache(AMOPSTRATEGY, - ObjectIdGetDatum(opfamily), - ObjectIdGetDatum(lefttype), - ObjectIdGetDatum(righttype), - Int16GetDatum(strategy)); + tp = SearchSysCache4(AMOPSTRATEGY, + ObjectIdGetDatum(opfamily), + ObjectIdGetDatum(lefttype), + ObjectIdGetDatum(righttype), + Int16GetDatum(strategy)); if (!HeapTupleIsValid(tp)) return InvalidOid; amop_tup = (Form_pg_amop) GETSTRUCT(tp); @@ -149,13 +184,13 @@ get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, * (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 + * 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 + * 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. */ @@ -176,9 +211,7 @@ get_ordering_op_properties(Oid opno, * 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); + catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno)); for (i = 0; i < catlist->n_members; i++) { @@ -211,19 +244,22 @@ get_ordering_op_properties(Oid opno, } /* - * get_compare_function_for_ordering_op - * Get the OID of the datatype-specific btree comparison function + * get_sort_function_for_ordering_op + * Get the OID of the datatype-specific btree sort support function, + * or if there is none, the btree comparison function, * associated with an ordering operator (a "<" or ">" operator). * - * *cmpfunc receives the comparison function OID. + * *sortfunc receives the support or comparison function OID. + * *issupport is set TRUE if it's a support func, FALSE if a comparison func. * *reverse is set FALSE if the operator is "<", TRUE if it's ">" - * (indicating the comparison result must be negated before use). + * (indicating that comparison results 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.) */ bool -get_compare_function_for_ordering_op(Oid opno, Oid *cmpfunc, bool *reverse) +get_sort_function_for_ordering_op(Oid opno, Oid *sortfunc, + bool *issupport, bool *reverse) { Oid opfamily; Oid opcintype; @@ -234,19 +270,31 @@ get_compare_function_for_ordering_op(Oid opno, Oid *cmpfunc, bool *reverse) &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); + *sortfunc = get_opfamily_proc(opfamily, + opcintype, + opcintype, + BTSORTSUPPORT_PROC); + if (OidIsValid(*sortfunc)) + *issupport = true; + else + { + /* opfamily doesn't provide sort support, get comparison func */ + *sortfunc = get_opfamily_proc(opfamily, + opcintype, + opcintype, + BTORDER_PROC); + if (!OidIsValid(*sortfunc)) /* should not happen */ + elog(ERROR, "missing support function %d(%u,%u) in opfamily %u", + BTORDER_PROC, opcintype, opcintype, opfamily); + *issupport = false; + } *reverse = (strategy == BTGreaterStrategyNumber); return true; } /* ensure outputs are set on failure */ - *cmpfunc = InvalidOid; + *sortfunc = InvalidOid; + *issupport = false; *reverse = false; return false; } @@ -256,11 +304,14 @@ get_compare_function_for_ordering_op(Oid opno, Oid *cmpfunc, bool *reverse) * Get the OID of the datatype-specific btree equality operator * associated with an ordering operator (a "<" or ">" operator). * + * If "reverse" isn't NULL, also set *reverse to FALSE if the operator is "<", + * TRUE if it's ">" + * * Returns InvalidOid if no matching equality operator can be found. * (This indicates that the operator is not a valid ordering operator.) */ Oid -get_equality_op_for_ordering_op(Oid opno) +get_equality_op_for_ordering_op(Oid opno, bool *reverse) { Oid result = InvalidOid; Oid opfamily; @@ -276,6 +327,8 @@ get_equality_op_for_ordering_op(Oid opno) opcintype, opcintype, BTEqualStrategyNumber); + if (reverse) + *reverse = (strategy == BTGreaterStrategyNumber); } return result; @@ -306,9 +359,7 @@ get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type) * 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); + catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno)); for (i = 0; i < catlist->n_members; i++) { @@ -322,7 +373,7 @@ get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type) if (aform->amopstrategy == BTEqualStrategyNumber) { /* Found a suitable opfamily, get matching ordering operator */ - Oid typid; + Oid typid; typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype; result = get_opfamily_member(aform->amopfamily, @@ -350,7 +401,7 @@ get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type) * * 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 + * 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 @@ -369,9 +420,7 @@ get_mergejoin_opfamilies(Oid opno) * 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); + catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno)); for (i = 0; i < catlist->n_members; i++) { @@ -423,9 +472,7 @@ get_compatible_hash_operators(Oid opno, * 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); + catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno)); for (i = 0; i < catlist->n_members; i++) { @@ -445,6 +492,7 @@ get_compatible_hash_operators(Oid opno, result = true; break; } + /* * Get the matching single-type operator(s). Failure probably * shouldn't happen --- it implies a bogus opfamily --- but @@ -524,9 +572,7 @@ get_op_hash_functions(Oid opno, * 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); + catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno)); for (i = 0; i < catlist->n_members; i++) { @@ -591,55 +637,30 @@ get_op_hash_functions(Oid opno, /* * get_op_btree_interpretation * 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. + * and what properties it has within each one. The results are returned + * as a palloc'd list of OpBtreeInterpretation structs. * * In addition to the normal btree operators, we consider a <> operator to be * 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 **opfamilies, List **opstrats) +List * +get_op_btree_interpretation(Oid opno) { + List *result = NIL; + OpBtreeInterpretation *thisresult; CatCList *catlist; - bool op_negated; int i; - *opfamilies = NIL; - *opstrats = NIL; - /* * Find all the pg_amop entries containing the operator. */ - catlist = SearchSysCacheList(AMOPOPID, 1, - ObjectIdGetDatum(opno), - 0, 0, 0); - - /* - * 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) - { - Oid op_negator = get_negator(opno); - - if (OidIsValid(op_negator)) - { - op_negated = true; - ReleaseSysCacheList(catlist); - catlist = SearchSysCacheList(AMOPOPID, 1, - ObjectIdGetDatum(op_negator), - 0, 0, 0); - } - } + catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno)); - /* 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 opfamily_id; StrategyNumber op_strategy; /* must be btree */ @@ -647,56 +668,110 @@ get_op_btree_interpretation(Oid opno, List **opfamilies, List **opstrats) 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); - if (op_negated) + thisresult = (OpBtreeInterpretation *) + palloc(sizeof(OpBtreeInterpretation)); + thisresult->opfamily_id = op_form->amopfamily; + thisresult->strategy = op_strategy; + thisresult->oplefttype = op_form->amoplefttype; + thisresult->oprighttype = op_form->amoprighttype; + result = lappend(result, thisresult); + } + + ReleaseSysCacheList(catlist); + + /* + * If we didn't find any btree opfamily containing the operator, perhaps + * it is a <> operator. See if it has a negator that is in an opfamily. + */ + if (result == NIL) + { + Oid op_negator = get_negator(opno); + + if (OidIsValid(op_negator)) { - /* Only consider negators that are = */ - if (op_strategy != BTEqualStrategyNumber) - continue; - op_strategy = ROWCOMPARE_NE; - } + catlist = SearchSysCacheList1(AMOPOPID, + ObjectIdGetDatum(op_negator)); + + 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); + StrategyNumber op_strategy; - *opfamilies = lappend_oid(*opfamilies, opfamily_id); - *opstrats = lappend_int(*opstrats, op_strategy); + /* must be btree */ + if (op_form->amopmethod != BTREE_AM_OID) + continue; + + /* Get the operator's btree strategy number */ + op_strategy = (StrategyNumber) op_form->amopstrategy; + Assert(op_strategy >= 1 && op_strategy <= 5); + + /* Only consider negators that are = */ + if (op_strategy != BTEqualStrategyNumber) + continue; + + /* OK, report it with "strategy" ROWCOMPARE_NE */ + thisresult = (OpBtreeInterpretation *) + palloc(sizeof(OpBtreeInterpretation)); + thisresult->opfamily_id = op_form->amopfamily; + thisresult->strategy = ROWCOMPARE_NE; + thisresult->oplefttype = op_form->amoplefttype; + thisresult->oprighttype = op_form->amoprighttype; + result = lappend(result, thisresult); + } + + ReleaseSysCacheList(catlist); + } } - ReleaseSysCacheList(catlist); + return result; } /* - * ops_in_same_btree_opfamily - * Return TRUE if there exists a btree opfamily containing both operators. - * (This implies that they have compatible notions of equality.) + * equality_ops_are_compatible + * Return TRUE if the two given equality operators have compatible + * semantics. + * + * This is trivially true if they are the same operator. Otherwise, + * we look to see if they can be found in the same btree or hash opfamily. + * Either finding allows us to assume that they have compatible notions + * of equality. (The reason we need to do these pushups is that one might + * be a cross-type operator; for instance int24eq vs int4eq.) */ bool -ops_in_same_btree_opfamily(Oid opno1, Oid opno2) +equality_ops_are_compatible(Oid opno1, Oid opno2) { - bool result = false; + bool result; CatCList *catlist; int i; + /* Easy if they're the same operator */ + if (opno1 == opno2) + return true; + /* * We search through all the pg_amop entries for opno1. */ - catlist = SearchSysCacheList(AMOPOPID, 1, - ObjectIdGetDatum(opno1), - 0, 0, 0); + catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno1)); + + result = false; 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); - /* must be btree */ - if (op_form->amopmethod != BTREE_AM_OID) - continue; - - if (op_in_opfamily(opno2, op_form->amopfamily)) + /* must be btree or hash */ + if (op_form->amopmethod == BTREE_AM_OID || + op_form->amopmethod == HASH_AM_OID) { - result = true; - break; + if (op_in_opfamily(opno2, op_form->amopfamily)) + { + result = true; + break; + } } } @@ -722,11 +797,11 @@ get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum) Form_pg_amproc amproc_tup; RegProcedure result; - tp = SearchSysCache(AMPROCNUM, - ObjectIdGetDatum(opfamily), - ObjectIdGetDatum(lefttype), - ObjectIdGetDatum(righttype), - Int16GetDatum(procnum)); + tp = SearchSysCache4(AMPROCNUM, + ObjectIdGetDatum(opfamily), + ObjectIdGetDatum(lefttype), + ObjectIdGetDatum(righttype), + Int16GetDatum(procnum)); if (!HeapTupleIsValid(tp)) return InvalidOid; amproc_tup = (Form_pg_amproc) GETSTRUCT(tp); @@ -750,10 +825,9 @@ get_attname(Oid relid, AttrNumber attnum) { HeapTuple tp; - tp = SearchSysCache(ATTNUM, - ObjectIdGetDatum(relid), - Int16GetDatum(attnum), - 0, 0); + tp = SearchSysCache2(ATTNUM, + ObjectIdGetDatum(relid), + Int16GetDatum(attnum)); if (HeapTupleIsValid(tp)) { Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp); @@ -823,10 +897,9 @@ get_atttype(Oid relid, AttrNumber attnum) { HeapTuple tp; - tp = SearchSysCache(ATTNUM, - ObjectIdGetDatum(relid), - Int16GetDatum(attnum), - 0, 0); + tp = SearchSysCache2(ATTNUM, + ObjectIdGetDatum(relid), + Int16GetDatum(attnum)); if (HeapTupleIsValid(tp)) { Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp); @@ -851,10 +924,9 @@ get_atttypmod(Oid relid, AttrNumber attnum) { HeapTuple tp; - tp = SearchSysCache(ATTNUM, - ObjectIdGetDatum(relid), - Int16GetDatum(attnum), - 0, 0); + tp = SearchSysCache2(ATTNUM, + ObjectIdGetDatum(relid), + Int16GetDatum(attnum)); if (HeapTupleIsValid(tp)) { Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp); @@ -869,25 +941,24 @@ get_atttypmod(Oid relid, AttrNumber attnum) } /* - * get_atttypetypmod + * get_atttypetypmodcoll * - * A two-fer: given the relation id and the attribute number, - * fetch both type OID and atttypmod in a single cache lookup. + * A three-fer: given the relation id and the attribute number, + * fetch atttypid, atttypmod, and attcollation in a single cache lookup. * * Unlike the otherwise-similar get_atttype/get_atttypmod, this routine * raises an error if it can't obtain the information. */ void -get_atttypetypmod(Oid relid, AttrNumber attnum, - Oid *typid, int32 *typmod) +get_atttypetypmodcoll(Oid relid, AttrNumber attnum, + Oid *typid, int32 *typmod, Oid *collid) { HeapTuple tp; Form_pg_attribute att_tup; - tp = SearchSysCache(ATTNUM, - ObjectIdGetDatum(relid), - Int16GetDatum(attnum), - 0, 0); + tp = SearchSysCache2(ATTNUM, + ObjectIdGetDatum(relid), + Int16GetDatum(attnum)); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for attribute %d of relation %u", attnum, relid); @@ -895,9 +966,40 @@ get_atttypetypmod(Oid relid, AttrNumber attnum, *typid = att_tup->atttypid; *typmod = att_tup->atttypmod; + *collid = att_tup->attcollation; ReleaseSysCache(tp); } +/* ---------- COLLATION CACHE ---------- */ + +/* + * get_collation_name + * Returns the name of a given pg_collation entry. + * + * Returns a palloc'd copy of the string, or NULL if no such constraint. + * + * NOTE: since collation name is not unique, be wary of code that uses this + * for anything except preparing error messages. + */ +char * +get_collation_name(Oid colloid) +{ + HeapTuple tp; + + tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(colloid)); + if (HeapTupleIsValid(tp)) + { + Form_pg_collation colltup = (Form_pg_collation) GETSTRUCT(tp); + char *result; + + result = pstrdup(NameStr(colltup->collname)); + ReleaseSysCache(tp); + return result; + } + else + return NULL; +} + /* ---------- CONSTRAINT CACHE ---------- */ /* @@ -914,9 +1016,7 @@ get_constraint_name(Oid conoid) { HeapTuple tp; - tp = SearchSysCache(CONSTROID, - ObjectIdGetDatum(conoid), - 0, 0, 0); + tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conoid)); if (HeapTupleIsValid(tp)) { Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp); @@ -944,9 +1044,7 @@ get_opclass_family(Oid opclass) Form_pg_opclass cla_tup; Oid result; - tp = SearchSysCache(CLAOID, - ObjectIdGetDatum(opclass), - 0, 0, 0); + tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass)); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for opclass %u", opclass); cla_tup = (Form_pg_opclass) GETSTRUCT(tp); @@ -968,9 +1066,7 @@ get_opclass_input_type(Oid opclass) Form_pg_opclass cla_tup; Oid result; - tp = SearchSysCache(CLAOID, - ObjectIdGetDatum(opclass), - 0, 0, 0); + tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass)); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for opclass %u", opclass); cla_tup = (Form_pg_opclass) GETSTRUCT(tp); @@ -993,9 +1089,7 @@ get_opcode(Oid opno) { HeapTuple tp; - tp = SearchSysCache(OPEROID, - ObjectIdGetDatum(opno), - 0, 0, 0); + tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno)); if (HeapTupleIsValid(tp)) { Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); @@ -1020,9 +1114,7 @@ get_opname(Oid opno) { HeapTuple tp; - tp = SearchSysCache(OPEROID, - ObjectIdGetDatum(opno), - 0, 0, 0); + tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno)); if (HeapTupleIsValid(tp)) { Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); @@ -1048,9 +1140,7 @@ op_input_types(Oid opno, Oid *lefttype, Oid *righttype) HeapTuple tp; Form_pg_operator optup; - tp = SearchSysCache(OPEROID, - ObjectIdGetDatum(opno), - 0, 0, 0); + tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno)); if (!HeapTupleIsValid(tp)) /* shouldn't happen */ elog(ERROR, "cache lookup failed for operator %u", opno); optup = (Form_pg_operator) GETSTRUCT(tp); @@ -1066,22 +1156,48 @@ op_input_types(Oid opno, Oid *lefttype, Oid *righttype) * 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.) + * + * In some cases (currently only array_eq and record_eq), mergejoinability + * depends on the specific input data type the operator is invoked for, so + * that must be passed as well. We currently assume that only one input's type + * is needed to check this --- by convention, pass the left input's data type. */ bool -op_mergejoinable(Oid opno) +op_mergejoinable(Oid opno, Oid inputtype) { - HeapTuple tp; bool result = false; + HeapTuple tp; + TypeCacheEntry *typentry; - tp = SearchSysCache(OPEROID, - ObjectIdGetDatum(opno), - 0, 0, 0); - if (HeapTupleIsValid(tp)) + /* + * For array_eq or record_eq, we can sort if the element or field types + * are all sortable. We could implement all the checks for that here, but + * the typcache already does that and caches the results too, so let's + * rely on the typcache. + */ + if (opno == ARRAY_EQ_OP) { - Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); + typentry = lookup_type_cache(inputtype, TYPECACHE_CMP_PROC); + if (typentry->cmp_proc == F_BTARRAYCMP) + result = true; + } + else if (opno == RECORD_EQ_OP) + { + typentry = lookup_type_cache(inputtype, TYPECACHE_CMP_PROC); + if (typentry->cmp_proc == F_BTRECORDCMP) + result = true; + } + else + { + /* For all other operators, rely on pg_operator.oprcanmerge */ + tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno)); + if (HeapTupleIsValid(tp)) + { + Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); - result = optup->oprcanmerge; - ReleaseSysCache(tp); + result = optup->oprcanmerge; + ReleaseSysCache(tp); + } } return result; } @@ -1091,22 +1207,38 @@ op_mergejoinable(Oid opno) * * Returns true if the operator is hashjoinable. (There must be a suitable * hash opfamily entry for this operator if it is so marked.) + * + * In some cases (currently only array_eq), hashjoinability depends on the + * specific input data type the operator is invoked for, so that must be + * passed as well. We currently assume that only one input's type is needed + * to check this --- by convention, pass the left input's data type. */ bool -op_hashjoinable(Oid opno) +op_hashjoinable(Oid opno, Oid inputtype) { - HeapTuple tp; bool result = false; + HeapTuple tp; + TypeCacheEntry *typentry; - tp = SearchSysCache(OPEROID, - ObjectIdGetDatum(opno), - 0, 0, 0); - if (HeapTupleIsValid(tp)) + /* As in op_mergejoinable, let the typcache handle the hard cases */ + /* Eventually we'll need a similar case for record_eq ... */ + if (opno == ARRAY_EQ_OP) { - Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); + typentry = lookup_type_cache(inputtype, TYPECACHE_HASH_PROC); + if (typentry->hash_proc == F_HASH_ARRAY) + result = true; + } + else + { + /* For all other operators, rely on pg_operator.oprcanhash */ + tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno)); + if (HeapTupleIsValid(tp)) + { + Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); - result = optup->oprcanhash; - ReleaseSysCache(tp); + result = optup->oprcanhash; + ReleaseSysCache(tp); + } } return result; } @@ -1153,9 +1285,7 @@ get_commutator(Oid opno) { HeapTuple tp; - tp = SearchSysCache(OPEROID, - ObjectIdGetDatum(opno), - 0, 0, 0); + tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno)); if (HeapTupleIsValid(tp)) { Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); @@ -1179,9 +1309,7 @@ get_negator(Oid opno) { HeapTuple tp; - tp = SearchSysCache(OPEROID, - ObjectIdGetDatum(opno), - 0, 0, 0); + tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno)); if (HeapTupleIsValid(tp)) { Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); @@ -1205,9 +1333,7 @@ get_oprrest(Oid opno) { HeapTuple tp; - tp = SearchSysCache(OPEROID, - ObjectIdGetDatum(opno), - 0, 0, 0); + tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno)); if (HeapTupleIsValid(tp)) { Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); @@ -1231,9 +1357,7 @@ get_oprjoin(Oid opno) { HeapTuple tp; - tp = SearchSysCache(OPEROID, - ObjectIdGetDatum(opno), - 0, 0, 0); + tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno)); if (HeapTupleIsValid(tp)) { Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp); @@ -1260,9 +1384,7 @@ get_func_name(Oid funcid) { HeapTuple tp; - tp = SearchSysCache(PROCOID, - ObjectIdGetDatum(funcid), - 0, 0, 0); + tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (HeapTupleIsValid(tp)) { Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp); @@ -1276,6 +1398,30 @@ get_func_name(Oid funcid) return NULL; } +/* + * get_func_namespace + * + * Returns the pg_namespace OID associated with a given function. + */ +Oid +get_func_namespace(Oid funcid) +{ + HeapTuple tp; + + tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); + if (HeapTupleIsValid(tp)) + { + Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp); + Oid result; + + result = functup->pronamespace; + ReleaseSysCache(tp); + return result; + } + else + return InvalidOid; +} + /* * get_func_rettype * Given procedure id, return the function's result type. @@ -1286,9 +1432,7 @@ get_func_rettype(Oid funcid) HeapTuple tp; Oid result; - tp = SearchSysCache(PROCOID, - ObjectIdGetDatum(funcid), - 0, 0, 0); + tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for function %u", funcid); @@ -1307,9 +1451,7 @@ get_func_nargs(Oid funcid) HeapTuple tp; int result; - tp = SearchSysCache(PROCOID, - ObjectIdGetDatum(funcid), - 0, 0, 0); + tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for function %u", funcid); @@ -1332,9 +1474,7 @@ get_func_signature(Oid funcid, Oid **argtypes, int *nargs) Form_pg_proc procstruct; Oid result; - tp = SearchSysCache(PROCOID, - ObjectIdGetDatum(funcid), - 0, 0, 0); + tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for function %u", funcid); @@ -1360,9 +1500,7 @@ get_func_retset(Oid funcid) HeapTuple tp; bool result; - tp = SearchSysCache(PROCOID, - ObjectIdGetDatum(funcid), - 0, 0, 0); + tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for function %u", funcid); @@ -1381,9 +1519,7 @@ func_strict(Oid funcid) HeapTuple tp; bool result; - tp = SearchSysCache(PROCOID, - ObjectIdGetDatum(funcid), - 0, 0, 0); + tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for function %u", funcid); @@ -1402,9 +1538,7 @@ func_volatile(Oid funcid) HeapTuple tp; char result; - tp = SearchSysCache(PROCOID, - ObjectIdGetDatum(funcid), - 0, 0, 0); + tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for function %u", funcid); @@ -1423,9 +1557,7 @@ get_func_cost(Oid funcid) HeapTuple tp; float4 result; - tp = SearchSysCache(PROCOID, - ObjectIdGetDatum(funcid), - 0, 0, 0); + tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for function %u", funcid); @@ -1444,9 +1576,7 @@ get_func_rows(Oid funcid) HeapTuple tp; float4 result; - tp = SearchSysCache(PROCOID, - ObjectIdGetDatum(funcid), - 0, 0, 0); + tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for function %u", funcid); @@ -1466,10 +1596,9 @@ get_func_rows(Oid funcid) Oid get_relname_relid(const char *relname, Oid relnamespace) { - return GetSysCacheOid(RELNAMENSP, - PointerGetDatum(relname), - ObjectIdGetDatum(relnamespace), - 0, 0); + return GetSysCacheOid2(RELNAMENSP, + PointerGetDatum(relname), + ObjectIdGetDatum(relnamespace)); } #ifdef NOT_USED @@ -1483,9 +1612,7 @@ get_relnatts(Oid relid) { HeapTuple tp; - tp = SearchSysCache(RELOID, - ObjectIdGetDatum(relid), - 0, 0, 0); + tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); if (HeapTupleIsValid(tp)) { Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp); @@ -1514,9 +1641,7 @@ get_rel_name(Oid relid) { HeapTuple tp; - tp = SearchSysCache(RELOID, - ObjectIdGetDatum(relid), - 0, 0, 0); + tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); if (HeapTupleIsValid(tp)) { Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp); @@ -1540,9 +1665,7 @@ get_rel_namespace(Oid relid) { HeapTuple tp; - tp = SearchSysCache(RELOID, - ObjectIdGetDatum(relid), - 0, 0, 0); + tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); if (HeapTupleIsValid(tp)) { Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp); @@ -1569,9 +1692,7 @@ get_rel_type_id(Oid relid) { HeapTuple tp; - tp = SearchSysCache(RELOID, - ObjectIdGetDatum(relid), - 0, 0, 0); + tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); if (HeapTupleIsValid(tp)) { Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp); @@ -1595,9 +1716,7 @@ get_rel_relkind(Oid relid) { HeapTuple tp; - tp = SearchSysCache(RELOID, - ObjectIdGetDatum(relid), - 0, 0, 0); + tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); if (HeapTupleIsValid(tp)) { Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp); @@ -1611,6 +1730,33 @@ get_rel_relkind(Oid relid) return '\0'; } +/* + * get_rel_tablespace + * + * Returns the pg_tablespace OID associated with a given relation. + * + * Note: InvalidOid might mean either that we couldn't find the relation, + * or that it is in the database's default tablespace. + */ +Oid +get_rel_tablespace(Oid relid) +{ + HeapTuple tp; + + tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); + if (HeapTupleIsValid(tp)) + { + Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp); + Oid result; + + result = reltup->reltablespace; + ReleaseSysCache(tp); + return result; + } + else + return InvalidOid; +} + /* ---------- TYPE CACHE ---------- */ @@ -1625,9 +1771,7 @@ get_typisdefined(Oid typid) { HeapTuple tp; - tp = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); if (HeapTupleIsValid(tp)) { Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); @@ -1651,9 +1795,7 @@ get_typlen(Oid typid) { HeapTuple tp; - tp = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); if (HeapTupleIsValid(tp)) { Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); @@ -1678,9 +1820,7 @@ get_typbyval(Oid typid) { HeapTuple tp; - tp = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); if (HeapTupleIsValid(tp)) { Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); @@ -1710,9 +1850,7 @@ get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval) HeapTuple tp; Form_pg_type typtup; - tp = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for type %u", typid); typtup = (Form_pg_type) GETSTRUCT(tp); @@ -1733,9 +1871,7 @@ get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, HeapTuple tp; Form_pg_type typtup; - tp = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for type %u", typid); typtup = (Form_pg_type) GETSTRUCT(tp); @@ -1767,10 +1903,9 @@ getTypeIOParam(HeapTuple typeTuple) /* * Array types get their typelem as parameter; everybody else gets their - * own type OID as parameter. (As of 8.2, domains must get their own OID - * even if their base type is an array.) + * own type OID as parameter. */ - if (typeStruct->typtype == TYPTYPE_BASE && OidIsValid(typeStruct->typelem)) + if (OidIsValid(typeStruct->typelem)) return typeStruct->typelem; else return HeapTupleGetOid(typeTuple); @@ -1828,9 +1963,7 @@ get_type_io_data(Oid typid, return; } - typeTuple = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); if (!HeapTupleIsValid(typeTuple)) elog(ERROR, "cache lookup failed for type %u", typid); typeStruct = (Form_pg_type) GETSTRUCT(typeTuple); @@ -1864,9 +1997,7 @@ get_typalign(Oid typid) { HeapTuple tp; - tp = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); if (HeapTupleIsValid(tp)) { Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); @@ -1886,9 +2017,7 @@ get_typstorage(Oid typid) { HeapTuple tp; - tp = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); if (HeapTupleIsValid(tp)) { Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); @@ -1921,9 +2050,7 @@ get_typdefault(Oid typid) bool isNull; Node *expr; - typeTuple = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); if (!HeapTupleIsValid(typeTuple)) elog(ERROR, "cache lookup failed for type %u", typid); type = (Form_pg_type) GETSTRUCT(typeTuple); @@ -1941,8 +2068,7 @@ get_typdefault(Oid typid) if (!isNull) { /* We have an expression default */ - expr = stringToNode(DatumGetCString(DirectFunctionCall1(textout, - datum))); + expr = stringToNode(TextDatumGetCString(datum)); } else { @@ -1957,14 +2083,14 @@ get_typdefault(Oid typid) char *strDefaultVal; /* Convert text datum to C string */ - strDefaultVal = DatumGetCString(DirectFunctionCall1(textout, - datum)); + strDefaultVal = TextDatumGetCString(datum); /* Convert C string to a value of the given type */ datum = OidInputFunctionCall(type->typinput, strDefaultVal, getTypeIOParam(typeTuple), -1); /* Build a Const node containing the value */ expr = (Node *) makeConst(typid, -1, + type->typcollation, type->typlen, datum, false, @@ -2016,9 +2142,7 @@ getBaseTypeAndTypmod(Oid typid, int32 *typmod) HeapTuple tup; Form_pg_type typTup; - tup = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", typid); typTup = (Form_pg_type) GETSTRUCT(tup); @@ -2103,9 +2227,7 @@ get_typtype(Oid typid) { HeapTuple tp; - tp = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); if (HeapTupleIsValid(tp)) { Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); @@ -2133,7 +2255,7 @@ type_is_rowtype(Oid typid) /* * type_is_enum - * Returns true if the given type is an enum type. + * Returns true if the given type is an enum type. */ bool type_is_enum(Oid typid) @@ -2141,6 +2263,37 @@ type_is_enum(Oid typid) return (get_typtype(typid) == TYPTYPE_ENUM); } +/* + * type_is_range + * Returns true if the given type is a range type. + */ +bool +type_is_range(Oid typid) +{ + return (get_typtype(typid) == TYPTYPE_RANGE); +} + +/* + * get_type_category_preferred + * + * Given the type OID, fetch its category and preferred-type status. + * Throws error on failure. + */ +void +get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred) +{ + HeapTuple tp; + Form_pg_type typtup; + + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for type %u", typid); + typtup = (Form_pg_type) GETSTRUCT(tp); + *typcategory = typtup->typcategory; + *typispreferred = typtup->typispreferred; + ReleaseSysCache(tp); +} + /* * get_typ_typrelid * @@ -2152,9 +2305,7 @@ get_typ_typrelid(Oid typid) { HeapTuple tp; - tp = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); if (HeapTupleIsValid(tp)) { Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); @@ -2181,9 +2332,7 @@ get_element_type(Oid typid) { HeapTuple tp; - tp = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); if (HeapTupleIsValid(tp)) { Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); @@ -2210,11 +2359,9 @@ Oid get_array_type(Oid typid) { HeapTuple tp; - Oid result = InvalidOid; + Oid result = InvalidOid; - tp = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); if (HeapTupleIsValid(tp)) { result = ((Form_pg_type) GETSTRUCT(tp))->typarray; @@ -2223,6 +2370,52 @@ get_array_type(Oid typid) return result; } +/* + * get_base_element_type + * Given the type OID, get the typelem, looking "through" any domain + * to its underlying array type. + * + * This is equivalent to get_element_type(getBaseType(typid)), but avoids + * an extra cache lookup. Note that it fails to provide any information + * about the typmod of the array. + */ +Oid +get_base_element_type(Oid typid) +{ + /* + * We loop to find the bottom base type in a stack of domains. + */ + for (;;) + { + HeapTuple tup; + Form_pg_type typTup; + + tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); + if (!HeapTupleIsValid(tup)) + break; + typTup = (Form_pg_type) GETSTRUCT(tup); + if (typTup->typtype != TYPTYPE_DOMAIN) + { + /* Not a domain, so stop descending */ + Oid result; + + /* This test must match get_element_type */ + if (typTup->typlen == -1) + result = typTup->typelem; + else + result = InvalidOid; + ReleaseSysCache(tup); + return result; + } + + typid = typTup->typbasetype; + ReleaseSysCache(tup); + } + + /* Like get_element_type, silently return InvalidOid for bogus input */ + return InvalidOid; +} + /* * getTypeInputInfo * @@ -2234,9 +2427,7 @@ getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam) HeapTuple typeTuple; Form_pg_type pt; - typeTuple = SearchSysCache(TYPEOID, - ObjectIdGetDatum(type), - 0, 0, 0); + typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type)); if (!HeapTupleIsValid(typeTuple)) elog(ERROR, "cache lookup failed for type %u", type); pt = (Form_pg_type) GETSTRUCT(typeTuple); @@ -2269,9 +2460,7 @@ getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena) HeapTuple typeTuple; Form_pg_type pt; - typeTuple = SearchSysCache(TYPEOID, - ObjectIdGetDatum(type), - 0, 0, 0); + typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type)); if (!HeapTupleIsValid(typeTuple)) elog(ERROR, "cache lookup failed for type %u", type); pt = (Form_pg_type) GETSTRUCT(typeTuple); @@ -2304,9 +2493,7 @@ getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam) HeapTuple typeTuple; Form_pg_type pt; - typeTuple = SearchSysCache(TYPEOID, - ObjectIdGetDatum(type), - 0, 0, 0); + typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type)); if (!HeapTupleIsValid(typeTuple)) elog(ERROR, "cache lookup failed for type %u", type); pt = (Form_pg_type) GETSTRUCT(typeTuple); @@ -2339,9 +2526,7 @@ getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena) HeapTuple typeTuple; Form_pg_type pt; - typeTuple = SearchSysCache(TYPEOID, - ObjectIdGetDatum(type), - 0, 0, 0); + typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type)); if (!HeapTupleIsValid(typeTuple)) elog(ERROR, "cache lookup failed for type %u", type); pt = (Form_pg_type) GETSTRUCT(typeTuple); @@ -2373,9 +2558,7 @@ get_typmodin(Oid typid) { HeapTuple tp; - tp = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); if (HeapTupleIsValid(tp)) { Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); @@ -2400,9 +2583,7 @@ get_typmodout(Oid typid) { HeapTuple tp; - tp = SearchSysCache(TYPEOID, - ObjectIdGetDatum(typid), - 0, 0, 0); + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); if (HeapTupleIsValid(tp)) { Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); @@ -2415,7 +2596,43 @@ get_typmodout(Oid typid) else return InvalidOid; } -#endif /* NOT_USED */ +#endif /* NOT_USED */ + +/* + * get_typcollation + * + * Given the type OID, return the type's typcollation attribute. + */ +Oid +get_typcollation(Oid typid) +{ + HeapTuple tp; + + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); + if (HeapTupleIsValid(tp)) + { + Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); + Oid result; + + result = typtup->typcollation; + ReleaseSysCache(tp); + return result; + } + else + return InvalidOid; +} + + +/* + * type_is_collatable + * + * Return whether the type cares about collations + */ +bool +type_is_collatable(Oid typid) +{ + return OidIsValid(get_typcollation(typid)); +} /* ---------- STATISTICS CACHE ---------- */ @@ -2425,20 +2642,33 @@ get_typmodout(Oid typid) * * Given the table and attribute number of a column, get the average * width of entries in the column. Return zero if no data available. + * + * Currently this is only consulted for individual tables, not for inheritance + * trees, so we don't need an "inh" parameter. + * + * Calling a hook at this point looks somewhat strange, but is required + * because the optimizer calls this function without any other way for + * plug-ins to control the result. */ int32 get_attavgwidth(Oid relid, AttrNumber attnum) { HeapTuple tp; + int32 stawidth; - tp = SearchSysCache(STATRELATT, - ObjectIdGetDatum(relid), - Int16GetDatum(attnum), - 0, 0); + if (get_attavgwidth_hook) + { + stawidth = (*get_attavgwidth_hook) (relid, attnum); + if (stawidth > 0) + return stawidth; + } + tp = SearchSysCache3(STATRELATTINH, + ObjectIdGetDatum(relid), + Int16GetDatum(attnum), + BoolGetDatum(false)); if (HeapTupleIsValid(tp)) { - int32 stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth; - + stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth; ReleaseSysCache(tp); if (stawidth > 0) return stawidth; @@ -2456,12 +2686,16 @@ get_attavgwidth(Oid relid, AttrNumber attnum) * already-looked-up tuple in the pg_statistic cache. We do this since * most callers will want to extract more than one value from the cache * entry, and we don't want to repeat the cache lookup unnecessarily. + * Also, this API allows this routine to be used with statistics tuples + * that have been provided by a stats hook and didn't really come from + * pg_statistic. * * statstuple: pg_statistics tuple to be examined. * atttype: type OID of attribute (can be InvalidOid if values == NULL). * atttypmod: typmod of attribute (can be 0 if values == NULL). * reqkind: STAKIND code for desired statistics slot kind. * reqop: STAOP value wanted, or InvalidOid if don't care. + * actualop: if not NULL, *actualop receives the actual STAOP value. * values, nvalues: if not NULL, the slot's stavalues are extracted. * numbers, nnumbers: if not NULL, the slot's stanumbers are extracted. * @@ -2469,11 +2703,16 @@ get_attavgwidth(Oid relid, AttrNumber attnum) * If the attribute type is pass-by-reference, the values referenced by * the values array are themselves palloc'd. The palloc'd stuff can be * freed by calling free_attstatsslot. + * + * Note: at present, atttype/atttypmod aren't actually used here at all. + * But the caller must have the correct (or at least binary-compatible) + * type ID to pass to free_attstatsslot later. */ bool get_attstatsslot(HeapTuple statstuple, Oid atttype, int32 atttypmod, int reqkind, Oid reqop, + Oid *actualop, Datum **values, int *nvalues, float4 **numbers, int *nnumbers) { @@ -2483,6 +2722,7 @@ get_attstatsslot(HeapTuple statstuple, Datum val; bool isnull; ArrayType *statarray; + Oid arrayelemtype; int narrayelem; HeapTuple typeTuple; Form_pg_type typeForm; @@ -2496,26 +2736,34 @@ get_attstatsslot(HeapTuple statstuple, if (i >= STATISTIC_NUM_SLOTS) return false; /* not there */ + if (actualop) + *actualop = (&stats->staop1)[i]; + if (values) { - val = SysCacheGetAttr(STATRELATT, statstuple, + val = SysCacheGetAttr(STATRELATTINH, statstuple, Anum_pg_statistic_stavalues1 + i, &isnull); if (isnull) elog(ERROR, "stavalues is null"); statarray = DatumGetArrayTypeP(val); - /* Need to get info about the array element type */ - typeTuple = SearchSysCache(TYPEOID, - ObjectIdGetDatum(atttype), - 0, 0, 0); + /* + * Need to get info about the array element type. We look at the + * actual element type embedded in the array, which might be only + * binary-compatible with the passed-in atttype. The info we extract + * here should be the same either way, but deconstruct_array is picky + * about having an exact type OID match. + */ + arrayelemtype = ARR_ELEMTYPE(statarray); + typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrayelemtype)); if (!HeapTupleIsValid(typeTuple)) - elog(ERROR, "cache lookup failed for type %u", atttype); + elog(ERROR, "cache lookup failed for type %u", arrayelemtype); typeForm = (Form_pg_type) GETSTRUCT(typeTuple); /* Deconstruct array into Datum elements; NULLs not expected */ deconstruct_array(statarray, - atttype, + arrayelemtype, typeForm->typlen, typeForm->typbyval, typeForm->typalign, @@ -2547,7 +2795,7 @@ get_attstatsslot(HeapTuple statstuple, if (numbers) { - val = SysCacheGetAttr(STATRELATT, statstuple, + val = SysCacheGetAttr(STATRELATTINH, statstuple, Anum_pg_statistic_stanumbers1 + i, &isnull); if (isnull) @@ -2617,9 +2865,7 @@ get_namespace_name(Oid nspid) { HeapTuple tp; - tp = SearchSysCache(NAMESPACEOID, - ObjectIdGetDatum(nspid), - 0, 0, 0); + tp = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid)); if (HeapTupleIsValid(tp)) { Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp); @@ -2633,35 +2879,29 @@ get_namespace_name(Oid nspid) return NULL; } -/* ---------- PG_AUTHID CACHE ---------- */ +/* ---------- PG_RANGE CACHE ---------- */ /* - * get_roleid - * Given a role name, look up the role's OID. - * Returns InvalidOid if no such role. + * get_range_subtype + * Returns the subtype of a given range type + * + * Returns InvalidOid if the type is not a range type. */ Oid -get_roleid(const char *rolname) +get_range_subtype(Oid rangeOid) { - return GetSysCacheOid(AUTHNAME, - PointerGetDatum(rolname), - 0, 0, 0); -} + HeapTuple tp; -/* - * get_roleid_checked - * Given a role name, look up the role's OID. - * ereports if no such role. - */ -Oid -get_roleid_checked(const char *rolname) -{ - Oid roleid; + tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid)); + if (HeapTupleIsValid(tp)) + { + Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp); + Oid result; - roleid = get_roleid(rolname); - if (!OidIsValid(roleid)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("role \"%s\" does not exist", rolname))); - return roleid; + result = rngtup->rngsubtype; + ReleaseSysCache(tp); + return result; + } + else + return InvalidOid; }