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

Generated by: LCOV version 2.0-1