LCOV - code coverage report
Current view: top level - src/backend/utils/cache - lsyscache.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 1055 1189 88.7 %
Date: 2025-04-29 23:15:32 Functions: 119 121 98.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * lsyscache.c
       4             :  *    Convenience routines for common queries in the system catalog cache.
       5             :  *
       6             :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  * IDENTIFICATION
      10             :  *    src/backend/utils/cache/lsyscache.c
      11             :  *
      12             :  * NOTES
      13             :  *    Eventually, the index information should go through here, too.
      14             :  *-------------------------------------------------------------------------
      15             :  */
      16             : #include "postgres.h"
      17             : 
      18             : #include "access/hash.h"
      19             : #include "access/htup_details.h"
      20             : #include "bootstrap/bootstrap.h"
      21             : #include "catalog/namespace.h"
      22             : #include "catalog/pg_am.h"
      23             : #include "catalog/pg_amop.h"
      24             : #include "catalog/pg_amproc.h"
      25             : #include "catalog/pg_cast.h"
      26             : #include "catalog/pg_class.h"
      27             : #include "catalog/pg_collation.h"
      28             : #include "catalog/pg_constraint.h"
      29             : #include "catalog/pg_index.h"
      30             : #include "catalog/pg_language.h"
      31             : #include "catalog/pg_namespace.h"
      32             : #include "catalog/pg_opclass.h"
      33             : #include "catalog/pg_opfamily.h"
      34             : #include "catalog/pg_operator.h"
      35             : #include "catalog/pg_proc.h"
      36             : #include "catalog/pg_publication.h"
      37             : #include "catalog/pg_range.h"
      38             : #include "catalog/pg_statistic.h"
      39             : #include "catalog/pg_subscription.h"
      40             : #include "catalog/pg_transform.h"
      41             : #include "catalog/pg_type.h"
      42             : #include "miscadmin.h"
      43             : #include "nodes/makefuncs.h"
      44             : #include "utils/array.h"
      45             : #include "utils/builtins.h"
      46             : #include "utils/catcache.h"
      47             : #include "utils/datum.h"
      48             : #include "utils/fmgroids.h"
      49             : #include "utils/lsyscache.h"
      50             : #include "utils/syscache.h"
      51             : #include "utils/typcache.h"
      52             : 
      53             : /* Hook for plugins to get control in get_attavgwidth() */
      54             : get_attavgwidth_hook_type get_attavgwidth_hook = NULL;
      55             : 
      56             : 
      57             : /*              ---------- AMOP CACHES ----------                        */
      58             : 
      59             : /*
      60             :  * op_in_opfamily
      61             :  *
      62             :  *      Return t iff operator 'opno' is in operator family 'opfamily'.
      63             :  *
      64             :  * This function only considers search operators, not ordering operators.
      65             :  */
      66             : bool
      67      561456 : op_in_opfamily(Oid opno, Oid opfamily)
      68             : {
      69      561456 :     return SearchSysCacheExists3(AMOPOPID,
      70             :                                  ObjectIdGetDatum(opno),
      71             :                                  CharGetDatum(AMOP_SEARCH),
      72             :                                  ObjectIdGetDatum(opfamily));
      73             : }
      74             : 
      75             : /*
      76             :  * get_op_opfamily_strategy
      77             :  *
      78             :  *      Get the operator's strategy number within the specified opfamily,
      79             :  *      or 0 if it's not a member of the opfamily.
      80             :  *
      81             :  * This function only considers search operators, not ordering operators.
      82             :  */
      83             : int
      84      671928 : get_op_opfamily_strategy(Oid opno, Oid opfamily)
      85             : {
      86             :     HeapTuple   tp;
      87             :     Form_pg_amop amop_tup;
      88             :     int         result;
      89             : 
      90      671928 :     tp = SearchSysCache3(AMOPOPID,
      91             :                          ObjectIdGetDatum(opno),
      92             :                          CharGetDatum(AMOP_SEARCH),
      93             :                          ObjectIdGetDatum(opfamily));
      94      671928 :     if (!HeapTupleIsValid(tp))
      95           0 :         return 0;
      96      671928 :     amop_tup = (Form_pg_amop) GETSTRUCT(tp);
      97      671928 :     result = amop_tup->amopstrategy;
      98      671928 :     ReleaseSysCache(tp);
      99      671928 :     return result;
     100             : }
     101             : 
     102             : /*
     103             :  * get_op_opfamily_sortfamily
     104             :  *
     105             :  *      If the operator is an ordering operator within the specified opfamily,
     106             :  *      return its amopsortfamily OID; else return InvalidOid.
     107             :  */
     108             : Oid
     109         474 : get_op_opfamily_sortfamily(Oid opno, Oid opfamily)
     110             : {
     111             :     HeapTuple   tp;
     112             :     Form_pg_amop amop_tup;
     113             :     Oid         result;
     114             : 
     115         474 :     tp = SearchSysCache3(AMOPOPID,
     116             :                          ObjectIdGetDatum(opno),
     117             :                          CharGetDatum(AMOP_ORDER),
     118             :                          ObjectIdGetDatum(opfamily));
     119         474 :     if (!HeapTupleIsValid(tp))
     120           0 :         return InvalidOid;
     121         474 :     amop_tup = (Form_pg_amop) GETSTRUCT(tp);
     122         474 :     result = amop_tup->amopsortfamily;
     123         474 :     ReleaseSysCache(tp);
     124         474 :     return result;
     125             : }
     126             : 
     127             : /*
     128             :  * get_op_opfamily_properties
     129             :  *
     130             :  *      Get the operator's strategy number and declared input data types
     131             :  *      within the specified opfamily.
     132             :  *
     133             :  * Caller should already have verified that opno is a member of opfamily,
     134             :  * therefore we raise an error if the tuple is not found.
     135             :  */
     136             : void
     137      378256 : get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op,
     138             :                            int *strategy,
     139             :                            Oid *lefttype,
     140             :                            Oid *righttype)
     141             : {
     142             :     HeapTuple   tp;
     143             :     Form_pg_amop amop_tup;
     144             : 
     145      378256 :     tp = SearchSysCache3(AMOPOPID,
     146             :                          ObjectIdGetDatum(opno),
     147             :                          CharGetDatum(ordering_op ? AMOP_ORDER : AMOP_SEARCH),
     148             :                          ObjectIdGetDatum(opfamily));
     149      378256 :     if (!HeapTupleIsValid(tp))
     150           0 :         elog(ERROR, "operator %u is not a member of opfamily %u",
     151             :              opno, opfamily);
     152      378256 :     amop_tup = (Form_pg_amop) GETSTRUCT(tp);
     153      378256 :     *strategy = amop_tup->amopstrategy;
     154      378256 :     *lefttype = amop_tup->amoplefttype;
     155      378256 :     *righttype = amop_tup->amoprighttype;
     156      378256 :     ReleaseSysCache(tp);
     157      378256 : }
     158             : 
     159             : /*
     160             :  * get_opfamily_member
     161             :  *      Get the OID of the operator that implements the specified strategy
     162             :  *      with the specified datatypes for the specified opfamily.
     163             :  *
     164             :  * Returns InvalidOid if there is no pg_amop entry for the given keys.
     165             :  */
     166             : Oid
     167     3615566 : get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
     168             :                     int16 strategy)
     169             : {
     170             :     HeapTuple   tp;
     171             :     Form_pg_amop amop_tup;
     172             :     Oid         result;
     173             : 
     174     3615566 :     tp = SearchSysCache4(AMOPSTRATEGY,
     175             :                          ObjectIdGetDatum(opfamily),
     176             :                          ObjectIdGetDatum(lefttype),
     177             :                          ObjectIdGetDatum(righttype),
     178             :                          Int16GetDatum(strategy));
     179     3615566 :     if (!HeapTupleIsValid(tp))
     180         754 :         return InvalidOid;
     181     3614812 :     amop_tup = (Form_pg_amop) GETSTRUCT(tp);
     182     3614812 :     result = amop_tup->amopopr;
     183     3614812 :     ReleaseSysCache(tp);
     184     3614812 :     return result;
     185             : }
     186             : 
     187             : /*
     188             :  * get_opfamily_member_for_cmptype
     189             :  *      Get the OID of the operator that implements the specified comparison
     190             :  *      type with the specified datatypes for the specified opfamily.
     191             :  *
     192             :  * Returns InvalidOid if there is no mapping for the comparison type or no
     193             :  * pg_amop entry for the given keys.
     194             :  */
     195             : Oid
     196     2527004 : get_opfamily_member_for_cmptype(Oid opfamily, Oid lefttype, Oid righttype,
     197             :                                 CompareType cmptype)
     198             : {
     199             :     Oid         opmethod;
     200             :     StrategyNumber strategy;
     201             : 
     202     2527004 :     opmethod = get_opfamily_method(opfamily);
     203     2527004 :     strategy = IndexAmTranslateCompareType(cmptype, opmethod, opfamily, true);
     204     2527004 :     if (!strategy)
     205           0 :         return InvalidOid;
     206     2527004 :     return get_opfamily_member(opfamily, lefttype, righttype, strategy);
     207             : }
     208             : 
     209             : /*
     210             :  * get_opmethod_canorder
     211             :  *      Return amcanorder field for given index AM.
     212             :  *
     213             :  * To speed things up in the common cases, we're hardcoding the results from
     214             :  * the built-in index types.  Note that we also need to hardcode the negative
     215             :  * results from the built-in non-btree index types, since you'll usually get a
     216             :  * few hits for those as well.  It would be nice to organize and cache this a
     217             :  * bit differently to avoid the hardcoding.
     218             :  */
     219             : static bool
     220    12587082 : get_opmethod_canorder(Oid amoid)
     221             : {
     222    12587082 :     switch (amoid)
     223             :     {
     224     3026418 :         case BTREE_AM_OID:
     225     3026418 :             return true;
     226     9559464 :         case HASH_AM_OID:
     227             :         case GIST_AM_OID:
     228             :         case GIN_AM_OID:
     229             :         case SPGIST_AM_OID:
     230             :         case BRIN_AM_OID:
     231     9559464 :             return false;
     232        1200 :         default:
     233             :             {
     234             :                 bool        result;
     235        1200 :                 IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(amoid, false);
     236             : 
     237        1200 :                 result = amroutine->amcanorder;
     238        1200 :                 pfree(amroutine);
     239        1200 :                 return result;
     240             :             }
     241             :     }
     242             : }
     243             : 
     244             : /*
     245             :  * get_ordering_op_properties
     246             :  *      Given the OID of an ordering operator (a "<" or ">" operator),
     247             :  *      determine its opfamily, its declared input datatype, and its
     248             :  *      comparison type.
     249             :  *
     250             :  * Returns true if successful, false if no matching pg_amop entry exists.
     251             :  * (This indicates that the operator is not a valid ordering operator.)
     252             :  *
     253             :  * Note: the operator could be registered in multiple families, for example
     254             :  * if someone were to build a "reverse sort" opfamily.  This would result in
     255             :  * uncertainty as to whether "ORDER BY USING op" would default to NULLS FIRST
     256             :  * or NULLS LAST, as well as inefficient planning due to failure to match up
     257             :  * pathkeys that should be the same.  So we want a determinate result here.
     258             :  * Because of the way the syscache search works, we'll use the interpretation
     259             :  * associated with the opfamily with smallest OID, which is probably
     260             :  * determinate enough.  Since there is no longer any particularly good reason
     261             :  * to build reverse-sort opfamilies, it doesn't seem worth expending any
     262             :  * additional effort on ensuring consistency.
     263             :  */
     264             : bool
     265      537556 : get_ordering_op_properties(Oid opno,
     266             :                            Oid *opfamily, Oid *opcintype, CompareType *cmptype)
     267             : {
     268      537556 :     bool        result = false;
     269             :     CatCList   *catlist;
     270             :     int         i;
     271             : 
     272             :     /* ensure outputs are initialized on failure */
     273      537556 :     *opfamily = InvalidOid;
     274      537556 :     *opcintype = InvalidOid;
     275      537556 :     *cmptype = COMPARE_INVALID;
     276             : 
     277             :     /*
     278             :      * Search pg_amop to see if the target operator is registered as the "<"
     279             :      * or ">" operator of any btree opfamily.
     280             :      */
     281      537556 :     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
     282             : 
     283      537560 :     for (i = 0; i < catlist->n_members; i++)
     284             :     {
     285      537560 :         HeapTuple   tuple = &catlist->members[i]->tuple;
     286      537560 :         Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
     287             :         CompareType am_cmptype;
     288             : 
     289             :         /* must be ordering index */
     290      537560 :         if (!get_opmethod_canorder(aform->amopmethod))
     291           4 :             continue;
     292             : 
     293      537556 :         am_cmptype = IndexAmTranslateStrategy(aform->amopstrategy,
     294             :                                               aform->amopmethod,
     295             :                                               aform->amopfamily,
     296             :                                               true);
     297             : 
     298      537556 :         if (am_cmptype == COMPARE_LT || am_cmptype == COMPARE_GT)
     299             :         {
     300             :             /* Found it ... should have consistent input types */
     301      537556 :             if (aform->amoplefttype == aform->amoprighttype)
     302             :             {
     303             :                 /* Found a suitable opfamily, return info */
     304      537556 :                 *opfamily = aform->amopfamily;
     305      537556 :                 *opcintype = aform->amoplefttype;
     306      537556 :                 *cmptype = am_cmptype;
     307      537556 :                 result = true;
     308      537556 :                 break;
     309             :             }
     310             :         }
     311             :     }
     312             : 
     313      537556 :     ReleaseSysCacheList(catlist);
     314             : 
     315      537556 :     return result;
     316             : }
     317             : 
     318             : /*
     319             :  * get_equality_op_for_ordering_op
     320             :  *      Get the OID of the datatype-specific equality operator
     321             :  *      associated with an ordering operator (a "<" or ">" operator).
     322             :  *
     323             :  * If "reverse" isn't NULL, also set *reverse to false if the operator is "<",
     324             :  * true if it's ">"
     325             :  *
     326             :  * Returns InvalidOid if no matching equality operator can be found.
     327             :  * (This indicates that the operator is not a valid ordering operator.)
     328             :  */
     329             : Oid
     330        2080 : get_equality_op_for_ordering_op(Oid opno, bool *reverse)
     331             : {
     332        2080 :     Oid         result = InvalidOid;
     333             :     Oid         opfamily;
     334             :     Oid         opcintype;
     335             :     CompareType cmptype;
     336             : 
     337             :     /* Find the operator in pg_amop */
     338        2080 :     if (get_ordering_op_properties(opno,
     339             :                                    &opfamily, &opcintype, &cmptype))
     340             :     {
     341             :         /* Found a suitable opfamily, get matching equality operator */
     342        2080 :         result = get_opfamily_member_for_cmptype(opfamily,
     343             :                                                  opcintype,
     344             :                                                  opcintype,
     345             :                                                  COMPARE_EQ);
     346        2080 :         if (reverse)
     347        1012 :             *reverse = (cmptype == COMPARE_GT);
     348             :     }
     349             : 
     350        2080 :     return result;
     351             : }
     352             : 
     353             : /*
     354             :  * get_ordering_op_for_equality_op
     355             :  *      Get the OID of a datatype-specific "less than" ordering operator
     356             :  *      associated with an equality operator.  (If there are multiple
     357             :  *      possibilities, assume any one will do.)
     358             :  *
     359             :  * This function is used when we have to sort data before unique-ifying,
     360             :  * and don't much care which sorting op is used as long as it's compatible
     361             :  * with the intended equality operator.  Since we need a sorting operator,
     362             :  * it should be single-data-type even if the given operator is cross-type.
     363             :  * The caller specifies whether to find an op for the LHS or RHS data type.
     364             :  *
     365             :  * Returns InvalidOid if no matching ordering operator can be found.
     366             :  */
     367             : Oid
     368          26 : get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type)
     369             : {
     370          26 :     Oid         result = InvalidOid;
     371             :     CatCList   *catlist;
     372             :     int         i;
     373             : 
     374             :     /*
     375             :      * Search pg_amop to see if the target operator is registered as the "="
     376             :      * operator of any btree opfamily.
     377             :      */
     378          26 :     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
     379             : 
     380          26 :     for (i = 0; i < catlist->n_members; i++)
     381             :     {
     382          26 :         HeapTuple   tuple = &catlist->members[i]->tuple;
     383          26 :         Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
     384             :         CompareType cmptype;
     385             : 
     386             :         /* must be ordering index */
     387          26 :         if (!get_opmethod_canorder(aform->amopmethod))
     388           0 :             continue;
     389             : 
     390          26 :         cmptype = IndexAmTranslateStrategy(aform->amopstrategy,
     391             :                                            aform->amopmethod,
     392             :                                            aform->amopfamily,
     393             :                                            true);
     394          26 :         if (cmptype == COMPARE_EQ)
     395             :         {
     396             :             /* Found a suitable opfamily, get matching ordering operator */
     397             :             Oid         typid;
     398             : 
     399          26 :             typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
     400          26 :             result = get_opfamily_member_for_cmptype(aform->amopfamily,
     401             :                                                      typid, typid,
     402             :                                                      COMPARE_LT);
     403          26 :             if (OidIsValid(result))
     404          26 :                 break;
     405             :             /* failure probably shouldn't happen, but keep looking if so */
     406             :         }
     407             :     }
     408             : 
     409          26 :     ReleaseSysCacheList(catlist);
     410             : 
     411          26 :     return result;
     412             : }
     413             : 
     414             : /*
     415             :  * get_mergejoin_opfamilies
     416             :  *      Given a putatively mergejoinable operator, return a list of the OIDs
     417             :  *      of the amcanorder opfamilies in which it represents equality.
     418             :  *
     419             :  * It is possible (though at present unusual) for an operator to be equality
     420             :  * in more than one opfamily, hence the result is a list.  This also lets us
     421             :  * return NIL if the operator is not found in any opfamilies.
     422             :  *
     423             :  * The planner currently uses simple equal() tests to compare the lists
     424             :  * returned by this function, which makes the list order relevant, though
     425             :  * strictly speaking it should not be.  Because of the way syscache list
     426             :  * searches are handled, in normal operation the result will be sorted by OID
     427             :  * so everything works fine.  If running with system index usage disabled,
     428             :  * the result ordering is unspecified and hence the planner might fail to
     429             :  * recognize optimization opportunities ... but that's hardly a scenario in
     430             :  * which performance is good anyway, so there's no point in expending code
     431             :  * or cycles here to guarantee the ordering in that case.
     432             :  */
     433             : List *
     434     2410130 : get_mergejoin_opfamilies(Oid opno)
     435             : {
     436     2410130 :     List       *result = NIL;
     437             :     CatCList   *catlist;
     438             :     int         i;
     439             : 
     440             :     /*
     441             :      * Search pg_amop to see if the target operator is registered as the "="
     442             :      * operator of any opfamily of an ordering index type.
     443             :      */
     444     2410130 :     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
     445             : 
     446    14445362 :     for (i = 0; i < catlist->n_members; i++)
     447             :     {
     448    12035232 :         HeapTuple   tuple = &catlist->members[i]->tuple;
     449    12035232 :         Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
     450             : 
     451             :         /* must be ordering index equality */
     452    14520066 :         if (get_opmethod_canorder(aform->amopmethod) &&
     453     2484834 :             IndexAmTranslateStrategy(aform->amopstrategy,
     454             :                                      aform->amopmethod,
     455             :                                      aform->amopfamily,
     456             :                                      true) == COMPARE_EQ)
     457     2484834 :             result = lappend_oid(result, aform->amopfamily);
     458             :     }
     459             : 
     460     2410130 :     ReleaseSysCacheList(catlist);
     461             : 
     462     2410130 :     return result;
     463             : }
     464             : 
     465             : /*
     466             :  * get_compatible_hash_operators
     467             :  *      Get the OID(s) of hash equality operator(s) compatible with the given
     468             :  *      operator, but operating on its LHS and/or RHS datatype.
     469             :  *
     470             :  * An operator for the LHS type is sought and returned into *lhs_opno if
     471             :  * lhs_opno isn't NULL.  Similarly, an operator for the RHS type is sought
     472             :  * and returned into *rhs_opno if rhs_opno isn't NULL.
     473             :  *
     474             :  * If the given operator is not cross-type, the results should be the same
     475             :  * operator, but in cross-type situations they will be different.
     476             :  *
     477             :  * Returns true if able to find the requested operator(s), false if not.
     478             :  * (This indicates that the operator should not have been marked oprcanhash.)
     479             :  */
     480             : bool
     481        1956 : get_compatible_hash_operators(Oid opno,
     482             :                               Oid *lhs_opno, Oid *rhs_opno)
     483             : {
     484        1956 :     bool        result = false;
     485             :     CatCList   *catlist;
     486             :     int         i;
     487             : 
     488             :     /* Ensure output args are initialized on failure */
     489        1956 :     if (lhs_opno)
     490           0 :         *lhs_opno = InvalidOid;
     491        1956 :     if (rhs_opno)
     492        1956 :         *rhs_opno = InvalidOid;
     493             : 
     494             :     /*
     495             :      * Search pg_amop to see if the target operator is registered as the "="
     496             :      * operator of any hash opfamily.  If the operator is registered in
     497             :      * multiple opfamilies, assume we can use any one.
     498             :      */
     499        1956 :     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
     500             : 
     501        3912 :     for (i = 0; i < catlist->n_members; i++)
     502             :     {
     503        3912 :         HeapTuple   tuple = &catlist->members[i]->tuple;
     504        3912 :         Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
     505             : 
     506        3912 :         if (aform->amopmethod == HASH_AM_OID &&
     507        1956 :             aform->amopstrategy == HTEqualStrategyNumber)
     508             :         {
     509             :             /* No extra lookup needed if given operator is single-type */
     510        1956 :             if (aform->amoplefttype == aform->amoprighttype)
     511             :             {
     512        1908 :                 if (lhs_opno)
     513           0 :                     *lhs_opno = opno;
     514        1908 :                 if (rhs_opno)
     515        1908 :                     *rhs_opno = opno;
     516        1908 :                 result = true;
     517        1908 :                 break;
     518             :             }
     519             : 
     520             :             /*
     521             :              * Get the matching single-type operator(s).  Failure probably
     522             :              * shouldn't happen --- it implies a bogus opfamily --- but
     523             :              * continue looking if so.
     524             :              */
     525          48 :             if (lhs_opno)
     526             :             {
     527           0 :                 *lhs_opno = get_opfamily_member(aform->amopfamily,
     528             :                                                 aform->amoplefttype,
     529             :                                                 aform->amoplefttype,
     530             :                                                 HTEqualStrategyNumber);
     531           0 :                 if (!OidIsValid(*lhs_opno))
     532           0 :                     continue;
     533             :                 /* Matching LHS found, done if caller doesn't want RHS */
     534           0 :                 if (!rhs_opno)
     535             :                 {
     536           0 :                     result = true;
     537           0 :                     break;
     538             :                 }
     539             :             }
     540          48 :             if (rhs_opno)
     541             :             {
     542          48 :                 *rhs_opno = get_opfamily_member(aform->amopfamily,
     543             :                                                 aform->amoprighttype,
     544             :                                                 aform->amoprighttype,
     545             :                                                 HTEqualStrategyNumber);
     546          48 :                 if (!OidIsValid(*rhs_opno))
     547             :                 {
     548             :                     /* Forget any LHS operator from this opfamily */
     549           0 :                     if (lhs_opno)
     550           0 :                         *lhs_opno = InvalidOid;
     551           0 :                     continue;
     552             :                 }
     553             :                 /* Matching RHS found, so done */
     554          48 :                 result = true;
     555          48 :                 break;
     556             :             }
     557             :         }
     558             :     }
     559             : 
     560        1956 :     ReleaseSysCacheList(catlist);
     561             : 
     562        1956 :     return result;
     563             : }
     564             : 
     565             : /*
     566             :  * get_op_hash_functions
     567             :  *      Get the OID(s) of the standard hash support function(s) compatible with
     568             :  *      the given operator, operating on its LHS and/or RHS datatype as required.
     569             :  *
     570             :  * A function for the LHS type is sought and returned into *lhs_procno if
     571             :  * lhs_procno isn't NULL.  Similarly, a function for the RHS type is sought
     572             :  * and returned into *rhs_procno if rhs_procno isn't NULL.
     573             :  *
     574             :  * If the given operator is not cross-type, the results should be the same
     575             :  * function, but in cross-type situations they will be different.
     576             :  *
     577             :  * Returns true if able to find the requested function(s), false if not.
     578             :  * (This indicates that the operator should not have been marked oprcanhash.)
     579             :  */
     580             : bool
     581       71526 : get_op_hash_functions(Oid opno,
     582             :                       RegProcedure *lhs_procno, RegProcedure *rhs_procno)
     583             : {
     584       71526 :     bool        result = false;
     585             :     CatCList   *catlist;
     586             :     int         i;
     587             : 
     588             :     /* Ensure output args are initialized on failure */
     589       71526 :     if (lhs_procno)
     590       71526 :         *lhs_procno = InvalidOid;
     591       71526 :     if (rhs_procno)
     592       71526 :         *rhs_procno = InvalidOid;
     593             : 
     594             :     /*
     595             :      * Search pg_amop to see if the target operator is registered as the "="
     596             :      * operator of any hash opfamily.  If the operator is registered in
     597             :      * multiple opfamilies, assume we can use any one.
     598             :      */
     599       71526 :     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
     600             : 
     601      143292 :     for (i = 0; i < catlist->n_members; i++)
     602             :     {
     603      142790 :         HeapTuple   tuple = &catlist->members[i]->tuple;
     604      142790 :         Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
     605             : 
     606      142790 :         if (aform->amopmethod == HASH_AM_OID &&
     607       71024 :             aform->amopstrategy == HTEqualStrategyNumber)
     608             :         {
     609             :             /*
     610             :              * Get the matching support function(s).  Failure probably
     611             :              * shouldn't happen --- it implies a bogus opfamily --- but
     612             :              * continue looking if so.
     613             :              */
     614       71024 :             if (lhs_procno)
     615             :             {
     616       71024 :                 *lhs_procno = get_opfamily_proc(aform->amopfamily,
     617             :                                                 aform->amoplefttype,
     618             :                                                 aform->amoplefttype,
     619             :                                                 HASHSTANDARD_PROC);
     620       71024 :                 if (!OidIsValid(*lhs_procno))
     621           0 :                     continue;
     622             :                 /* Matching LHS found, done if caller doesn't want RHS */
     623       71024 :                 if (!rhs_procno)
     624             :                 {
     625           0 :                     result = true;
     626           0 :                     break;
     627             :                 }
     628             :                 /* Only one lookup needed if given operator is single-type */
     629       71024 :                 if (aform->amoplefttype == aform->amoprighttype)
     630             :                 {
     631       70732 :                     *rhs_procno = *lhs_procno;
     632       70732 :                     result = true;
     633       70732 :                     break;
     634             :                 }
     635             :             }
     636         292 :             if (rhs_procno)
     637             :             {
     638         292 :                 *rhs_procno = get_opfamily_proc(aform->amopfamily,
     639             :                                                 aform->amoprighttype,
     640             :                                                 aform->amoprighttype,
     641             :                                                 HASHSTANDARD_PROC);
     642         292 :                 if (!OidIsValid(*rhs_procno))
     643             :                 {
     644             :                     /* Forget any LHS function from this opfamily */
     645           0 :                     if (lhs_procno)
     646           0 :                         *lhs_procno = InvalidOid;
     647           0 :                     continue;
     648             :                 }
     649             :                 /* Matching RHS found, so done */
     650         292 :                 result = true;
     651         292 :                 break;
     652             :             }
     653             :         }
     654             :     }
     655             : 
     656       71526 :     ReleaseSysCacheList(catlist);
     657             : 
     658       71526 :     return result;
     659             : }
     660             : 
     661             : /*
     662             :  * get_op_index_interpretation
     663             :  *      Given an operator's OID, find out which amcanorder opfamilies it belongs to,
     664             :  *      and what properties it has within each one.  The results are returned
     665             :  *      as a palloc'd list of OpIndexInterpretation structs.
     666             :  *
     667             :  * In addition to the normal btree operators, we consider a <> operator to be
     668             :  * a "member" of an opfamily if its negator is an equality operator of the
     669             :  * opfamily.  COMPARE_NE is returned as the strategy number for this case.
     670             :  */
     671             : List *
     672        5072 : get_op_index_interpretation(Oid opno)
     673             : {
     674        5072 :     List       *result = NIL;
     675             :     OpIndexInterpretation *thisresult;
     676             :     CatCList   *catlist;
     677             :     int         i;
     678             : 
     679             :     /*
     680             :      * Find all the pg_amop entries containing the operator.
     681             :      */
     682        5072 :     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
     683             : 
     684       19336 :     for (i = 0; i < catlist->n_members; i++)
     685             :     {
     686       14264 :         HeapTuple   op_tuple = &catlist->members[i]->tuple;
     687       14264 :         Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
     688             :         CompareType cmptype;
     689             : 
     690             :         /* must be ordering index */
     691       14264 :         if (!get_opmethod_canorder(op_form->amopmethod))
     692       10262 :             continue;
     693             : 
     694             :         /* Get the operator's comparision type */
     695        4002 :         cmptype = IndexAmTranslateStrategy(op_form->amopstrategy,
     696             :                                            op_form->amopmethod,
     697             :                                            op_form->amopfamily,
     698             :                                            true);
     699             : 
     700             :         /* should not happen */
     701        4002 :         if (cmptype == COMPARE_INVALID)
     702           0 :             continue;
     703             : 
     704             :         thisresult = (OpIndexInterpretation *)
     705        4002 :             palloc(sizeof(OpIndexInterpretation));
     706        4002 :         thisresult->opfamily_id = op_form->amopfamily;
     707        4002 :         thisresult->cmptype = cmptype;
     708        4002 :         thisresult->oplefttype = op_form->amoplefttype;
     709        4002 :         thisresult->oprighttype = op_form->amoprighttype;
     710        4002 :         result = lappend(result, thisresult);
     711             :     }
     712             : 
     713        5072 :     ReleaseSysCacheList(catlist);
     714             : 
     715             :     /*
     716             :      * If we didn't find any btree opfamily containing the operator, perhaps
     717             :      * it is a <> operator.  See if it has a negator that is in an opfamily.
     718             :      */
     719        5072 :     if (result == NIL)
     720             :     {
     721        1346 :         Oid         op_negator = get_negator(opno);
     722             : 
     723        1346 :         if (OidIsValid(op_negator))
     724             :         {
     725        1322 :             catlist = SearchSysCacheList1(AMOPOPID,
     726             :                                           ObjectIdGetDatum(op_negator));
     727             : 
     728        5246 :             for (i = 0; i < catlist->n_members; i++)
     729             :             {
     730        3924 :                 HeapTuple   op_tuple = &catlist->members[i]->tuple;
     731        3924 :                 Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
     732        3924 :                 IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false);
     733             :                 CompareType cmptype;
     734             : 
     735             :                 /* must be ordering index */
     736        3924 :                 if (!amroutine->amcanorder)
     737        2996 :                     continue;
     738             : 
     739             :                 /* Get the operator's comparision type */
     740         928 :                 cmptype = IndexAmTranslateStrategy(op_form->amopstrategy,
     741             :                                                    op_form->amopmethod,
     742             :                                                    op_form->amopfamily,
     743             :                                                    true);
     744             : 
     745             :                 /* Only consider negators that are = */
     746         928 :                 if (cmptype != COMPARE_EQ)
     747           0 :                     continue;
     748             : 
     749             :                 /* OK, report it as COMPARE_NE */
     750             :                 thisresult = (OpIndexInterpretation *)
     751         928 :                     palloc(sizeof(OpIndexInterpretation));
     752         928 :                 thisresult->opfamily_id = op_form->amopfamily;
     753         928 :                 thisresult->cmptype = COMPARE_NE;
     754         928 :                 thisresult->oplefttype = op_form->amoplefttype;
     755         928 :                 thisresult->oprighttype = op_form->amoprighttype;
     756         928 :                 result = lappend(result, thisresult);
     757             :             }
     758             : 
     759        1322 :             ReleaseSysCacheList(catlist);
     760             :         }
     761             :     }
     762             : 
     763        5072 :     return result;
     764             : }
     765             : 
     766             : /*
     767             :  * equality_ops_are_compatible
     768             :  *      Return true if the two given equality operators have compatible
     769             :  *      semantics.
     770             :  *
     771             :  * This is trivially true if they are the same operator.  Otherwise,
     772             :  * Otherwise, we look to see if they both belong to an opfamily that
     773             :  * guarantees compatible semantics for equality.  Either finding allows us to
     774             :  * assume that they have compatible notions of equality.  (The reason we need
     775             :  * to do these pushups is that one might be a cross-type operator; for
     776             :  * instance int24eq vs int4eq.)
     777             :  */
     778             : bool
     779         178 : equality_ops_are_compatible(Oid opno1, Oid opno2)
     780             : {
     781             :     bool        result;
     782             :     CatCList   *catlist;
     783             :     int         i;
     784             : 
     785             :     /* Easy if they're the same operator */
     786         178 :     if (opno1 == opno2)
     787         172 :         return true;
     788             : 
     789             :     /*
     790             :      * We search through all the pg_amop entries for opno1.
     791             :      */
     792           6 :     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno1));
     793             : 
     794           6 :     result = false;
     795           6 :     for (i = 0; i < catlist->n_members; i++)
     796             :     {
     797           6 :         HeapTuple   op_tuple = &catlist->members[i]->tuple;
     798           6 :         Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
     799             : 
     800             :         /*
     801             :          * op_in_opfamily() is cheaper than GetIndexAmRoutineByAmId(), so
     802             :          * check it first
     803             :          */
     804           6 :         if (op_in_opfamily(opno2, op_form->amopfamily))
     805             :         {
     806           6 :             IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false);
     807             : 
     808           6 :             if (amroutine->amconsistentequality)
     809             :             {
     810           6 :                 result = true;
     811           6 :                 break;
     812             :             }
     813             :         }
     814             :     }
     815             : 
     816           6 :     ReleaseSysCacheList(catlist);
     817             : 
     818           6 :     return result;
     819             : }
     820             : 
     821             : /*
     822             :  * comparison_ops_are_compatible
     823             :  *      Return true if the two given comparison operators have compatible
     824             :  *      semantics.
     825             :  *
     826             :  * This is trivially true if they are the same operator.  Otherwise, we look
     827             :  * to see if they both belong to an opfamily that guarantees compatible
     828             :  * semantics for ordering.  (For example, for btree, '<' and '>=' ops match if
     829             :  * they belong to the same family.)
     830             :  *
     831             :  * (This is identical to equality_ops_are_compatible(), except that we check
     832             :  * amconsistentordering instead of amconsistentequality.)
     833             :  */
     834             : bool
     835      218826 : comparison_ops_are_compatible(Oid opno1, Oid opno2)
     836             : {
     837             :     bool        result;
     838             :     CatCList   *catlist;
     839             :     int         i;
     840             : 
     841             :     /* Easy if they're the same operator */
     842      218826 :     if (opno1 == opno2)
     843      101390 :         return true;
     844             : 
     845             :     /*
     846             :      * We search through all the pg_amop entries for opno1.
     847             :      */
     848      117436 :     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno1));
     849             : 
     850      117436 :     result = false;
     851      117760 :     for (i = 0; i < catlist->n_members; i++)
     852             :     {
     853      117652 :         HeapTuple   op_tuple = &catlist->members[i]->tuple;
     854      117652 :         Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
     855             : 
     856             :         /*
     857             :          * op_in_opfamily() is cheaper than GetIndexAmRoutineByAmId(), so
     858             :          * check it first
     859             :          */
     860      117652 :         if (op_in_opfamily(opno2, op_form->amopfamily))
     861             :         {
     862      117340 :             IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false);
     863             : 
     864      117340 :             if (amroutine->amconsistentordering)
     865             :             {
     866      117328 :                 result = true;
     867      117328 :                 break;
     868             :             }
     869             :         }
     870             :     }
     871             : 
     872      117436 :     ReleaseSysCacheList(catlist);
     873             : 
     874      117436 :     return result;
     875             : }
     876             : 
     877             : 
     878             : /*              ---------- AMPROC CACHES ----------                      */
     879             : 
     880             : /*
     881             :  * get_opfamily_proc
     882             :  *      Get the OID of the specified support function
     883             :  *      for the specified opfamily and datatypes.
     884             :  *
     885             :  * Returns InvalidOid if there is no pg_amproc entry for the given keys.
     886             :  */
     887             : Oid
     888      783698 : get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
     889             : {
     890             :     HeapTuple   tp;
     891             :     Form_pg_amproc amproc_tup;
     892             :     RegProcedure result;
     893             : 
     894      783698 :     tp = SearchSysCache4(AMPROCNUM,
     895             :                          ObjectIdGetDatum(opfamily),
     896             :                          ObjectIdGetDatum(lefttype),
     897             :                          ObjectIdGetDatum(righttype),
     898             :                          Int16GetDatum(procnum));
     899      783698 :     if (!HeapTupleIsValid(tp))
     900       33344 :         return InvalidOid;
     901      750354 :     amproc_tup = (Form_pg_amproc) GETSTRUCT(tp);
     902      750354 :     result = amproc_tup->amproc;
     903      750354 :     ReleaseSysCache(tp);
     904      750354 :     return result;
     905             : }
     906             : 
     907             : 
     908             : /*              ---------- ATTRIBUTE CACHES ----------                   */
     909             : 
     910             : /*
     911             :  * get_attname
     912             :  *      Given the relation id and the attribute number, return the "attname"
     913             :  *      field from the attribute relation as a palloc'ed string.
     914             :  *
     915             :  * If no such attribute exists and missing_ok is true, NULL is returned;
     916             :  * otherwise a not-intended-for-user-consumption error is thrown.
     917             :  */
     918             : char *
     919       89912 : get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
     920             : {
     921             :     HeapTuple   tp;
     922             : 
     923       89912 :     tp = SearchSysCache2(ATTNUM,
     924             :                          ObjectIdGetDatum(relid), Int16GetDatum(attnum));
     925       89912 :     if (HeapTupleIsValid(tp))
     926             :     {
     927       89888 :         Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
     928             :         char       *result;
     929             : 
     930       89888 :         result = pstrdup(NameStr(att_tup->attname));
     931       89888 :         ReleaseSysCache(tp);
     932       89888 :         return result;
     933             :     }
     934             : 
     935          24 :     if (!missing_ok)
     936           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
     937             :              attnum, relid);
     938          24 :     return NULL;
     939             : }
     940             : 
     941             : /*
     942             :  * get_attnum
     943             :  *
     944             :  *      Given the relation id and the attribute name,
     945             :  *      return the "attnum" field from the attribute relation.
     946             :  *
     947             :  *      Returns InvalidAttrNumber if the attr doesn't exist (or is dropped).
     948             :  */
     949             : AttrNumber
     950       36074 : get_attnum(Oid relid, const char *attname)
     951             : {
     952             :     HeapTuple   tp;
     953             : 
     954       36074 :     tp = SearchSysCacheAttName(relid, attname);
     955       36074 :     if (HeapTupleIsValid(tp))
     956             :     {
     957       35926 :         Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
     958             :         AttrNumber  result;
     959             : 
     960       35926 :         result = att_tup->attnum;
     961       35926 :         ReleaseSysCache(tp);
     962       35926 :         return result;
     963             :     }
     964             :     else
     965         148 :         return InvalidAttrNumber;
     966             : }
     967             : 
     968             : /*
     969             :  * get_attgenerated
     970             :  *
     971             :  *      Given the relation id and the attribute number,
     972             :  *      return the "attgenerated" field from the attribute relation.
     973             :  *
     974             :  *      Errors if not found.
     975             :  *
     976             :  *      Since not generated is represented by '\0', this can also be used as a
     977             :  *      Boolean test.
     978             :  */
     979             : char
     980        2582 : get_attgenerated(Oid relid, AttrNumber attnum)
     981             : {
     982             :     HeapTuple   tp;
     983             :     Form_pg_attribute att_tup;
     984             :     char        result;
     985             : 
     986        2582 :     tp = SearchSysCache2(ATTNUM,
     987             :                          ObjectIdGetDatum(relid),
     988             :                          Int16GetDatum(attnum));
     989        2582 :     if (!HeapTupleIsValid(tp))
     990           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
     991             :              attnum, relid);
     992        2582 :     att_tup = (Form_pg_attribute) GETSTRUCT(tp);
     993        2582 :     result = att_tup->attgenerated;
     994        2582 :     ReleaseSysCache(tp);
     995        2582 :     return result;
     996             : }
     997             : 
     998             : /*
     999             :  * get_atttype
    1000             :  *
    1001             :  *      Given the relation OID and the attribute number with the relation,
    1002             :  *      return the attribute type OID.
    1003             :  */
    1004             : Oid
    1005        3252 : get_atttype(Oid relid, AttrNumber attnum)
    1006             : {
    1007             :     HeapTuple   tp;
    1008             : 
    1009        3252 :     tp = SearchSysCache2(ATTNUM,
    1010             :                          ObjectIdGetDatum(relid),
    1011             :                          Int16GetDatum(attnum));
    1012        3252 :     if (HeapTupleIsValid(tp))
    1013             :     {
    1014        3252 :         Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
    1015             :         Oid         result;
    1016             : 
    1017        3252 :         result = att_tup->atttypid;
    1018        3252 :         ReleaseSysCache(tp);
    1019        3252 :         return result;
    1020             :     }
    1021             :     else
    1022           0 :         return InvalidOid;
    1023             : }
    1024             : 
    1025             : /*
    1026             :  * get_atttypetypmodcoll
    1027             :  *
    1028             :  *      A three-fer: given the relation id and the attribute number,
    1029             :  *      fetch atttypid, atttypmod, and attcollation in a single cache lookup.
    1030             :  *
    1031             :  * Unlike the otherwise-similar get_atttype, this routine
    1032             :  * raises an error if it can't obtain the information.
    1033             :  */
    1034             : void
    1035       18190 : get_atttypetypmodcoll(Oid relid, AttrNumber attnum,
    1036             :                       Oid *typid, int32 *typmod, Oid *collid)
    1037             : {
    1038             :     HeapTuple   tp;
    1039             :     Form_pg_attribute att_tup;
    1040             : 
    1041       18190 :     tp = SearchSysCache2(ATTNUM,
    1042             :                          ObjectIdGetDatum(relid),
    1043             :                          Int16GetDatum(attnum));
    1044       18190 :     if (!HeapTupleIsValid(tp))
    1045           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
    1046             :              attnum, relid);
    1047       18190 :     att_tup = (Form_pg_attribute) GETSTRUCT(tp);
    1048             : 
    1049       18190 :     *typid = att_tup->atttypid;
    1050       18190 :     *typmod = att_tup->atttypmod;
    1051       18190 :     *collid = att_tup->attcollation;
    1052       18190 :     ReleaseSysCache(tp);
    1053       18190 : }
    1054             : 
    1055             : /*
    1056             :  * get_attoptions
    1057             :  *
    1058             :  *      Given the relation id and the attribute number,
    1059             :  *      return the attribute options text[] datum, if any.
    1060             :  */
    1061             : Datum
    1062     1044402 : get_attoptions(Oid relid, int16 attnum)
    1063             : {
    1064             :     HeapTuple   tuple;
    1065             :     Datum       attopts;
    1066             :     Datum       result;
    1067             :     bool        isnull;
    1068             : 
    1069     1044402 :     tuple = SearchSysCache2(ATTNUM,
    1070             :                             ObjectIdGetDatum(relid),
    1071             :                             Int16GetDatum(attnum));
    1072             : 
    1073     1044402 :     if (!HeapTupleIsValid(tuple))
    1074           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
    1075             :              attnum, relid);
    1076             : 
    1077     1044402 :     attopts = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attoptions,
    1078             :                               &isnull);
    1079             : 
    1080     1044402 :     if (isnull)
    1081     1044050 :         result = (Datum) 0;
    1082             :     else
    1083         352 :         result = datumCopy(attopts, false, -1); /* text[] */
    1084             : 
    1085     1044402 :     ReleaseSysCache(tuple);
    1086             : 
    1087     1044402 :     return result;
    1088             : }
    1089             : 
    1090             : /*              ---------- PG_CAST CACHE ----------                  */
    1091             : 
    1092             : /*
    1093             :  * get_cast_oid - given two type OIDs, look up a cast OID
    1094             :  *
    1095             :  * If missing_ok is false, throw an error if the cast is not found.  If
    1096             :  * true, just return InvalidOid.
    1097             :  */
    1098             : Oid
    1099          76 : get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok)
    1100             : {
    1101             :     Oid         oid;
    1102             : 
    1103          76 :     oid = GetSysCacheOid2(CASTSOURCETARGET, Anum_pg_cast_oid,
    1104             :                           ObjectIdGetDatum(sourcetypeid),
    1105             :                           ObjectIdGetDatum(targettypeid));
    1106          76 :     if (!OidIsValid(oid) && !missing_ok)
    1107           6 :         ereport(ERROR,
    1108             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    1109             :                  errmsg("cast from type %s to type %s does not exist",
    1110             :                         format_type_be(sourcetypeid),
    1111             :                         format_type_be(targettypeid))));
    1112          70 :     return oid;
    1113             : }
    1114             : 
    1115             : /*              ---------- COLLATION CACHE ----------                    */
    1116             : 
    1117             : /*
    1118             :  * get_collation_name
    1119             :  *      Returns the name of a given pg_collation entry.
    1120             :  *
    1121             :  * Returns a palloc'd copy of the string, or NULL if no such collation.
    1122             :  *
    1123             :  * NOTE: since collation name is not unique, be wary of code that uses this
    1124             :  * for anything except preparing error messages.
    1125             :  */
    1126             : char *
    1127         338 : get_collation_name(Oid colloid)
    1128             : {
    1129             :     HeapTuple   tp;
    1130             : 
    1131         338 :     tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(colloid));
    1132         338 :     if (HeapTupleIsValid(tp))
    1133             :     {
    1134         338 :         Form_pg_collation colltup = (Form_pg_collation) GETSTRUCT(tp);
    1135             :         char       *result;
    1136             : 
    1137         338 :         result = pstrdup(NameStr(colltup->collname));
    1138         338 :         ReleaseSysCache(tp);
    1139         338 :         return result;
    1140             :     }
    1141             :     else
    1142           0 :         return NULL;
    1143             : }
    1144             : 
    1145             : bool
    1146        1636 : get_collation_isdeterministic(Oid colloid)
    1147             : {
    1148             :     HeapTuple   tp;
    1149             :     Form_pg_collation colltup;
    1150             :     bool        result;
    1151             : 
    1152        1636 :     tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(colloid));
    1153        1636 :     if (!HeapTupleIsValid(tp))
    1154           0 :         elog(ERROR, "cache lookup failed for collation %u", colloid);
    1155        1636 :     colltup = (Form_pg_collation) GETSTRUCT(tp);
    1156        1636 :     result = colltup->collisdeterministic;
    1157        1636 :     ReleaseSysCache(tp);
    1158        1636 :     return result;
    1159             : }
    1160             : 
    1161             : /*              ---------- CONSTRAINT CACHE ----------                   */
    1162             : 
    1163             : /*
    1164             :  * get_constraint_name
    1165             :  *      Returns the name of a given pg_constraint entry.
    1166             :  *
    1167             :  * Returns a palloc'd copy of the string, or NULL if no such constraint.
    1168             :  *
    1169             :  * NOTE: since constraint name is not unique, be wary of code that uses this
    1170             :  * for anything except preparing error messages.
    1171             :  */
    1172             : char *
    1173         842 : get_constraint_name(Oid conoid)
    1174             : {
    1175             :     HeapTuple   tp;
    1176             : 
    1177         842 :     tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conoid));
    1178         842 :     if (HeapTupleIsValid(tp))
    1179             :     {
    1180         842 :         Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp);
    1181             :         char       *result;
    1182             : 
    1183         842 :         result = pstrdup(NameStr(contup->conname));
    1184         842 :         ReleaseSysCache(tp);
    1185         842 :         return result;
    1186             :     }
    1187             :     else
    1188           0 :         return NULL;
    1189             : }
    1190             : 
    1191             : /*
    1192             :  * get_constraint_index
    1193             :  *      Given the OID of a unique, primary-key, or exclusion constraint,
    1194             :  *      return the OID of the underlying index.
    1195             :  *
    1196             :  * Returns InvalidOid if the constraint could not be found or is of
    1197             :  * the wrong type.
    1198             :  *
    1199             :  * The intent of this function is to return the index "owned" by the
    1200             :  * specified constraint.  Therefore we must check contype, since some
    1201             :  * pg_constraint entries (e.g. for foreign-key constraints) store the
    1202             :  * OID of an index that is referenced but not owned by the constraint.
    1203             :  */
    1204             : Oid
    1205        1016 : get_constraint_index(Oid conoid)
    1206             : {
    1207             :     HeapTuple   tp;
    1208             : 
    1209        1016 :     tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conoid));
    1210        1016 :     if (HeapTupleIsValid(tp))
    1211             :     {
    1212        1016 :         Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp);
    1213             :         Oid         result;
    1214             : 
    1215        1016 :         if (contup->contype == CONSTRAINT_UNIQUE ||
    1216         770 :             contup->contype == CONSTRAINT_PRIMARY ||
    1217         440 :             contup->contype == CONSTRAINT_EXCLUSION)
    1218         648 :             result = contup->conindid;
    1219             :         else
    1220         368 :             result = InvalidOid;
    1221        1016 :         ReleaseSysCache(tp);
    1222        1016 :         return result;
    1223             :     }
    1224             :     else
    1225           0 :         return InvalidOid;
    1226             : }
    1227             : 
    1228             : /*
    1229             :  * get_constraint_type
    1230             :  *      Return the pg_constraint.contype value for the given constraint.
    1231             :  *
    1232             :  * No frills.
    1233             :  */
    1234             : char
    1235         804 : get_constraint_type(Oid conoid)
    1236             : {
    1237             :     HeapTuple   tp;
    1238             :     char        contype;
    1239             : 
    1240         804 :     tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conoid));
    1241         804 :     if (!HeapTupleIsValid(tp))
    1242           0 :         elog(ERROR, "cache lookup failed for constraint %u", conoid);
    1243             : 
    1244         804 :     contype = ((Form_pg_constraint) GETSTRUCT(tp))->contype;
    1245         804 :     ReleaseSysCache(tp);
    1246             : 
    1247         804 :     return contype;
    1248             : }
    1249             : 
    1250             : /*              ---------- LANGUAGE CACHE ----------                     */
    1251             : 
    1252             : char *
    1253         272 : get_language_name(Oid langoid, bool missing_ok)
    1254             : {
    1255             :     HeapTuple   tp;
    1256             : 
    1257         272 :     tp = SearchSysCache1(LANGOID, ObjectIdGetDatum(langoid));
    1258         272 :     if (HeapTupleIsValid(tp))
    1259             :     {
    1260         266 :         Form_pg_language lantup = (Form_pg_language) GETSTRUCT(tp);
    1261             :         char       *result;
    1262             : 
    1263         266 :         result = pstrdup(NameStr(lantup->lanname));
    1264         266 :         ReleaseSysCache(tp);
    1265         266 :         return result;
    1266             :     }
    1267             : 
    1268           6 :     if (!missing_ok)
    1269           0 :         elog(ERROR, "cache lookup failed for language %u",
    1270             :              langoid);
    1271           6 :     return NULL;
    1272             : }
    1273             : 
    1274             : /*              ---------- OPCLASS CACHE ----------                      */
    1275             : 
    1276             : /*
    1277             :  * get_opclass_family
    1278             :  *
    1279             :  *      Returns the OID of the operator family the opclass belongs to.
    1280             :  */
    1281             : Oid
    1282      199574 : get_opclass_family(Oid opclass)
    1283             : {
    1284             :     HeapTuple   tp;
    1285             :     Form_pg_opclass cla_tup;
    1286             :     Oid         result;
    1287             : 
    1288      199574 :     tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
    1289      199574 :     if (!HeapTupleIsValid(tp))
    1290           0 :         elog(ERROR, "cache lookup failed for opclass %u", opclass);
    1291      199574 :     cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
    1292             : 
    1293      199574 :     result = cla_tup->opcfamily;
    1294      199574 :     ReleaseSysCache(tp);
    1295      199574 :     return result;
    1296             : }
    1297             : 
    1298             : /*
    1299             :  * get_opclass_input_type
    1300             :  *
    1301             :  *      Returns the OID of the datatype the opclass indexes.
    1302             :  */
    1303             : Oid
    1304      200588 : get_opclass_input_type(Oid opclass)
    1305             : {
    1306             :     HeapTuple   tp;
    1307             :     Form_pg_opclass cla_tup;
    1308             :     Oid         result;
    1309             : 
    1310      200588 :     tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
    1311      200588 :     if (!HeapTupleIsValid(tp))
    1312           0 :         elog(ERROR, "cache lookup failed for opclass %u", opclass);
    1313      200588 :     cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
    1314             : 
    1315      200588 :     result = cla_tup->opcintype;
    1316      200588 :     ReleaseSysCache(tp);
    1317      200588 :     return result;
    1318             : }
    1319             : 
    1320             : /*
    1321             :  * get_opclass_opfamily_and_input_type
    1322             :  *
    1323             :  *      Returns the OID of the operator family the opclass belongs to,
    1324             :  *              the OID of the datatype the opclass indexes
    1325             :  */
    1326             : bool
    1327        3518 : get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
    1328             : {
    1329             :     HeapTuple   tp;
    1330             :     Form_pg_opclass cla_tup;
    1331             : 
    1332        3518 :     tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
    1333        3518 :     if (!HeapTupleIsValid(tp))
    1334           0 :         return false;
    1335             : 
    1336        3518 :     cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
    1337             : 
    1338        3518 :     *opfamily = cla_tup->opcfamily;
    1339        3518 :     *opcintype = cla_tup->opcintype;
    1340             : 
    1341        3518 :     ReleaseSysCache(tp);
    1342             : 
    1343        3518 :     return true;
    1344             : }
    1345             : 
    1346             : /*
    1347             :  * get_opclass_method
    1348             :  *
    1349             :  *      Returns the OID of the index access method the opclass belongs to.
    1350             :  */
    1351             : Oid
    1352        1886 : get_opclass_method(Oid opclass)
    1353             : {
    1354             :     HeapTuple   tp;
    1355             :     Form_pg_opclass cla_tup;
    1356             :     Oid         result;
    1357             : 
    1358        1886 :     tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
    1359        1886 :     if (!HeapTupleIsValid(tp))
    1360           0 :         elog(ERROR, "cache lookup failed for opclass %u", opclass);
    1361        1886 :     cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
    1362             : 
    1363        1886 :     result = cla_tup->opcmethod;
    1364        1886 :     ReleaseSysCache(tp);
    1365        1886 :     return result;
    1366             : }
    1367             : 
    1368             : /*              ---------- OPFAMILY CACHE ----------                     */
    1369             : 
    1370             : /*
    1371             :  * get_opfamily_method
    1372             :  *
    1373             :  *      Returns the OID of the index access method the opfamily is for.
    1374             :  */
    1375             : Oid
    1376     2654536 : get_opfamily_method(Oid opfid)
    1377             : {
    1378             :     HeapTuple   tp;
    1379             :     Form_pg_opfamily opfform;
    1380             :     Oid         result;
    1381             : 
    1382     2654536 :     tp = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
    1383     2654536 :     if (!HeapTupleIsValid(tp))
    1384           0 :         elog(ERROR, "cache lookup failed for operator family %u", opfid);
    1385     2654536 :     opfform = (Form_pg_opfamily) GETSTRUCT(tp);
    1386             : 
    1387     2654536 :     result = opfform->opfmethod;
    1388     2654536 :     ReleaseSysCache(tp);
    1389     2654536 :     return result;
    1390             : }
    1391             : 
    1392             : char *
    1393        1264 : get_opfamily_name(Oid opfid, bool missing_ok)
    1394             : {
    1395             :     HeapTuple   tup;
    1396             :     char       *opfname;
    1397             :     Form_pg_opfamily opfform;
    1398             : 
    1399        1264 :     tup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
    1400             : 
    1401        1264 :     if (!HeapTupleIsValid(tup))
    1402             :     {
    1403           0 :         if (!missing_ok)
    1404           0 :             elog(ERROR, "cache lookup failed for operator family %u", opfid);
    1405           0 :         return NULL;
    1406             :     }
    1407             : 
    1408        1264 :     opfform = (Form_pg_opfamily) GETSTRUCT(tup);
    1409        1264 :     opfname = pstrdup(NameStr(opfform->opfname));
    1410             : 
    1411        1264 :     ReleaseSysCache(tup);
    1412             : 
    1413        1264 :     return opfname;
    1414             : }
    1415             : 
    1416             : /*              ---------- OPERATOR CACHE ----------                     */
    1417             : 
    1418             : /*
    1419             :  * get_opcode
    1420             :  *
    1421             :  *      Returns the regproc id of the routine used to implement an
    1422             :  *      operator given the operator oid.
    1423             :  */
    1424             : RegProcedure
    1425     1533218 : get_opcode(Oid opno)
    1426             : {
    1427             :     HeapTuple   tp;
    1428             : 
    1429     1533218 :     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1430     1533218 :     if (HeapTupleIsValid(tp))
    1431             :     {
    1432     1533218 :         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
    1433             :         RegProcedure result;
    1434             : 
    1435     1533218 :         result = optup->oprcode;
    1436     1533218 :         ReleaseSysCache(tp);
    1437     1533218 :         return result;
    1438             :     }
    1439             :     else
    1440           0 :         return (RegProcedure) InvalidOid;
    1441             : }
    1442             : 
    1443             : /*
    1444             :  * get_opname
    1445             :  *    returns the name of the operator with the given opno
    1446             :  *
    1447             :  * Note: returns a palloc'd copy of the string, or NULL if no such operator.
    1448             :  */
    1449             : char *
    1450          72 : get_opname(Oid opno)
    1451             : {
    1452             :     HeapTuple   tp;
    1453             : 
    1454          72 :     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1455          72 :     if (HeapTupleIsValid(tp))
    1456             :     {
    1457          72 :         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
    1458             :         char       *result;
    1459             : 
    1460          72 :         result = pstrdup(NameStr(optup->oprname));
    1461          72 :         ReleaseSysCache(tp);
    1462          72 :         return result;
    1463             :     }
    1464             :     else
    1465           0 :         return NULL;
    1466             : }
    1467             : 
    1468             : /*
    1469             :  * get_op_rettype
    1470             :  *      Given operator oid, return the operator's result type.
    1471             :  */
    1472             : Oid
    1473       32584 : get_op_rettype(Oid opno)
    1474             : {
    1475             :     HeapTuple   tp;
    1476             : 
    1477       32584 :     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1478       32584 :     if (HeapTupleIsValid(tp))
    1479             :     {
    1480       32584 :         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
    1481             :         Oid         result;
    1482             : 
    1483       32584 :         result = optup->oprresult;
    1484       32584 :         ReleaseSysCache(tp);
    1485       32584 :         return result;
    1486             :     }
    1487             :     else
    1488           0 :         return InvalidOid;
    1489             : }
    1490             : 
    1491             : /*
    1492             :  * op_input_types
    1493             :  *
    1494             :  *      Returns the left and right input datatypes for an operator
    1495             :  *      (InvalidOid if not relevant).
    1496             :  */
    1497             : void
    1498      431056 : op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
    1499             : {
    1500             :     HeapTuple   tp;
    1501             :     Form_pg_operator optup;
    1502             : 
    1503      431056 :     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1504      431056 :     if (!HeapTupleIsValid(tp))  /* shouldn't happen */
    1505           0 :         elog(ERROR, "cache lookup failed for operator %u", opno);
    1506      431056 :     optup = (Form_pg_operator) GETSTRUCT(tp);
    1507      431056 :     *lefttype = optup->oprleft;
    1508      431056 :     *righttype = optup->oprright;
    1509      431056 :     ReleaseSysCache(tp);
    1510      431056 : }
    1511             : 
    1512             : /*
    1513             :  * op_mergejoinable
    1514             :  *
    1515             :  * Returns true if the operator is potentially mergejoinable.  (The planner
    1516             :  * will fail to find any mergejoin plans unless there are suitable btree
    1517             :  * opfamily entries for this operator and associated sortops.  The pg_operator
    1518             :  * flag is just a hint to tell the planner whether to bother looking.)
    1519             :  *
    1520             :  * In some cases (currently only array_eq and record_eq), mergejoinability
    1521             :  * depends on the specific input data type the operator is invoked for, so
    1522             :  * that must be passed as well. We currently assume that only one input's type
    1523             :  * is needed to check this --- by convention, pass the left input's data type.
    1524             :  */
    1525             : bool
    1526      568072 : op_mergejoinable(Oid opno, Oid inputtype)
    1527             : {
    1528      568072 :     bool        result = false;
    1529             :     HeapTuple   tp;
    1530             :     TypeCacheEntry *typentry;
    1531             : 
    1532             :     /*
    1533             :      * For array_eq or record_eq, we can sort if the element or field types
    1534             :      * are all sortable.  We could implement all the checks for that here, but
    1535             :      * the typcache already does that and caches the results too, so let's
    1536             :      * rely on the typcache.
    1537             :      */
    1538      568072 :     if (opno == ARRAY_EQ_OP)
    1539             :     {
    1540         654 :         typentry = lookup_type_cache(inputtype, TYPECACHE_CMP_PROC);
    1541         654 :         if (typentry->cmp_proc == F_BTARRAYCMP)
    1542         654 :             result = true;
    1543             :     }
    1544      567418 :     else if (opno == RECORD_EQ_OP)
    1545             :     {
    1546          76 :         typentry = lookup_type_cache(inputtype, TYPECACHE_CMP_PROC);
    1547          76 :         if (typentry->cmp_proc == F_BTRECORDCMP)
    1548          76 :             result = true;
    1549             :     }
    1550             :     else
    1551             :     {
    1552             :         /* For all other operators, rely on pg_operator.oprcanmerge */
    1553      567342 :         tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1554      567342 :         if (HeapTupleIsValid(tp))
    1555             :         {
    1556      567342 :             Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
    1557             : 
    1558      567342 :             result = optup->oprcanmerge;
    1559      567342 :             ReleaseSysCache(tp);
    1560             :         }
    1561             :     }
    1562      568072 :     return result;
    1563             : }
    1564             : 
    1565             : /*
    1566             :  * op_hashjoinable
    1567             :  *
    1568             :  * Returns true if the operator is hashjoinable.  (There must be a suitable
    1569             :  * hash opfamily entry for this operator if it is so marked.)
    1570             :  *
    1571             :  * In some cases (currently only array_eq), hashjoinability depends on the
    1572             :  * specific input data type the operator is invoked for, so that must be
    1573             :  * passed as well.  We currently assume that only one input's type is needed
    1574             :  * to check this --- by convention, pass the left input's data type.
    1575             :  */
    1576             : bool
    1577      451330 : op_hashjoinable(Oid opno, Oid inputtype)
    1578             : {
    1579      451330 :     bool        result = false;
    1580             :     HeapTuple   tp;
    1581             :     TypeCacheEntry *typentry;
    1582             : 
    1583             :     /* As in op_mergejoinable, let the typcache handle the hard cases */
    1584      451330 :     if (opno == ARRAY_EQ_OP)
    1585             :     {
    1586         468 :         typentry = lookup_type_cache(inputtype, TYPECACHE_HASH_PROC);
    1587         468 :         if (typentry->hash_proc == F_HASH_ARRAY)
    1588         468 :             result = true;
    1589             :     }
    1590      450862 :     else if (opno == RECORD_EQ_OP)
    1591             :     {
    1592          78 :         typentry = lookup_type_cache(inputtype, TYPECACHE_HASH_PROC);
    1593          78 :         if (typentry->hash_proc == F_HASH_RECORD)
    1594          66 :             result = true;
    1595             :     }
    1596             :     else
    1597             :     {
    1598             :         /* For all other operators, rely on pg_operator.oprcanhash */
    1599      450784 :         tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1600      450784 :         if (HeapTupleIsValid(tp))
    1601             :         {
    1602      450784 :             Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
    1603             : 
    1604      450784 :             result = optup->oprcanhash;
    1605      450784 :             ReleaseSysCache(tp);
    1606             :         }
    1607             :     }
    1608      451330 :     return result;
    1609             : }
    1610             : 
    1611             : /*
    1612             :  * op_strict
    1613             :  *
    1614             :  * Get the proisstrict flag for the operator's underlying function.
    1615             :  */
    1616             : bool
    1617       64878 : op_strict(Oid opno)
    1618             : {
    1619       64878 :     RegProcedure funcid = get_opcode(opno);
    1620             : 
    1621       64878 :     if (funcid == (RegProcedure) InvalidOid)
    1622           0 :         elog(ERROR, "operator %u does not exist", opno);
    1623             : 
    1624       64878 :     return func_strict((Oid) funcid);
    1625             : }
    1626             : 
    1627             : /*
    1628             :  * op_volatile
    1629             :  *
    1630             :  * Get the provolatile flag for the operator's underlying function.
    1631             :  */
    1632             : char
    1633       20930 : op_volatile(Oid opno)
    1634             : {
    1635       20930 :     RegProcedure funcid = get_opcode(opno);
    1636             : 
    1637       20930 :     if (funcid == (RegProcedure) InvalidOid)
    1638           0 :         elog(ERROR, "operator %u does not exist", opno);
    1639             : 
    1640       20930 :     return func_volatile((Oid) funcid);
    1641             : }
    1642             : 
    1643             : /*
    1644             :  * get_commutator
    1645             :  *
    1646             :  *      Returns the corresponding commutator of an operator.
    1647             :  */
    1648             : Oid
    1649      717050 : get_commutator(Oid opno)
    1650             : {
    1651             :     HeapTuple   tp;
    1652             : 
    1653      717050 :     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1654      717050 :     if (HeapTupleIsValid(tp))
    1655             :     {
    1656      717050 :         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
    1657             :         Oid         result;
    1658             : 
    1659      717050 :         result = optup->oprcom;
    1660      717050 :         ReleaseSysCache(tp);
    1661      717050 :         return result;
    1662             :     }
    1663             :     else
    1664           0 :         return InvalidOid;
    1665             : }
    1666             : 
    1667             : /*
    1668             :  * get_negator
    1669             :  *
    1670             :  *      Returns the corresponding negator of an operator.
    1671             :  */
    1672             : Oid
    1673       83944 : get_negator(Oid opno)
    1674             : {
    1675             :     HeapTuple   tp;
    1676             : 
    1677       83944 :     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1678       83944 :     if (HeapTupleIsValid(tp))
    1679             :     {
    1680       83944 :         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
    1681             :         Oid         result;
    1682             : 
    1683       83944 :         result = optup->oprnegate;
    1684       83944 :         ReleaseSysCache(tp);
    1685       83944 :         return result;
    1686             :     }
    1687             :     else
    1688           0 :         return InvalidOid;
    1689             : }
    1690             : 
    1691             : /*
    1692             :  * get_oprrest
    1693             :  *
    1694             :  *      Returns procedure id for computing selectivity of an operator.
    1695             :  */
    1696             : RegProcedure
    1697     1193138 : get_oprrest(Oid opno)
    1698             : {
    1699             :     HeapTuple   tp;
    1700             : 
    1701     1193138 :     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1702     1193138 :     if (HeapTupleIsValid(tp))
    1703             :     {
    1704     1193138 :         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
    1705             :         RegProcedure result;
    1706             : 
    1707     1193138 :         result = optup->oprrest;
    1708     1193138 :         ReleaseSysCache(tp);
    1709     1193138 :         return result;
    1710             :     }
    1711             :     else
    1712           0 :         return (RegProcedure) InvalidOid;
    1713             : }
    1714             : 
    1715             : /*
    1716             :  * get_oprjoin
    1717             :  *
    1718             :  *      Returns procedure id for computing selectivity of a join.
    1719             :  */
    1720             : RegProcedure
    1721      235878 : get_oprjoin(Oid opno)
    1722             : {
    1723             :     HeapTuple   tp;
    1724             : 
    1725      235878 :     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1726      235878 :     if (HeapTupleIsValid(tp))
    1727             :     {
    1728      235878 :         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
    1729             :         RegProcedure result;
    1730             : 
    1731      235878 :         result = optup->oprjoin;
    1732      235878 :         ReleaseSysCache(tp);
    1733      235878 :         return result;
    1734             :     }
    1735             :     else
    1736           0 :         return (RegProcedure) InvalidOid;
    1737             : }
    1738             : 
    1739             : /*              ---------- FUNCTION CACHE ----------                     */
    1740             : 
    1741             : /*
    1742             :  * get_func_name
    1743             :  *    returns the name of the function with the given funcid
    1744             :  *
    1745             :  * Note: returns a palloc'd copy of the string, or NULL if no such function.
    1746             :  */
    1747             : char *
    1748         806 : get_func_name(Oid funcid)
    1749             : {
    1750             :     HeapTuple   tp;
    1751             : 
    1752         806 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1753         806 :     if (HeapTupleIsValid(tp))
    1754             :     {
    1755         806 :         Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
    1756             :         char       *result;
    1757             : 
    1758         806 :         result = pstrdup(NameStr(functup->proname));
    1759         806 :         ReleaseSysCache(tp);
    1760         806 :         return result;
    1761             :     }
    1762             :     else
    1763           0 :         return NULL;
    1764             : }
    1765             : 
    1766             : /*
    1767             :  * get_func_namespace
    1768             :  *
    1769             :  *      Returns the pg_namespace OID associated with a given function.
    1770             :  */
    1771             : Oid
    1772         196 : get_func_namespace(Oid funcid)
    1773             : {
    1774             :     HeapTuple   tp;
    1775             : 
    1776         196 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1777         196 :     if (HeapTupleIsValid(tp))
    1778             :     {
    1779         196 :         Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
    1780             :         Oid         result;
    1781             : 
    1782         196 :         result = functup->pronamespace;
    1783         196 :         ReleaseSysCache(tp);
    1784         196 :         return result;
    1785             :     }
    1786             :     else
    1787           0 :         return InvalidOid;
    1788             : }
    1789             : 
    1790             : /*
    1791             :  * get_func_rettype
    1792             :  *      Given procedure id, return the function's result type.
    1793             :  */
    1794             : Oid
    1795       24446 : get_func_rettype(Oid funcid)
    1796             : {
    1797             :     HeapTuple   tp;
    1798             :     Oid         result;
    1799             : 
    1800       24446 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1801       24446 :     if (!HeapTupleIsValid(tp))
    1802           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1803             : 
    1804       24446 :     result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
    1805       24446 :     ReleaseSysCache(tp);
    1806       24446 :     return result;
    1807             : }
    1808             : 
    1809             : /*
    1810             :  * get_func_nargs
    1811             :  *      Given procedure id, return the number of arguments.
    1812             :  */
    1813             : int
    1814           0 : get_func_nargs(Oid funcid)
    1815             : {
    1816             :     HeapTuple   tp;
    1817             :     int         result;
    1818             : 
    1819           0 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1820           0 :     if (!HeapTupleIsValid(tp))
    1821           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1822             : 
    1823           0 :     result = ((Form_pg_proc) GETSTRUCT(tp))->pronargs;
    1824           0 :     ReleaseSysCache(tp);
    1825           0 :     return result;
    1826             : }
    1827             : 
    1828             : /*
    1829             :  * get_func_signature
    1830             :  *      Given procedure id, return the function's argument and result types.
    1831             :  *      (The return value is the result type.)
    1832             :  *
    1833             :  * The arguments are returned as a palloc'd array.
    1834             :  */
    1835             : Oid
    1836        1528 : get_func_signature(Oid funcid, Oid **argtypes, int *nargs)
    1837             : {
    1838             :     HeapTuple   tp;
    1839             :     Form_pg_proc procstruct;
    1840             :     Oid         result;
    1841             : 
    1842        1528 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1843        1528 :     if (!HeapTupleIsValid(tp))
    1844           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1845             : 
    1846        1528 :     procstruct = (Form_pg_proc) GETSTRUCT(tp);
    1847             : 
    1848        1528 :     result = procstruct->prorettype;
    1849        1528 :     *nargs = (int) procstruct->pronargs;
    1850             :     Assert(*nargs == procstruct->proargtypes.dim1);
    1851        1528 :     *argtypes = (Oid *) palloc(*nargs * sizeof(Oid));
    1852        1528 :     memcpy(*argtypes, procstruct->proargtypes.values, *nargs * sizeof(Oid));
    1853             : 
    1854        1528 :     ReleaseSysCache(tp);
    1855        1528 :     return result;
    1856             : }
    1857             : 
    1858             : /*
    1859             :  * get_func_variadictype
    1860             :  *      Given procedure id, return the function's provariadic field.
    1861             :  */
    1862             : Oid
    1863         276 : get_func_variadictype(Oid funcid)
    1864             : {
    1865             :     HeapTuple   tp;
    1866             :     Oid         result;
    1867             : 
    1868         276 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1869         276 :     if (!HeapTupleIsValid(tp))
    1870           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1871             : 
    1872         276 :     result = ((Form_pg_proc) GETSTRUCT(tp))->provariadic;
    1873         276 :     ReleaseSysCache(tp);
    1874         276 :     return result;
    1875             : }
    1876             : 
    1877             : /*
    1878             :  * get_func_retset
    1879             :  *      Given procedure id, return the function's proretset flag.
    1880             :  */
    1881             : bool
    1882      652250 : get_func_retset(Oid funcid)
    1883             : {
    1884             :     HeapTuple   tp;
    1885             :     bool        result;
    1886             : 
    1887      652250 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1888      652250 :     if (!HeapTupleIsValid(tp))
    1889           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1890             : 
    1891      652250 :     result = ((Form_pg_proc) GETSTRUCT(tp))->proretset;
    1892      652250 :     ReleaseSysCache(tp);
    1893      652250 :     return result;
    1894             : }
    1895             : 
    1896             : /*
    1897             :  * func_strict
    1898             :  *      Given procedure id, return the function's proisstrict flag.
    1899             :  */
    1900             : bool
    1901      281086 : func_strict(Oid funcid)
    1902             : {
    1903             :     HeapTuple   tp;
    1904             :     bool        result;
    1905             : 
    1906      281086 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1907      281086 :     if (!HeapTupleIsValid(tp))
    1908           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1909             : 
    1910      281086 :     result = ((Form_pg_proc) GETSTRUCT(tp))->proisstrict;
    1911      281086 :     ReleaseSysCache(tp);
    1912      281086 :     return result;
    1913             : }
    1914             : 
    1915             : /*
    1916             :  * func_volatile
    1917             :  *      Given procedure id, return the function's provolatile flag.
    1918             :  */
    1919             : char
    1920     1012174 : func_volatile(Oid funcid)
    1921             : {
    1922             :     HeapTuple   tp;
    1923             :     char        result;
    1924             : 
    1925     1012174 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1926     1012174 :     if (!HeapTupleIsValid(tp))
    1927           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1928             : 
    1929     1012174 :     result = ((Form_pg_proc) GETSTRUCT(tp))->provolatile;
    1930     1012174 :     ReleaseSysCache(tp);
    1931     1012174 :     return result;
    1932             : }
    1933             : 
    1934             : /*
    1935             :  * func_parallel
    1936             :  *      Given procedure id, return the function's proparallel flag.
    1937             :  */
    1938             : char
    1939     1474640 : func_parallel(Oid funcid)
    1940             : {
    1941             :     HeapTuple   tp;
    1942             :     char        result;
    1943             : 
    1944     1474640 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1945     1474640 :     if (!HeapTupleIsValid(tp))
    1946           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1947             : 
    1948     1474640 :     result = ((Form_pg_proc) GETSTRUCT(tp))->proparallel;
    1949     1474640 :     ReleaseSysCache(tp);
    1950     1474640 :     return result;
    1951             : }
    1952             : 
    1953             : /*
    1954             :  * get_func_prokind
    1955             :  *     Given procedure id, return the routine kind.
    1956             :  */
    1957             : char
    1958       43036 : get_func_prokind(Oid funcid)
    1959             : {
    1960             :     HeapTuple   tp;
    1961             :     char        result;
    1962             : 
    1963       43036 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1964       43036 :     if (!HeapTupleIsValid(tp))
    1965           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1966             : 
    1967       43036 :     result = ((Form_pg_proc) GETSTRUCT(tp))->prokind;
    1968       43036 :     ReleaseSysCache(tp);
    1969       43036 :     return result;
    1970             : }
    1971             : 
    1972             : /*
    1973             :  * get_func_leakproof
    1974             :  *     Given procedure id, return the function's leakproof field.
    1975             :  */
    1976             : bool
    1977        6794 : get_func_leakproof(Oid funcid)
    1978             : {
    1979             :     HeapTuple   tp;
    1980             :     bool        result;
    1981             : 
    1982        6794 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1983        6794 :     if (!HeapTupleIsValid(tp))
    1984           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1985             : 
    1986        6794 :     result = ((Form_pg_proc) GETSTRUCT(tp))->proleakproof;
    1987        6794 :     ReleaseSysCache(tp);
    1988        6794 :     return result;
    1989             : }
    1990             : 
    1991             : /*
    1992             :  * get_func_support
    1993             :  *
    1994             :  *      Returns the support function OID associated with a given function,
    1995             :  *      or InvalidOid if there is none.
    1996             :  */
    1997             : RegProcedure
    1998       37232 : get_func_support(Oid funcid)
    1999             : {
    2000             :     HeapTuple   tp;
    2001             : 
    2002       37232 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    2003       37232 :     if (HeapTupleIsValid(tp))
    2004             :     {
    2005       37232 :         Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
    2006             :         RegProcedure result;
    2007             : 
    2008       37232 :         result = functup->prosupport;
    2009       37232 :         ReleaseSysCache(tp);
    2010       37232 :         return result;
    2011             :     }
    2012             :     else
    2013           0 :         return (RegProcedure) InvalidOid;
    2014             : }
    2015             : 
    2016             : /*              ---------- RELATION CACHE ----------                     */
    2017             : 
    2018             : /*
    2019             :  * get_relname_relid
    2020             :  *      Given name and namespace of a relation, look up the OID.
    2021             :  *
    2022             :  * Returns InvalidOid if there is no such relation.
    2023             :  */
    2024             : Oid
    2025     1604256 : get_relname_relid(const char *relname, Oid relnamespace)
    2026             : {
    2027     1604256 :     return GetSysCacheOid2(RELNAMENSP, Anum_pg_class_oid,
    2028             :                            PointerGetDatum(relname),
    2029             :                            ObjectIdGetDatum(relnamespace));
    2030             : }
    2031             : 
    2032             : #ifdef NOT_USED
    2033             : /*
    2034             :  * get_relnatts
    2035             :  *
    2036             :  *      Returns the number of attributes for a given relation.
    2037             :  */
    2038             : int
    2039             : get_relnatts(Oid relid)
    2040             : {
    2041             :     HeapTuple   tp;
    2042             : 
    2043             :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    2044             :     if (HeapTupleIsValid(tp))
    2045             :     {
    2046             :         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
    2047             :         int         result;
    2048             : 
    2049             :         result = reltup->relnatts;
    2050             :         ReleaseSysCache(tp);
    2051             :         return result;
    2052             :     }
    2053             :     else
    2054             :         return InvalidAttrNumber;
    2055             : }
    2056             : #endif
    2057             : 
    2058             : /*
    2059             :  * get_rel_name
    2060             :  *      Returns the name of a given relation.
    2061             :  *
    2062             :  * Returns a palloc'd copy of the string, or NULL if no such relation.
    2063             :  *
    2064             :  * NOTE: since relation name is not unique, be wary of code that uses this
    2065             :  * for anything except preparing error messages.
    2066             :  */
    2067             : char *
    2068      193378 : get_rel_name(Oid relid)
    2069             : {
    2070             :     HeapTuple   tp;
    2071             : 
    2072      193378 :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    2073      193378 :     if (HeapTupleIsValid(tp))
    2074             :     {
    2075      193366 :         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
    2076             :         char       *result;
    2077             : 
    2078      193366 :         result = pstrdup(NameStr(reltup->relname));
    2079      193366 :         ReleaseSysCache(tp);
    2080      193366 :         return result;
    2081             :     }
    2082             :     else
    2083          12 :         return NULL;
    2084             : }
    2085             : 
    2086             : /*
    2087             :  * get_rel_namespace
    2088             :  *
    2089             :  *      Returns the pg_namespace OID associated with a given relation.
    2090             :  */
    2091             : Oid
    2092      418826 : get_rel_namespace(Oid relid)
    2093             : {
    2094             :     HeapTuple   tp;
    2095             : 
    2096      418826 :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    2097      418826 :     if (HeapTupleIsValid(tp))
    2098             :     {
    2099      418826 :         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
    2100             :         Oid         result;
    2101             : 
    2102      418826 :         result = reltup->relnamespace;
    2103      418826 :         ReleaseSysCache(tp);
    2104      418826 :         return result;
    2105             :     }
    2106             :     else
    2107           0 :         return InvalidOid;
    2108             : }
    2109             : 
    2110             : /*
    2111             :  * get_rel_type_id
    2112             :  *
    2113             :  *      Returns the pg_type OID associated with a given relation.
    2114             :  *
    2115             :  * Note: not all pg_class entries have associated pg_type OIDs; so be
    2116             :  * careful to check for InvalidOid result.
    2117             :  */
    2118             : Oid
    2119        8832 : get_rel_type_id(Oid relid)
    2120             : {
    2121             :     HeapTuple   tp;
    2122             : 
    2123        8832 :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    2124        8832 :     if (HeapTupleIsValid(tp))
    2125             :     {
    2126        8832 :         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
    2127             :         Oid         result;
    2128             : 
    2129        8832 :         result = reltup->reltype;
    2130        8832 :         ReleaseSysCache(tp);
    2131        8832 :         return result;
    2132             :     }
    2133             :     else
    2134           0 :         return InvalidOid;
    2135             : }
    2136             : 
    2137             : /*
    2138             :  * get_rel_relkind
    2139             :  *
    2140             :  *      Returns the relkind associated with a given relation.
    2141             :  */
    2142             : char
    2143      217338 : get_rel_relkind(Oid relid)
    2144             : {
    2145             :     HeapTuple   tp;
    2146             : 
    2147      217338 :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    2148      217338 :     if (HeapTupleIsValid(tp))
    2149             :     {
    2150      217338 :         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
    2151             :         char        result;
    2152             : 
    2153      217338 :         result = reltup->relkind;
    2154      217338 :         ReleaseSysCache(tp);
    2155      217338 :         return result;
    2156             :     }
    2157             :     else
    2158           0 :         return '\0';
    2159             : }
    2160             : 
    2161             : /*
    2162             :  * get_rel_relispartition
    2163             :  *
    2164             :  *      Returns the relispartition flag associated with a given relation.
    2165             :  */
    2166             : bool
    2167       21528 : get_rel_relispartition(Oid relid)
    2168             : {
    2169             :     HeapTuple   tp;
    2170             : 
    2171       21528 :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    2172       21528 :     if (HeapTupleIsValid(tp))
    2173             :     {
    2174       21528 :         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
    2175             :         bool        result;
    2176             : 
    2177       21528 :         result = reltup->relispartition;
    2178       21528 :         ReleaseSysCache(tp);
    2179       21528 :         return result;
    2180             :     }
    2181             :     else
    2182           0 :         return false;
    2183             : }
    2184             : 
    2185             : /*
    2186             :  * get_rel_tablespace
    2187             :  *
    2188             :  *      Returns the pg_tablespace OID associated with a given relation.
    2189             :  *
    2190             :  * Note: InvalidOid might mean either that we couldn't find the relation,
    2191             :  * or that it is in the database's default tablespace.
    2192             :  */
    2193             : Oid
    2194        8342 : get_rel_tablespace(Oid relid)
    2195             : {
    2196             :     HeapTuple   tp;
    2197             : 
    2198        8342 :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    2199        8342 :     if (HeapTupleIsValid(tp))
    2200             :     {
    2201        8342 :         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
    2202             :         Oid         result;
    2203             : 
    2204        8342 :         result = reltup->reltablespace;
    2205        8342 :         ReleaseSysCache(tp);
    2206        8342 :         return result;
    2207             :     }
    2208             :     else
    2209           0 :         return InvalidOid;
    2210             : }
    2211             : 
    2212             : /*
    2213             :  * get_rel_persistence
    2214             :  *
    2215             :  *      Returns the relpersistence associated with a given relation.
    2216             :  */
    2217             : char
    2218      374408 : get_rel_persistence(Oid relid)
    2219             : {
    2220             :     HeapTuple   tp;
    2221             :     Form_pg_class reltup;
    2222             :     char        result;
    2223             : 
    2224      374408 :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    2225      374408 :     if (!HeapTupleIsValid(tp))
    2226           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
    2227      374408 :     reltup = (Form_pg_class) GETSTRUCT(tp);
    2228      374408 :     result = reltup->relpersistence;
    2229      374408 :     ReleaseSysCache(tp);
    2230             : 
    2231      374408 :     return result;
    2232             : }
    2233             : 
    2234             : /*
    2235             :  * get_rel_relam
    2236             :  *
    2237             :  *      Returns the relam associated with a given relation.
    2238             :  */
    2239             : Oid
    2240        7740 : get_rel_relam(Oid relid)
    2241             : {
    2242             :     HeapTuple   tp;
    2243             :     Form_pg_class reltup;
    2244             :     Oid         result;
    2245             : 
    2246        7740 :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    2247        7740 :     if (!HeapTupleIsValid(tp))
    2248           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
    2249        7740 :     reltup = (Form_pg_class) GETSTRUCT(tp);
    2250        7740 :     result = reltup->relam;
    2251        7740 :     ReleaseSysCache(tp);
    2252             : 
    2253        7740 :     return result;
    2254             : }
    2255             : 
    2256             : 
    2257             : /*              ---------- TRANSFORM CACHE ----------                        */
    2258             : 
    2259             : Oid
    2260        1690 : get_transform_fromsql(Oid typid, Oid langid, List *trftypes)
    2261             : {
    2262             :     HeapTuple   tup;
    2263             : 
    2264        1690 :     if (!list_member_oid(trftypes, typid))
    2265        1528 :         return InvalidOid;
    2266             : 
    2267         162 :     tup = SearchSysCache2(TRFTYPELANG, ObjectIdGetDatum(typid),
    2268             :                           ObjectIdGetDatum(langid));
    2269         162 :     if (HeapTupleIsValid(tup))
    2270             :     {
    2271             :         Oid         funcid;
    2272             : 
    2273         162 :         funcid = ((Form_pg_transform) GETSTRUCT(tup))->trffromsql;
    2274         162 :         ReleaseSysCache(tup);
    2275         162 :         return funcid;
    2276             :     }
    2277             :     else
    2278           0 :         return InvalidOid;
    2279             : }
    2280             : 
    2281             : Oid
    2282        2074 : get_transform_tosql(Oid typid, Oid langid, List *trftypes)
    2283             : {
    2284             :     HeapTuple   tup;
    2285             : 
    2286        2074 :     if (!list_member_oid(trftypes, typid))
    2287        1892 :         return InvalidOid;
    2288             : 
    2289         182 :     tup = SearchSysCache2(TRFTYPELANG, ObjectIdGetDatum(typid),
    2290             :                           ObjectIdGetDatum(langid));
    2291         182 :     if (HeapTupleIsValid(tup))
    2292             :     {
    2293             :         Oid         funcid;
    2294             : 
    2295         182 :         funcid = ((Form_pg_transform) GETSTRUCT(tup))->trftosql;
    2296         182 :         ReleaseSysCache(tup);
    2297         182 :         return funcid;
    2298             :     }
    2299             :     else
    2300           0 :         return InvalidOid;
    2301             : }
    2302             : 
    2303             : 
    2304             : /*              ---------- TYPE CACHE ----------                         */
    2305             : 
    2306             : /*
    2307             :  * get_typisdefined
    2308             :  *
    2309             :  *      Given the type OID, determine whether the type is defined
    2310             :  *      (if not, it's only a shell).
    2311             :  */
    2312             : bool
    2313         300 : get_typisdefined(Oid typid)
    2314             : {
    2315             :     HeapTuple   tp;
    2316             : 
    2317         300 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2318         300 :     if (HeapTupleIsValid(tp))
    2319             :     {
    2320         300 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    2321             :         bool        result;
    2322             : 
    2323         300 :         result = typtup->typisdefined;
    2324         300 :         ReleaseSysCache(tp);
    2325         300 :         return result;
    2326             :     }
    2327             :     else
    2328           0 :         return false;
    2329             : }
    2330             : 
    2331             : /*
    2332             :  * get_typlen
    2333             :  *
    2334             :  *      Given the type OID, return the length of the type.
    2335             :  */
    2336             : int16
    2337     2781072 : get_typlen(Oid typid)
    2338             : {
    2339             :     HeapTuple   tp;
    2340             : 
    2341     2781072 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2342     2781072 :     if (HeapTupleIsValid(tp))
    2343             :     {
    2344     2781072 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    2345             :         int16       result;
    2346             : 
    2347     2781072 :         result = typtup->typlen;
    2348     2781072 :         ReleaseSysCache(tp);
    2349     2781072 :         return result;
    2350             :     }
    2351             :     else
    2352           0 :         return 0;
    2353             : }
    2354             : 
    2355             : /*
    2356             :  * get_typbyval
    2357             :  *
    2358             :  *      Given the type OID, determine whether the type is returned by value or
    2359             :  *      not.  Returns true if by value, false if by reference.
    2360             :  */
    2361             : bool
    2362       65268 : get_typbyval(Oid typid)
    2363             : {
    2364             :     HeapTuple   tp;
    2365             : 
    2366       65268 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2367       65268 :     if (HeapTupleIsValid(tp))
    2368             :     {
    2369       65268 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    2370             :         bool        result;
    2371             : 
    2372       65268 :         result = typtup->typbyval;
    2373       65268 :         ReleaseSysCache(tp);
    2374       65268 :         return result;
    2375             :     }
    2376             :     else
    2377           0 :         return false;
    2378             : }
    2379             : 
    2380             : /*
    2381             :  * get_typlenbyval
    2382             :  *
    2383             :  *      A two-fer: given the type OID, return both typlen and typbyval.
    2384             :  *
    2385             :  *      Since both pieces of info are needed to know how to copy a Datum,
    2386             :  *      many places need both.  Might as well get them with one cache lookup
    2387             :  *      instead of two.  Also, this routine raises an error instead of
    2388             :  *      returning a bogus value when given a bad type OID.
    2389             :  */
    2390             : void
    2391      837692 : get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
    2392             : {
    2393             :     HeapTuple   tp;
    2394             :     Form_pg_type typtup;
    2395             : 
    2396      837692 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2397      837692 :     if (!HeapTupleIsValid(tp))
    2398           0 :         elog(ERROR, "cache lookup failed for type %u", typid);
    2399      837692 :     typtup = (Form_pg_type) GETSTRUCT(tp);
    2400      837692 :     *typlen = typtup->typlen;
    2401      837692 :     *typbyval = typtup->typbyval;
    2402      837692 :     ReleaseSysCache(tp);
    2403      837692 : }
    2404             : 
    2405             : /*
    2406             :  * get_typlenbyvalalign
    2407             :  *
    2408             :  *      A three-fer: given the type OID, return typlen, typbyval, typalign.
    2409             :  */
    2410             : void
    2411     1858160 : get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
    2412             :                      char *typalign)
    2413             : {
    2414             :     HeapTuple   tp;
    2415             :     Form_pg_type typtup;
    2416             : 
    2417     1858160 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2418     1858160 :     if (!HeapTupleIsValid(tp))
    2419           0 :         elog(ERROR, "cache lookup failed for type %u", typid);
    2420     1858160 :     typtup = (Form_pg_type) GETSTRUCT(tp);
    2421     1858160 :     *typlen = typtup->typlen;
    2422     1858160 :     *typbyval = typtup->typbyval;
    2423     1858160 :     *typalign = typtup->typalign;
    2424     1858160 :     ReleaseSysCache(tp);
    2425     1858160 : }
    2426             : 
    2427             : /*
    2428             :  * getTypeIOParam
    2429             :  *      Given a pg_type row, select the type OID to pass to I/O functions
    2430             :  *
    2431             :  * Formerly, all I/O functions were passed pg_type.typelem as their second
    2432             :  * parameter, but we now have a more complex rule about what to pass.
    2433             :  * This knowledge is intended to be centralized here --- direct references
    2434             :  * to typelem elsewhere in the code are wrong, if they are associated with
    2435             :  * I/O calls and not with actual subscripting operations!  (But see
    2436             :  * bootstrap.c's boot_get_type_io_data() if you need to change this.)
    2437             :  *
    2438             :  * As of PostgreSQL 8.1, output functions receive only the value itself
    2439             :  * and not any auxiliary parameters, so the name of this routine is now
    2440             :  * a bit of a misnomer ... it should be getTypeInputParam.
    2441             :  */
    2442             : Oid
    2443     1823598 : getTypeIOParam(HeapTuple typeTuple)
    2444             : {
    2445     1823598 :     Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
    2446             : 
    2447             :     /*
    2448             :      * Array types get their typelem as parameter; everybody else gets their
    2449             :      * own type OID as parameter.
    2450             :      */
    2451     1823598 :     if (OidIsValid(typeStruct->typelem))
    2452       88424 :         return typeStruct->typelem;
    2453             :     else
    2454     1735174 :         return typeStruct->oid;
    2455             : }
    2456             : 
    2457             : /*
    2458             :  * get_type_io_data
    2459             :  *
    2460             :  *      A six-fer:  given the type OID, return typlen, typbyval, typalign,
    2461             :  *                  typdelim, typioparam, and IO function OID. The IO function
    2462             :  *                  returned is controlled by IOFuncSelector
    2463             :  */
    2464             : void
    2465      126282 : get_type_io_data(Oid typid,
    2466             :                  IOFuncSelector which_func,
    2467             :                  int16 *typlen,
    2468             :                  bool *typbyval,
    2469             :                  char *typalign,
    2470             :                  char *typdelim,
    2471             :                  Oid *typioparam,
    2472             :                  Oid *func)
    2473             : {
    2474             :     HeapTuple   typeTuple;
    2475             :     Form_pg_type typeStruct;
    2476             : 
    2477             :     /*
    2478             :      * In bootstrap mode, pass it off to bootstrap.c.  This hack allows us to
    2479             :      * use array_in and array_out during bootstrap.
    2480             :      */
    2481      126282 :     if (IsBootstrapProcessingMode())
    2482             :     {
    2483             :         Oid         typinput;
    2484             :         Oid         typoutput;
    2485             : 
    2486       46844 :         boot_get_type_io_data(typid,
    2487             :                               typlen,
    2488             :                               typbyval,
    2489             :                               typalign,
    2490             :                               typdelim,
    2491             :                               typioparam,
    2492             :                               &typinput,
    2493             :                               &typoutput);
    2494       46844 :         switch (which_func)
    2495             :         {
    2496       46844 :             case IOFunc_input:
    2497       46844 :                 *func = typinput;
    2498       46844 :                 break;
    2499           0 :             case IOFunc_output:
    2500           0 :                 *func = typoutput;
    2501           0 :                 break;
    2502           0 :             default:
    2503           0 :                 elog(ERROR, "binary I/O not supported during bootstrap");
    2504             :                 break;
    2505             :         }
    2506       46844 :         return;
    2507             :     }
    2508             : 
    2509       79438 :     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2510       79438 :     if (!HeapTupleIsValid(typeTuple))
    2511           0 :         elog(ERROR, "cache lookup failed for type %u", typid);
    2512       79438 :     typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
    2513             : 
    2514       79438 :     *typlen = typeStruct->typlen;
    2515       79438 :     *typbyval = typeStruct->typbyval;
    2516       79438 :     *typalign = typeStruct->typalign;
    2517       79438 :     *typdelim = typeStruct->typdelim;
    2518       79438 :     *typioparam = getTypeIOParam(typeTuple);
    2519       79438 :     switch (which_func)
    2520             :     {
    2521       37358 :         case IOFunc_input:
    2522       37358 :             *func = typeStruct->typinput;
    2523       37358 :             break;
    2524       41984 :         case IOFunc_output:
    2525       41984 :             *func = typeStruct->typoutput;
    2526       41984 :             break;
    2527          56 :         case IOFunc_receive:
    2528          56 :             *func = typeStruct->typreceive;
    2529          56 :             break;
    2530          40 :         case IOFunc_send:
    2531          40 :             *func = typeStruct->typsend;
    2532          40 :             break;
    2533             :     }
    2534       79438 :     ReleaseSysCache(typeTuple);
    2535             : }
    2536             : 
    2537             : #ifdef NOT_USED
    2538             : char
    2539             : get_typalign(Oid typid)
    2540             : {
    2541             :     HeapTuple   tp;
    2542             : 
    2543             :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2544             :     if (HeapTupleIsValid(tp))
    2545             :     {
    2546             :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    2547             :         char        result;
    2548             : 
    2549             :         result = typtup->typalign;
    2550             :         ReleaseSysCache(tp);
    2551             :         return result;
    2552             :     }
    2553             :     else
    2554             :         return TYPALIGN_INT;
    2555             : }
    2556             : #endif
    2557             : 
    2558             : char
    2559       96166 : get_typstorage(Oid typid)
    2560             : {
    2561             :     HeapTuple   tp;
    2562             : 
    2563       96166 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2564       96166 :     if (HeapTupleIsValid(tp))
    2565             :     {
    2566       96166 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    2567             :         char        result;
    2568             : 
    2569       96166 :         result = typtup->typstorage;
    2570       96166 :         ReleaseSysCache(tp);
    2571       96166 :         return result;
    2572             :     }
    2573             :     else
    2574           0 :         return TYPSTORAGE_PLAIN;
    2575             : }
    2576             : 
    2577             : /*
    2578             :  * get_typdefault
    2579             :  *    Given a type OID, return the type's default value, if any.
    2580             :  *
    2581             :  *    The result is a palloc'd expression node tree, or NULL if there
    2582             :  *    is no defined default for the datatype.
    2583             :  *
    2584             :  * NB: caller should be prepared to coerce result to correct datatype;
    2585             :  * the returned expression tree might produce something of the wrong type.
    2586             :  */
    2587             : Node *
    2588       37524 : get_typdefault(Oid typid)
    2589             : {
    2590             :     HeapTuple   typeTuple;
    2591             :     Form_pg_type type;
    2592             :     Datum       datum;
    2593             :     bool        isNull;
    2594             :     Node       *expr;
    2595             : 
    2596       37524 :     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2597       37524 :     if (!HeapTupleIsValid(typeTuple))
    2598           0 :         elog(ERROR, "cache lookup failed for type %u", typid);
    2599       37524 :     type = (Form_pg_type) GETSTRUCT(typeTuple);
    2600             : 
    2601             :     /*
    2602             :      * typdefault and typdefaultbin are potentially null, so don't try to
    2603             :      * access 'em as struct fields. Must do it the hard way with
    2604             :      * SysCacheGetAttr.
    2605             :      */
    2606       37524 :     datum = SysCacheGetAttr(TYPEOID,
    2607             :                             typeTuple,
    2608             :                             Anum_pg_type_typdefaultbin,
    2609             :                             &isNull);
    2610             : 
    2611       37524 :     if (!isNull)
    2612             :     {
    2613             :         /* We have an expression default */
    2614         218 :         expr = stringToNode(TextDatumGetCString(datum));
    2615             :     }
    2616             :     else
    2617             :     {
    2618             :         /* Perhaps we have a plain literal default */
    2619       37306 :         datum = SysCacheGetAttr(TYPEOID,
    2620             :                                 typeTuple,
    2621             :                                 Anum_pg_type_typdefault,
    2622             :                                 &isNull);
    2623             : 
    2624       37306 :         if (!isNull)
    2625             :         {
    2626             :             char       *strDefaultVal;
    2627             : 
    2628             :             /* Convert text datum to C string */
    2629          12 :             strDefaultVal = TextDatumGetCString(datum);
    2630             :             /* Convert C string to a value of the given type */
    2631          12 :             datum = OidInputFunctionCall(type->typinput, strDefaultVal,
    2632             :                                          getTypeIOParam(typeTuple), -1);
    2633             :             /* Build a Const node containing the value */
    2634          12 :             expr = (Node *) makeConst(typid,
    2635             :                                       -1,
    2636             :                                       type->typcollation,
    2637          12 :                                       type->typlen,
    2638             :                                       datum,
    2639             :                                       false,
    2640          12 :                                       type->typbyval);
    2641          12 :             pfree(strDefaultVal);
    2642             :         }
    2643             :         else
    2644             :         {
    2645             :             /* No default */
    2646       37294 :             expr = NULL;
    2647             :         }
    2648             :     }
    2649             : 
    2650       37524 :     ReleaseSysCache(typeTuple);
    2651             : 
    2652       37524 :     return expr;
    2653             : }
    2654             : 
    2655             : /*
    2656             :  * getBaseType
    2657             :  *      If the given type is a domain, return its base type;
    2658             :  *      otherwise return the type's own OID.
    2659             :  */
    2660             : Oid
    2661     5719894 : getBaseType(Oid typid)
    2662             : {
    2663     5719894 :     int32       typmod = -1;
    2664             : 
    2665     5719894 :     return getBaseTypeAndTypmod(typid, &typmod);
    2666             : }
    2667             : 
    2668             : /*
    2669             :  * getBaseTypeAndTypmod
    2670             :  *      If the given type is a domain, return its base type and typmod;
    2671             :  *      otherwise return the type's own OID, and leave *typmod unchanged.
    2672             :  *
    2673             :  * Note that the "applied typmod" should be -1 for every domain level
    2674             :  * above the bottommost; therefore, if the passed-in typid is indeed
    2675             :  * a domain, *typmod should be -1.
    2676             :  */
    2677             : Oid
    2678     8226880 : getBaseTypeAndTypmod(Oid typid, int32 *typmod)
    2679             : {
    2680             :     /*
    2681             :      * We loop to find the bottom base type in a stack of domains.
    2682             :      */
    2683             :     for (;;)
    2684      298044 :     {
    2685             :         HeapTuple   tup;
    2686             :         Form_pg_type typTup;
    2687             : 
    2688     8226880 :         tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2689     8226880 :         if (!HeapTupleIsValid(tup))
    2690           0 :             elog(ERROR, "cache lookup failed for type %u", typid);
    2691     8226880 :         typTup = (Form_pg_type) GETSTRUCT(tup);
    2692     8226880 :         if (typTup->typtype != TYPTYPE_DOMAIN)
    2693             :         {
    2694             :             /* Not a domain, so done */
    2695     7928836 :             ReleaseSysCache(tup);
    2696     7928836 :             break;
    2697             :         }
    2698             : 
    2699             :         Assert(*typmod == -1);
    2700      298044 :         typid = typTup->typbasetype;
    2701      298044 :         *typmod = typTup->typtypmod;
    2702             : 
    2703      298044 :         ReleaseSysCache(tup);
    2704             :     }
    2705             : 
    2706     7928836 :     return typid;
    2707             : }
    2708             : 
    2709             : /*
    2710             :  * get_typavgwidth
    2711             :  *
    2712             :  *    Given a type OID and a typmod value (pass -1 if typmod is unknown),
    2713             :  *    estimate the average width of values of the type.  This is used by
    2714             :  *    the planner, which doesn't require absolutely correct results;
    2715             :  *    it's OK (and expected) to guess if we don't know for sure.
    2716             :  */
    2717             : int32
    2718     1781938 : get_typavgwidth(Oid typid, int32 typmod)
    2719             : {
    2720     1781938 :     int         typlen = get_typlen(typid);
    2721             :     int32       maxwidth;
    2722             : 
    2723             :     /*
    2724             :      * Easy if it's a fixed-width type
    2725             :      */
    2726     1781938 :     if (typlen > 0)
    2727     1164258 :         return typlen;
    2728             : 
    2729             :     /*
    2730             :      * type_maximum_size knows the encoding of typmod for some datatypes;
    2731             :      * don't duplicate that knowledge here.
    2732             :      */
    2733      617680 :     maxwidth = type_maximum_size(typid, typmod);
    2734      617680 :     if (maxwidth > 0)
    2735             :     {
    2736             :         /*
    2737             :          * For BPCHAR, the max width is also the only width.  Otherwise we
    2738             :          * need to guess about the typical data width given the max. A sliding
    2739             :          * scale for percentage of max width seems reasonable.
    2740             :          */
    2741       43008 :         if (typid == BPCHAROID)
    2742       21692 :             return maxwidth;
    2743       21316 :         if (maxwidth <= 32)
    2744       16638 :             return maxwidth;    /* assume full width */
    2745        4678 :         if (maxwidth < 1000)
    2746        4566 :             return 32 + (maxwidth - 32) / 2;    /* assume 50% */
    2747             : 
    2748             :         /*
    2749             :          * Beyond 1000, assume we're looking at something like
    2750             :          * "varchar(10000)" where the limit isn't actually reached often, and
    2751             :          * use a fixed estimate.
    2752             :          */
    2753         112 :         return 32 + (1000 - 32) / 2;
    2754             :     }
    2755             : 
    2756             :     /*
    2757             :      * Oops, we have no idea ... wild guess time.
    2758             :      */
    2759      574672 :     return 32;
    2760             : }
    2761             : 
    2762             : /*
    2763             :  * get_typtype
    2764             :  *
    2765             :  *      Given the type OID, find if it is a basic type, a complex type, etc.
    2766             :  *      It returns the null char if the cache lookup fails...
    2767             :  */
    2768             : char
    2769      959714 : get_typtype(Oid typid)
    2770             : {
    2771             :     HeapTuple   tp;
    2772             : 
    2773      959714 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2774      959714 :     if (HeapTupleIsValid(tp))
    2775             :     {
    2776      959576 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    2777             :         char        result;
    2778             : 
    2779      959576 :         result = typtup->typtype;
    2780      959576 :         ReleaseSysCache(tp);
    2781      959576 :         return result;
    2782             :     }
    2783             :     else
    2784         138 :         return '\0';
    2785             : }
    2786             : 
    2787             : /*
    2788             :  * type_is_rowtype
    2789             :  *
    2790             :  *      Convenience function to determine whether a type OID represents
    2791             :  *      a "rowtype" type --- either RECORD or a named composite type
    2792             :  *      (including a domain over a named composite type).
    2793             :  */
    2794             : bool
    2795      227126 : type_is_rowtype(Oid typid)
    2796             : {
    2797      227126 :     if (typid == RECORDOID)
    2798      122924 :         return true;            /* easy case */
    2799      104202 :     switch (get_typtype(typid))
    2800             :     {
    2801        3660 :         case TYPTYPE_COMPOSITE:
    2802        3660 :             return true;
    2803         260 :         case TYPTYPE_DOMAIN:
    2804         260 :             if (get_typtype(getBaseType(typid)) == TYPTYPE_COMPOSITE)
    2805          82 :                 return true;
    2806         178 :             break;
    2807      100282 :         default:
    2808      100282 :             break;
    2809             :     }
    2810      100460 :     return false;
    2811             : }
    2812             : 
    2813             : /*
    2814             :  * type_is_enum
    2815             :  *    Returns true if the given type is an enum type.
    2816             :  */
    2817             : bool
    2818      104998 : type_is_enum(Oid typid)
    2819             : {
    2820      104998 :     return (get_typtype(typid) == TYPTYPE_ENUM);
    2821             : }
    2822             : 
    2823             : /*
    2824             :  * type_is_range
    2825             :  *    Returns true if the given type is a range type.
    2826             :  */
    2827             : bool
    2828       27200 : type_is_range(Oid typid)
    2829             : {
    2830       27200 :     return (get_typtype(typid) == TYPTYPE_RANGE);
    2831             : }
    2832             : 
    2833             : /*
    2834             :  * type_is_multirange
    2835             :  *    Returns true if the given type is a multirange type.
    2836             :  */
    2837             : bool
    2838       60246 : type_is_multirange(Oid typid)
    2839             : {
    2840       60246 :     return (get_typtype(typid) == TYPTYPE_MULTIRANGE);
    2841             : }
    2842             : 
    2843             : /*
    2844             :  * get_type_category_preferred
    2845             :  *
    2846             :  *      Given the type OID, fetch its category and preferred-type status.
    2847             :  *      Throws error on failure.
    2848             :  */
    2849             : void
    2850      395988 : get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
    2851             : {
    2852             :     HeapTuple   tp;
    2853             :     Form_pg_type typtup;
    2854             : 
    2855      395988 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2856      395988 :     if (!HeapTupleIsValid(tp))
    2857           0 :         elog(ERROR, "cache lookup failed for type %u", typid);
    2858      395988 :     typtup = (Form_pg_type) GETSTRUCT(tp);
    2859      395988 :     *typcategory = typtup->typcategory;
    2860      395988 :     *typispreferred = typtup->typispreferred;
    2861      395988 :     ReleaseSysCache(tp);
    2862      395988 : }
    2863             : 
    2864             : /*
    2865             :  * get_typ_typrelid
    2866             :  *
    2867             :  *      Given the type OID, get the typrelid (InvalidOid if not a complex
    2868             :  *      type).
    2869             :  */
    2870             : Oid
    2871       14740 : get_typ_typrelid(Oid typid)
    2872             : {
    2873             :     HeapTuple   tp;
    2874             : 
    2875       14740 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2876       14740 :     if (HeapTupleIsValid(tp))
    2877             :     {
    2878       14740 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    2879             :         Oid         result;
    2880             : 
    2881       14740 :         result = typtup->typrelid;
    2882       14740 :         ReleaseSysCache(tp);
    2883       14740 :         return result;
    2884             :     }
    2885             :     else
    2886           0 :         return InvalidOid;
    2887             : }
    2888             : 
    2889             : /*
    2890             :  * get_element_type
    2891             :  *
    2892             :  *      Given the type OID, get the typelem (InvalidOid if not an array type).
    2893             :  *
    2894             :  * NB: this only succeeds for "true" arrays having array_subscript_handler
    2895             :  * as typsubscript.  For other types, InvalidOid is returned independently
    2896             :  * of whether they have typelem or typsubscript set.
    2897             :  */
    2898             : Oid
    2899     1440548 : get_element_type(Oid typid)
    2900             : {
    2901             :     HeapTuple   tp;
    2902             : 
    2903     1440548 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2904     1440548 :     if (HeapTupleIsValid(tp))
    2905             :     {
    2906     1440502 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    2907             :         Oid         result;
    2908             : 
    2909     1440502 :         if (IsTrueArrayType(typtup))
    2910      127718 :             result = typtup->typelem;
    2911             :         else
    2912     1312784 :             result = InvalidOid;
    2913     1440502 :         ReleaseSysCache(tp);
    2914     1440502 :         return result;
    2915             :     }
    2916             :     else
    2917          46 :         return InvalidOid;
    2918             : }
    2919             : 
    2920             : /*
    2921             :  * get_array_type
    2922             :  *
    2923             :  *      Given the type OID, get the corresponding "true" array type.
    2924             :  *      Returns InvalidOid if no array type can be found.
    2925             :  */
    2926             : Oid
    2927      205148 : get_array_type(Oid typid)
    2928             : {
    2929             :     HeapTuple   tp;
    2930      205148 :     Oid         result = InvalidOid;
    2931             : 
    2932      205148 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2933      205148 :     if (HeapTupleIsValid(tp))
    2934             :     {
    2935      205148 :         result = ((Form_pg_type) GETSTRUCT(tp))->typarray;
    2936      205148 :         ReleaseSysCache(tp);
    2937             :     }
    2938      205148 :     return result;
    2939             : }
    2940             : 
    2941             : /*
    2942             :  * get_promoted_array_type
    2943             :  *
    2944             :  *      The "promoted" type is what you'd get from an ARRAY(SELECT ...)
    2945             :  *      construct, that is, either the corresponding "true" array type
    2946             :  *      if the input is a scalar type that has such an array type,
    2947             :  *      or the same type if the input is already a "true" array type.
    2948             :  *      Returns InvalidOid if neither rule is satisfied.
    2949             :  */
    2950             : Oid
    2951       19240 : get_promoted_array_type(Oid typid)
    2952             : {
    2953       19240 :     Oid         array_type = get_array_type(typid);
    2954             : 
    2955       19240 :     if (OidIsValid(array_type))
    2956       19204 :         return array_type;
    2957          36 :     if (OidIsValid(get_element_type(typid)))
    2958          36 :         return typid;
    2959           0 :     return InvalidOid;
    2960             : }
    2961             : 
    2962             : /*
    2963             :  * get_base_element_type
    2964             :  *      Given the type OID, get the typelem, looking "through" any domain
    2965             :  *      to its underlying array type.
    2966             :  *
    2967             :  * This is equivalent to get_element_type(getBaseType(typid)), but avoids
    2968             :  * an extra cache lookup.  Note that it fails to provide any information
    2969             :  * about the typmod of the array.
    2970             :  */
    2971             : Oid
    2972      244288 : get_base_element_type(Oid typid)
    2973             : {
    2974             :     /*
    2975             :      * We loop to find the bottom base type in a stack of domains.
    2976             :      */
    2977             :     for (;;)
    2978          66 :     {
    2979             :         HeapTuple   tup;
    2980             :         Form_pg_type typTup;
    2981             : 
    2982      244288 :         tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2983      244288 :         if (!HeapTupleIsValid(tup))
    2984         252 :             break;
    2985      244036 :         typTup = (Form_pg_type) GETSTRUCT(tup);
    2986      244036 :         if (typTup->typtype != TYPTYPE_DOMAIN)
    2987             :         {
    2988             :             /* Not a domain, so stop descending */
    2989             :             Oid         result;
    2990             : 
    2991             :             /* This test must match get_element_type */
    2992      243970 :             if (IsTrueArrayType(typTup))
    2993       78628 :                 result = typTup->typelem;
    2994             :             else
    2995      165342 :                 result = InvalidOid;
    2996      243970 :             ReleaseSysCache(tup);
    2997      243970 :             return result;
    2998             :         }
    2999             : 
    3000          66 :         typid = typTup->typbasetype;
    3001          66 :         ReleaseSysCache(tup);
    3002             :     }
    3003             : 
    3004             :     /* Like get_element_type, silently return InvalidOid for bogus input */
    3005         252 :     return InvalidOid;
    3006             : }
    3007             : 
    3008             : /*
    3009             :  * getTypeInputInfo
    3010             :  *
    3011             :  *      Get info needed for converting values of a type to internal form
    3012             :  */
    3013             : void
    3014      642290 : getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
    3015             : {
    3016             :     HeapTuple   typeTuple;
    3017             :     Form_pg_type pt;
    3018             : 
    3019      642290 :     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
    3020      642290 :     if (!HeapTupleIsValid(typeTuple))
    3021           0 :         elog(ERROR, "cache lookup failed for type %u", type);
    3022      642290 :     pt = (Form_pg_type) GETSTRUCT(typeTuple);
    3023             : 
    3024      642290 :     if (!pt->typisdefined)
    3025           0 :         ereport(ERROR,
    3026             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    3027             :                  errmsg("type %s is only a shell",
    3028             :                         format_type_be(type))));
    3029      642290 :     if (!OidIsValid(pt->typinput))
    3030           0 :         ereport(ERROR,
    3031             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    3032             :                  errmsg("no input function available for type %s",
    3033             :                         format_type_be(type))));
    3034             : 
    3035      642290 :     *typInput = pt->typinput;
    3036      642290 :     *typIOParam = getTypeIOParam(typeTuple);
    3037             : 
    3038      642290 :     ReleaseSysCache(typeTuple);
    3039      642290 : }
    3040             : 
    3041             : /*
    3042             :  * getTypeOutputInfo
    3043             :  *
    3044             :  *      Get info needed for printing values of a type
    3045             :  */
    3046             : void
    3047     1763768 : getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
    3048             : {
    3049             :     HeapTuple   typeTuple;
    3050             :     Form_pg_type pt;
    3051             : 
    3052     1763768 :     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
    3053     1763768 :     if (!HeapTupleIsValid(typeTuple))
    3054           0 :         elog(ERROR, "cache lookup failed for type %u", type);
    3055     1763768 :     pt = (Form_pg_type) GETSTRUCT(typeTuple);
    3056             : 
    3057     1763768 :     if (!pt->typisdefined)
    3058           0 :         ereport(ERROR,
    3059             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    3060             :                  errmsg("type %s is only a shell",
    3061             :                         format_type_be(type))));
    3062     1763768 :     if (!OidIsValid(pt->typoutput))
    3063           0 :         ereport(ERROR,
    3064             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    3065             :                  errmsg("no output function available for type %s",
    3066             :                         format_type_be(type))));
    3067             : 
    3068     1763768 :     *typOutput = pt->typoutput;
    3069     1763768 :     *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
    3070             : 
    3071     1763768 :     ReleaseSysCache(typeTuple);
    3072     1763768 : }
    3073             : 
    3074             : /*
    3075             :  * getTypeBinaryInputInfo
    3076             :  *
    3077             :  *      Get info needed for binary input of values of a type
    3078             :  */
    3079             : void
    3080      314214 : getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
    3081             : {
    3082             :     HeapTuple   typeTuple;
    3083             :     Form_pg_type pt;
    3084             : 
    3085      314214 :     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
    3086      314214 :     if (!HeapTupleIsValid(typeTuple))
    3087           0 :         elog(ERROR, "cache lookup failed for type %u", type);
    3088      314214 :     pt = (Form_pg_type) GETSTRUCT(typeTuple);
    3089             : 
    3090      314214 :     if (!pt->typisdefined)
    3091           0 :         ereport(ERROR,
    3092             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    3093             :                  errmsg("type %s is only a shell",
    3094             :                         format_type_be(type))));
    3095      314214 :     if (!OidIsValid(pt->typreceive))
    3096           2 :         ereport(ERROR,
    3097             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    3098             :                  errmsg("no binary input function available for type %s",
    3099             :                         format_type_be(type))));
    3100             : 
    3101      314212 :     *typReceive = pt->typreceive;
    3102      314212 :     *typIOParam = getTypeIOParam(typeTuple);
    3103             : 
    3104      314212 :     ReleaseSysCache(typeTuple);
    3105      314212 : }
    3106             : 
    3107             : /*
    3108             :  * getTypeBinaryOutputInfo
    3109             :  *
    3110             :  *      Get info needed for binary output of values of a type
    3111             :  */
    3112             : void
    3113        2368 : getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
    3114             : {
    3115             :     HeapTuple   typeTuple;
    3116             :     Form_pg_type pt;
    3117             : 
    3118        2368 :     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
    3119        2368 :     if (!HeapTupleIsValid(typeTuple))
    3120           0 :         elog(ERROR, "cache lookup failed for type %u", type);
    3121        2368 :     pt = (Form_pg_type) GETSTRUCT(typeTuple);
    3122             : 
    3123        2368 :     if (!pt->typisdefined)
    3124           0 :         ereport(ERROR,
    3125             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    3126             :                  errmsg("type %s is only a shell",
    3127             :                         format_type_be(type))));
    3128        2368 :     if (!OidIsValid(pt->typsend))
    3129           2 :         ereport(ERROR,
    3130             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    3131             :                  errmsg("no binary output function available for type %s",
    3132             :                         format_type_be(type))));
    3133             : 
    3134        2366 :     *typSend = pt->typsend;
    3135        2366 :     *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
    3136             : 
    3137        2366 :     ReleaseSysCache(typeTuple);
    3138        2366 : }
    3139             : 
    3140             : /*
    3141             :  * get_typmodin
    3142             :  *
    3143             :  *      Given the type OID, return the type's typmodin procedure, if any.
    3144             :  */
    3145             : Oid
    3146           0 : get_typmodin(Oid typid)
    3147             : {
    3148             :     HeapTuple   tp;
    3149             : 
    3150           0 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    3151           0 :     if (HeapTupleIsValid(tp))
    3152             :     {
    3153           0 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    3154             :         Oid         result;
    3155             : 
    3156           0 :         result = typtup->typmodin;
    3157           0 :         ReleaseSysCache(tp);
    3158           0 :         return result;
    3159             :     }
    3160             :     else
    3161           0 :         return InvalidOid;
    3162             : }
    3163             : 
    3164             : #ifdef NOT_USED
    3165             : /*
    3166             :  * get_typmodout
    3167             :  *
    3168             :  *      Given the type OID, return the type's typmodout procedure, if any.
    3169             :  */
    3170             : Oid
    3171             : get_typmodout(Oid typid)
    3172             : {
    3173             :     HeapTuple   tp;
    3174             : 
    3175             :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    3176             :     if (HeapTupleIsValid(tp))
    3177             :     {
    3178             :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    3179             :         Oid         result;
    3180             : 
    3181             :         result = typtup->typmodout;
    3182             :         ReleaseSysCache(tp);
    3183             :         return result;
    3184             :     }
    3185             :     else
    3186             :         return InvalidOid;
    3187             : }
    3188             : #endif                          /* NOT_USED */
    3189             : 
    3190             : /*
    3191             :  * get_typcollation
    3192             :  *
    3193             :  *      Given the type OID, return the type's typcollation attribute.
    3194             :  */
    3195             : Oid
    3196     2671612 : get_typcollation(Oid typid)
    3197             : {
    3198             :     HeapTuple   tp;
    3199             : 
    3200     2671612 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    3201     2671612 :     if (HeapTupleIsValid(tp))
    3202             :     {
    3203     2671122 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    3204             :         Oid         result;
    3205             : 
    3206     2671122 :         result = typtup->typcollation;
    3207     2671122 :         ReleaseSysCache(tp);
    3208     2671122 :         return result;
    3209             :     }
    3210             :     else
    3211         490 :         return InvalidOid;
    3212             : }
    3213             : 
    3214             : 
    3215             : /*
    3216             :  * type_is_collatable
    3217             :  *
    3218             :  *      Return whether the type cares about collations
    3219             :  */
    3220             : bool
    3221      499666 : type_is_collatable(Oid typid)
    3222             : {
    3223      499666 :     return OidIsValid(get_typcollation(typid));
    3224             : }
    3225             : 
    3226             : 
    3227             : /*
    3228             :  * get_typsubscript
    3229             :  *
    3230             :  *      Given the type OID, return the type's subscripting handler's OID,
    3231             :  *      if it has one.
    3232             :  *
    3233             :  * If typelemp isn't NULL, we also store the type's typelem value there.
    3234             :  * This saves some callers an extra catalog lookup.
    3235             :  */
    3236             : RegProcedure
    3237       44440 : get_typsubscript(Oid typid, Oid *typelemp)
    3238             : {
    3239             :     HeapTuple   tp;
    3240             : 
    3241       44440 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    3242       44440 :     if (HeapTupleIsValid(tp))
    3243             :     {
    3244       44440 :         Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp);
    3245       44440 :         RegProcedure handler = typform->typsubscript;
    3246             : 
    3247       44440 :         if (typelemp)
    3248       13138 :             *typelemp = typform->typelem;
    3249       44440 :         ReleaseSysCache(tp);
    3250       44440 :         return handler;
    3251             :     }
    3252             :     else
    3253             :     {
    3254           0 :         if (typelemp)
    3255           0 :             *typelemp = InvalidOid;
    3256           0 :         return InvalidOid;
    3257             :     }
    3258             : }
    3259             : 
    3260             : /*
    3261             :  * getSubscriptingRoutines
    3262             :  *
    3263             :  *      Given the type OID, fetch the type's subscripting methods struct.
    3264             :  *      Return NULL if type is not subscriptable.
    3265             :  *
    3266             :  * If typelemp isn't NULL, we also store the type's typelem value there.
    3267             :  * This saves some callers an extra catalog lookup.
    3268             :  */
    3269             : const struct SubscriptRoutines *
    3270       44438 : getSubscriptingRoutines(Oid typid, Oid *typelemp)
    3271             : {
    3272       44438 :     RegProcedure typsubscript = get_typsubscript(typid, typelemp);
    3273             : 
    3274       44438 :     if (!OidIsValid(typsubscript))
    3275          10 :         return NULL;
    3276             : 
    3277       44428 :     return (const struct SubscriptRoutines *)
    3278       44428 :         DatumGetPointer(OidFunctionCall0(typsubscript));
    3279             : }
    3280             : 
    3281             : 
    3282             : /*              ---------- STATISTICS CACHE ----------                   */
    3283             : 
    3284             : /*
    3285             :  * get_attavgwidth
    3286             :  *
    3287             :  *    Given the table and attribute number of a column, get the average
    3288             :  *    width of entries in the column.  Return zero if no data available.
    3289             :  *
    3290             :  * Currently this is only consulted for individual tables, not for inheritance
    3291             :  * trees, so we don't need an "inh" parameter.
    3292             :  *
    3293             :  * Calling a hook at this point looks somewhat strange, but is required
    3294             :  * because the optimizer calls this function without any other way for
    3295             :  * plug-ins to control the result.
    3296             :  */
    3297             : int32
    3298     1512904 : get_attavgwidth(Oid relid, AttrNumber attnum)
    3299             : {
    3300             :     HeapTuple   tp;
    3301             :     int32       stawidth;
    3302             : 
    3303     1512904 :     if (get_attavgwidth_hook)
    3304             :     {
    3305           0 :         stawidth = (*get_attavgwidth_hook) (relid, attnum);
    3306           0 :         if (stawidth > 0)
    3307           0 :             return stawidth;
    3308             :     }
    3309     1512904 :     tp = SearchSysCache3(STATRELATTINH,
    3310             :                          ObjectIdGetDatum(relid),
    3311             :                          Int16GetDatum(attnum),
    3312             :                          BoolGetDatum(false));
    3313     1512904 :     if (HeapTupleIsValid(tp))
    3314             :     {
    3315      726440 :         stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
    3316      726440 :         ReleaseSysCache(tp);
    3317      726440 :         if (stawidth > 0)
    3318      706938 :             return stawidth;
    3319             :     }
    3320      805966 :     return 0;
    3321             : }
    3322             : 
    3323             : /*
    3324             :  * get_attstatsslot
    3325             :  *
    3326             :  *      Extract the contents of a "slot" of a pg_statistic tuple.
    3327             :  *      Returns true if requested slot type was found, else false.
    3328             :  *
    3329             :  * Unlike other routines in this file, this takes a pointer to an
    3330             :  * already-looked-up tuple in the pg_statistic cache.  We do this since
    3331             :  * most callers will want to extract more than one value from the cache
    3332             :  * entry, and we don't want to repeat the cache lookup unnecessarily.
    3333             :  * Also, this API allows this routine to be used with statistics tuples
    3334             :  * that have been provided by a stats hook and didn't really come from
    3335             :  * pg_statistic.
    3336             :  *
    3337             :  * sslot: pointer to output area (typically, a local variable in the caller).
    3338             :  * statstuple: pg_statistic tuple to be examined.
    3339             :  * reqkind: STAKIND code for desired statistics slot kind.
    3340             :  * reqop: STAOP value wanted, or InvalidOid if don't care.
    3341             :  * flags: bitmask of ATTSTATSSLOT_VALUES and/or ATTSTATSSLOT_NUMBERS.
    3342             :  *
    3343             :  * If a matching slot is found, true is returned, and *sslot is filled thus:
    3344             :  * staop: receives the actual STAOP value.
    3345             :  * stacoll: receives the actual STACOLL value.
    3346             :  * valuetype: receives actual datatype of the elements of stavalues.
    3347             :  * values: receives pointer to an array of the slot's stavalues.
    3348             :  * nvalues: receives number of stavalues.
    3349             :  * numbers: receives pointer to an array of the slot's stanumbers (as float4).
    3350             :  * nnumbers: receives number of stanumbers.
    3351             :  *
    3352             :  * valuetype/values/nvalues are InvalidOid/NULL/0 if ATTSTATSSLOT_VALUES
    3353             :  * wasn't specified.  Likewise, numbers/nnumbers are NULL/0 if
    3354             :  * ATTSTATSSLOT_NUMBERS wasn't specified.
    3355             :  *
    3356             :  * If no matching slot is found, false is returned, and *sslot is zeroed.
    3357             :  *
    3358             :  * Note that the current API doesn't allow for searching for a slot with
    3359             :  * a particular collation.  If we ever actually support recording more than
    3360             :  * one collation, we'll have to extend the API, but for now simple is good.
    3361             :  *
    3362             :  * The data referred to by the fields of sslot is locally palloc'd and
    3363             :  * is independent of the original pg_statistic tuple.  When the caller
    3364             :  * is done with it, call free_attstatsslot to release the palloc'd data.
    3365             :  *
    3366             :  * If it's desirable to call free_attstatsslot when get_attstatsslot might
    3367             :  * not have been called, memset'ing sslot to zeroes will allow that.
    3368             :  *
    3369             :  * Passing flags=0 can be useful to quickly check if the requested slot type
    3370             :  * exists.  In this case no arrays are extracted, so free_attstatsslot need
    3371             :  * not be called.
    3372             :  */
    3373             : bool
    3374     2274042 : get_attstatsslot(AttStatsSlot *sslot, HeapTuple statstuple,
    3375             :                  int reqkind, Oid reqop, int flags)
    3376             : {
    3377     2274042 :     Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(statstuple);
    3378             :     int         i;
    3379             :     Datum       val;
    3380             :     ArrayType  *statarray;
    3381             :     Oid         arrayelemtype;
    3382             :     int         narrayelem;
    3383             :     HeapTuple   typeTuple;
    3384             :     Form_pg_type typeForm;
    3385             : 
    3386             :     /* initialize *sslot properly */
    3387     2274042 :     memset(sslot, 0, sizeof(AttStatsSlot));
    3388             : 
    3389     6419638 :     for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
    3390             :     {
    3391     5750446 :         if ((&stats->stakind1)[i] == reqkind &&
    3392      688352 :             (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
    3393             :             break;
    3394             :     }
    3395     2274042 :     if (i >= STATISTIC_NUM_SLOTS)
    3396      669192 :         return false;           /* not there */
    3397             : 
    3398     1604850 :     sslot->staop = (&stats->staop1)[i];
    3399     1604850 :     sslot->stacoll = (&stats->stacoll1)[i];
    3400             : 
    3401     1604850 :     if (flags & ATTSTATSSLOT_VALUES)
    3402             :     {
    3403      770978 :         val = SysCacheGetAttrNotNull(STATRELATTINH, statstuple,
    3404      770978 :                                      Anum_pg_statistic_stavalues1 + i);
    3405             : 
    3406             :         /*
    3407             :          * Detoast the array if needed, and in any case make a copy that's
    3408             :          * under control of this AttStatsSlot.
    3409             :          */
    3410      770978 :         statarray = DatumGetArrayTypePCopy(val);
    3411             : 
    3412             :         /*
    3413             :          * Extract the actual array element type, and pass it back in case the
    3414             :          * caller needs it.
    3415             :          */
    3416      770978 :         sslot->valuetype = arrayelemtype = ARR_ELEMTYPE(statarray);
    3417             : 
    3418             :         /* Need info about element type */
    3419      770978 :         typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrayelemtype));
    3420      770978 :         if (!HeapTupleIsValid(typeTuple))
    3421           0 :             elog(ERROR, "cache lookup failed for type %u", arrayelemtype);
    3422      770978 :         typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
    3423             : 
    3424             :         /* Deconstruct array into Datum elements; NULLs not expected */
    3425      770978 :         deconstruct_array(statarray,
    3426             :                           arrayelemtype,
    3427      770978 :                           typeForm->typlen,
    3428      770978 :                           typeForm->typbyval,
    3429      770978 :                           typeForm->typalign,
    3430             :                           &sslot->values, NULL, &sslot->nvalues);
    3431             : 
    3432             :         /*
    3433             :          * If the element type is pass-by-reference, we now have a bunch of
    3434             :          * Datums that are pointers into the statarray, so we need to keep
    3435             :          * that until free_attstatsslot.  Otherwise, all the useful info is in
    3436             :          * sslot->values[], so we can free the array object immediately.
    3437             :          */
    3438      770978 :         if (!typeForm->typbyval)
    3439       49628 :             sslot->values_arr = statarray;
    3440             :         else
    3441      721350 :             pfree(statarray);
    3442             : 
    3443      770978 :         ReleaseSysCache(typeTuple);
    3444             :     }
    3445             : 
    3446     1604850 :     if (flags & ATTSTATSSLOT_NUMBERS)
    3447             :     {
    3448     1151888 :         val = SysCacheGetAttrNotNull(STATRELATTINH, statstuple,
    3449     1151888 :                                      Anum_pg_statistic_stanumbers1 + i);
    3450             : 
    3451             :         /*
    3452             :          * Detoast the array if needed, and in any case make a copy that's
    3453             :          * under control of this AttStatsSlot.
    3454             :          */
    3455     1151888 :         statarray = DatumGetArrayTypePCopy(val);
    3456             : 
    3457             :         /*
    3458             :          * We expect the array to be a 1-D float4 array; verify that. We don't
    3459             :          * need to use deconstruct_array() since the array data is just going
    3460             :          * to look like a C array of float4 values.
    3461             :          */
    3462     1151888 :         narrayelem = ARR_DIMS(statarray)[0];
    3463     1151888 :         if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
    3464     1151888 :             ARR_HASNULL(statarray) ||
    3465     1151888 :             ARR_ELEMTYPE(statarray) != FLOAT4OID)
    3466           0 :             elog(ERROR, "stanumbers is not a 1-D float4 array");
    3467             : 
    3468             :         /* Give caller a pointer directly into the statarray */
    3469     1151888 :         sslot->numbers = (float4 *) ARR_DATA_PTR(statarray);
    3470     1151888 :         sslot->nnumbers = narrayelem;
    3471             : 
    3472             :         /* We'll free the statarray in free_attstatsslot */
    3473     1151888 :         sslot->numbers_arr = statarray;
    3474             :     }
    3475             : 
    3476     1604850 :     return true;
    3477             : }
    3478             : 
    3479             : /*
    3480             :  * free_attstatsslot
    3481             :  *      Free data allocated by get_attstatsslot
    3482             :  */
    3483             : void
    3484     1994990 : free_attstatsslot(AttStatsSlot *sslot)
    3485             : {
    3486             :     /* The values[] array was separately palloc'd by deconstruct_array */
    3487     1994990 :     if (sslot->values)
    3488      770978 :         pfree(sslot->values);
    3489             :     /* The numbers[] array points into numbers_arr, do not pfree it */
    3490             :     /* Free the detoasted array objects, if any */
    3491     1994990 :     if (sslot->values_arr)
    3492       49628 :         pfree(sslot->values_arr);
    3493     1994990 :     if (sslot->numbers_arr)
    3494     1151888 :         pfree(sslot->numbers_arr);
    3495     1994990 : }
    3496             : 
    3497             : /*              ---------- PG_NAMESPACE CACHE ----------                 */
    3498             : 
    3499             : /*
    3500             :  * get_namespace_name
    3501             :  *      Returns the name of a given namespace
    3502             :  *
    3503             :  * Returns a palloc'd copy of the string, or NULL if no such namespace.
    3504             :  */
    3505             : char *
    3506      920732 : get_namespace_name(Oid nspid)
    3507             : {
    3508             :     HeapTuple   tp;
    3509             : 
    3510      920732 :     tp = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid));
    3511      920732 :     if (HeapTupleIsValid(tp))
    3512             :     {
    3513      920708 :         Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
    3514             :         char       *result;
    3515             : 
    3516      920708 :         result = pstrdup(NameStr(nsptup->nspname));
    3517      920708 :         ReleaseSysCache(tp);
    3518      920708 :         return result;
    3519             :     }
    3520             :     else
    3521          24 :         return NULL;
    3522             : }
    3523             : 
    3524             : /*
    3525             :  * get_namespace_name_or_temp
    3526             :  *      As above, but if it is this backend's temporary namespace, return
    3527             :  *      "pg_temp" instead.
    3528             :  */
    3529             : char *
    3530       49578 : get_namespace_name_or_temp(Oid nspid)
    3531             : {
    3532       49578 :     if (isTempNamespace(nspid))
    3533         308 :         return pstrdup("pg_temp");
    3534             :     else
    3535       49270 :         return get_namespace_name(nspid);
    3536             : }
    3537             : 
    3538             : /*              ---------- PG_RANGE CACHES ----------                */
    3539             : 
    3540             : /*
    3541             :  * get_range_subtype
    3542             :  *      Returns the subtype of a given range type
    3543             :  *
    3544             :  * Returns InvalidOid if the type is not a range type.
    3545             :  */
    3546             : Oid
    3547       21190 : get_range_subtype(Oid rangeOid)
    3548             : {
    3549             :     HeapTuple   tp;
    3550             : 
    3551       21190 :     tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
    3552       21190 :     if (HeapTupleIsValid(tp))
    3553             :     {
    3554       15960 :         Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
    3555             :         Oid         result;
    3556             : 
    3557       15960 :         result = rngtup->rngsubtype;
    3558       15960 :         ReleaseSysCache(tp);
    3559       15960 :         return result;
    3560             :     }
    3561             :     else
    3562        5230 :         return InvalidOid;
    3563             : }
    3564             : 
    3565             : /*
    3566             :  * get_range_collation
    3567             :  *      Returns the collation of a given range type
    3568             :  *
    3569             :  * Returns InvalidOid if the type is not a range type,
    3570             :  * or if its subtype is not collatable.
    3571             :  */
    3572             : Oid
    3573        1970 : get_range_collation(Oid rangeOid)
    3574             : {
    3575             :     HeapTuple   tp;
    3576             : 
    3577        1970 :     tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
    3578        1970 :     if (HeapTupleIsValid(tp))
    3579             :     {
    3580        1970 :         Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
    3581             :         Oid         result;
    3582             : 
    3583        1970 :         result = rngtup->rngcollation;
    3584        1970 :         ReleaseSysCache(tp);
    3585        1970 :         return result;
    3586             :     }
    3587             :     else
    3588           0 :         return InvalidOid;
    3589             : }
    3590             : 
    3591             : /*
    3592             :  * get_range_multirange
    3593             :  *      Returns the multirange type of a given range type
    3594             :  *
    3595             :  * Returns InvalidOid if the type is not a range type.
    3596             :  */
    3597             : Oid
    3598         288 : get_range_multirange(Oid rangeOid)
    3599             : {
    3600             :     HeapTuple   tp;
    3601             : 
    3602         288 :     tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
    3603         288 :     if (HeapTupleIsValid(tp))
    3604             :     {
    3605         288 :         Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
    3606             :         Oid         result;
    3607             : 
    3608         288 :         result = rngtup->rngmultitypid;
    3609         288 :         ReleaseSysCache(tp);
    3610         288 :         return result;
    3611             :     }
    3612             :     else
    3613           0 :         return InvalidOid;
    3614             : }
    3615             : 
    3616             : /*
    3617             :  * get_multirange_range
    3618             :  *      Returns the range type of a given multirange
    3619             :  *
    3620             :  * Returns InvalidOid if the type is not a multirange.
    3621             :  */
    3622             : Oid
    3623       20994 : get_multirange_range(Oid multirangeOid)
    3624             : {
    3625             :     HeapTuple   tp;
    3626             : 
    3627       20994 :     tp = SearchSysCache1(RANGEMULTIRANGE, ObjectIdGetDatum(multirangeOid));
    3628       20994 :     if (HeapTupleIsValid(tp))
    3629             :     {
    3630        6108 :         Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
    3631             :         Oid         result;
    3632             : 
    3633        6108 :         result = rngtup->rngtypid;
    3634        6108 :         ReleaseSysCache(tp);
    3635        6108 :         return result;
    3636             :     }
    3637             :     else
    3638       14886 :         return InvalidOid;
    3639             : }
    3640             : 
    3641             : /*              ---------- PG_INDEX CACHE ----------                 */
    3642             : 
    3643             : /*
    3644             :  * get_index_column_opclass
    3645             :  *
    3646             :  *      Given the index OID and column number,
    3647             :  *      return opclass of the index column
    3648             :  *          or InvalidOid if the index was not found
    3649             :  *              or column is non-key one.
    3650             :  */
    3651             : Oid
    3652         190 : get_index_column_opclass(Oid index_oid, int attno)
    3653             : {
    3654             :     HeapTuple   tuple;
    3655             :     Form_pg_index rd_index;
    3656             :     Datum       datum;
    3657             :     oidvector  *indclass;
    3658             :     Oid         opclass;
    3659             : 
    3660             :     /* First we need to know the column's opclass. */
    3661             : 
    3662         190 :     tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
    3663         190 :     if (!HeapTupleIsValid(tuple))
    3664           0 :         return InvalidOid;
    3665             : 
    3666         190 :     rd_index = (Form_pg_index) GETSTRUCT(tuple);
    3667             : 
    3668             :     /* caller is supposed to guarantee this */
    3669             :     Assert(attno > 0 && attno <= rd_index->indnatts);
    3670             : 
    3671             :     /* Non-key attributes don't have an opclass */
    3672         190 :     if (attno > rd_index->indnkeyatts)
    3673             :     {
    3674           0 :         ReleaseSysCache(tuple);
    3675           0 :         return InvalidOid;
    3676             :     }
    3677             : 
    3678         190 :     datum = SysCacheGetAttrNotNull(INDEXRELID, tuple, Anum_pg_index_indclass);
    3679         190 :     indclass = ((oidvector *) DatumGetPointer(datum));
    3680             : 
    3681             :     Assert(attno <= indclass->dim1);
    3682         190 :     opclass = indclass->values[attno - 1];
    3683             : 
    3684         190 :     ReleaseSysCache(tuple);
    3685             : 
    3686         190 :     return opclass;
    3687             : }
    3688             : 
    3689             : /*
    3690             :  * get_index_isreplident
    3691             :  *
    3692             :  *      Given the index OID, return pg_index.indisreplident.
    3693             :  */
    3694             : bool
    3695         444 : get_index_isreplident(Oid index_oid)
    3696             : {
    3697             :     HeapTuple   tuple;
    3698             :     Form_pg_index rd_index;
    3699             :     bool        result;
    3700             : 
    3701         444 :     tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
    3702         444 :     if (!HeapTupleIsValid(tuple))
    3703           0 :         return false;
    3704             : 
    3705         444 :     rd_index = (Form_pg_index) GETSTRUCT(tuple);
    3706         444 :     result = rd_index->indisreplident;
    3707         444 :     ReleaseSysCache(tuple);
    3708             : 
    3709         444 :     return result;
    3710             : }
    3711             : 
    3712             : /*
    3713             :  * get_index_isvalid
    3714             :  *
    3715             :  *      Given the index OID, return pg_index.indisvalid.
    3716             :  */
    3717             : bool
    3718        7018 : get_index_isvalid(Oid index_oid)
    3719             : {
    3720             :     bool        isvalid;
    3721             :     HeapTuple   tuple;
    3722             :     Form_pg_index rd_index;
    3723             : 
    3724        7018 :     tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
    3725        7018 :     if (!HeapTupleIsValid(tuple))
    3726           0 :         elog(ERROR, "cache lookup failed for index %u", index_oid);
    3727             : 
    3728        7018 :     rd_index = (Form_pg_index) GETSTRUCT(tuple);
    3729        7018 :     isvalid = rd_index->indisvalid;
    3730        7018 :     ReleaseSysCache(tuple);
    3731             : 
    3732        7018 :     return isvalid;
    3733             : }
    3734             : 
    3735             : /*
    3736             :  * get_index_isclustered
    3737             :  *
    3738             :  *      Given the index OID, return pg_index.indisclustered.
    3739             :  */
    3740             : bool
    3741         734 : get_index_isclustered(Oid index_oid)
    3742             : {
    3743             :     bool        isclustered;
    3744             :     HeapTuple   tuple;
    3745             :     Form_pg_index rd_index;
    3746             : 
    3747         734 :     tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
    3748         734 :     if (!HeapTupleIsValid(tuple))
    3749           0 :         elog(ERROR, "cache lookup failed for index %u", index_oid);
    3750             : 
    3751         734 :     rd_index = (Form_pg_index) GETSTRUCT(tuple);
    3752         734 :     isclustered = rd_index->indisclustered;
    3753         734 :     ReleaseSysCache(tuple);
    3754             : 
    3755         734 :     return isclustered;
    3756             : }
    3757             : 
    3758             : /*
    3759             :  * get_publication_oid - given a publication name, look up the OID
    3760             :  *
    3761             :  * If missing_ok is false, throw an error if name not found.  If true, just
    3762             :  * return InvalidOid.
    3763             :  */
    3764             : Oid
    3765        3046 : get_publication_oid(const char *pubname, bool missing_ok)
    3766             : {
    3767             :     Oid         oid;
    3768             : 
    3769        3046 :     oid = GetSysCacheOid1(PUBLICATIONNAME, Anum_pg_publication_oid,
    3770             :                           CStringGetDatum(pubname));
    3771        3046 :     if (!OidIsValid(oid) && !missing_ok)
    3772           6 :         ereport(ERROR,
    3773             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    3774             :                  errmsg("publication \"%s\" does not exist", pubname)));
    3775        3040 :     return oid;
    3776             : }
    3777             : 
    3778             : /*
    3779             :  * get_publication_name - given a publication Oid, look up the name
    3780             :  *
    3781             :  * If missing_ok is false, throw an error if name not found.  If true, just
    3782             :  * return NULL.
    3783             :  */
    3784             : char *
    3785         676 : get_publication_name(Oid pubid, bool missing_ok)
    3786             : {
    3787             :     HeapTuple   tup;
    3788             :     char       *pubname;
    3789             :     Form_pg_publication pubform;
    3790             : 
    3791         676 :     tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
    3792             : 
    3793         676 :     if (!HeapTupleIsValid(tup))
    3794             :     {
    3795          18 :         if (!missing_ok)
    3796           0 :             elog(ERROR, "cache lookup failed for publication %u", pubid);
    3797          18 :         return NULL;
    3798             :     }
    3799             : 
    3800         658 :     pubform = (Form_pg_publication) GETSTRUCT(tup);
    3801         658 :     pubname = pstrdup(NameStr(pubform->pubname));
    3802             : 
    3803         658 :     ReleaseSysCache(tup);
    3804             : 
    3805         658 :     return pubname;
    3806             : }
    3807             : 
    3808             : /*
    3809             :  * get_subscription_oid - given a subscription name, look up the OID
    3810             :  *
    3811             :  * If missing_ok is false, throw an error if name not found.  If true, just
    3812             :  * return InvalidOid.
    3813             :  */
    3814             : Oid
    3815          74 : get_subscription_oid(const char *subname, bool missing_ok)
    3816             : {
    3817             :     Oid         oid;
    3818             : 
    3819          74 :     oid = GetSysCacheOid2(SUBSCRIPTIONNAME, Anum_pg_subscription_oid,
    3820             :                           MyDatabaseId, CStringGetDatum(subname));
    3821          74 :     if (!OidIsValid(oid) && !missing_ok)
    3822           6 :         ereport(ERROR,
    3823             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    3824             :                  errmsg("subscription \"%s\" does not exist", subname)));
    3825          68 :     return oid;
    3826             : }
    3827             : 
    3828             : /*
    3829             :  * get_subscription_name - given a subscription OID, look up the name
    3830             :  *
    3831             :  * If missing_ok is false, throw an error if name not found.  If true, just
    3832             :  * return NULL.
    3833             :  */
    3834             : char *
    3835          60 : get_subscription_name(Oid subid, bool missing_ok)
    3836             : {
    3837             :     HeapTuple   tup;
    3838             :     char       *subname;
    3839             :     Form_pg_subscription subform;
    3840             : 
    3841          60 :     tup = SearchSysCache1(SUBSCRIPTIONOID, ObjectIdGetDatum(subid));
    3842             : 
    3843          60 :     if (!HeapTupleIsValid(tup))
    3844             :     {
    3845          18 :         if (!missing_ok)
    3846           0 :             elog(ERROR, "cache lookup failed for subscription %u", subid);
    3847          18 :         return NULL;
    3848             :     }
    3849             : 
    3850          42 :     subform = (Form_pg_subscription) GETSTRUCT(tup);
    3851          42 :     subname = pstrdup(NameStr(subform->subname));
    3852             : 
    3853          42 :     ReleaseSysCache(tup);
    3854             : 
    3855          42 :     return subname;
    3856             : }

Generated by: LCOV version 1.14