LCOV - code coverage report
Current view: top level - src/backend/utils/cache - lsyscache.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 852 979 87.0 %
Date: 2019-09-22 07:07:17 Functions: 95 97 97.9 %
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-2019, 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 "access/nbtree.h"
      21             : #include "bootstrap/bootstrap.h"
      22             : #include "catalog/namespace.h"
      23             : #include "catalog/pg_am.h"
      24             : #include "catalog/pg_amop.h"
      25             : #include "catalog/pg_amproc.h"
      26             : #include "catalog/pg_collation.h"
      27             : #include "catalog/pg_constraint.h"
      28             : #include "catalog/pg_language.h"
      29             : #include "catalog/pg_namespace.h"
      30             : #include "catalog/pg_opclass.h"
      31             : #include "catalog/pg_operator.h"
      32             : #include "catalog/pg_proc.h"
      33             : #include "catalog/pg_range.h"
      34             : #include "catalog/pg_statistic.h"
      35             : #include "catalog/pg_transform.h"
      36             : #include "catalog/pg_type.h"
      37             : #include "miscadmin.h"
      38             : #include "nodes/makefuncs.h"
      39             : #include "utils/array.h"
      40             : #include "utils/builtins.h"
      41             : #include "utils/catcache.h"
      42             : #include "utils/datum.h"
      43             : #include "utils/fmgroids.h"
      44             : #include "utils/lsyscache.h"
      45             : #include "utils/rel.h"
      46             : #include "utils/syscache.h"
      47             : #include "utils/typcache.h"
      48             : 
      49             : /* Hook for plugins to get control in get_attavgwidth() */
      50             : get_attavgwidth_hook_type get_attavgwidth_hook = NULL;
      51             : 
      52             : 
      53             : /*              ---------- AMOP CACHES ----------                        */
      54             : 
      55             : /*
      56             :  * op_in_opfamily
      57             :  *
      58             :  *      Return t iff operator 'opno' is in operator family 'opfamily'.
      59             :  *
      60             :  * This function only considers search operators, not ordering operators.
      61             :  */
      62             : bool
      63      216740 : op_in_opfamily(Oid opno, Oid opfamily)
      64             : {
      65      216740 :     return SearchSysCacheExists3(AMOPOPID,
      66             :                                  ObjectIdGetDatum(opno),
      67             :                                  CharGetDatum(AMOP_SEARCH),
      68             :                                  ObjectIdGetDatum(opfamily));
      69             : }
      70             : 
      71             : /*
      72             :  * get_op_opfamily_strategy
      73             :  *
      74             :  *      Get the operator's strategy number within the specified opfamily,
      75             :  *      or 0 if it's not a member of the opfamily.
      76             :  *
      77             :  * This function only considers search operators, not ordering operators.
      78             :  */
      79             : int
      80      354838 : get_op_opfamily_strategy(Oid opno, Oid opfamily)
      81             : {
      82             :     HeapTuple   tp;
      83             :     Form_pg_amop amop_tup;
      84             :     int         result;
      85             : 
      86      354838 :     tp = SearchSysCache3(AMOPOPID,
      87             :                          ObjectIdGetDatum(opno),
      88             :                          CharGetDatum(AMOP_SEARCH),
      89             :                          ObjectIdGetDatum(opfamily));
      90      354838 :     if (!HeapTupleIsValid(tp))
      91           0 :         return 0;
      92      354838 :     amop_tup = (Form_pg_amop) GETSTRUCT(tp);
      93      354838 :     result = amop_tup->amopstrategy;
      94      354838 :     ReleaseSysCache(tp);
      95      354838 :     return result;
      96             : }
      97             : 
      98             : /*
      99             :  * get_op_opfamily_sortfamily
     100             :  *
     101             :  *      If the operator is an ordering operator within the specified opfamily,
     102             :  *      return its amopsortfamily OID; else return InvalidOid.
     103             :  */
     104             : Oid
     105         316 : get_op_opfamily_sortfamily(Oid opno, Oid opfamily)
     106             : {
     107             :     HeapTuple   tp;
     108             :     Form_pg_amop amop_tup;
     109             :     Oid         result;
     110             : 
     111         316 :     tp = SearchSysCache3(AMOPOPID,
     112             :                          ObjectIdGetDatum(opno),
     113             :                          CharGetDatum(AMOP_ORDER),
     114             :                          ObjectIdGetDatum(opfamily));
     115         316 :     if (!HeapTupleIsValid(tp))
     116           0 :         return InvalidOid;
     117         316 :     amop_tup = (Form_pg_amop) GETSTRUCT(tp);
     118         316 :     result = amop_tup->amopsortfamily;
     119         316 :     ReleaseSysCache(tp);
     120         316 :     return result;
     121             : }
     122             : 
     123             : /*
     124             :  * get_op_opfamily_properties
     125             :  *
     126             :  *      Get the operator's strategy number and declared input data types
     127             :  *      within the specified opfamily.
     128             :  *
     129             :  * Caller should already have verified that opno is a member of opfamily,
     130             :  * therefore we raise an error if the tuple is not found.
     131             :  */
     132             : void
     133      181168 : get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op,
     134             :                            int *strategy,
     135             :                            Oid *lefttype,
     136             :                            Oid *righttype)
     137             : {
     138             :     HeapTuple   tp;
     139             :     Form_pg_amop amop_tup;
     140             : 
     141      181168 :     tp = SearchSysCache3(AMOPOPID,
     142             :                          ObjectIdGetDatum(opno),
     143             :                          CharGetDatum(ordering_op ? AMOP_ORDER : AMOP_SEARCH),
     144             :                          ObjectIdGetDatum(opfamily));
     145      181168 :     if (!HeapTupleIsValid(tp))
     146           0 :         elog(ERROR, "operator %u is not a member of opfamily %u",
     147             :              opno, opfamily);
     148      181168 :     amop_tup = (Form_pg_amop) GETSTRUCT(tp);
     149      181168 :     *strategy = amop_tup->amopstrategy;
     150      181168 :     *lefttype = amop_tup->amoplefttype;
     151      181168 :     *righttype = amop_tup->amoprighttype;
     152      181168 :     ReleaseSysCache(tp);
     153      181168 : }
     154             : 
     155             : /*
     156             :  * get_opfamily_member
     157             :  *      Get the OID of the operator that implements the specified strategy
     158             :  *      with the specified datatypes for the specified opfamily.
     159             :  *
     160             :  * Returns InvalidOid if there is no pg_amop entry for the given keys.
     161             :  */
     162             : Oid
     163     1424766 : get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
     164             :                     int16 strategy)
     165             : {
     166             :     HeapTuple   tp;
     167             :     Form_pg_amop amop_tup;
     168             :     Oid         result;
     169             : 
     170     1424766 :     tp = SearchSysCache4(AMOPSTRATEGY,
     171             :                          ObjectIdGetDatum(opfamily),
     172             :                          ObjectIdGetDatum(lefttype),
     173             :                          ObjectIdGetDatum(righttype),
     174             :                          Int16GetDatum(strategy));
     175     1424766 :     if (!HeapTupleIsValid(tp))
     176         244 :         return InvalidOid;
     177     1424522 :     amop_tup = (Form_pg_amop) GETSTRUCT(tp);
     178     1424522 :     result = amop_tup->amopopr;
     179     1424522 :     ReleaseSysCache(tp);
     180     1424522 :     return result;
     181             : }
     182             : 
     183             : /*
     184             :  * get_ordering_op_properties
     185             :  *      Given the OID of an ordering operator (a btree "<" or ">" operator),
     186             :  *      determine its opfamily, its declared input datatype, and its
     187             :  *      strategy number (BTLessStrategyNumber or BTGreaterStrategyNumber).
     188             :  *
     189             :  * Returns true if successful, false if no matching pg_amop entry exists.
     190             :  * (This indicates that the operator is not a valid ordering operator.)
     191             :  *
     192             :  * Note: the operator could be registered in multiple families, for example
     193             :  * if someone were to build a "reverse sort" opfamily.  This would result in
     194             :  * uncertainty as to whether "ORDER BY USING op" would default to NULLS FIRST
     195             :  * or NULLS LAST, as well as inefficient planning due to failure to match up
     196             :  * pathkeys that should be the same.  So we want a determinate result here.
     197             :  * Because of the way the syscache search works, we'll use the interpretation
     198             :  * associated with the opfamily with smallest OID, which is probably
     199             :  * determinate enough.  Since there is no longer any particularly good reason
     200             :  * to build reverse-sort opfamilies, it doesn't seem worth expending any
     201             :  * additional effort on ensuring consistency.
     202             :  */
     203             : bool
     204     1363304 : get_ordering_op_properties(Oid opno,
     205             :                            Oid *opfamily, Oid *opcintype, int16 *strategy)
     206             : {
     207     1363304 :     bool        result = false;
     208             :     CatCList   *catlist;
     209             :     int         i;
     210             : 
     211             :     /* ensure outputs are initialized on failure */
     212     1363304 :     *opfamily = InvalidOid;
     213     1363304 :     *opcintype = InvalidOid;
     214     1363304 :     *strategy = 0;
     215             : 
     216             :     /*
     217             :      * Search pg_amop to see if the target operator is registered as the "<"
     218             :      * or ">" operator of any btree opfamily.
     219             :      */
     220     1363304 :     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
     221             : 
     222     1363304 :     for (i = 0; i < catlist->n_members; i++)
     223             :     {
     224     1363304 :         HeapTuple   tuple = &catlist->members[i]->tuple;
     225     1363304 :         Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
     226             : 
     227             :         /* must be btree */
     228     1363304 :         if (aform->amopmethod != BTREE_AM_OID)
     229           0 :             continue;
     230             : 
     231     1367034 :         if (aform->amopstrategy == BTLessStrategyNumber ||
     232        3730 :             aform->amopstrategy == BTGreaterStrategyNumber)
     233             :         {
     234             :             /* Found it ... should have consistent input types */
     235     1363304 :             if (aform->amoplefttype == aform->amoprighttype)
     236             :             {
     237             :                 /* Found a suitable opfamily, return info */
     238     1363304 :                 *opfamily = aform->amopfamily;
     239     1363304 :                 *opcintype = aform->amoplefttype;
     240     1363304 :                 *strategy = aform->amopstrategy;
     241     1363304 :                 result = true;
     242     1363304 :                 break;
     243             :             }
     244             :         }
     245             :     }
     246             : 
     247     1363304 :     ReleaseSysCacheList(catlist);
     248             : 
     249     1363304 :     return result;
     250             : }
     251             : 
     252             : /*
     253             :  * get_equality_op_for_ordering_op
     254             :  *      Get the OID of the datatype-specific btree equality operator
     255             :  *      associated with an ordering operator (a "<" or ">" operator).
     256             :  *
     257             :  * If "reverse" isn't NULL, also set *reverse to false if the operator is "<",
     258             :  * true if it's ">"
     259             :  *
     260             :  * Returns InvalidOid if no matching equality operator can be found.
     261             :  * (This indicates that the operator is not a valid ordering operator.)
     262             :  */
     263             : Oid
     264         754 : get_equality_op_for_ordering_op(Oid opno, bool *reverse)
     265             : {
     266         754 :     Oid         result = InvalidOid;
     267             :     Oid         opfamily;
     268             :     Oid         opcintype;
     269             :     int16       strategy;
     270             : 
     271             :     /* Find the operator in pg_amop */
     272         754 :     if (get_ordering_op_properties(opno,
     273             :                                    &opfamily, &opcintype, &strategy))
     274             :     {
     275             :         /* Found a suitable opfamily, get matching equality operator */
     276         754 :         result = get_opfamily_member(opfamily,
     277             :                                      opcintype,
     278             :                                      opcintype,
     279             :                                      BTEqualStrategyNumber);
     280         754 :         if (reverse)
     281         752 :             *reverse = (strategy == BTGreaterStrategyNumber);
     282             :     }
     283             : 
     284         754 :     return result;
     285             : }
     286             : 
     287             : /*
     288             :  * get_ordering_op_for_equality_op
     289             :  *      Get the OID of a datatype-specific btree ordering operator
     290             :  *      associated with an equality operator.  (If there are multiple
     291             :  *      possibilities, assume any one will do.)
     292             :  *
     293             :  * This function is used when we have to sort data before unique-ifying,
     294             :  * and don't much care which sorting op is used as long as it's compatible
     295             :  * with the intended equality operator.  Since we need a sorting operator,
     296             :  * it should be single-data-type even if the given operator is cross-type.
     297             :  * The caller specifies whether to find an op for the LHS or RHS data type.
     298             :  *
     299             :  * Returns InvalidOid if no matching ordering operator can be found.
     300             :  */
     301             : Oid
     302           2 : get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type)
     303             : {
     304           2 :     Oid         result = InvalidOid;
     305             :     CatCList   *catlist;
     306             :     int         i;
     307             : 
     308             :     /*
     309             :      * Search pg_amop to see if the target operator is registered as the "="
     310             :      * operator of any btree opfamily.
     311             :      */
     312           2 :     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
     313             : 
     314           2 :     for (i = 0; i < catlist->n_members; i++)
     315             :     {
     316           2 :         HeapTuple   tuple = &catlist->members[i]->tuple;
     317           2 :         Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
     318             : 
     319             :         /* must be btree */
     320           2 :         if (aform->amopmethod != BTREE_AM_OID)
     321           0 :             continue;
     322             : 
     323           2 :         if (aform->amopstrategy == BTEqualStrategyNumber)
     324             :         {
     325             :             /* Found a suitable opfamily, get matching ordering operator */
     326             :             Oid         typid;
     327             : 
     328           2 :             typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
     329           2 :             result = get_opfamily_member(aform->amopfamily,
     330             :                                          typid, typid,
     331             :                                          BTLessStrategyNumber);
     332           2 :             if (OidIsValid(result))
     333           2 :                 break;
     334             :             /* failure probably shouldn't happen, but keep looking if so */
     335             :         }
     336             :     }
     337             : 
     338           2 :     ReleaseSysCacheList(catlist);
     339             : 
     340           2 :     return result;
     341             : }
     342             : 
     343             : /*
     344             :  * get_mergejoin_opfamilies
     345             :  *      Given a putatively mergejoinable operator, return a list of the OIDs
     346             :  *      of the btree opfamilies in which it represents equality.
     347             :  *
     348             :  * It is possible (though at present unusual) for an operator to be equality
     349             :  * in more than one opfamily, hence the result is a list.  This also lets us
     350             :  * return NIL if the operator is not found in any opfamilies.
     351             :  *
     352             :  * The planner currently uses simple equal() tests to compare the lists
     353             :  * returned by this function, which makes the list order relevant, though
     354             :  * strictly speaking it should not be.  Because of the way syscache list
     355             :  * searches are handled, in normal operation the result will be sorted by OID
     356             :  * so everything works fine.  If running with system index usage disabled,
     357             :  * the result ordering is unspecified and hence the planner might fail to
     358             :  * recognize optimization opportunities ... but that's hardly a scenario in
     359             :  * which performance is good anyway, so there's no point in expending code
     360             :  * or cycles here to guarantee the ordering in that case.
     361             :  */
     362             : List *
     363     1013858 : get_mergejoin_opfamilies(Oid opno)
     364             : {
     365     1013858 :     List       *result = NIL;
     366             :     CatCList   *catlist;
     367             :     int         i;
     368             : 
     369             :     /*
     370             :      * Search pg_amop to see if the target operator is registered as the "="
     371             :      * operator of any btree opfamily.
     372             :      */
     373     1013858 :     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
     374             : 
     375     4213408 :     for (i = 0; i < catlist->n_members; i++)
     376             :     {
     377     3199550 :         HeapTuple   tuple = &catlist->members[i]->tuple;
     378     3199550 :         Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
     379             : 
     380             :         /* must be btree equality */
     381     4236472 :         if (aform->amopmethod == BTREE_AM_OID &&
     382     1036922 :             aform->amopstrategy == BTEqualStrategyNumber)
     383     1036922 :             result = lappend_oid(result, aform->amopfamily);
     384             :     }
     385             : 
     386     1013858 :     ReleaseSysCacheList(catlist);
     387             : 
     388     1013858 :     return result;
     389             : }
     390             : 
     391             : /*
     392             :  * get_compatible_hash_operators
     393             :  *      Get the OID(s) of hash equality operator(s) compatible with the given
     394             :  *      operator, but operating on its LHS and/or RHS datatype.
     395             :  *
     396             :  * An operator for the LHS type is sought and returned into *lhs_opno if
     397             :  * lhs_opno isn't NULL.  Similarly, an operator for the RHS type is sought
     398             :  * and returned into *rhs_opno if rhs_opno isn't NULL.
     399             :  *
     400             :  * If the given operator is not cross-type, the results should be the same
     401             :  * operator, but in cross-type situations they will be different.
     402             :  *
     403             :  * Returns true if able to find the requested operator(s), false if not.
     404             :  * (This indicates that the operator should not have been marked oprcanhash.)
     405             :  */
     406             : bool
     407        2066 : get_compatible_hash_operators(Oid opno,
     408             :                               Oid *lhs_opno, Oid *rhs_opno)
     409             : {
     410        2066 :     bool        result = false;
     411             :     CatCList   *catlist;
     412             :     int         i;
     413             : 
     414             :     /* Ensure output args are initialized on failure */
     415        2066 :     if (lhs_opno)
     416           0 :         *lhs_opno = InvalidOid;
     417        2066 :     if (rhs_opno)
     418        2066 :         *rhs_opno = InvalidOid;
     419             : 
     420             :     /*
     421             :      * Search pg_amop to see if the target operator is registered as the "="
     422             :      * operator of any hash opfamily.  If the operator is registered in
     423             :      * multiple opfamilies, assume we can use any one.
     424             :      */
     425        2066 :     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
     426             : 
     427        4132 :     for (i = 0; i < catlist->n_members; i++)
     428             :     {
     429        4132 :         HeapTuple   tuple = &catlist->members[i]->tuple;
     430        4132 :         Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
     431             : 
     432        6198 :         if (aform->amopmethod == HASH_AM_OID &&
     433        2066 :             aform->amopstrategy == HTEqualStrategyNumber)
     434             :         {
     435             :             /* No extra lookup needed if given operator is single-type */
     436        2066 :             if (aform->amoplefttype == aform->amoprighttype)
     437             :             {
     438        2022 :                 if (lhs_opno)
     439           0 :                     *lhs_opno = opno;
     440        2022 :                 if (rhs_opno)
     441        2022 :                     *rhs_opno = opno;
     442        2022 :                 result = true;
     443        2022 :                 break;
     444             :             }
     445             : 
     446             :             /*
     447             :              * Get the matching single-type operator(s).  Failure probably
     448             :              * shouldn't happen --- it implies a bogus opfamily --- but
     449             :              * continue looking if so.
     450             :              */
     451          44 :             if (lhs_opno)
     452             :             {
     453           0 :                 *lhs_opno = get_opfamily_member(aform->amopfamily,
     454             :                                                 aform->amoplefttype,
     455             :                                                 aform->amoplefttype,
     456             :                                                 HTEqualStrategyNumber);
     457           0 :                 if (!OidIsValid(*lhs_opno))
     458           0 :                     continue;
     459             :                 /* Matching LHS found, done if caller doesn't want RHS */
     460           0 :                 if (!rhs_opno)
     461             :                 {
     462           0 :                     result = true;
     463           0 :                     break;
     464             :                 }
     465             :             }
     466          44 :             if (rhs_opno)
     467             :             {
     468          44 :                 *rhs_opno = get_opfamily_member(aform->amopfamily,
     469             :                                                 aform->amoprighttype,
     470             :                                                 aform->amoprighttype,
     471             :                                                 HTEqualStrategyNumber);
     472          44 :                 if (!OidIsValid(*rhs_opno))
     473             :                 {
     474             :                     /* Forget any LHS operator from this opfamily */
     475           0 :                     if (lhs_opno)
     476           0 :                         *lhs_opno = InvalidOid;
     477           0 :                     continue;
     478             :                 }
     479             :                 /* Matching RHS found, so done */
     480          44 :                 result = true;
     481          44 :                 break;
     482             :             }
     483             :         }
     484             :     }
     485             : 
     486        2066 :     ReleaseSysCacheList(catlist);
     487             : 
     488        2066 :     return result;
     489             : }
     490             : 
     491             : /*
     492             :  * get_op_hash_functions
     493             :  *      Get the OID(s) of the standard hash support function(s) compatible with
     494             :  *      the given operator, operating on its LHS and/or RHS datatype as required.
     495             :  *
     496             :  * A function for the LHS type is sought and returned into *lhs_procno if
     497             :  * lhs_procno isn't NULL.  Similarly, a function for the RHS type is sought
     498             :  * and returned into *rhs_procno if rhs_procno isn't NULL.
     499             :  *
     500             :  * If the given operator is not cross-type, the results should be the same
     501             :  * function, but in cross-type situations they will be different.
     502             :  *
     503             :  * Returns true if able to find the requested function(s), false if not.
     504             :  * (This indicates that the operator should not have been marked oprcanhash.)
     505             :  */
     506             : bool
     507      265642 : get_op_hash_functions(Oid opno,
     508             :                       RegProcedure *lhs_procno, RegProcedure *rhs_procno)
     509             : {
     510      265642 :     bool        result = false;
     511             :     CatCList   *catlist;
     512             :     int         i;
     513             : 
     514             :     /* Ensure output args are initialized on failure */
     515      265642 :     if (lhs_procno)
     516      265642 :         *lhs_procno = InvalidOid;
     517      265642 :     if (rhs_procno)
     518      265642 :         *rhs_procno = InvalidOid;
     519             : 
     520             :     /*
     521             :      * Search pg_amop to see if the target operator is registered as the "="
     522             :      * operator of any hash opfamily.  If the operator is registered in
     523             :      * multiple opfamilies, assume we can use any one.
     524             :      */
     525      265642 :     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
     526             : 
     527      287444 :     for (i = 0; i < catlist->n_members; i++)
     528             :     {
     529      287444 :         HeapTuple   tuple = &catlist->members[i]->tuple;
     530      287444 :         Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
     531             : 
     532      553086 :         if (aform->amopmethod == HASH_AM_OID &&
     533      265642 :             aform->amopstrategy == HTEqualStrategyNumber)
     534             :         {
     535             :             /*
     536             :              * Get the matching support function(s).  Failure probably
     537             :              * shouldn't happen --- it implies a bogus opfamily --- but
     538             :              * continue looking if so.
     539             :              */
     540      265642 :             if (lhs_procno)
     541             :             {
     542      265642 :                 *lhs_procno = get_opfamily_proc(aform->amopfamily,
     543             :                                                 aform->amoplefttype,
     544             :                                                 aform->amoplefttype,
     545             :                                                 HASHSTANDARD_PROC);
     546      265642 :                 if (!OidIsValid(*lhs_procno))
     547           0 :                     continue;
     548             :                 /* Matching LHS found, done if caller doesn't want RHS */
     549      265642 :                 if (!rhs_procno)
     550             :                 {
     551           0 :                     result = true;
     552           0 :                     break;
     553             :                 }
     554             :                 /* Only one lookup needed if given operator is single-type */
     555      265642 :                 if (aform->amoplefttype == aform->amoprighttype)
     556             :                 {
     557      265106 :                     *rhs_procno = *lhs_procno;
     558      265106 :                     result = true;
     559      265106 :                     break;
     560             :                 }
     561             :             }
     562         536 :             if (rhs_procno)
     563             :             {
     564         536 :                 *rhs_procno = get_opfamily_proc(aform->amopfamily,
     565             :                                                 aform->amoprighttype,
     566             :                                                 aform->amoprighttype,
     567             :                                                 HASHSTANDARD_PROC);
     568         536 :                 if (!OidIsValid(*rhs_procno))
     569             :                 {
     570             :                     /* Forget any LHS function from this opfamily */
     571           0 :                     if (lhs_procno)
     572           0 :                         *lhs_procno = InvalidOid;
     573           0 :                     continue;
     574             :                 }
     575             :                 /* Matching RHS found, so done */
     576         536 :                 result = true;
     577         536 :                 break;
     578             :             }
     579             :         }
     580             :     }
     581             : 
     582      265642 :     ReleaseSysCacheList(catlist);
     583             : 
     584      265642 :     return result;
     585             : }
     586             : 
     587             : /*
     588             :  * get_op_btree_interpretation
     589             :  *      Given an operator's OID, find out which btree opfamilies it belongs to,
     590             :  *      and what properties it has within each one.  The results are returned
     591             :  *      as a palloc'd list of OpBtreeInterpretation structs.
     592             :  *
     593             :  * In addition to the normal btree operators, we consider a <> operator to be
     594             :  * a "member" of an opfamily if its negator is an equality operator of the
     595             :  * opfamily.  ROWCOMPARE_NE is returned as the strategy number for this case.
     596             :  */
     597             : List *
     598        6420 : get_op_btree_interpretation(Oid opno)
     599             : {
     600        6420 :     List       *result = NIL;
     601             :     OpBtreeInterpretation *thisresult;
     602             :     CatCList   *catlist;
     603             :     int         i;
     604             : 
     605             :     /*
     606             :      * Find all the pg_amop entries containing the operator.
     607             :      */
     608        6420 :     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
     609             : 
     610       17368 :     for (i = 0; i < catlist->n_members; i++)
     611             :     {
     612       10948 :         HeapTuple   op_tuple = &catlist->members[i]->tuple;
     613       10948 :         Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
     614             :         StrategyNumber op_strategy;
     615             : 
     616             :         /* must be btree */
     617       10948 :         if (op_form->amopmethod != BTREE_AM_OID)
     618        7012 :             continue;
     619             : 
     620             :         /* Get the operator's btree strategy number */
     621        3936 :         op_strategy = (StrategyNumber) op_form->amopstrategy;
     622             :         Assert(op_strategy >= 1 && op_strategy <= 5);
     623             : 
     624        3936 :         thisresult = (OpBtreeInterpretation *)
     625             :             palloc(sizeof(OpBtreeInterpretation));
     626        3936 :         thisresult->opfamily_id = op_form->amopfamily;
     627        3936 :         thisresult->strategy = op_strategy;
     628        3936 :         thisresult->oplefttype = op_form->amoplefttype;
     629        3936 :         thisresult->oprighttype = op_form->amoprighttype;
     630        3936 :         result = lappend(result, thisresult);
     631             :     }
     632             : 
     633        6420 :     ReleaseSysCacheList(catlist);
     634             : 
     635             :     /*
     636             :      * If we didn't find any btree opfamily containing the operator, perhaps
     637             :      * it is a <> operator.  See if it has a negator that is in an opfamily.
     638             :      */
     639        6420 :     if (result == NIL)
     640             :     {
     641        2896 :         Oid         op_negator = get_negator(opno);
     642             : 
     643        2896 :         if (OidIsValid(op_negator))
     644             :         {
     645        2880 :             catlist = SearchSysCacheList1(AMOPOPID,
     646             :                                           ObjectIdGetDatum(op_negator));
     647             : 
     648       10968 :             for (i = 0; i < catlist->n_members; i++)
     649             :             {
     650        8088 :                 HeapTuple   op_tuple = &catlist->members[i]->tuple;
     651        8088 :                 Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
     652             :                 StrategyNumber op_strategy;
     653             : 
     654             :                 /* must be btree */
     655        8088 :                 if (op_form->amopmethod != BTREE_AM_OID)
     656        5412 :                     continue;
     657             : 
     658             :                 /* Get the operator's btree strategy number */
     659        2676 :                 op_strategy = (StrategyNumber) op_form->amopstrategy;
     660             :                 Assert(op_strategy >= 1 && op_strategy <= 5);
     661             : 
     662             :                 /* Only consider negators that are = */
     663        2676 :                 if (op_strategy != BTEqualStrategyNumber)
     664           0 :                     continue;
     665             : 
     666             :                 /* OK, report it with "strategy" ROWCOMPARE_NE */
     667        2676 :                 thisresult = (OpBtreeInterpretation *)
     668             :                     palloc(sizeof(OpBtreeInterpretation));
     669        2676 :                 thisresult->opfamily_id = op_form->amopfamily;
     670        2676 :                 thisresult->strategy = ROWCOMPARE_NE;
     671        2676 :                 thisresult->oplefttype = op_form->amoplefttype;
     672        2676 :                 thisresult->oprighttype = op_form->amoprighttype;
     673        2676 :                 result = lappend(result, thisresult);
     674             :             }
     675             : 
     676        2880 :             ReleaseSysCacheList(catlist);
     677             :         }
     678             :     }
     679             : 
     680        6420 :     return result;
     681             : }
     682             : 
     683             : /*
     684             :  * equality_ops_are_compatible
     685             :  *      Return true if the two given equality operators have compatible
     686             :  *      semantics.
     687             :  *
     688             :  * This is trivially true if they are the same operator.  Otherwise,
     689             :  * we look to see if they can be found in the same btree or hash opfamily.
     690             :  * Either finding allows us to assume that they have compatible notions
     691             :  * of equality.  (The reason we need to do these pushups is that one might
     692             :  * be a cross-type operator; for instance int24eq vs int4eq.)
     693             :  */
     694             : bool
     695          88 : equality_ops_are_compatible(Oid opno1, Oid opno2)
     696             : {
     697             :     bool        result;
     698             :     CatCList   *catlist;
     699             :     int         i;
     700             : 
     701             :     /* Easy if they're the same operator */
     702          88 :     if (opno1 == opno2)
     703          84 :         return true;
     704             : 
     705             :     /*
     706             :      * We search through all the pg_amop entries for opno1.
     707             :      */
     708           4 :     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno1));
     709             : 
     710           4 :     result = false;
     711           4 :     for (i = 0; i < catlist->n_members; i++)
     712             :     {
     713           4 :         HeapTuple   op_tuple = &catlist->members[i]->tuple;
     714           4 :         Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
     715             : 
     716             :         /* must be btree or hash */
     717           4 :         if (op_form->amopmethod == BTREE_AM_OID ||
     718           0 :             op_form->amopmethod == HASH_AM_OID)
     719             :         {
     720           4 :             if (op_in_opfamily(opno2, op_form->amopfamily))
     721             :             {
     722           4 :                 result = true;
     723           4 :                 break;
     724             :             }
     725             :         }
     726             :     }
     727             : 
     728           4 :     ReleaseSysCacheList(catlist);
     729             : 
     730           4 :     return result;
     731             : }
     732             : 
     733             : 
     734             : /*              ---------- AMPROC CACHES ----------                      */
     735             : 
     736             : /*
     737             :  * get_opfamily_proc
     738             :  *      Get the OID of the specified support function
     739             :  *      for the specified opfamily and datatypes.
     740             :  *
     741             :  * Returns InvalidOid if there is no pg_amproc entry for the given keys.
     742             :  */
     743             : Oid
     744     1907038 : get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
     745             : {
     746             :     HeapTuple   tp;
     747             :     Form_pg_amproc amproc_tup;
     748             :     RegProcedure result;
     749             : 
     750     1907038 :     tp = SearchSysCache4(AMPROCNUM,
     751             :                          ObjectIdGetDatum(opfamily),
     752             :                          ObjectIdGetDatum(lefttype),
     753             :                          ObjectIdGetDatum(righttype),
     754             :                          Int16GetDatum(procnum));
     755     1907038 :     if (!HeapTupleIsValid(tp))
     756       60124 :         return InvalidOid;
     757     1846914 :     amproc_tup = (Form_pg_amproc) GETSTRUCT(tp);
     758     1846914 :     result = amproc_tup->amproc;
     759     1846914 :     ReleaseSysCache(tp);
     760     1846914 :     return result;
     761             : }
     762             : 
     763             : 
     764             : /*              ---------- ATTRIBUTE CACHES ----------                   */
     765             : 
     766             : /*
     767             :  * get_attname
     768             :  *      Given the relation id and the attribute number, return the "attname"
     769             :  *      field from the attribute relation as a palloc'ed string.
     770             :  *
     771             :  * If no such attribute exists and missing_ok is true, NULL is returned;
     772             :  * otherwise a not-intended-for-user-consumption error is thrown.
     773             :  */
     774             : char *
     775       31564 : get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
     776             : {
     777             :     HeapTuple   tp;
     778             : 
     779       31564 :     tp = SearchSysCache2(ATTNUM,
     780             :                          ObjectIdGetDatum(relid), Int16GetDatum(attnum));
     781       31564 :     if (HeapTupleIsValid(tp))
     782             :     {
     783       31560 :         Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
     784             :         char       *result;
     785             : 
     786       31560 :         result = pstrdup(NameStr(att_tup->attname));
     787       31560 :         ReleaseSysCache(tp);
     788       31560 :         return result;
     789             :     }
     790             : 
     791           4 :     if (!missing_ok)
     792           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
     793             :              attnum, relid);
     794           4 :     return NULL;
     795             : }
     796             : 
     797             : /*
     798             :  * get_attnum
     799             :  *
     800             :  *      Given the relation id and the attribute name,
     801             :  *      return the "attnum" field from the attribute relation.
     802             :  *
     803             :  *      Returns InvalidAttrNumber if the attr doesn't exist (or is dropped).
     804             :  */
     805             : AttrNumber
     806        4220 : get_attnum(Oid relid, const char *attname)
     807             : {
     808             :     HeapTuple   tp;
     809             : 
     810        4220 :     tp = SearchSysCacheAttName(relid, attname);
     811        4220 :     if (HeapTupleIsValid(tp))
     812             :     {
     813        4180 :         Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
     814             :         AttrNumber  result;
     815             : 
     816        4180 :         result = att_tup->attnum;
     817        4180 :         ReleaseSysCache(tp);
     818        4180 :         return result;
     819             :     }
     820             :     else
     821          40 :         return InvalidAttrNumber;
     822             : }
     823             : 
     824             : /*
     825             :  * get_attgenerated
     826             :  *
     827             :  *      Given the relation id and the attribute name,
     828             :  *      return the "attgenerated" field from the attribute relation.
     829             :  *
     830             :  *      Errors if not found.
     831             :  *
     832             :  *      Since not generated is represented by '\0', this can also be used as a
     833             :  *      Boolean test.
     834             :  */
     835             : char
     836         204 : get_attgenerated(Oid relid, AttrNumber attnum)
     837             : {
     838             :     HeapTuple   tp;
     839             :     Form_pg_attribute att_tup;
     840             :     char        result;
     841             : 
     842         204 :     tp = SearchSysCache2(ATTNUM,
     843             :                          ObjectIdGetDatum(relid),
     844             :                          Int16GetDatum(attnum));
     845         204 :     if (!HeapTupleIsValid(tp))
     846           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
     847             :              attnum, relid);
     848         204 :     att_tup = (Form_pg_attribute) GETSTRUCT(tp);
     849         204 :     result = att_tup->attgenerated;
     850         204 :     ReleaseSysCache(tp);
     851         204 :     return result;
     852             : }
     853             : 
     854             : /*
     855             :  * get_atttype
     856             :  *
     857             :  *      Given the relation OID and the attribute number with the relation,
     858             :  *      return the attribute type OID.
     859             :  */
     860             : Oid
     861         704 : get_atttype(Oid relid, AttrNumber attnum)
     862             : {
     863             :     HeapTuple   tp;
     864             : 
     865         704 :     tp = SearchSysCache2(ATTNUM,
     866             :                          ObjectIdGetDatum(relid),
     867             :                          Int16GetDatum(attnum));
     868         704 :     if (HeapTupleIsValid(tp))
     869             :     {
     870         704 :         Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
     871             :         Oid         result;
     872             : 
     873         704 :         result = att_tup->atttypid;
     874         704 :         ReleaseSysCache(tp);
     875         704 :         return result;
     876             :     }
     877             :     else
     878           0 :         return InvalidOid;
     879             : }
     880             : 
     881             : /*
     882             :  * get_atttypetypmodcoll
     883             :  *
     884             :  *      A three-fer: given the relation id and the attribute number,
     885             :  *      fetch atttypid, atttypmod, and attcollation in a single cache lookup.
     886             :  *
     887             :  * Unlike the otherwise-similar get_atttype, this routine
     888             :  * raises an error if it can't obtain the information.
     889             :  */
     890             : void
     891        5806 : get_atttypetypmodcoll(Oid relid, AttrNumber attnum,
     892             :                       Oid *typid, int32 *typmod, Oid *collid)
     893             : {
     894             :     HeapTuple   tp;
     895             :     Form_pg_attribute att_tup;
     896             : 
     897        5806 :     tp = SearchSysCache2(ATTNUM,
     898             :                          ObjectIdGetDatum(relid),
     899             :                          Int16GetDatum(attnum));
     900        5806 :     if (!HeapTupleIsValid(tp))
     901           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
     902             :              attnum, relid);
     903        5806 :     att_tup = (Form_pg_attribute) GETSTRUCT(tp);
     904             : 
     905        5806 :     *typid = att_tup->atttypid;
     906        5806 :     *typmod = att_tup->atttypmod;
     907        5806 :     *collid = att_tup->attcollation;
     908        5806 :     ReleaseSysCache(tp);
     909        5806 : }
     910             : 
     911             : /*              ---------- COLLATION CACHE ----------                    */
     912             : 
     913             : /*
     914             :  * get_collation_name
     915             :  *      Returns the name of a given pg_collation entry.
     916             :  *
     917             :  * Returns a palloc'd copy of the string, or NULL if no such collation.
     918             :  *
     919             :  * NOTE: since collation name is not unique, be wary of code that uses this
     920             :  * for anything except preparing error messages.
     921             :  */
     922             : char *
     923         106 : get_collation_name(Oid colloid)
     924             : {
     925             :     HeapTuple   tp;
     926             : 
     927         106 :     tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(colloid));
     928         106 :     if (HeapTupleIsValid(tp))
     929             :     {
     930         106 :         Form_pg_collation colltup = (Form_pg_collation) GETSTRUCT(tp);
     931             :         char       *result;
     932             : 
     933         106 :         result = pstrdup(NameStr(colltup->collname));
     934         106 :         ReleaseSysCache(tp);
     935         106 :         return result;
     936             :     }
     937             :     else
     938           0 :         return NULL;
     939             : }
     940             : 
     941             : bool
     942        3138 : get_collation_isdeterministic(Oid colloid)
     943             : {
     944             :     HeapTuple   tp;
     945             :     Form_pg_collation colltup;
     946             :     bool        result;
     947             : 
     948        3138 :     tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(colloid));
     949        3138 :     if (!HeapTupleIsValid(tp))
     950           0 :         elog(ERROR, "cache lookup failed for collation %u", colloid);
     951        3138 :     colltup = (Form_pg_collation) GETSTRUCT(tp);
     952        3138 :     result = colltup->collisdeterministic;
     953        3138 :     ReleaseSysCache(tp);
     954        3138 :     return result;
     955             : }
     956             : 
     957             : /*              ---------- CONSTRAINT CACHE ----------                   */
     958             : 
     959             : /*
     960             :  * get_constraint_name
     961             :  *      Returns the name of a given pg_constraint entry.
     962             :  *
     963             :  * Returns a palloc'd copy of the string, or NULL if no such constraint.
     964             :  *
     965             :  * NOTE: since constraint name is not unique, be wary of code that uses this
     966             :  * for anything except preparing error messages.
     967             :  */
     968             : char *
     969         350 : get_constraint_name(Oid conoid)
     970             : {
     971             :     HeapTuple   tp;
     972             : 
     973         350 :     tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conoid));
     974         350 :     if (HeapTupleIsValid(tp))
     975             :     {
     976         350 :         Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp);
     977             :         char       *result;
     978             : 
     979         350 :         result = pstrdup(NameStr(contup->conname));
     980         350 :         ReleaseSysCache(tp);
     981         350 :         return result;
     982             :     }
     983             :     else
     984           0 :         return NULL;
     985             : }
     986             : 
     987             : /*              ---------- LANGUAGE CACHE ----------                     */
     988             : 
     989             : char *
     990          80 : get_language_name(Oid langoid, bool missing_ok)
     991             : {
     992             :     HeapTuple   tp;
     993             : 
     994          80 :     tp = SearchSysCache1(LANGOID, ObjectIdGetDatum(langoid));
     995          80 :     if (HeapTupleIsValid(tp))
     996             :     {
     997          80 :         Form_pg_language lantup = (Form_pg_language) GETSTRUCT(tp);
     998             :         char       *result;
     999             : 
    1000          80 :         result = pstrdup(NameStr(lantup->lanname));
    1001          80 :         ReleaseSysCache(tp);
    1002          80 :         return result;
    1003             :     }
    1004             : 
    1005           0 :     if (!missing_ok)
    1006           0 :         elog(ERROR, "cache lookup failed for language %u",
    1007             :              langoid);
    1008           0 :     return NULL;
    1009             : }
    1010             : 
    1011             : /*              ---------- OPCLASS CACHE ----------                      */
    1012             : 
    1013             : /*
    1014             :  * get_opclass_family
    1015             :  *
    1016             :  *      Returns the OID of the operator family the opclass belongs to.
    1017             :  */
    1018             : Oid
    1019       26296 : get_opclass_family(Oid opclass)
    1020             : {
    1021             :     HeapTuple   tp;
    1022             :     Form_pg_opclass cla_tup;
    1023             :     Oid         result;
    1024             : 
    1025       26296 :     tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
    1026       26296 :     if (!HeapTupleIsValid(tp))
    1027           0 :         elog(ERROR, "cache lookup failed for opclass %u", opclass);
    1028       26296 :     cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
    1029             : 
    1030       26296 :     result = cla_tup->opcfamily;
    1031       26296 :     ReleaseSysCache(tp);
    1032       26296 :     return result;
    1033             : }
    1034             : 
    1035             : /*
    1036             :  * get_opclass_input_type
    1037             :  *
    1038             :  *      Returns the OID of the datatype the opclass indexes.
    1039             :  */
    1040             : Oid
    1041       25840 : get_opclass_input_type(Oid opclass)
    1042             : {
    1043             :     HeapTuple   tp;
    1044             :     Form_pg_opclass cla_tup;
    1045             :     Oid         result;
    1046             : 
    1047       25840 :     tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
    1048       25840 :     if (!HeapTupleIsValid(tp))
    1049           0 :         elog(ERROR, "cache lookup failed for opclass %u", opclass);
    1050       25840 :     cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
    1051             : 
    1052       25840 :     result = cla_tup->opcintype;
    1053       25840 :     ReleaseSysCache(tp);
    1054       25840 :     return result;
    1055             : }
    1056             : 
    1057             : /*
    1058             :  * get_opclass_opfamily_and_input_type
    1059             :  *
    1060             :  *      Returns the OID of the operator family the opclass belongs to,
    1061             :  *              the OID of the datatype the opclass indexes
    1062             :  */
    1063             : bool
    1064          24 : get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
    1065             : {
    1066             :     HeapTuple   tp;
    1067             :     Form_pg_opclass cla_tup;
    1068             : 
    1069          24 :     tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
    1070          24 :     if (!HeapTupleIsValid(tp))
    1071           0 :         return false;
    1072             : 
    1073          24 :     cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
    1074             : 
    1075          24 :     *opfamily = cla_tup->opcfamily;
    1076          24 :     *opcintype = cla_tup->opcintype;
    1077             : 
    1078          24 :     ReleaseSysCache(tp);
    1079             : 
    1080          24 :     return true;
    1081             : }
    1082             : 
    1083             : /*              ---------- OPERATOR CACHE ----------                     */
    1084             : 
    1085             : /*
    1086             :  * get_opcode
    1087             :  *
    1088             :  *      Returns the regproc id of the routine used to implement an
    1089             :  *      operator given the operator oid.
    1090             :  */
    1091             : RegProcedure
    1092     1104118 : get_opcode(Oid opno)
    1093             : {
    1094             :     HeapTuple   tp;
    1095             : 
    1096     1104118 :     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1097     1104118 :     if (HeapTupleIsValid(tp))
    1098             :     {
    1099     1104118 :         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
    1100             :         RegProcedure result;
    1101             : 
    1102     1104118 :         result = optup->oprcode;
    1103     1104118 :         ReleaseSysCache(tp);
    1104     1104118 :         return result;
    1105             :     }
    1106             :     else
    1107           0 :         return (RegProcedure) InvalidOid;
    1108             : }
    1109             : 
    1110             : /*
    1111             :  * get_opname
    1112             :  *    returns the name of the operator with the given opno
    1113             :  *
    1114             :  * Note: returns a palloc'd copy of the string, or NULL if no such operator.
    1115             :  */
    1116             : char *
    1117           8 : get_opname(Oid opno)
    1118             : {
    1119             :     HeapTuple   tp;
    1120             : 
    1121           8 :     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1122           8 :     if (HeapTupleIsValid(tp))
    1123             :     {
    1124           8 :         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
    1125             :         char       *result;
    1126             : 
    1127           8 :         result = pstrdup(NameStr(optup->oprname));
    1128           8 :         ReleaseSysCache(tp);
    1129           8 :         return result;
    1130             :     }
    1131             :     else
    1132           0 :         return NULL;
    1133             : }
    1134             : 
    1135             : /*
    1136             :  * get_op_rettype
    1137             :  *      Given operator oid, return the operator's result type.
    1138             :  */
    1139             : Oid
    1140          74 : get_op_rettype(Oid opno)
    1141             : {
    1142             :     HeapTuple   tp;
    1143             : 
    1144          74 :     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1145          74 :     if (HeapTupleIsValid(tp))
    1146             :     {
    1147          74 :         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
    1148             :         Oid         result;
    1149             : 
    1150          74 :         result = optup->oprresult;
    1151          74 :         ReleaseSysCache(tp);
    1152          74 :         return result;
    1153             :     }
    1154             :     else
    1155           0 :         return InvalidOid;
    1156             : }
    1157             : 
    1158             : /*
    1159             :  * op_input_types
    1160             :  *
    1161             :  *      Returns the left and right input datatypes for an operator
    1162             :  *      (InvalidOid if not relevant).
    1163             :  */
    1164             : void
    1165      249030 : op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
    1166             : {
    1167             :     HeapTuple   tp;
    1168             :     Form_pg_operator optup;
    1169             : 
    1170      249030 :     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1171      249030 :     if (!HeapTupleIsValid(tp))  /* shouldn't happen */
    1172           0 :         elog(ERROR, "cache lookup failed for operator %u", opno);
    1173      249030 :     optup = (Form_pg_operator) GETSTRUCT(tp);
    1174      249030 :     *lefttype = optup->oprleft;
    1175      249030 :     *righttype = optup->oprright;
    1176      249030 :     ReleaseSysCache(tp);
    1177      249030 : }
    1178             : 
    1179             : /*
    1180             :  * op_mergejoinable
    1181             :  *
    1182             :  * Returns true if the operator is potentially mergejoinable.  (The planner
    1183             :  * will fail to find any mergejoin plans unless there are suitable btree
    1184             :  * opfamily entries for this operator and associated sortops.  The pg_operator
    1185             :  * flag is just a hint to tell the planner whether to bother looking.)
    1186             :  *
    1187             :  * In some cases (currently only array_eq and record_eq), mergejoinability
    1188             :  * depends on the specific input data type the operator is invoked for, so
    1189             :  * that must be passed as well. We currently assume that only one input's type
    1190             :  * is needed to check this --- by convention, pass the left input's data type.
    1191             :  */
    1192             : bool
    1193      296290 : op_mergejoinable(Oid opno, Oid inputtype)
    1194             : {
    1195      296290 :     bool        result = false;
    1196             :     HeapTuple   tp;
    1197             :     TypeCacheEntry *typentry;
    1198             : 
    1199             :     /*
    1200             :      * For array_eq or record_eq, we can sort if the element or field types
    1201             :      * are all sortable.  We could implement all the checks for that here, but
    1202             :      * the typcache already does that and caches the results too, so let's
    1203             :      * rely on the typcache.
    1204             :      */
    1205      296290 :     if (opno == ARRAY_EQ_OP)
    1206             :     {
    1207         104 :         typentry = lookup_type_cache(inputtype, TYPECACHE_CMP_PROC);
    1208         104 :         if (typentry->cmp_proc == F_BTARRAYCMP)
    1209         104 :             result = true;
    1210             :     }
    1211      296186 :     else if (opno == RECORD_EQ_OP)
    1212             :     {
    1213          44 :         typentry = lookup_type_cache(inputtype, TYPECACHE_CMP_PROC);
    1214          44 :         if (typentry->cmp_proc == F_BTRECORDCMP)
    1215          44 :             result = true;
    1216             :     }
    1217             :     else
    1218             :     {
    1219             :         /* For all other operators, rely on pg_operator.oprcanmerge */
    1220      296142 :         tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1221      296142 :         if (HeapTupleIsValid(tp))
    1222             :         {
    1223      296142 :             Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
    1224             : 
    1225      296142 :             result = optup->oprcanmerge;
    1226      296142 :             ReleaseSysCache(tp);
    1227             :         }
    1228             :     }
    1229      296290 :     return result;
    1230             : }
    1231             : 
    1232             : /*
    1233             :  * op_hashjoinable
    1234             :  *
    1235             :  * Returns true if the operator is hashjoinable.  (There must be a suitable
    1236             :  * hash opfamily entry for this operator if it is so marked.)
    1237             :  *
    1238             :  * In some cases (currently only array_eq), hashjoinability depends on the
    1239             :  * specific input data type the operator is invoked for, so that must be
    1240             :  * passed as well.  We currently assume that only one input's type is needed
    1241             :  * to check this --- by convention, pass the left input's data type.
    1242             :  */
    1243             : bool
    1244      200924 : op_hashjoinable(Oid opno, Oid inputtype)
    1245             : {
    1246      200924 :     bool        result = false;
    1247             :     HeapTuple   tp;
    1248             :     TypeCacheEntry *typentry;
    1249             : 
    1250             :     /* As in op_mergejoinable, let the typcache handle the hard cases */
    1251             :     /* Eventually we'll need a similar case for record_eq ... */
    1252      200924 :     if (opno == ARRAY_EQ_OP)
    1253             :     {
    1254           0 :         typentry = lookup_type_cache(inputtype, TYPECACHE_HASH_PROC);
    1255           0 :         if (typentry->hash_proc == F_HASH_ARRAY)
    1256           0 :             result = true;
    1257             :     }
    1258             :     else
    1259             :     {
    1260             :         /* For all other operators, rely on pg_operator.oprcanhash */
    1261      200924 :         tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1262      200924 :         if (HeapTupleIsValid(tp))
    1263             :         {
    1264      200924 :             Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
    1265             : 
    1266      200924 :             result = optup->oprcanhash;
    1267      200924 :             ReleaseSysCache(tp);
    1268             :         }
    1269             :     }
    1270      200924 :     return result;
    1271             : }
    1272             : 
    1273             : /*
    1274             :  * op_strict
    1275             :  *
    1276             :  * Get the proisstrict flag for the operator's underlying function.
    1277             :  */
    1278             : bool
    1279      270518 : op_strict(Oid opno)
    1280             : {
    1281      270518 :     RegProcedure funcid = get_opcode(opno);
    1282             : 
    1283      270518 :     if (funcid == (RegProcedure) InvalidOid)
    1284           0 :         elog(ERROR, "operator %u does not exist", opno);
    1285             : 
    1286      270518 :     return func_strict((Oid) funcid);
    1287             : }
    1288             : 
    1289             : /*
    1290             :  * op_volatile
    1291             :  *
    1292             :  * Get the provolatile flag for the operator's underlying function.
    1293             :  */
    1294             : char
    1295        8468 : op_volatile(Oid opno)
    1296             : {
    1297        8468 :     RegProcedure funcid = get_opcode(opno);
    1298             : 
    1299        8468 :     if (funcid == (RegProcedure) InvalidOid)
    1300           0 :         elog(ERROR, "operator %u does not exist", opno);
    1301             : 
    1302        8468 :     return func_volatile((Oid) funcid);
    1303             : }
    1304             : 
    1305             : /*
    1306             :  * get_commutator
    1307             :  *
    1308             :  *      Returns the corresponding commutator of an operator.
    1309             :  */
    1310             : Oid
    1311       36982 : get_commutator(Oid opno)
    1312             : {
    1313             :     HeapTuple   tp;
    1314             : 
    1315       36982 :     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1316       36982 :     if (HeapTupleIsValid(tp))
    1317             :     {
    1318       36982 :         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
    1319             :         Oid         result;
    1320             : 
    1321       36982 :         result = optup->oprcom;
    1322       36982 :         ReleaseSysCache(tp);
    1323       36982 :         return result;
    1324             :     }
    1325             :     else
    1326           0 :         return InvalidOid;
    1327             : }
    1328             : 
    1329             : /*
    1330             :  * get_negator
    1331             :  *
    1332             :  *      Returns the corresponding negator of an operator.
    1333             :  */
    1334             : Oid
    1335       27342 : get_negator(Oid opno)
    1336             : {
    1337             :     HeapTuple   tp;
    1338             : 
    1339       27342 :     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1340       27342 :     if (HeapTupleIsValid(tp))
    1341             :     {
    1342       27342 :         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
    1343             :         Oid         result;
    1344             : 
    1345       27342 :         result = optup->oprnegate;
    1346       27342 :         ReleaseSysCache(tp);
    1347       27342 :         return result;
    1348             :     }
    1349             :     else
    1350           0 :         return InvalidOid;
    1351             : }
    1352             : 
    1353             : /*
    1354             :  * get_oprrest
    1355             :  *
    1356             :  *      Returns procedure id for computing selectivity of an operator.
    1357             :  */
    1358             : RegProcedure
    1359      568098 : get_oprrest(Oid opno)
    1360             : {
    1361             :     HeapTuple   tp;
    1362             : 
    1363      568098 :     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1364      568098 :     if (HeapTupleIsValid(tp))
    1365             :     {
    1366      568098 :         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
    1367             :         RegProcedure result;
    1368             : 
    1369      568098 :         result = optup->oprrest;
    1370      568098 :         ReleaseSysCache(tp);
    1371      568098 :         return result;
    1372             :     }
    1373             :     else
    1374           0 :         return (RegProcedure) InvalidOid;
    1375             : }
    1376             : 
    1377             : /*
    1378             :  * get_oprjoin
    1379             :  *
    1380             :  *      Returns procedure id for computing selectivity of a join.
    1381             :  */
    1382             : RegProcedure
    1383      114198 : get_oprjoin(Oid opno)
    1384             : {
    1385             :     HeapTuple   tp;
    1386             : 
    1387      114198 :     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
    1388      114198 :     if (HeapTupleIsValid(tp))
    1389             :     {
    1390      114198 :         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
    1391             :         RegProcedure result;
    1392             : 
    1393      114198 :         result = optup->oprjoin;
    1394      114198 :         ReleaseSysCache(tp);
    1395      114198 :         return result;
    1396             :     }
    1397             :     else
    1398           0 :         return (RegProcedure) InvalidOid;
    1399             : }
    1400             : 
    1401             : /*              ---------- FUNCTION CACHE ----------                     */
    1402             : 
    1403             : /*
    1404             :  * get_func_name
    1405             :  *    returns the name of the function with the given funcid
    1406             :  *
    1407             :  * Note: returns a palloc'd copy of the string, or NULL if no such function.
    1408             :  */
    1409             : char *
    1410         236 : get_func_name(Oid funcid)
    1411             : {
    1412             :     HeapTuple   tp;
    1413             : 
    1414         236 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1415         236 :     if (HeapTupleIsValid(tp))
    1416             :     {
    1417         236 :         Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
    1418             :         char       *result;
    1419             : 
    1420         236 :         result = pstrdup(NameStr(functup->proname));
    1421         236 :         ReleaseSysCache(tp);
    1422         236 :         return result;
    1423             :     }
    1424             :     else
    1425           0 :         return NULL;
    1426             : }
    1427             : 
    1428             : /*
    1429             :  * get_func_namespace
    1430             :  *
    1431             :  *      Returns the pg_namespace OID associated with a given function.
    1432             :  */
    1433             : Oid
    1434          34 : get_func_namespace(Oid funcid)
    1435             : {
    1436             :     HeapTuple   tp;
    1437             : 
    1438          34 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1439          34 :     if (HeapTupleIsValid(tp))
    1440             :     {
    1441          34 :         Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
    1442             :         Oid         result;
    1443             : 
    1444          34 :         result = functup->pronamespace;
    1445          34 :         ReleaseSysCache(tp);
    1446          34 :         return result;
    1447             :     }
    1448             :     else
    1449           0 :         return InvalidOid;
    1450             : }
    1451             : 
    1452             : /*
    1453             :  * get_func_rettype
    1454             :  *      Given procedure id, return the function's result type.
    1455             :  */
    1456             : Oid
    1457       13250 : get_func_rettype(Oid funcid)
    1458             : {
    1459             :     HeapTuple   tp;
    1460             :     Oid         result;
    1461             : 
    1462       13250 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1463       13250 :     if (!HeapTupleIsValid(tp))
    1464           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1465             : 
    1466       13250 :     result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
    1467       13250 :     ReleaseSysCache(tp);
    1468       13250 :     return result;
    1469             : }
    1470             : 
    1471             : /*
    1472             :  * get_func_nargs
    1473             :  *      Given procedure id, return the number of arguments.
    1474             :  */
    1475             : int
    1476           0 : get_func_nargs(Oid funcid)
    1477             : {
    1478             :     HeapTuple   tp;
    1479             :     int         result;
    1480             : 
    1481           0 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1482           0 :     if (!HeapTupleIsValid(tp))
    1483           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1484             : 
    1485           0 :     result = ((Form_pg_proc) GETSTRUCT(tp))->pronargs;
    1486           0 :     ReleaseSysCache(tp);
    1487           0 :     return result;
    1488             : }
    1489             : 
    1490             : /*
    1491             :  * get_func_signature
    1492             :  *      Given procedure id, return the function's argument and result types.
    1493             :  *      (The return value is the result type.)
    1494             :  *
    1495             :  * The arguments are returned as a palloc'd array.
    1496             :  */
    1497             : Oid
    1498         690 : get_func_signature(Oid funcid, Oid **argtypes, int *nargs)
    1499             : {
    1500             :     HeapTuple   tp;
    1501             :     Form_pg_proc procstruct;
    1502             :     Oid         result;
    1503             : 
    1504         690 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1505         690 :     if (!HeapTupleIsValid(tp))
    1506           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1507             : 
    1508         690 :     procstruct = (Form_pg_proc) GETSTRUCT(tp);
    1509             : 
    1510         690 :     result = procstruct->prorettype;
    1511         690 :     *nargs = (int) procstruct->pronargs;
    1512             :     Assert(*nargs == procstruct->proargtypes.dim1);
    1513         690 :     *argtypes = (Oid *) palloc(*nargs * sizeof(Oid));
    1514         690 :     memcpy(*argtypes, procstruct->proargtypes.values, *nargs * sizeof(Oid));
    1515             : 
    1516         690 :     ReleaseSysCache(tp);
    1517         690 :     return result;
    1518             : }
    1519             : 
    1520             : /*
    1521             :  * get_func_variadictype
    1522             :  *      Given procedure id, return the function's provariadic field.
    1523             :  */
    1524             : Oid
    1525         158 : get_func_variadictype(Oid funcid)
    1526             : {
    1527             :     HeapTuple   tp;
    1528             :     Oid         result;
    1529             : 
    1530         158 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1531         158 :     if (!HeapTupleIsValid(tp))
    1532           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1533             : 
    1534         158 :     result = ((Form_pg_proc) GETSTRUCT(tp))->provariadic;
    1535         158 :     ReleaseSysCache(tp);
    1536         158 :     return result;
    1537             : }
    1538             : 
    1539             : /*
    1540             :  * get_func_retset
    1541             :  *      Given procedure id, return the function's proretset flag.
    1542             :  */
    1543             : bool
    1544      539178 : get_func_retset(Oid funcid)
    1545             : {
    1546             :     HeapTuple   tp;
    1547             :     bool        result;
    1548             : 
    1549      539178 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1550      539178 :     if (!HeapTupleIsValid(tp))
    1551           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1552             : 
    1553      539178 :     result = ((Form_pg_proc) GETSTRUCT(tp))->proretset;
    1554      539178 :     ReleaseSysCache(tp);
    1555      539178 :     return result;
    1556             : }
    1557             : 
    1558             : /*
    1559             :  * func_strict
    1560             :  *      Given procedure id, return the function's proisstrict flag.
    1561             :  */
    1562             : bool
    1563      482470 : func_strict(Oid funcid)
    1564             : {
    1565             :     HeapTuple   tp;
    1566             :     bool        result;
    1567             : 
    1568      482470 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1569      482470 :     if (!HeapTupleIsValid(tp))
    1570           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1571             : 
    1572      482470 :     result = ((Form_pg_proc) GETSTRUCT(tp))->proisstrict;
    1573      482470 :     ReleaseSysCache(tp);
    1574      482470 :     return result;
    1575             : }
    1576             : 
    1577             : /*
    1578             :  * func_volatile
    1579             :  *      Given procedure id, return the function's provolatile flag.
    1580             :  */
    1581             : char
    1582      606152 : func_volatile(Oid funcid)
    1583             : {
    1584             :     HeapTuple   tp;
    1585             :     char        result;
    1586             : 
    1587      606152 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1588      606152 :     if (!HeapTupleIsValid(tp))
    1589           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1590             : 
    1591      606152 :     result = ((Form_pg_proc) GETSTRUCT(tp))->provolatile;
    1592      606152 :     ReleaseSysCache(tp);
    1593      606152 :     return result;
    1594             : }
    1595             : 
    1596             : /*
    1597             :  * func_parallel
    1598             :  *      Given procedure id, return the function's proparallel flag.
    1599             :  */
    1600             : char
    1601      867486 : func_parallel(Oid funcid)
    1602             : {
    1603             :     HeapTuple   tp;
    1604             :     char        result;
    1605             : 
    1606      867486 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1607      867486 :     if (!HeapTupleIsValid(tp))
    1608           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1609             : 
    1610      867486 :     result = ((Form_pg_proc) GETSTRUCT(tp))->proparallel;
    1611      867486 :     ReleaseSysCache(tp);
    1612      867486 :     return result;
    1613             : }
    1614             : 
    1615             : /*
    1616             :  * get_func_prokind
    1617             :  *     Given procedure id, return the routine kind.
    1618             :  */
    1619             : char
    1620       19818 : get_func_prokind(Oid funcid)
    1621             : {
    1622             :     HeapTuple   tp;
    1623             :     char        result;
    1624             : 
    1625       19818 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1626       19818 :     if (!HeapTupleIsValid(tp))
    1627           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1628             : 
    1629       19818 :     result = ((Form_pg_proc) GETSTRUCT(tp))->prokind;
    1630       19818 :     ReleaseSysCache(tp);
    1631       19818 :     return result;
    1632             : }
    1633             : 
    1634             : /*
    1635             :  * get_func_leakproof
    1636             :  *     Given procedure id, return the function's leakproof field.
    1637             :  */
    1638             : bool
    1639        4312 : get_func_leakproof(Oid funcid)
    1640             : {
    1641             :     HeapTuple   tp;
    1642             :     bool        result;
    1643             : 
    1644        4312 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1645        4312 :     if (!HeapTupleIsValid(tp))
    1646           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1647             : 
    1648        4312 :     result = ((Form_pg_proc) GETSTRUCT(tp))->proleakproof;
    1649        4312 :     ReleaseSysCache(tp);
    1650        4312 :     return result;
    1651             : }
    1652             : 
    1653             : /*
    1654             :  * get_func_support
    1655             :  *
    1656             :  *      Returns the support function OID associated with a given function,
    1657             :  *      or InvalidOid if there is none.
    1658             :  */
    1659             : RegProcedure
    1660       13782 : get_func_support(Oid funcid)
    1661             : {
    1662             :     HeapTuple   tp;
    1663             : 
    1664       13782 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1665       13782 :     if (HeapTupleIsValid(tp))
    1666             :     {
    1667       13782 :         Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
    1668             :         RegProcedure result;
    1669             : 
    1670       13782 :         result = functup->prosupport;
    1671       13782 :         ReleaseSysCache(tp);
    1672       13782 :         return result;
    1673             :     }
    1674             :     else
    1675           0 :         return (RegProcedure) InvalidOid;
    1676             : }
    1677             : 
    1678             : /*              ---------- RELATION CACHE ----------                     */
    1679             : 
    1680             : /*
    1681             :  * get_relname_relid
    1682             :  *      Given name and namespace of a relation, look up the OID.
    1683             :  *
    1684             :  * Returns InvalidOid if there is no such relation.
    1685             :  */
    1686             : Oid
    1687     1228742 : get_relname_relid(const char *relname, Oid relnamespace)
    1688             : {
    1689     1228742 :     return GetSysCacheOid2(RELNAMENSP, Anum_pg_class_oid,
    1690             :                            PointerGetDatum(relname),
    1691             :                            ObjectIdGetDatum(relnamespace));
    1692             : }
    1693             : 
    1694             : #ifdef NOT_USED
    1695             : /*
    1696             :  * get_relnatts
    1697             :  *
    1698             :  *      Returns the number of attributes for a given relation.
    1699             :  */
    1700             : int
    1701             : get_relnatts(Oid relid)
    1702             : {
    1703             :     HeapTuple   tp;
    1704             : 
    1705             :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    1706             :     if (HeapTupleIsValid(tp))
    1707             :     {
    1708             :         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
    1709             :         int         result;
    1710             : 
    1711             :         result = reltup->relnatts;
    1712             :         ReleaseSysCache(tp);
    1713             :         return result;
    1714             :     }
    1715             :     else
    1716             :         return InvalidAttrNumber;
    1717             : }
    1718             : #endif
    1719             : 
    1720             : /*
    1721             :  * get_rel_name
    1722             :  *      Returns the name of a given relation.
    1723             :  *
    1724             :  * Returns a palloc'd copy of the string, or NULL if no such relation.
    1725             :  *
    1726             :  * NOTE: since relation name is not unique, be wary of code that uses this
    1727             :  * for anything except preparing error messages.
    1728             :  */
    1729             : char *
    1730       47448 : get_rel_name(Oid relid)
    1731             : {
    1732             :     HeapTuple   tp;
    1733             : 
    1734       47448 :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    1735       47448 :     if (HeapTupleIsValid(tp))
    1736             :     {
    1737       47440 :         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
    1738             :         char       *result;
    1739             : 
    1740       47440 :         result = pstrdup(NameStr(reltup->relname));
    1741       47440 :         ReleaseSysCache(tp);
    1742       47440 :         return result;
    1743             :     }
    1744             :     else
    1745           8 :         return NULL;
    1746             : }
    1747             : 
    1748             : /*
    1749             :  * get_rel_namespace
    1750             :  *
    1751             :  *      Returns the pg_namespace OID associated with a given relation.
    1752             :  */
    1753             : Oid
    1754      294470 : get_rel_namespace(Oid relid)
    1755             : {
    1756             :     HeapTuple   tp;
    1757             : 
    1758      294470 :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    1759      294470 :     if (HeapTupleIsValid(tp))
    1760             :     {
    1761      294470 :         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
    1762             :         Oid         result;
    1763             : 
    1764      294470 :         result = reltup->relnamespace;
    1765      294470 :         ReleaseSysCache(tp);
    1766      294470 :         return result;
    1767             :     }
    1768             :     else
    1769           0 :         return InvalidOid;
    1770             : }
    1771             : 
    1772             : /*
    1773             :  * get_rel_type_id
    1774             :  *
    1775             :  *      Returns the pg_type OID associated with a given relation.
    1776             :  *
    1777             :  * Note: not all pg_class entries have associated pg_type OIDs; so be
    1778             :  * careful to check for InvalidOid result.
    1779             :  */
    1780             : Oid
    1781       19612 : get_rel_type_id(Oid relid)
    1782             : {
    1783             :     HeapTuple   tp;
    1784             : 
    1785       19612 :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    1786       19612 :     if (HeapTupleIsValid(tp))
    1787             :     {
    1788       19612 :         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
    1789             :         Oid         result;
    1790             : 
    1791       19612 :         result = reltup->reltype;
    1792       19612 :         ReleaseSysCache(tp);
    1793       19612 :         return result;
    1794             :     }
    1795             :     else
    1796           0 :         return InvalidOid;
    1797             : }
    1798             : 
    1799             : /*
    1800             :  * get_rel_relkind
    1801             :  *
    1802             :  *      Returns the relkind associated with a given relation.
    1803             :  */
    1804             : char
    1805       79506 : get_rel_relkind(Oid relid)
    1806             : {
    1807             :     HeapTuple   tp;
    1808             : 
    1809       79506 :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    1810       79506 :     if (HeapTupleIsValid(tp))
    1811             :     {
    1812       79506 :         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
    1813             :         char        result;
    1814             : 
    1815       79506 :         result = reltup->relkind;
    1816       79506 :         ReleaseSysCache(tp);
    1817       79506 :         return result;
    1818             :     }
    1819             :     else
    1820           0 :         return '\0';
    1821             : }
    1822             : 
    1823             : /*
    1824             :  * get_rel_relispartition
    1825             :  *
    1826             :  *      Returns the relispartition flag associated with a given relation.
    1827             :  */
    1828             : bool
    1829        2570 : get_rel_relispartition(Oid relid)
    1830             : {
    1831             :     HeapTuple   tp;
    1832             : 
    1833        2570 :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    1834        2570 :     if (HeapTupleIsValid(tp))
    1835             :     {
    1836        2570 :         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
    1837             :         bool        result;
    1838             : 
    1839        2570 :         result = reltup->relispartition;
    1840        2570 :         ReleaseSysCache(tp);
    1841        2570 :         return result;
    1842             :     }
    1843             :     else
    1844           0 :         return false;
    1845             : }
    1846             : 
    1847             : /*
    1848             :  * get_rel_tablespace
    1849             :  *
    1850             :  *      Returns the pg_tablespace OID associated with a given relation.
    1851             :  *
    1852             :  * Note: InvalidOid might mean either that we couldn't find the relation,
    1853             :  * or that it is in the database's default tablespace.
    1854             :  */
    1855             : Oid
    1856        3774 : get_rel_tablespace(Oid relid)
    1857             : {
    1858             :     HeapTuple   tp;
    1859             : 
    1860        3774 :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    1861        3774 :     if (HeapTupleIsValid(tp))
    1862             :     {
    1863        3774 :         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
    1864             :         Oid         result;
    1865             : 
    1866        3774 :         result = reltup->reltablespace;
    1867        3774 :         ReleaseSysCache(tp);
    1868        3774 :         return result;
    1869             :     }
    1870             :     else
    1871           0 :         return InvalidOid;
    1872             : }
    1873             : 
    1874             : /*
    1875             :  * get_rel_persistence
    1876             :  *
    1877             :  *      Returns the relpersistence associated with a given relation.
    1878             :  */
    1879             : char
    1880      176642 : get_rel_persistence(Oid relid)
    1881             : {
    1882             :     HeapTuple   tp;
    1883             :     Form_pg_class reltup;
    1884             :     char        result;
    1885             : 
    1886      176642 :     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
    1887      176642 :     if (!HeapTupleIsValid(tp))
    1888           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
    1889      176642 :     reltup = (Form_pg_class) GETSTRUCT(tp);
    1890      176642 :     result = reltup->relpersistence;
    1891      176642 :     ReleaseSysCache(tp);
    1892             : 
    1893      176642 :     return result;
    1894             : }
    1895             : 
    1896             : 
    1897             : /*              ---------- TRANSFORM CACHE ----------                        */
    1898             : 
    1899             : Oid
    1900        1506 : get_transform_fromsql(Oid typid, Oid langid, List *trftypes)
    1901             : {
    1902             :     HeapTuple   tup;
    1903             : 
    1904        1506 :     if (!list_member_oid(trftypes, typid))
    1905        1360 :         return InvalidOid;
    1906             : 
    1907         146 :     tup = SearchSysCache2(TRFTYPELANG, typid, langid);
    1908         146 :     if (HeapTupleIsValid(tup))
    1909             :     {
    1910             :         Oid         funcid;
    1911             : 
    1912         146 :         funcid = ((Form_pg_transform) GETSTRUCT(tup))->trffromsql;
    1913         146 :         ReleaseSysCache(tup);
    1914         146 :         return funcid;
    1915             :     }
    1916             :     else
    1917           0 :         return InvalidOid;
    1918             : }
    1919             : 
    1920             : Oid
    1921        1986 : get_transform_tosql(Oid typid, Oid langid, List *trftypes)
    1922             : {
    1923             :     HeapTuple   tup;
    1924             : 
    1925        1986 :     if (!list_member_oid(trftypes, typid))
    1926        1822 :         return InvalidOid;
    1927             : 
    1928         164 :     tup = SearchSysCache2(TRFTYPELANG, typid, langid);
    1929         164 :     if (HeapTupleIsValid(tup))
    1930             :     {
    1931             :         Oid         funcid;
    1932             : 
    1933         164 :         funcid = ((Form_pg_transform) GETSTRUCT(tup))->trftosql;
    1934         164 :         ReleaseSysCache(tup);
    1935         164 :         return funcid;
    1936             :     }
    1937             :     else
    1938           0 :         return InvalidOid;
    1939             : }
    1940             : 
    1941             : 
    1942             : /*              ---------- TYPE CACHE ----------                         */
    1943             : 
    1944             : /*
    1945             :  * get_typisdefined
    1946             :  *
    1947             :  *      Given the type OID, determine whether the type is defined
    1948             :  *      (if not, it's only a shell).
    1949             :  */
    1950             : bool
    1951         178 : get_typisdefined(Oid typid)
    1952             : {
    1953             :     HeapTuple   tp;
    1954             : 
    1955         178 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    1956         178 :     if (HeapTupleIsValid(tp))
    1957             :     {
    1958         178 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    1959             :         bool        result;
    1960             : 
    1961         178 :         result = typtup->typisdefined;
    1962         178 :         ReleaseSysCache(tp);
    1963         178 :         return result;
    1964             :     }
    1965             :     else
    1966           0 :         return false;
    1967             : }
    1968             : 
    1969             : /*
    1970             :  * get_typlen
    1971             :  *
    1972             :  *      Given the type OID, return the length of the type.
    1973             :  */
    1974             : int16
    1975     1685898 : get_typlen(Oid typid)
    1976             : {
    1977             :     HeapTuple   tp;
    1978             : 
    1979     1685898 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    1980     1685898 :     if (HeapTupleIsValid(tp))
    1981             :     {
    1982     1685898 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    1983             :         int16       result;
    1984             : 
    1985     1685898 :         result = typtup->typlen;
    1986     1685898 :         ReleaseSysCache(tp);
    1987     1685898 :         return result;
    1988             :     }
    1989             :     else
    1990           0 :         return 0;
    1991             : }
    1992             : 
    1993             : /*
    1994             :  * get_typbyval
    1995             :  *
    1996             :  *      Given the type OID, determine whether the type is returned by value or
    1997             :  *      not.  Returns true if by value, false if by reference.
    1998             :  */
    1999             : bool
    2000       27978 : get_typbyval(Oid typid)
    2001             : {
    2002             :     HeapTuple   tp;
    2003             : 
    2004       27978 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2005       27978 :     if (HeapTupleIsValid(tp))
    2006             :     {
    2007       27978 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    2008             :         bool        result;
    2009             : 
    2010       27978 :         result = typtup->typbyval;
    2011       27978 :         ReleaseSysCache(tp);
    2012       27978 :         return result;
    2013             :     }
    2014             :     else
    2015           0 :         return false;
    2016             : }
    2017             : 
    2018             : /*
    2019             :  * get_typlenbyval
    2020             :  *
    2021             :  *      A two-fer: given the type OID, return both typlen and typbyval.
    2022             :  *
    2023             :  *      Since both pieces of info are needed to know how to copy a Datum,
    2024             :  *      many places need both.  Might as well get them with one cache lookup
    2025             :  *      instead of two.  Also, this routine raises an error instead of
    2026             :  *      returning a bogus value when given a bad type OID.
    2027             :  */
    2028             : void
    2029      329116 : get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
    2030             : {
    2031             :     HeapTuple   tp;
    2032             :     Form_pg_type typtup;
    2033             : 
    2034      329116 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2035      329116 :     if (!HeapTupleIsValid(tp))
    2036           0 :         elog(ERROR, "cache lookup failed for type %u", typid);
    2037      329116 :     typtup = (Form_pg_type) GETSTRUCT(tp);
    2038      329116 :     *typlen = typtup->typlen;
    2039      329116 :     *typbyval = typtup->typbyval;
    2040      329116 :     ReleaseSysCache(tp);
    2041      329116 : }
    2042             : 
    2043             : /*
    2044             :  * get_typlenbyvalalign
    2045             :  *
    2046             :  *      A three-fer: given the type OID, return typlen, typbyval, typalign.
    2047             :  */
    2048             : void
    2049     2437188 : get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
    2050             :                      char *typalign)
    2051             : {
    2052             :     HeapTuple   tp;
    2053             :     Form_pg_type typtup;
    2054             : 
    2055     2437188 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2056     2437188 :     if (!HeapTupleIsValid(tp))
    2057           0 :         elog(ERROR, "cache lookup failed for type %u", typid);
    2058     2437188 :     typtup = (Form_pg_type) GETSTRUCT(tp);
    2059     2437188 :     *typlen = typtup->typlen;
    2060     2437188 :     *typbyval = typtup->typbyval;
    2061     2437188 :     *typalign = typtup->typalign;
    2062     2437188 :     ReleaseSysCache(tp);
    2063     2437188 : }
    2064             : 
    2065             : /*
    2066             :  * getTypeIOParam
    2067             :  *      Given a pg_type row, select the type OID to pass to I/O functions
    2068             :  *
    2069             :  * Formerly, all I/O functions were passed pg_type.typelem as their second
    2070             :  * parameter, but we now have a more complex rule about what to pass.
    2071             :  * This knowledge is intended to be centralized here --- direct references
    2072             :  * to typelem elsewhere in the code are wrong, if they are associated with
    2073             :  * I/O calls and not with actual subscripting operations!  (But see
    2074             :  * bootstrap.c's boot_get_type_io_data() if you need to change this.)
    2075             :  *
    2076             :  * As of PostgreSQL 8.1, output functions receive only the value itself
    2077             :  * and not any auxiliary parameters, so the name of this routine is now
    2078             :  * a bit of a misnomer ... it should be getTypeInputParam.
    2079             :  */
    2080             : Oid
    2081      843960 : getTypeIOParam(HeapTuple typeTuple)
    2082             : {
    2083      843960 :     Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
    2084             : 
    2085             :     /*
    2086             :      * Array types get their typelem as parameter; everybody else gets their
    2087             :      * own type OID as parameter.
    2088             :      */
    2089      843960 :     if (OidIsValid(typeStruct->typelem))
    2090       93130 :         return typeStruct->typelem;
    2091             :     else
    2092      750830 :         return typeStruct->oid;
    2093             : }
    2094             : 
    2095             : /*
    2096             :  * get_type_io_data
    2097             :  *
    2098             :  *      A six-fer:  given the type OID, return typlen, typbyval, typalign,
    2099             :  *                  typdelim, typioparam, and IO function OID. The IO function
    2100             :  *                  returned is controlled by IOFuncSelector
    2101             :  */
    2102             : void
    2103      125168 : get_type_io_data(Oid typid,
    2104             :                  IOFuncSelector which_func,
    2105             :                  int16 *typlen,
    2106             :                  bool *typbyval,
    2107             :                  char *typalign,
    2108             :                  char *typdelim,
    2109             :                  Oid *typioparam,
    2110             :                  Oid *func)
    2111             : {
    2112             :     HeapTuple   typeTuple;
    2113             :     Form_pg_type typeStruct;
    2114             : 
    2115             :     /*
    2116             :      * In bootstrap mode, pass it off to bootstrap.c.  This hack allows us to
    2117             :      * use array_in and array_out during bootstrap.
    2118             :      */
    2119      125168 :     if (IsBootstrapProcessingMode())
    2120             :     {
    2121             :         Oid         typinput;
    2122             :         Oid         typoutput;
    2123             : 
    2124      100160 :         boot_get_type_io_data(typid,
    2125             :                               typlen,
    2126             :                               typbyval,
    2127             :                               typalign,
    2128             :                               typdelim,
    2129             :                               typioparam,
    2130             :                               &typinput,
    2131             :                               &typoutput);
    2132      100160 :         switch (which_func)
    2133             :         {
    2134             :             case IOFunc_input:
    2135      100160 :                 *func = typinput;
    2136      100160 :                 break;
    2137             :             case IOFunc_output:
    2138           0 :                 *func = typoutput;
    2139           0 :                 break;
    2140             :             default:
    2141           0 :                 elog(ERROR, "binary I/O not supported during bootstrap");
    2142             :                 break;
    2143             :         }
    2144      100160 :         return;
    2145             :     }
    2146             : 
    2147       25008 :     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2148       25008 :     if (!HeapTupleIsValid(typeTuple))
    2149           0 :         elog(ERROR, "cache lookup failed for type %u", typid);
    2150       25008 :     typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
    2151             : 
    2152       25008 :     *typlen = typeStruct->typlen;
    2153       25008 :     *typbyval = typeStruct->typbyval;
    2154       25008 :     *typalign = typeStruct->typalign;
    2155       25008 :     *typdelim = typeStruct->typdelim;
    2156       25008 :     *typioparam = getTypeIOParam(typeTuple);
    2157       25008 :     switch (which_func)
    2158             :     {
    2159             :         case IOFunc_input:
    2160       15660 :             *func = typeStruct->typinput;
    2161       15660 :             break;
    2162             :         case IOFunc_output:
    2163        9348 :             *func = typeStruct->typoutput;
    2164        9348 :             break;
    2165             :         case IOFunc_receive:
    2166           0 :             *func = typeStruct->typreceive;
    2167           0 :             break;
    2168             :         case IOFunc_send:
    2169           0 :             *func = typeStruct->typsend;
    2170           0 :             break;
    2171             :     }
    2172       25008 :     ReleaseSysCache(typeTuple);
    2173             : }
    2174             : 
    2175             : #ifdef NOT_USED
    2176             : char
    2177             : get_typalign(Oid typid)
    2178             : {
    2179             :     HeapTuple   tp;
    2180             : 
    2181             :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2182             :     if (HeapTupleIsValid(tp))
    2183             :     {
    2184             :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    2185             :         char        result;
    2186             : 
    2187             :         result = typtup->typalign;
    2188             :         ReleaseSysCache(tp);
    2189             :         return result;
    2190             :     }
    2191             :     else
    2192             :         return 'i';
    2193             : }
    2194             : #endif
    2195             : 
    2196             : char
    2197       36052 : get_typstorage(Oid typid)
    2198             : {
    2199             :     HeapTuple   tp;
    2200             : 
    2201       36052 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2202       36052 :     if (HeapTupleIsValid(tp))
    2203             :     {
    2204       36052 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    2205             :         char        result;
    2206             : 
    2207       36052 :         result = typtup->typstorage;
    2208       36052 :         ReleaseSysCache(tp);
    2209       36052 :         return result;
    2210             :     }
    2211             :     else
    2212           0 :         return 'p';
    2213             : }
    2214             : 
    2215             : /*
    2216             :  * get_typdefault
    2217             :  *    Given a type OID, return the type's default value, if any.
    2218             :  *
    2219             :  *    The result is a palloc'd expression node tree, or NULL if there
    2220             :  *    is no defined default for the datatype.
    2221             :  *
    2222             :  * NB: caller should be prepared to coerce result to correct datatype;
    2223             :  * the returned expression tree might produce something of the wrong type.
    2224             :  */
    2225             : Node *
    2226       15508 : get_typdefault(Oid typid)
    2227             : {
    2228             :     HeapTuple   typeTuple;
    2229             :     Form_pg_type type;
    2230             :     Datum       datum;
    2231             :     bool        isNull;
    2232             :     Node       *expr;
    2233             : 
    2234       15508 :     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2235       15508 :     if (!HeapTupleIsValid(typeTuple))
    2236           0 :         elog(ERROR, "cache lookup failed for type %u", typid);
    2237       15508 :     type = (Form_pg_type) GETSTRUCT(typeTuple);
    2238             : 
    2239             :     /*
    2240             :      * typdefault and typdefaultbin are potentially null, so don't try to
    2241             :      * access 'em as struct fields. Must do it the hard way with
    2242             :      * SysCacheGetAttr.
    2243             :      */
    2244       15508 :     datum = SysCacheGetAttr(TYPEOID,
    2245             :                             typeTuple,
    2246             :                             Anum_pg_type_typdefaultbin,
    2247             :                             &isNull);
    2248             : 
    2249       15508 :     if (!isNull)
    2250             :     {
    2251             :         /* We have an expression default */
    2252         138 :         expr = stringToNode(TextDatumGetCString(datum));
    2253             :     }
    2254             :     else
    2255             :     {
    2256             :         /* Perhaps we have a plain literal default */
    2257       15370 :         datum = SysCacheGetAttr(TYPEOID,
    2258             :                                 typeTuple,
    2259             :                                 Anum_pg_type_typdefault,
    2260             :                                 &isNull);
    2261             : 
    2262       15370 :         if (!isNull)
    2263             :         {
    2264             :             char       *strDefaultVal;
    2265             : 
    2266             :             /* Convert text datum to C string */
    2267           8 :             strDefaultVal = TextDatumGetCString(datum);
    2268             :             /* Convert C string to a value of the given type */
    2269           8 :             datum = OidInputFunctionCall(type->typinput, strDefaultVal,
    2270             :                                          getTypeIOParam(typeTuple), -1);
    2271             :             /* Build a Const node containing the value */
    2272          16 :             expr = (Node *) makeConst(typid,
    2273             :                                       -1,
    2274             :                                       type->typcollation,
    2275           8 :                                       type->typlen,
    2276             :                                       datum,
    2277             :                                       false,
    2278           8 :                                       type->typbyval);
    2279           8 :             pfree(strDefaultVal);
    2280             :         }
    2281             :         else
    2282             :         {
    2283             :             /* No default */
    2284       15362 :             expr = NULL;
    2285             :         }
    2286             :     }
    2287             : 
    2288       15508 :     ReleaseSysCache(typeTuple);
    2289             : 
    2290       15508 :     return expr;
    2291             : }
    2292             : 
    2293             : /*
    2294             :  * getBaseType
    2295             :  *      If the given type is a domain, return its base type;
    2296             :  *      otherwise return the type's own OID.
    2297             :  */
    2298             : Oid
    2299     4148348 : getBaseType(Oid typid)
    2300             : {
    2301     4148348 :     int32       typmod = -1;
    2302             : 
    2303     4148348 :     return getBaseTypeAndTypmod(typid, &typmod);
    2304             : }
    2305             : 
    2306             : /*
    2307             :  * getBaseTypeAndTypmod
    2308             :  *      If the given type is a domain, return its base type and typmod;
    2309             :  *      otherwise return the type's own OID, and leave *typmod unchanged.
    2310             :  *
    2311             :  * Note that the "applied typmod" should be -1 for every domain level
    2312             :  * above the bottommost; therefore, if the passed-in typid is indeed
    2313             :  * a domain, *typmod should be -1.
    2314             :  */
    2315             : Oid
    2316     6661112 : getBaseTypeAndTypmod(Oid typid, int32 *typmod)
    2317             : {
    2318             :     /*
    2319             :      * We loop to find the bottom base type in a stack of domains.
    2320             :      */
    2321             :     for (;;)
    2322      929118 :     {
    2323             :         HeapTuple   tup;
    2324             :         Form_pg_type typTup;
    2325             : 
    2326     6661112 :         tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2327     6661112 :         if (!HeapTupleIsValid(tup))
    2328           0 :             elog(ERROR, "cache lookup failed for type %u", typid);
    2329     6661112 :         typTup = (Form_pg_type) GETSTRUCT(tup);
    2330     6661112 :         if (typTup->typtype != TYPTYPE_DOMAIN)
    2331             :         {
    2332             :             /* Not a domain, so done */
    2333     5731994 :             ReleaseSysCache(tup);
    2334     5731994 :             break;
    2335             :         }
    2336             : 
    2337             :         Assert(*typmod == -1);
    2338      929118 :         typid = typTup->typbasetype;
    2339      929118 :         *typmod = typTup->typtypmod;
    2340             : 
    2341      929118 :         ReleaseSysCache(tup);
    2342             :     }
    2343             : 
    2344     5731994 :     return typid;
    2345             : }
    2346             : 
    2347             : /*
    2348             :  * get_typavgwidth
    2349             :  *
    2350             :  *    Given a type OID and a typmod value (pass -1 if typmod is unknown),
    2351             :  *    estimate the average width of values of the type.  This is used by
    2352             :  *    the planner, which doesn't require absolutely correct results;
    2353             :  *    it's OK (and expected) to guess if we don't know for sure.
    2354             :  */
    2355             : int32
    2356     1017260 : get_typavgwidth(Oid typid, int32 typmod)
    2357             : {
    2358     1017260 :     int         typlen = get_typlen(typid);
    2359             :     int32       maxwidth;
    2360             : 
    2361             :     /*
    2362             :      * Easy if it's a fixed-width type
    2363             :      */
    2364     1017260 :     if (typlen > 0)
    2365      635922 :         return typlen;
    2366             : 
    2367             :     /*
    2368             :      * type_maximum_size knows the encoding of typmod for some datatypes;
    2369             :      * don't duplicate that knowledge here.
    2370             :      */
    2371      381338 :     maxwidth = type_maximum_size(typid, typmod);
    2372      381338 :     if (maxwidth > 0)
    2373             :     {
    2374             :         /*
    2375             :          * For BPCHAR, the max width is also the only width.  Otherwise we
    2376             :          * need to guess about the typical data width given the max. A sliding
    2377             :          * scale for percentage of max width seems reasonable.
    2378             :          */
    2379       16894 :         if (typid == BPCHAROID)
    2380       10514 :             return maxwidth;
    2381        6380 :         if (maxwidth <= 32)
    2382        3466 :             return maxwidth;    /* assume full width */
    2383        2914 :         if (maxwidth < 1000)
    2384        2826 :             return 32 + (maxwidth - 32) / 2;    /* assume 50% */
    2385             : 
    2386             :         /*
    2387             :          * Beyond 1000, assume we're looking at something like
    2388             :          * "varchar(10000)" where the limit isn't actually reached often, and
    2389             :          * use a fixed estimate.
    2390             :          */
    2391          88 :         return 32 + (1000 - 32) / 2;
    2392             :     }
    2393             : 
    2394             :     /*
    2395             :      * Oops, we have no idea ... wild guess time.
    2396             :      */
    2397      364444 :     return 32;
    2398             : }
    2399             : 
    2400             : /*
    2401             :  * get_typtype
    2402             :  *
    2403             :  *      Given the type OID, find if it is a basic type, a complex type, etc.
    2404             :  *      It returns the null char if the cache lookup fails...
    2405             :  */
    2406             : char
    2407     2485316 : get_typtype(Oid typid)
    2408             : {
    2409             :     HeapTuple   tp;
    2410             : 
    2411     2485316 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2412     2485316 :     if (HeapTupleIsValid(tp))
    2413             :     {
    2414     2485282 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    2415             :         char        result;
    2416             : 
    2417     2485282 :         result = typtup->typtype;
    2418     2485282 :         ReleaseSysCache(tp);
    2419     2485282 :         return result;
    2420             :     }
    2421             :     else
    2422          34 :         return '\0';
    2423             : }
    2424             : 
    2425             : /*
    2426             :  * type_is_rowtype
    2427             :  *
    2428             :  *      Convenience function to determine whether a type OID represents
    2429             :  *      a "rowtype" type --- either RECORD or a named composite type
    2430             :  *      (including a domain over a named composite type).
    2431             :  */
    2432             : bool
    2433     1418692 : type_is_rowtype(Oid typid)
    2434             : {
    2435     1418692 :     if (typid == RECORDOID)
    2436       35412 :         return true;            /* easy case */
    2437     1383280 :     switch (get_typtype(typid))
    2438             :     {
    2439             :         case TYPTYPE_COMPOSITE:
    2440        2208 :             return true;
    2441             :         case TYPTYPE_DOMAIN:
    2442         210 :             if (get_typtype(getBaseType(typid)) == TYPTYPE_COMPOSITE)
    2443          52 :                 return true;
    2444         158 :             break;
    2445             :         default:
    2446     1380862 :             break;
    2447             :     }
    2448     1381020 :     return false;
    2449             : }
    2450             : 
    2451             : /*
    2452             :  * type_is_enum
    2453             :  *    Returns true if the given type is an enum type.
    2454             :  */
    2455             : bool
    2456       41048 : type_is_enum(Oid typid)
    2457             : {
    2458       41048 :     return (get_typtype(typid) == TYPTYPE_ENUM);
    2459             : }
    2460             : 
    2461             : /*
    2462             :  * type_is_range
    2463             :  *    Returns true if the given type is a range type.
    2464             :  */
    2465             : bool
    2466       13628 : type_is_range(Oid typid)
    2467             : {
    2468       13628 :     return (get_typtype(typid) == TYPTYPE_RANGE);
    2469             : }
    2470             : 
    2471             : /*
    2472             :  * get_type_category_preferred
    2473             :  *
    2474             :  *      Given the type OID, fetch its category and preferred-type status.
    2475             :  *      Throws error on failure.
    2476             :  */
    2477             : void
    2478      269470 : get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
    2479             : {
    2480             :     HeapTuple   tp;
    2481             :     Form_pg_type typtup;
    2482             : 
    2483      269470 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2484      269470 :     if (!HeapTupleIsValid(tp))
    2485           0 :         elog(ERROR, "cache lookup failed for type %u", typid);
    2486      269470 :     typtup = (Form_pg_type) GETSTRUCT(tp);
    2487      269470 :     *typcategory = typtup->typcategory;
    2488      269470 :     *typispreferred = typtup->typispreferred;
    2489      269470 :     ReleaseSysCache(tp);
    2490      269470 : }
    2491             : 
    2492             : /*
    2493             :  * get_typ_typrelid
    2494             :  *
    2495             :  *      Given the type OID, get the typrelid (InvalidOid if not a complex
    2496             :  *      type).
    2497             :  */
    2498             : Oid
    2499       20060 : get_typ_typrelid(Oid typid)
    2500             : {
    2501             :     HeapTuple   tp;
    2502             : 
    2503       20060 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2504       20060 :     if (HeapTupleIsValid(tp))
    2505             :     {
    2506       20060 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    2507             :         Oid         result;
    2508             : 
    2509       20060 :         result = typtup->typrelid;
    2510       20060 :         ReleaseSysCache(tp);
    2511       20060 :         return result;
    2512             :     }
    2513             :     else
    2514           0 :         return InvalidOid;
    2515             : }
    2516             : 
    2517             : /*
    2518             :  * get_element_type
    2519             :  *
    2520             :  *      Given the type OID, get the typelem (InvalidOid if not an array type).
    2521             :  *
    2522             :  * NB: this only considers varlena arrays to be true arrays; InvalidOid is
    2523             :  * returned if the input is a fixed-length array type.
    2524             :  */
    2525             : Oid
    2526     1488674 : get_element_type(Oid typid)
    2527             : {
    2528             :     HeapTuple   tp;
    2529             : 
    2530     1488674 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2531     1488674 :     if (HeapTupleIsValid(tp))
    2532             :     {
    2533     1488658 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    2534             :         Oid         result;
    2535             : 
    2536     1488658 :         if (typtup->typlen == -1)
    2537      491926 :             result = typtup->typelem;
    2538             :         else
    2539      996732 :             result = InvalidOid;
    2540     1488658 :         ReleaseSysCache(tp);
    2541     1488658 :         return result;
    2542             :     }
    2543             :     else
    2544          16 :         return InvalidOid;
    2545             : }
    2546             : 
    2547             : /*
    2548             :  * get_array_type
    2549             :  *
    2550             :  *      Given the type OID, get the corresponding "true" array type.
    2551             :  *      Returns InvalidOid if no array type can be found.
    2552             :  */
    2553             : Oid
    2554      117528 : get_array_type(Oid typid)
    2555             : {
    2556             :     HeapTuple   tp;
    2557      117528 :     Oid         result = InvalidOid;
    2558             : 
    2559      117528 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2560      117528 :     if (HeapTupleIsValid(tp))
    2561             :     {
    2562      117528 :         result = ((Form_pg_type) GETSTRUCT(tp))->typarray;
    2563      117528 :         ReleaseSysCache(tp);
    2564             :     }
    2565      117528 :     return result;
    2566             : }
    2567             : 
    2568             : /*
    2569             :  * get_promoted_array_type
    2570             :  *
    2571             :  *      The "promoted" type is what you'd get from an ARRAY(SELECT ...)
    2572             :  *      construct, that is, either the corresponding "true" array type
    2573             :  *      if the input is a scalar type that has such an array type,
    2574             :  *      or the same type if the input is already a "true" array type.
    2575             :  *      Returns InvalidOid if neither rule is satisfied.
    2576             :  */
    2577             : Oid
    2578       30588 : get_promoted_array_type(Oid typid)
    2579             : {
    2580       30588 :     Oid         array_type = get_array_type(typid);
    2581             : 
    2582       30588 :     if (OidIsValid(array_type))
    2583       30564 :         return array_type;
    2584          24 :     if (OidIsValid(get_element_type(typid)))
    2585          24 :         return typid;
    2586           0 :     return InvalidOid;
    2587             : }
    2588             : 
    2589             : /*
    2590             :  * get_base_element_type
    2591             :  *      Given the type OID, get the typelem, looking "through" any domain
    2592             :  *      to its underlying array type.
    2593             :  *
    2594             :  * This is equivalent to get_element_type(getBaseType(typid)), but avoids
    2595             :  * an extra cache lookup.  Note that it fails to provide any information
    2596             :  * about the typmod of the array.
    2597             :  */
    2598             : Oid
    2599      180618 : get_base_element_type(Oid typid)
    2600             : {
    2601             :     /*
    2602             :      * We loop to find the bottom base type in a stack of domains.
    2603             :      */
    2604             :     for (;;)
    2605          44 :     {
    2606             :         HeapTuple   tup;
    2607             :         Form_pg_type typTup;
    2608             : 
    2609      180618 :         tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2610      180618 :         if (!HeapTupleIsValid(tup))
    2611         732 :             break;
    2612      179886 :         typTup = (Form_pg_type) GETSTRUCT(tup);
    2613      179886 :         if (typTup->typtype != TYPTYPE_DOMAIN)
    2614             :         {
    2615             :             /* Not a domain, so stop descending */
    2616             :             Oid         result;
    2617             : 
    2618             :             /* This test must match get_element_type */
    2619      179842 :             if (typTup->typlen == -1)
    2620      110720 :                 result = typTup->typelem;
    2621             :             else
    2622       69122 :                 result = InvalidOid;
    2623      179842 :             ReleaseSysCache(tup);
    2624      179842 :             return result;
    2625             :         }
    2626             : 
    2627          44 :         typid = typTup->typbasetype;
    2628          44 :         ReleaseSysCache(tup);
    2629             :     }
    2630             : 
    2631             :     /* Like get_element_type, silently return InvalidOid for bogus input */
    2632         732 :     return InvalidOid;
    2633             : }
    2634             : 
    2635             : /*
    2636             :  * getTypeInputInfo
    2637             :  *
    2638             :  *      Get info needed for converting values of a type to internal form
    2639             :  */
    2640             : void
    2641      106604 : getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
    2642             : {
    2643             :     HeapTuple   typeTuple;
    2644             :     Form_pg_type pt;
    2645             : 
    2646      106604 :     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
    2647      106604 :     if (!HeapTupleIsValid(typeTuple))
    2648           0 :         elog(ERROR, "cache lookup failed for type %u", type);
    2649      106604 :     pt = (Form_pg_type) GETSTRUCT(typeTuple);
    2650             : 
    2651      106604 :     if (!pt->typisdefined)
    2652           0 :         ereport(ERROR,
    2653             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2654             :                  errmsg("type %s is only a shell",
    2655             :                         format_type_be(type))));
    2656      106604 :     if (!OidIsValid(pt->typinput))
    2657           0 :         ereport(ERROR,
    2658             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    2659             :                  errmsg("no input function available for type %s",
    2660             :                         format_type_be(type))));
    2661             : 
    2662      106604 :     *typInput = pt->typinput;
    2663      106604 :     *typIOParam = getTypeIOParam(typeTuple);
    2664             : 
    2665      106604 :     ReleaseSysCache(typeTuple);
    2666      106604 : }
    2667             : 
    2668             : /*
    2669             :  * getTypeOutputInfo
    2670             :  *
    2671             :  *      Get info needed for printing values of a type
    2672             :  */
    2673             : void
    2674     1008398 : getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
    2675             : {
    2676             :     HeapTuple   typeTuple;
    2677             :     Form_pg_type pt;
    2678             : 
    2679     1008398 :     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
    2680     1008398 :     if (!HeapTupleIsValid(typeTuple))
    2681           0 :         elog(ERROR, "cache lookup failed for type %u", type);
    2682     1008398 :     pt = (Form_pg_type) GETSTRUCT(typeTuple);
    2683             : 
    2684     1008398 :     if (!pt->typisdefined)
    2685           0 :         ereport(ERROR,
    2686             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2687             :                  errmsg("type %s is only a shell",
    2688             :                         format_type_be(type))));
    2689     1008398 :     if (!OidIsValid(pt->typoutput))
    2690           0 :         ereport(ERROR,
    2691             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    2692             :                  errmsg("no output function available for type %s",
    2693             :                         format_type_be(type))));
    2694             : 
    2695     1008398 :     *typOutput = pt->typoutput;
    2696     1008398 :     *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
    2697             : 
    2698     1008398 :     ReleaseSysCache(typeTuple);
    2699     1008398 : }
    2700             : 
    2701             : /*
    2702             :  * getTypeBinaryInputInfo
    2703             :  *
    2704             :  *      Get info needed for binary input of values of a type
    2705             :  */
    2706             : void
    2707        3876 : getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
    2708             : {
    2709             :     HeapTuple   typeTuple;
    2710             :     Form_pg_type pt;
    2711             : 
    2712        3876 :     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
    2713        3876 :     if (!HeapTupleIsValid(typeTuple))
    2714           0 :         elog(ERROR, "cache lookup failed for type %u", type);
    2715        3876 :     pt = (Form_pg_type) GETSTRUCT(typeTuple);
    2716             : 
    2717        3876 :     if (!pt->typisdefined)
    2718           0 :         ereport(ERROR,
    2719             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2720             :                  errmsg("type %s is only a shell",
    2721             :                         format_type_be(type))));
    2722        3876 :     if (!OidIsValid(pt->typreceive))
    2723           0 :         ereport(ERROR,
    2724             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    2725             :                  errmsg("no binary input function available for type %s",
    2726             :                         format_type_be(type))));
    2727             : 
    2728        3876 :     *typReceive = pt->typreceive;
    2729        3876 :     *typIOParam = getTypeIOParam(typeTuple);
    2730             : 
    2731        3876 :     ReleaseSysCache(typeTuple);
    2732        3876 : }
    2733             : 
    2734             : /*
    2735             :  * getTypeBinaryOutputInfo
    2736             :  *
    2737             :  *      Get info needed for binary output of values of a type
    2738             :  */
    2739             : void
    2740        1312 : getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
    2741             : {
    2742             :     HeapTuple   typeTuple;
    2743             :     Form_pg_type pt;
    2744             : 
    2745        1312 :     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
    2746        1312 :     if (!HeapTupleIsValid(typeTuple))
    2747           0 :         elog(ERROR, "cache lookup failed for type %u", type);
    2748        1312 :     pt = (Form_pg_type) GETSTRUCT(typeTuple);
    2749             : 
    2750        1312 :     if (!pt->typisdefined)
    2751           0 :         ereport(ERROR,
    2752             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2753             :                  errmsg("type %s is only a shell",
    2754             :                         format_type_be(type))));
    2755        1312 :     if (!OidIsValid(pt->typsend))
    2756           0 :         ereport(ERROR,
    2757             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    2758             :                  errmsg("no binary output function available for type %s",
    2759             :                         format_type_be(type))));
    2760             : 
    2761        1312 :     *typSend = pt->typsend;
    2762        1312 :     *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
    2763             : 
    2764        1312 :     ReleaseSysCache(typeTuple);
    2765        1312 : }
    2766             : 
    2767             : /*
    2768             :  * get_typmodin
    2769             :  *
    2770             :  *      Given the type OID, return the type's typmodin procedure, if any.
    2771             :  */
    2772             : Oid
    2773           0 : get_typmodin(Oid typid)
    2774             : {
    2775             :     HeapTuple   tp;
    2776             : 
    2777           0 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2778           0 :     if (HeapTupleIsValid(tp))
    2779             :     {
    2780           0 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    2781             :         Oid         result;
    2782             : 
    2783           0 :         result = typtup->typmodin;
    2784           0 :         ReleaseSysCache(tp);
    2785           0 :         return result;
    2786             :     }
    2787             :     else
    2788           0 :         return InvalidOid;
    2789             : }
    2790             : 
    2791             : #ifdef NOT_USED
    2792             : /*
    2793             :  * get_typmodout
    2794             :  *
    2795             :  *      Given the type OID, return the type's typmodout procedure, if any.
    2796             :  */
    2797             : Oid
    2798             : get_typmodout(Oid typid)
    2799             : {
    2800             :     HeapTuple   tp;
    2801             : 
    2802             :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2803             :     if (HeapTupleIsValid(tp))
    2804             :     {
    2805             :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    2806             :         Oid         result;
    2807             : 
    2808             :         result = typtup->typmodout;
    2809             :         ReleaseSysCache(tp);
    2810             :         return result;
    2811             :     }
    2812             :     else
    2813             :         return InvalidOid;
    2814             : }
    2815             : #endif                          /* NOT_USED */
    2816             : 
    2817             : /*
    2818             :  * get_typcollation
    2819             :  *
    2820             :  *      Given the type OID, return the type's typcollation attribute.
    2821             :  */
    2822             : Oid
    2823     3300108 : get_typcollation(Oid typid)
    2824             : {
    2825             :     HeapTuple   tp;
    2826             : 
    2827     3300108 :     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    2828     3300108 :     if (HeapTupleIsValid(tp))
    2829             :     {
    2830     3300100 :         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
    2831             :         Oid         result;
    2832             : 
    2833     3300100 :         result = typtup->typcollation;
    2834     3300100 :         ReleaseSysCache(tp);
    2835     3300100 :         return result;
    2836             :     }
    2837             :     else
    2838           8 :         return InvalidOid;
    2839             : }
    2840             : 
    2841             : 
    2842             : /*
    2843             :  * type_is_collatable
    2844             :  *
    2845             :  *      Return whether the type cares about collations
    2846             :  */
    2847             : bool
    2848      900556 : type_is_collatable(Oid typid)
    2849             : {
    2850      900556 :     return OidIsValid(get_typcollation(typid));
    2851             : }
    2852             : 
    2853             : 
    2854             : /*              ---------- STATISTICS CACHE ----------                   */
    2855             : 
    2856             : /*
    2857             :  * get_attavgwidth
    2858             :  *
    2859             :  *    Given the table and attribute number of a column, get the average
    2860             :  *    width of entries in the column.  Return zero if no data available.
    2861             :  *
    2862             :  * Currently this is only consulted for individual tables, not for inheritance
    2863             :  * trees, so we don't need an "inh" parameter.
    2864             :  *
    2865             :  * Calling a hook at this point looks somewhat strange, but is required
    2866             :  * because the optimizer calls this function without any other way for
    2867             :  * plug-ins to control the result.
    2868             :  */
    2869             : int32
    2870      916654 : get_attavgwidth(Oid relid, AttrNumber attnum)
    2871             : {
    2872             :     HeapTuple   tp;
    2873             :     int32       stawidth;
    2874             : 
    2875      916654 :     if (get_attavgwidth_hook)
    2876             :     {
    2877           0 :         stawidth = (*get_attavgwidth_hook) (relid, attnum);
    2878           0 :         if (stawidth > 0)
    2879           0 :             return stawidth;
    2880             :     }
    2881      916654 :     tp = SearchSysCache3(STATRELATTINH,
    2882             :                          ObjectIdGetDatum(relid),
    2883             :                          Int16GetDatum(attnum),
    2884             :                          BoolGetDatum(false));
    2885      916654 :     if (HeapTupleIsValid(tp))
    2886             :     {
    2887      529884 :         stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
    2888      529884 :         ReleaseSysCache(tp);
    2889      529884 :         if (stawidth > 0)
    2890      506072 :             return stawidth;
    2891             :     }
    2892      410582 :     return 0;
    2893             : }
    2894             : 
    2895             : /*
    2896             :  * get_attstatsslot
    2897             :  *
    2898             :  *      Extract the contents of a "slot" of a pg_statistic tuple.
    2899             :  *      Returns true if requested slot type was found, else false.
    2900             :  *
    2901             :  * Unlike other routines in this file, this takes a pointer to an
    2902             :  * already-looked-up tuple in the pg_statistic cache.  We do this since
    2903             :  * most callers will want to extract more than one value from the cache
    2904             :  * entry, and we don't want to repeat the cache lookup unnecessarily.
    2905             :  * Also, this API allows this routine to be used with statistics tuples
    2906             :  * that have been provided by a stats hook and didn't really come from
    2907             :  * pg_statistic.
    2908             :  *
    2909             :  * sslot: pointer to output area (typically, a local variable in the caller).
    2910             :  * statstuple: pg_statistic tuple to be examined.
    2911             :  * reqkind: STAKIND code for desired statistics slot kind.
    2912             :  * reqop: STAOP value wanted, or InvalidOid if don't care.
    2913             :  * flags: bitmask of ATTSTATSSLOT_VALUES and/or ATTSTATSSLOT_NUMBERS.
    2914             :  *
    2915             :  * If a matching slot is found, true is returned, and *sslot is filled thus:
    2916             :  * staop: receives the actual STAOP value.
    2917             :  * stacoll: receives the actual STACOLL value.
    2918             :  * valuetype: receives actual datatype of the elements of stavalues.
    2919             :  * values: receives pointer to an array of the slot's stavalues.
    2920             :  * nvalues: receives number of stavalues.
    2921             :  * numbers: receives pointer to an array of the slot's stanumbers (as float4).
    2922             :  * nnumbers: receives number of stanumbers.
    2923             :  *
    2924             :  * valuetype/values/nvalues are InvalidOid/NULL/0 if ATTSTATSSLOT_VALUES
    2925             :  * wasn't specified.  Likewise, numbers/nnumbers are NULL/0 if
    2926             :  * ATTSTATSSLOT_NUMBERS wasn't specified.
    2927             :  *
    2928             :  * If no matching slot is found, false is returned, and *sslot is zeroed.
    2929             :  *
    2930             :  * Note that the current API doesn't allow for searching for a slot with
    2931             :  * a particular collation.  If we ever actually support recording more than
    2932             :  * one collation, we'll have to extend the API, but for now simple is good.
    2933             :  *
    2934             :  * The data referred to by the fields of sslot is locally palloc'd and
    2935             :  * is independent of the original pg_statistic tuple.  When the caller
    2936             :  * is done with it, call free_attstatsslot to release the palloc'd data.
    2937             :  *
    2938             :  * If it's desirable to call free_attstatsslot when get_attstatsslot might
    2939             :  * not have been called, memset'ing sslot to zeroes will allow that.
    2940             :  */
    2941             : bool
    2942     1071992 : get_attstatsslot(AttStatsSlot *sslot, HeapTuple statstuple,
    2943             :                  int reqkind, Oid reqop, int flags)
    2944             : {
    2945     1071992 :     Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(statstuple);
    2946             :     int         i;
    2947             :     Datum       val;
    2948             :     bool        isnull;
    2949             :     ArrayType  *statarray;
    2950             :     Oid         arrayelemtype;
    2951             :     int         narrayelem;
    2952             :     HeapTuple   typeTuple;
    2953             :     Form_pg_type typeForm;
    2954             : 
    2955             :     /* initialize *sslot properly */
    2956     1071992 :     memset(sslot, 0, sizeof(AttStatsSlot));
    2957             : 
    2958     2877026 :     for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
    2959             :     {
    2960     2604422 :         if ((&stats->stakind1)[i] == reqkind &&
    2961      333836 :             (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
    2962             :             break;
    2963             :     }
    2964     1071992 :     if (i >= STATISTIC_NUM_SLOTS)
    2965      272604 :         return false;           /* not there */
    2966             : 
    2967      799388 :     sslot->staop = (&stats->staop1)[i];
    2968      799388 :     sslot->stacoll = (&stats->stacoll1)[i];
    2969             : 
    2970             :     /*
    2971             :      * XXX Hopefully-temporary hack: if stacoll isn't set, inject the default
    2972             :      * collation.  This won't matter for non-collation-aware datatypes.  For
    2973             :      * those that are, this covers cases where stacoll has not been set.  In
    2974             :      * the short term we need this because some code paths involving type NAME
    2975             :      * do not pass any collation to prefix_selectivity and related functions.
    2976             :      * Even when that's been fixed, it's likely that some add-on typanalyze
    2977             :      * functions won't get the word right away about filling stacoll during
    2978             :      * ANALYZE, so we'll probably need this for awhile.
    2979             :      */
    2980      799388 :     if (sslot->stacoll == InvalidOid)
    2981      760780 :         sslot->stacoll = DEFAULT_COLLATION_OID;
    2982             : 
    2983      799388 :     if (flags & ATTSTATSSLOT_VALUES)
    2984             :     {
    2985      447374 :         val = SysCacheGetAttr(STATRELATTINH, statstuple,
    2986      447374 :                               Anum_pg_statistic_stavalues1 + i,
    2987             :                               &isnull);
    2988      447374 :         if (isnull)
    2989           0 :             elog(ERROR, "stavalues is null");
    2990             : 
    2991             :         /*
    2992             :          * Detoast the array if needed, and in any case make a copy that's
    2993             :          * under control of this AttStatsSlot.
    2994             :          */
    2995      447374 :         statarray = DatumGetArrayTypePCopy(val);
    2996             : 
    2997             :         /*
    2998             :          * Extract the actual array element type, and pass it back in case the
    2999             :          * caller needs it.
    3000             :          */
    3001      447374 :         sslot->valuetype = arrayelemtype = ARR_ELEMTYPE(statarray);
    3002             : 
    3003             :         /* Need info about element type */
    3004      447374 :         typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrayelemtype));
    3005      447374 :         if (!HeapTupleIsValid(typeTuple))
    3006           0 :             elog(ERROR, "cache lookup failed for type %u", arrayelemtype);
    3007      447374 :         typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
    3008             : 
    3009             :         /* Deconstruct array into Datum elements; NULLs not expected */
    3010     1789496 :         deconstruct_array(statarray,
    3011             :                           arrayelemtype,
    3012      447374 :                           typeForm->typlen,
    3013      447374 :                           typeForm->typbyval,
    3014      447374 :                           typeForm->typalign,
    3015             :                           &sslot->values, NULL, &sslot->nvalues);
    3016             : 
    3017             :         /*
    3018             :          * If the element type is pass-by-reference, we now have a bunch of
    3019             :          * Datums that are pointers into the statarray, so we need to keep
    3020             :          * that until free_attstatsslot.  Otherwise, all the useful info is in
    3021             :          * sslot->values[], so we can free the array object immediately.
    3022             :          */
    3023      447374 :         if (!typeForm->typbyval)
    3024       12662 :             sslot->values_arr = statarray;
    3025             :         else
    3026      434712 :             pfree(statarray);
    3027             : 
    3028      447374 :         ReleaseSysCache(typeTuple);
    3029             :     }
    3030             : 
    3031      799388 :     if (flags & ATTSTATSSLOT_NUMBERS)
    3032             :     {
    3033      575142 :         val = SysCacheGetAttr(STATRELATTINH, statstuple,
    3034      575142 :                               Anum_pg_statistic_stanumbers1 + i,
    3035             :                               &isnull);
    3036      575142 :         if (isnull)
    3037           0 :             elog(ERROR, "stanumbers is null");
    3038             : 
    3039             :         /*
    3040             :          * Detoast the array if needed, and in any case make a copy that's
    3041             :          * under control of this AttStatsSlot.
    3042             :          */
    3043      575142 :         statarray = DatumGetArrayTypePCopy(val);
    3044             : 
    3045             :         /*
    3046             :          * We expect the array to be a 1-D float4 array; verify that. We don't
    3047             :          * need to use deconstruct_array() since the array data is just going
    3048             :          * to look like a C array of float4 values.
    3049             :          */
    3050      575142 :         narrayelem = ARR_DIMS(statarray)[0];
    3051     1150284 :         if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
    3052     1150284 :             ARR_HASNULL(statarray) ||
    3053      575142 :             ARR_ELEMTYPE(statarray) != FLOAT4OID)
    3054           0 :             elog(ERROR, "stanumbers is not a 1-D float4 array");
    3055             : 
    3056             :         /* Give caller a pointer directly into the statarray */
    3057      575142 :         sslot->numbers = (float4 *) ARR_DATA_PTR(statarray);
    3058      575142 :         sslot->nnumbers = narrayelem;
    3059             : 
    3060             :         /* We'll free the statarray in free_attstatsslot */
    3061      575142 :         sslot->numbers_arr = statarray;
    3062             :     }
    3063             : 
    3064      799388 :     return true;
    3065             : }
    3066             : 
    3067             : /*
    3068             :  * free_attstatsslot
    3069             :  *      Free data allocated by get_attstatsslot
    3070             :  */
    3071             : void
    3072      963210 : free_attstatsslot(AttStatsSlot *sslot)
    3073             : {
    3074             :     /* The values[] array was separately palloc'd by deconstruct_array */
    3075      963210 :     if (sslot->values)
    3076      447374 :         pfree(sslot->values);
    3077             :     /* The numbers[] array points into numbers_arr, do not pfree it */
    3078             :     /* Free the detoasted array objects, if any */
    3079      963210 :     if (sslot->values_arr)
    3080       12662 :         pfree(sslot->values_arr);
    3081      963210 :     if (sslot->numbers_arr)
    3082      575142 :         pfree(sslot->numbers_arr);
    3083      963210 : }
    3084             : 
    3085             : /*              ---------- PG_NAMESPACE CACHE ----------                 */
    3086             : 
    3087             : /*
    3088             :  * get_namespace_name
    3089             :  *      Returns the name of a given namespace
    3090             :  *
    3091             :  * Returns a palloc'd copy of the string, or NULL if no such namespace.
    3092             :  */
    3093             : char *
    3094      519998 : get_namespace_name(Oid nspid)
    3095             : {
    3096             :     HeapTuple   tp;
    3097             : 
    3098      519998 :     tp = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid));
    3099      519998 :     if (HeapTupleIsValid(tp))
    3100             :     {
    3101      519998 :         Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
    3102             :         char       *result;
    3103             : 
    3104      519998 :         result = pstrdup(NameStr(nsptup->nspname));
    3105      519998 :         ReleaseSysCache(tp);
    3106      519998 :         return result;
    3107             :     }
    3108             :     else
    3109           0 :         return NULL;
    3110             : }
    3111             : 
    3112             : /*
    3113             :  * get_namespace_name_or_temp
    3114             :  *      As above, but if it is this backend's temporary namespace, return
    3115             :  *      "pg_temp" instead.
    3116             :  */
    3117             : char *
    3118       11126 : get_namespace_name_or_temp(Oid nspid)
    3119             : {
    3120       11126 :     if (isTempNamespace(nspid))
    3121          24 :         return "pg_temp";
    3122             :     else
    3123       11102 :         return get_namespace_name(nspid);
    3124             : }
    3125             : 
    3126             : /*              ---------- PG_RANGE CACHE ----------                 */
    3127             : 
    3128             : /*
    3129             :  * get_range_subtype
    3130             :  *      Returns the subtype of a given range type
    3131             :  *
    3132             :  * Returns InvalidOid if the type is not a range type.
    3133             :  */
    3134             : Oid
    3135        5554 : get_range_subtype(Oid rangeOid)
    3136             : {
    3137             :     HeapTuple   tp;
    3138             : 
    3139        5554 :     tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
    3140        5554 :     if (HeapTupleIsValid(tp))
    3141             :     {
    3142        1416 :         Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
    3143             :         Oid         result;
    3144             : 
    3145        1416 :         result = rngtup->rngsubtype;
    3146        1416 :         ReleaseSysCache(tp);
    3147        1416 :         return result;
    3148             :     }
    3149             :     else
    3150        4138 :         return InvalidOid;
    3151             : }
    3152             : 
    3153             : /*              ---------- PG_INDEX CACHE ----------                 */
    3154             : 
    3155             : /*
    3156             :  * get_index_column_opclass
    3157             :  *
    3158             :  *      Given the index OID and column number,
    3159             :  *      return opclass of the index column
    3160             :  *          or InvalidOid if the index was not found
    3161             :  *              or column is non-key one.
    3162             :  */
    3163             : Oid
    3164          24 : get_index_column_opclass(Oid index_oid, int attno)
    3165             : {
    3166             :     HeapTuple   tuple;
    3167             :     Form_pg_index rd_index PG_USED_FOR_ASSERTS_ONLY;
    3168             :     Datum       datum;
    3169             :     bool        isnull;
    3170             :     oidvector  *indclass;
    3171             :     Oid         opclass;
    3172             : 
    3173             :     /* First we need to know the column's opclass. */
    3174             : 
    3175          24 :     tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
    3176          24 :     if (!HeapTupleIsValid(tuple))
    3177           0 :         return InvalidOid;
    3178             : 
    3179          24 :     rd_index = (Form_pg_index) GETSTRUCT(tuple);
    3180             : 
    3181             :     /* caller is supposed to guarantee this */
    3182             :     Assert(attno > 0 && attno <= rd_index->indnatts);
    3183             : 
    3184             :     /* Non-key attributes don't have an opclass */
    3185          24 :     if (attno > rd_index->indnkeyatts)
    3186             :     {
    3187           0 :         ReleaseSysCache(tuple);
    3188           0 :         return InvalidOid;
    3189             :     }
    3190             : 
    3191          24 :     datum = SysCacheGetAttr(INDEXRELID, tuple,
    3192             :                             Anum_pg_index_indclass, &isnull);
    3193             :     Assert(!isnull);
    3194             : 
    3195          24 :     indclass = ((oidvector *) DatumGetPointer(datum));
    3196             : 
    3197             :     Assert(attno <= indclass->dim1);
    3198          24 :     opclass = indclass->values[attno - 1];
    3199             : 
    3200          24 :     ReleaseSysCache(tuple);
    3201             : 
    3202          24 :     return opclass;
    3203             : }

Generated by: LCOV version 1.13