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

Generated by: LCOV version 2.0-1