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

Generated by: LCOV version 1.16