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

Generated by: LCOV version 2.0-1