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

Generated by: LCOV version 1.16