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

Generated by: LCOV version 2.0-1