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

Generated by: LCOV version 2.0-1