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

Generated by: LCOV version 2.0-1