Header And Logo

PostgreSQL
| The world's most advanced open source database.

lsyscache.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * lsyscache.c
00004  *    Convenience routines for common queries in the system catalog cache.
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  * IDENTIFICATION
00010  *    src/backend/utils/cache/lsyscache.c
00011  *
00012  * NOTES
00013  *    Eventually, the index information should go through here, too.
00014  *-------------------------------------------------------------------------
00015  */
00016 #include "postgres.h"
00017 
00018 #include "access/hash.h"
00019 #include "access/htup_details.h"
00020 #include "access/nbtree.h"
00021 #include "bootstrap/bootstrap.h"
00022 #include "catalog/pg_amop.h"
00023 #include "catalog/pg_amproc.h"
00024 #include "catalog/pg_collation.h"
00025 #include "catalog/pg_constraint.h"
00026 #include "catalog/pg_namespace.h"
00027 #include "catalog/pg_opclass.h"
00028 #include "catalog/pg_operator.h"
00029 #include "catalog/pg_proc.h"
00030 #include "catalog/pg_range.h"
00031 #include "catalog/pg_statistic.h"
00032 #include "catalog/pg_type.h"
00033 #include "miscadmin.h"
00034 #include "nodes/makefuncs.h"
00035 #include "utils/array.h"
00036 #include "utils/builtins.h"
00037 #include "utils/catcache.h"
00038 #include "utils/datum.h"
00039 #include "utils/fmgroids.h"
00040 #include "utils/lsyscache.h"
00041 #include "utils/rel.h"
00042 #include "utils/syscache.h"
00043 #include "utils/typcache.h"
00044 
00045 /* Hook for plugins to get control in get_attavgwidth() */
00046 get_attavgwidth_hook_type get_attavgwidth_hook = NULL;
00047 
00048 
00049 /*              ---------- AMOP CACHES ----------                        */
00050 
00051 /*
00052  * op_in_opfamily
00053  *
00054  *      Return t iff operator 'opno' is in operator family 'opfamily'.
00055  *
00056  * This function only considers search operators, not ordering operators.
00057  */
00058 bool
00059 op_in_opfamily(Oid opno, Oid opfamily)
00060 {
00061     return SearchSysCacheExists3(AMOPOPID,
00062                                  ObjectIdGetDatum(opno),
00063                                  CharGetDatum(AMOP_SEARCH),
00064                                  ObjectIdGetDatum(opfamily));
00065 }
00066 
00067 /*
00068  * get_op_opfamily_strategy
00069  *
00070  *      Get the operator's strategy number within the specified opfamily,
00071  *      or 0 if it's not a member of the opfamily.
00072  *
00073  * This function only considers search operators, not ordering operators.
00074  */
00075 int
00076 get_op_opfamily_strategy(Oid opno, Oid opfamily)
00077 {
00078     HeapTuple   tp;
00079     Form_pg_amop amop_tup;
00080     int         result;
00081 
00082     tp = SearchSysCache3(AMOPOPID,
00083                          ObjectIdGetDatum(opno),
00084                          CharGetDatum(AMOP_SEARCH),
00085                          ObjectIdGetDatum(opfamily));
00086     if (!HeapTupleIsValid(tp))
00087         return 0;
00088     amop_tup = (Form_pg_amop) GETSTRUCT(tp);
00089     result = amop_tup->amopstrategy;
00090     ReleaseSysCache(tp);
00091     return result;
00092 }
00093 
00094 /*
00095  * get_op_opfamily_sortfamily
00096  *
00097  *      If the operator is an ordering operator within the specified opfamily,
00098  *      return its amopsortfamily OID; else return InvalidOid.
00099  */
00100 Oid
00101 get_op_opfamily_sortfamily(Oid opno, Oid opfamily)
00102 {
00103     HeapTuple   tp;
00104     Form_pg_amop amop_tup;
00105     Oid         result;
00106 
00107     tp = SearchSysCache3(AMOPOPID,
00108                          ObjectIdGetDatum(opno),
00109                          CharGetDatum(AMOP_ORDER),
00110                          ObjectIdGetDatum(opfamily));
00111     if (!HeapTupleIsValid(tp))
00112         return InvalidOid;
00113     amop_tup = (Form_pg_amop) GETSTRUCT(tp);
00114     result = amop_tup->amopsortfamily;
00115     ReleaseSysCache(tp);
00116     return result;
00117 }
00118 
00119 /*
00120  * get_op_opfamily_properties
00121  *
00122  *      Get the operator's strategy number and declared input data types
00123  *      within the specified opfamily.
00124  *
00125  * Caller should already have verified that opno is a member of opfamily,
00126  * therefore we raise an error if the tuple is not found.
00127  */
00128 void
00129 get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op,
00130                            int *strategy,
00131                            Oid *lefttype,
00132                            Oid *righttype)
00133 {
00134     HeapTuple   tp;
00135     Form_pg_amop amop_tup;
00136 
00137     tp = SearchSysCache3(AMOPOPID,
00138                          ObjectIdGetDatum(opno),
00139                          CharGetDatum(ordering_op ? AMOP_ORDER : AMOP_SEARCH),
00140                          ObjectIdGetDatum(opfamily));
00141     if (!HeapTupleIsValid(tp))
00142         elog(ERROR, "operator %u is not a member of opfamily %u",
00143              opno, opfamily);
00144     amop_tup = (Form_pg_amop) GETSTRUCT(tp);
00145     *strategy = amop_tup->amopstrategy;
00146     *lefttype = amop_tup->amoplefttype;
00147     *righttype = amop_tup->amoprighttype;
00148     ReleaseSysCache(tp);
00149 }
00150 
00151 /*
00152  * get_opfamily_member
00153  *      Get the OID of the operator that implements the specified strategy
00154  *      with the specified datatypes for the specified opfamily.
00155  *
00156  * Returns InvalidOid if there is no pg_amop entry for the given keys.
00157  */
00158 Oid
00159 get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
00160                     int16 strategy)
00161 {
00162     HeapTuple   tp;
00163     Form_pg_amop amop_tup;
00164     Oid         result;
00165 
00166     tp = SearchSysCache4(AMOPSTRATEGY,
00167                          ObjectIdGetDatum(opfamily),
00168                          ObjectIdGetDatum(lefttype),
00169                          ObjectIdGetDatum(righttype),
00170                          Int16GetDatum(strategy));
00171     if (!HeapTupleIsValid(tp))
00172         return InvalidOid;
00173     amop_tup = (Form_pg_amop) GETSTRUCT(tp);
00174     result = amop_tup->amopopr;
00175     ReleaseSysCache(tp);
00176     return result;
00177 }
00178 
00179 /*
00180  * get_ordering_op_properties
00181  *      Given the OID of an ordering operator (a btree "<" or ">" operator),
00182  *      determine its opfamily, its declared input datatype, and its
00183  *      strategy number (BTLessStrategyNumber or BTGreaterStrategyNumber).
00184  *
00185  * Returns TRUE if successful, FALSE if no matching pg_amop entry exists.
00186  * (This indicates that the operator is not a valid ordering operator.)
00187  *
00188  * Note: the operator could be registered in multiple families, for example
00189  * if someone were to build a "reverse sort" opfamily.  This would result in
00190  * uncertainty as to whether "ORDER BY USING op" would default to NULLS FIRST
00191  * or NULLS LAST, as well as inefficient planning due to failure to match up
00192  * pathkeys that should be the same.  So we want a determinate result here.
00193  * Because of the way the syscache search works, we'll use the interpretation
00194  * associated with the opfamily with smallest OID, which is probably
00195  * determinate enough.  Since there is no longer any particularly good reason
00196  * to build reverse-sort opfamilies, it doesn't seem worth expending any
00197  * additional effort on ensuring consistency.
00198  */
00199 bool
00200 get_ordering_op_properties(Oid opno,
00201                            Oid *opfamily, Oid *opcintype, int16 *strategy)
00202 {
00203     bool        result = false;
00204     CatCList   *catlist;
00205     int         i;
00206 
00207     /* ensure outputs are initialized on failure */
00208     *opfamily = InvalidOid;
00209     *opcintype = InvalidOid;
00210     *strategy = 0;
00211 
00212     /*
00213      * Search pg_amop to see if the target operator is registered as the "<"
00214      * or ">" operator of any btree opfamily.
00215      */
00216     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
00217 
00218     for (i = 0; i < catlist->n_members; i++)
00219     {
00220         HeapTuple   tuple = &catlist->members[i]->tuple;
00221         Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
00222 
00223         /* must be btree */
00224         if (aform->amopmethod != BTREE_AM_OID)
00225             continue;
00226 
00227         if (aform->amopstrategy == BTLessStrategyNumber ||
00228             aform->amopstrategy == BTGreaterStrategyNumber)
00229         {
00230             /* Found it ... should have consistent input types */
00231             if (aform->amoplefttype == aform->amoprighttype)
00232             {
00233                 /* Found a suitable opfamily, return info */
00234                 *opfamily = aform->amopfamily;
00235                 *opcintype = aform->amoplefttype;
00236                 *strategy = aform->amopstrategy;
00237                 result = true;
00238                 break;
00239             }
00240         }
00241     }
00242 
00243     ReleaseSysCacheList(catlist);
00244 
00245     return result;
00246 }
00247 
00248 /*
00249  * get_sort_function_for_ordering_op
00250  *      Get the OID of the datatype-specific btree sort support function,
00251  *      or if there is none, the btree comparison function,
00252  *      associated with an ordering operator (a "<" or ">" operator).
00253  *
00254  * *sortfunc receives the support or comparison function OID.
00255  * *issupport is set TRUE if it's a support func, FALSE if a comparison func.
00256  * *reverse is set FALSE if the operator is "<", TRUE if it's ">"
00257  * (indicating that comparison results must be negated before use).
00258  *
00259  * Returns TRUE if successful, FALSE if no btree function can be found.
00260  * (This indicates that the operator is not a valid ordering operator.)
00261  */
00262 bool
00263 get_sort_function_for_ordering_op(Oid opno, Oid *sortfunc,
00264                                   bool *issupport, bool *reverse)
00265 {
00266     Oid         opfamily;
00267     Oid         opcintype;
00268     int16       strategy;
00269 
00270     /* Find the operator in pg_amop */
00271     if (get_ordering_op_properties(opno,
00272                                    &opfamily, &opcintype, &strategy))
00273     {
00274         /* Found a suitable opfamily, get matching support function */
00275         *sortfunc = get_opfamily_proc(opfamily,
00276                                       opcintype,
00277                                       opcintype,
00278                                       BTSORTSUPPORT_PROC);
00279         if (OidIsValid(*sortfunc))
00280             *issupport = true;
00281         else
00282         {
00283             /* opfamily doesn't provide sort support, get comparison func */
00284             *sortfunc = get_opfamily_proc(opfamily,
00285                                           opcintype,
00286                                           opcintype,
00287                                           BTORDER_PROC);
00288             if (!OidIsValid(*sortfunc)) /* should not happen */
00289                 elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
00290                      BTORDER_PROC, opcintype, opcintype, opfamily);
00291             *issupport = false;
00292         }
00293         *reverse = (strategy == BTGreaterStrategyNumber);
00294         return true;
00295     }
00296 
00297     /* ensure outputs are set on failure */
00298     *sortfunc = InvalidOid;
00299     *issupport = false;
00300     *reverse = false;
00301     return false;
00302 }
00303 
00304 /*
00305  * get_equality_op_for_ordering_op
00306  *      Get the OID of the datatype-specific btree equality operator
00307  *      associated with an ordering operator (a "<" or ">" operator).
00308  *
00309  * If "reverse" isn't NULL, also set *reverse to FALSE if the operator is "<",
00310  * TRUE if it's ">"
00311  *
00312  * Returns InvalidOid if no matching equality operator can be found.
00313  * (This indicates that the operator is not a valid ordering operator.)
00314  */
00315 Oid
00316 get_equality_op_for_ordering_op(Oid opno, bool *reverse)
00317 {
00318     Oid         result = InvalidOid;
00319     Oid         opfamily;
00320     Oid         opcintype;
00321     int16       strategy;
00322 
00323     /* Find the operator in pg_amop */
00324     if (get_ordering_op_properties(opno,
00325                                    &opfamily, &opcintype, &strategy))
00326     {
00327         /* Found a suitable opfamily, get matching equality operator */
00328         result = get_opfamily_member(opfamily,
00329                                      opcintype,
00330                                      opcintype,
00331                                      BTEqualStrategyNumber);
00332         if (reverse)
00333             *reverse = (strategy == BTGreaterStrategyNumber);
00334     }
00335 
00336     return result;
00337 }
00338 
00339 /*
00340  * get_ordering_op_for_equality_op
00341  *      Get the OID of a datatype-specific btree ordering operator
00342  *      associated with an equality operator.  (If there are multiple
00343  *      possibilities, assume any one will do.)
00344  *
00345  * This function is used when we have to sort data before unique-ifying,
00346  * and don't much care which sorting op is used as long as it's compatible
00347  * with the intended equality operator.  Since we need a sorting operator,
00348  * it should be single-data-type even if the given operator is cross-type.
00349  * The caller specifies whether to find an op for the LHS or RHS data type.
00350  *
00351  * Returns InvalidOid if no matching ordering operator can be found.
00352  */
00353 Oid
00354 get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type)
00355 {
00356     Oid         result = InvalidOid;
00357     CatCList   *catlist;
00358     int         i;
00359 
00360     /*
00361      * Search pg_amop to see if the target operator is registered as the "="
00362      * operator of any btree opfamily.
00363      */
00364     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
00365 
00366     for (i = 0; i < catlist->n_members; i++)
00367     {
00368         HeapTuple   tuple = &catlist->members[i]->tuple;
00369         Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
00370 
00371         /* must be btree */
00372         if (aform->amopmethod != BTREE_AM_OID)
00373             continue;
00374 
00375         if (aform->amopstrategy == BTEqualStrategyNumber)
00376         {
00377             /* Found a suitable opfamily, get matching ordering operator */
00378             Oid         typid;
00379 
00380             typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
00381             result = get_opfamily_member(aform->amopfamily,
00382                                          typid, typid,
00383                                          BTLessStrategyNumber);
00384             if (OidIsValid(result))
00385                 break;
00386             /* failure probably shouldn't happen, but keep looking if so */
00387         }
00388     }
00389 
00390     ReleaseSysCacheList(catlist);
00391 
00392     return result;
00393 }
00394 
00395 /*
00396  * get_mergejoin_opfamilies
00397  *      Given a putatively mergejoinable operator, return a list of the OIDs
00398  *      of the btree opfamilies in which it represents equality.
00399  *
00400  * It is possible (though at present unusual) for an operator to be equality
00401  * in more than one opfamily, hence the result is a list.  This also lets us
00402  * return NIL if the operator is not found in any opfamilies.
00403  *
00404  * The planner currently uses simple equal() tests to compare the lists
00405  * returned by this function, which makes the list order relevant, though
00406  * strictly speaking it should not be.  Because of the way syscache list
00407  * searches are handled, in normal operation the result will be sorted by OID
00408  * so everything works fine.  If running with system index usage disabled,
00409  * the result ordering is unspecified and hence the planner might fail to
00410  * recognize optimization opportunities ... but that's hardly a scenario in
00411  * which performance is good anyway, so there's no point in expending code
00412  * or cycles here to guarantee the ordering in that case.
00413  */
00414 List *
00415 get_mergejoin_opfamilies(Oid opno)
00416 {
00417     List       *result = NIL;
00418     CatCList   *catlist;
00419     int         i;
00420 
00421     /*
00422      * Search pg_amop to see if the target operator is registered as the "="
00423      * operator of any btree opfamily.
00424      */
00425     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
00426 
00427     for (i = 0; i < catlist->n_members; i++)
00428     {
00429         HeapTuple   tuple = &catlist->members[i]->tuple;
00430         Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
00431 
00432         /* must be btree equality */
00433         if (aform->amopmethod == BTREE_AM_OID &&
00434             aform->amopstrategy == BTEqualStrategyNumber)
00435             result = lappend_oid(result, aform->amopfamily);
00436     }
00437 
00438     ReleaseSysCacheList(catlist);
00439 
00440     return result;
00441 }
00442 
00443 /*
00444  * get_compatible_hash_operators
00445  *      Get the OID(s) of hash equality operator(s) compatible with the given
00446  *      operator, but operating on its LHS and/or RHS datatype.
00447  *
00448  * An operator for the LHS type is sought and returned into *lhs_opno if
00449  * lhs_opno isn't NULL.  Similarly, an operator for the RHS type is sought
00450  * and returned into *rhs_opno if rhs_opno isn't NULL.
00451  *
00452  * If the given operator is not cross-type, the results should be the same
00453  * operator, but in cross-type situations they will be different.
00454  *
00455  * Returns true if able to find the requested operator(s), false if not.
00456  * (This indicates that the operator should not have been marked oprcanhash.)
00457  */
00458 bool
00459 get_compatible_hash_operators(Oid opno,
00460                               Oid *lhs_opno, Oid *rhs_opno)
00461 {
00462     bool        result = false;
00463     CatCList   *catlist;
00464     int         i;
00465 
00466     /* Ensure output args are initialized on failure */
00467     if (lhs_opno)
00468         *lhs_opno = InvalidOid;
00469     if (rhs_opno)
00470         *rhs_opno = InvalidOid;
00471 
00472     /*
00473      * Search pg_amop to see if the target operator is registered as the "="
00474      * operator of any hash opfamily.  If the operator is registered in
00475      * multiple opfamilies, assume we can use any one.
00476      */
00477     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
00478 
00479     for (i = 0; i < catlist->n_members; i++)
00480     {
00481         HeapTuple   tuple = &catlist->members[i]->tuple;
00482         Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
00483 
00484         if (aform->amopmethod == HASH_AM_OID &&
00485             aform->amopstrategy == HTEqualStrategyNumber)
00486         {
00487             /* No extra lookup needed if given operator is single-type */
00488             if (aform->amoplefttype == aform->amoprighttype)
00489             {
00490                 if (lhs_opno)
00491                     *lhs_opno = opno;
00492                 if (rhs_opno)
00493                     *rhs_opno = opno;
00494                 result = true;
00495                 break;
00496             }
00497 
00498             /*
00499              * Get the matching single-type operator(s).  Failure probably
00500              * shouldn't happen --- it implies a bogus opfamily --- but
00501              * continue looking if so.
00502              */
00503             if (lhs_opno)
00504             {
00505                 *lhs_opno = get_opfamily_member(aform->amopfamily,
00506                                                 aform->amoplefttype,
00507                                                 aform->amoplefttype,
00508                                                 HTEqualStrategyNumber);
00509                 if (!OidIsValid(*lhs_opno))
00510                     continue;
00511                 /* Matching LHS found, done if caller doesn't want RHS */
00512                 if (!rhs_opno)
00513                 {
00514                     result = true;
00515                     break;
00516                 }
00517             }
00518             if (rhs_opno)
00519             {
00520                 *rhs_opno = get_opfamily_member(aform->amopfamily,
00521                                                 aform->amoprighttype,
00522                                                 aform->amoprighttype,
00523                                                 HTEqualStrategyNumber);
00524                 if (!OidIsValid(*rhs_opno))
00525                 {
00526                     /* Forget any LHS operator from this opfamily */
00527                     if (lhs_opno)
00528                         *lhs_opno = InvalidOid;
00529                     continue;
00530                 }
00531                 /* Matching RHS found, so done */
00532                 result = true;
00533                 break;
00534             }
00535         }
00536     }
00537 
00538     ReleaseSysCacheList(catlist);
00539 
00540     return result;
00541 }
00542 
00543 /*
00544  * get_op_hash_functions
00545  *      Get the OID(s) of hash support function(s) compatible with the given
00546  *      operator, operating on its LHS and/or RHS datatype as required.
00547  *
00548  * A function for the LHS type is sought and returned into *lhs_procno if
00549  * lhs_procno isn't NULL.  Similarly, a function for the RHS type is sought
00550  * and returned into *rhs_procno if rhs_procno isn't NULL.
00551  *
00552  * If the given operator is not cross-type, the results should be the same
00553  * function, but in cross-type situations they will be different.
00554  *
00555  * Returns true if able to find the requested function(s), false if not.
00556  * (This indicates that the operator should not have been marked oprcanhash.)
00557  */
00558 bool
00559 get_op_hash_functions(Oid opno,
00560                       RegProcedure *lhs_procno, RegProcedure *rhs_procno)
00561 {
00562     bool        result = false;
00563     CatCList   *catlist;
00564     int         i;
00565 
00566     /* Ensure output args are initialized on failure */
00567     if (lhs_procno)
00568         *lhs_procno = InvalidOid;
00569     if (rhs_procno)
00570         *rhs_procno = InvalidOid;
00571 
00572     /*
00573      * Search pg_amop to see if the target operator is registered as the "="
00574      * operator of any hash opfamily.  If the operator is registered in
00575      * multiple opfamilies, assume we can use any one.
00576      */
00577     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
00578 
00579     for (i = 0; i < catlist->n_members; i++)
00580     {
00581         HeapTuple   tuple = &catlist->members[i]->tuple;
00582         Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
00583 
00584         if (aform->amopmethod == HASH_AM_OID &&
00585             aform->amopstrategy == HTEqualStrategyNumber)
00586         {
00587             /*
00588              * Get the matching support function(s).  Failure probably
00589              * shouldn't happen --- it implies a bogus opfamily --- but
00590              * continue looking if so.
00591              */
00592             if (lhs_procno)
00593             {
00594                 *lhs_procno = get_opfamily_proc(aform->amopfamily,
00595                                                 aform->amoplefttype,
00596                                                 aform->amoplefttype,
00597                                                 HASHPROC);
00598                 if (!OidIsValid(*lhs_procno))
00599                     continue;
00600                 /* Matching LHS found, done if caller doesn't want RHS */
00601                 if (!rhs_procno)
00602                 {
00603                     result = true;
00604                     break;
00605                 }
00606                 /* Only one lookup needed if given operator is single-type */
00607                 if (aform->amoplefttype == aform->amoprighttype)
00608                 {
00609                     *rhs_procno = *lhs_procno;
00610                     result = true;
00611                     break;
00612                 }
00613             }
00614             if (rhs_procno)
00615             {
00616                 *rhs_procno = get_opfamily_proc(aform->amopfamily,
00617                                                 aform->amoprighttype,
00618                                                 aform->amoprighttype,
00619                                                 HASHPROC);
00620                 if (!OidIsValid(*rhs_procno))
00621                 {
00622                     /* Forget any LHS function from this opfamily */
00623                     if (lhs_procno)
00624                         *lhs_procno = InvalidOid;
00625                     continue;
00626                 }
00627                 /* Matching RHS found, so done */
00628                 result = true;
00629                 break;
00630             }
00631         }
00632     }
00633 
00634     ReleaseSysCacheList(catlist);
00635 
00636     return result;
00637 }
00638 
00639 /*
00640  * get_op_btree_interpretation
00641  *      Given an operator's OID, find out which btree opfamilies it belongs to,
00642  *      and what properties it has within each one.  The results are returned
00643  *      as a palloc'd list of OpBtreeInterpretation structs.
00644  *
00645  * In addition to the normal btree operators, we consider a <> operator to be
00646  * a "member" of an opfamily if its negator is an equality operator of the
00647  * opfamily.  ROWCOMPARE_NE is returned as the strategy number for this case.
00648  */
00649 List *
00650 get_op_btree_interpretation(Oid opno)
00651 {
00652     List       *result = NIL;
00653     OpBtreeInterpretation *thisresult;
00654     CatCList   *catlist;
00655     int         i;
00656 
00657     /*
00658      * Find all the pg_amop entries containing the operator.
00659      */
00660     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
00661 
00662     for (i = 0; i < catlist->n_members; i++)
00663     {
00664         HeapTuple   op_tuple = &catlist->members[i]->tuple;
00665         Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
00666         StrategyNumber op_strategy;
00667 
00668         /* must be btree */
00669         if (op_form->amopmethod != BTREE_AM_OID)
00670             continue;
00671 
00672         /* Get the operator's btree strategy number */
00673         op_strategy = (StrategyNumber) op_form->amopstrategy;
00674         Assert(op_strategy >= 1 && op_strategy <= 5);
00675 
00676         thisresult = (OpBtreeInterpretation *)
00677             palloc(sizeof(OpBtreeInterpretation));
00678         thisresult->opfamily_id = op_form->amopfamily;
00679         thisresult->strategy = op_strategy;
00680         thisresult->oplefttype = op_form->amoplefttype;
00681         thisresult->oprighttype = op_form->amoprighttype;
00682         result = lappend(result, thisresult);
00683     }
00684 
00685     ReleaseSysCacheList(catlist);
00686 
00687     /*
00688      * If we didn't find any btree opfamily containing the operator, perhaps
00689      * it is a <> operator.  See if it has a negator that is in an opfamily.
00690      */
00691     if (result == NIL)
00692     {
00693         Oid         op_negator = get_negator(opno);
00694 
00695         if (OidIsValid(op_negator))
00696         {
00697             catlist = SearchSysCacheList1(AMOPOPID,
00698                                           ObjectIdGetDatum(op_negator));
00699 
00700             for (i = 0; i < catlist->n_members; i++)
00701             {
00702                 HeapTuple   op_tuple = &catlist->members[i]->tuple;
00703                 Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
00704                 StrategyNumber op_strategy;
00705 
00706                 /* must be btree */
00707                 if (op_form->amopmethod != BTREE_AM_OID)
00708                     continue;
00709 
00710                 /* Get the operator's btree strategy number */
00711                 op_strategy = (StrategyNumber) op_form->amopstrategy;
00712                 Assert(op_strategy >= 1 && op_strategy <= 5);
00713 
00714                 /* Only consider negators that are = */
00715                 if (op_strategy != BTEqualStrategyNumber)
00716                     continue;
00717 
00718                 /* OK, report it with "strategy" ROWCOMPARE_NE */
00719                 thisresult = (OpBtreeInterpretation *)
00720                     palloc(sizeof(OpBtreeInterpretation));
00721                 thisresult->opfamily_id = op_form->amopfamily;
00722                 thisresult->strategy = ROWCOMPARE_NE;
00723                 thisresult->oplefttype = op_form->amoplefttype;
00724                 thisresult->oprighttype = op_form->amoprighttype;
00725                 result = lappend(result, thisresult);
00726             }
00727 
00728             ReleaseSysCacheList(catlist);
00729         }
00730     }
00731 
00732     return result;
00733 }
00734 
00735 /*
00736  * equality_ops_are_compatible
00737  *      Return TRUE if the two given equality operators have compatible
00738  *      semantics.
00739  *
00740  * This is trivially true if they are the same operator.  Otherwise,
00741  * we look to see if they can be found in the same btree or hash opfamily.
00742  * Either finding allows us to assume that they have compatible notions
00743  * of equality.  (The reason we need to do these pushups is that one might
00744  * be a cross-type operator; for instance int24eq vs int4eq.)
00745  */
00746 bool
00747 equality_ops_are_compatible(Oid opno1, Oid opno2)
00748 {
00749     bool        result;
00750     CatCList   *catlist;
00751     int         i;
00752 
00753     /* Easy if they're the same operator */
00754     if (opno1 == opno2)
00755         return true;
00756 
00757     /*
00758      * We search through all the pg_amop entries for opno1.
00759      */
00760     catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno1));
00761 
00762     result = false;
00763     for (i = 0; i < catlist->n_members; i++)
00764     {
00765         HeapTuple   op_tuple = &catlist->members[i]->tuple;
00766         Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
00767 
00768         /* must be btree or hash */
00769         if (op_form->amopmethod == BTREE_AM_OID ||
00770             op_form->amopmethod == HASH_AM_OID)
00771         {
00772             if (op_in_opfamily(opno2, op_form->amopfamily))
00773             {
00774                 result = true;
00775                 break;
00776             }
00777         }
00778     }
00779 
00780     ReleaseSysCacheList(catlist);
00781 
00782     return result;
00783 }
00784 
00785 
00786 /*              ---------- AMPROC CACHES ----------                      */
00787 
00788 /*
00789  * get_opfamily_proc
00790  *      Get the OID of the specified support function
00791  *      for the specified opfamily and datatypes.
00792  *
00793  * Returns InvalidOid if there is no pg_amproc entry for the given keys.
00794  */
00795 Oid
00796 get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
00797 {
00798     HeapTuple   tp;
00799     Form_pg_amproc amproc_tup;
00800     RegProcedure result;
00801 
00802     tp = SearchSysCache4(AMPROCNUM,
00803                          ObjectIdGetDatum(opfamily),
00804                          ObjectIdGetDatum(lefttype),
00805                          ObjectIdGetDatum(righttype),
00806                          Int16GetDatum(procnum));
00807     if (!HeapTupleIsValid(tp))
00808         return InvalidOid;
00809     amproc_tup = (Form_pg_amproc) GETSTRUCT(tp);
00810     result = amproc_tup->amproc;
00811     ReleaseSysCache(tp);
00812     return result;
00813 }
00814 
00815 
00816 /*              ---------- ATTRIBUTE CACHES ----------                   */
00817 
00818 /*
00819  * get_attname
00820  *      Given the relation id and the attribute number,
00821  *      return the "attname" field from the attribute relation.
00822  *
00823  * Note: returns a palloc'd copy of the string, or NULL if no such attribute.
00824  */
00825 char *
00826 get_attname(Oid relid, AttrNumber attnum)
00827 {
00828     HeapTuple   tp;
00829 
00830     tp = SearchSysCache2(ATTNUM,
00831                          ObjectIdGetDatum(relid),
00832                          Int16GetDatum(attnum));
00833     if (HeapTupleIsValid(tp))
00834     {
00835         Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
00836         char       *result;
00837 
00838         result = pstrdup(NameStr(att_tup->attname));
00839         ReleaseSysCache(tp);
00840         return result;
00841     }
00842     else
00843         return NULL;
00844 }
00845 
00846 /*
00847  * get_relid_attribute_name
00848  *
00849  * Same as above routine get_attname(), except that error
00850  * is handled by elog() instead of returning NULL.
00851  */
00852 char *
00853 get_relid_attribute_name(Oid relid, AttrNumber attnum)
00854 {
00855     char       *attname;
00856 
00857     attname = get_attname(relid, attnum);
00858     if (attname == NULL)
00859         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
00860              attnum, relid);
00861     return attname;
00862 }
00863 
00864 /*
00865  * get_attnum
00866  *
00867  *      Given the relation id and the attribute name,
00868  *      return the "attnum" field from the attribute relation.
00869  *
00870  *      Returns InvalidAttrNumber if the attr doesn't exist (or is dropped).
00871  */
00872 AttrNumber
00873 get_attnum(Oid relid, const char *attname)
00874 {
00875     HeapTuple   tp;
00876 
00877     tp = SearchSysCacheAttName(relid, attname);
00878     if (HeapTupleIsValid(tp))
00879     {
00880         Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
00881         AttrNumber  result;
00882 
00883         result = att_tup->attnum;
00884         ReleaseSysCache(tp);
00885         return result;
00886     }
00887     else
00888         return InvalidAttrNumber;
00889 }
00890 
00891 /*
00892  * get_atttype
00893  *
00894  *      Given the relation OID and the attribute number with the relation,
00895  *      return the attribute type OID.
00896  */
00897 Oid
00898 get_atttype(Oid relid, AttrNumber attnum)
00899 {
00900     HeapTuple   tp;
00901 
00902     tp = SearchSysCache2(ATTNUM,
00903                          ObjectIdGetDatum(relid),
00904                          Int16GetDatum(attnum));
00905     if (HeapTupleIsValid(tp))
00906     {
00907         Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
00908         Oid         result;
00909 
00910         result = att_tup->atttypid;
00911         ReleaseSysCache(tp);
00912         return result;
00913     }
00914     else
00915         return InvalidOid;
00916 }
00917 
00918 /*
00919  * get_atttypmod
00920  *
00921  *      Given the relation id and the attribute number,
00922  *      return the "atttypmod" field from the attribute relation.
00923  */
00924 int32
00925 get_atttypmod(Oid relid, AttrNumber attnum)
00926 {
00927     HeapTuple   tp;
00928 
00929     tp = SearchSysCache2(ATTNUM,
00930                          ObjectIdGetDatum(relid),
00931                          Int16GetDatum(attnum));
00932     if (HeapTupleIsValid(tp))
00933     {
00934         Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
00935         int32       result;
00936 
00937         result = att_tup->atttypmod;
00938         ReleaseSysCache(tp);
00939         return result;
00940     }
00941     else
00942         return -1;
00943 }
00944 
00945 /*
00946  * get_atttypetypmodcoll
00947  *
00948  *      A three-fer: given the relation id and the attribute number,
00949  *      fetch atttypid, atttypmod, and attcollation in a single cache lookup.
00950  *
00951  * Unlike the otherwise-similar get_atttype/get_atttypmod, this routine
00952  * raises an error if it can't obtain the information.
00953  */
00954 void
00955 get_atttypetypmodcoll(Oid relid, AttrNumber attnum,
00956                       Oid *typid, int32 *typmod, Oid *collid)
00957 {
00958     HeapTuple   tp;
00959     Form_pg_attribute att_tup;
00960 
00961     tp = SearchSysCache2(ATTNUM,
00962                          ObjectIdGetDatum(relid),
00963                          Int16GetDatum(attnum));
00964     if (!HeapTupleIsValid(tp))
00965         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
00966              attnum, relid);
00967     att_tup = (Form_pg_attribute) GETSTRUCT(tp);
00968 
00969     *typid = att_tup->atttypid;
00970     *typmod = att_tup->atttypmod;
00971     *collid = att_tup->attcollation;
00972     ReleaseSysCache(tp);
00973 }
00974 
00975 /*              ---------- COLLATION CACHE ----------                    */
00976 
00977 /*
00978  * get_collation_name
00979  *      Returns the name of a given pg_collation entry.
00980  *
00981  * Returns a palloc'd copy of the string, or NULL if no such constraint.
00982  *
00983  * NOTE: since collation name is not unique, be wary of code that uses this
00984  * for anything except preparing error messages.
00985  */
00986 char *
00987 get_collation_name(Oid colloid)
00988 {
00989     HeapTuple   tp;
00990 
00991     tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(colloid));
00992     if (HeapTupleIsValid(tp))
00993     {
00994         Form_pg_collation colltup = (Form_pg_collation) GETSTRUCT(tp);
00995         char       *result;
00996 
00997         result = pstrdup(NameStr(colltup->collname));
00998         ReleaseSysCache(tp);
00999         return result;
01000     }
01001     else
01002         return NULL;
01003 }
01004 
01005 /*              ---------- CONSTRAINT CACHE ----------                   */
01006 
01007 /*
01008  * get_constraint_name
01009  *      Returns the name of a given pg_constraint entry.
01010  *
01011  * Returns a palloc'd copy of the string, or NULL if no such constraint.
01012  *
01013  * NOTE: since constraint name is not unique, be wary of code that uses this
01014  * for anything except preparing error messages.
01015  */
01016 char *
01017 get_constraint_name(Oid conoid)
01018 {
01019     HeapTuple   tp;
01020 
01021     tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conoid));
01022     if (HeapTupleIsValid(tp))
01023     {
01024         Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp);
01025         char       *result;
01026 
01027         result = pstrdup(NameStr(contup->conname));
01028         ReleaseSysCache(tp);
01029         return result;
01030     }
01031     else
01032         return NULL;
01033 }
01034 
01035 /*              ---------- OPCLASS CACHE ----------                      */
01036 
01037 /*
01038  * get_opclass_family
01039  *
01040  *      Returns the OID of the operator family the opclass belongs to.
01041  */
01042 Oid
01043 get_opclass_family(Oid opclass)
01044 {
01045     HeapTuple   tp;
01046     Form_pg_opclass cla_tup;
01047     Oid         result;
01048 
01049     tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
01050     if (!HeapTupleIsValid(tp))
01051         elog(ERROR, "cache lookup failed for opclass %u", opclass);
01052     cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
01053 
01054     result = cla_tup->opcfamily;
01055     ReleaseSysCache(tp);
01056     return result;
01057 }
01058 
01059 /*
01060  * get_opclass_input_type
01061  *
01062  *      Returns the OID of the datatype the opclass indexes.
01063  */
01064 Oid
01065 get_opclass_input_type(Oid opclass)
01066 {
01067     HeapTuple   tp;
01068     Form_pg_opclass cla_tup;
01069     Oid         result;
01070 
01071     tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
01072     if (!HeapTupleIsValid(tp))
01073         elog(ERROR, "cache lookup failed for opclass %u", opclass);
01074     cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
01075 
01076     result = cla_tup->opcintype;
01077     ReleaseSysCache(tp);
01078     return result;
01079 }
01080 
01081 /*              ---------- OPERATOR CACHE ----------                     */
01082 
01083 /*
01084  * get_opcode
01085  *
01086  *      Returns the regproc id of the routine used to implement an
01087  *      operator given the operator oid.
01088  */
01089 RegProcedure
01090 get_opcode(Oid opno)
01091 {
01092     HeapTuple   tp;
01093 
01094     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
01095     if (HeapTupleIsValid(tp))
01096     {
01097         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
01098         RegProcedure result;
01099 
01100         result = optup->oprcode;
01101         ReleaseSysCache(tp);
01102         return result;
01103     }
01104     else
01105         return (RegProcedure) InvalidOid;
01106 }
01107 
01108 /*
01109  * get_opname
01110  *    returns the name of the operator with the given opno
01111  *
01112  * Note: returns a palloc'd copy of the string, or NULL if no such operator.
01113  */
01114 char *
01115 get_opname(Oid opno)
01116 {
01117     HeapTuple   tp;
01118 
01119     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
01120     if (HeapTupleIsValid(tp))
01121     {
01122         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
01123         char       *result;
01124 
01125         result = pstrdup(NameStr(optup->oprname));
01126         ReleaseSysCache(tp);
01127         return result;
01128     }
01129     else
01130         return NULL;
01131 }
01132 
01133 /*
01134  * op_input_types
01135  *
01136  *      Returns the left and right input datatypes for an operator
01137  *      (InvalidOid if not relevant).
01138  */
01139 void
01140 op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
01141 {
01142     HeapTuple   tp;
01143     Form_pg_operator optup;
01144 
01145     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
01146     if (!HeapTupleIsValid(tp))  /* shouldn't happen */
01147         elog(ERROR, "cache lookup failed for operator %u", opno);
01148     optup = (Form_pg_operator) GETSTRUCT(tp);
01149     *lefttype = optup->oprleft;
01150     *righttype = optup->oprright;
01151     ReleaseSysCache(tp);
01152 }
01153 
01154 /*
01155  * op_mergejoinable
01156  *
01157  * Returns true if the operator is potentially mergejoinable.  (The planner
01158  * will fail to find any mergejoin plans unless there are suitable btree
01159  * opfamily entries for this operator and associated sortops.  The pg_operator
01160  * flag is just a hint to tell the planner whether to bother looking.)
01161  *
01162  * In some cases (currently only array_eq and record_eq), mergejoinability
01163  * depends on the specific input data type the operator is invoked for, so
01164  * that must be passed as well. We currently assume that only one input's type
01165  * is needed to check this --- by convention, pass the left input's data type.
01166  */
01167 bool
01168 op_mergejoinable(Oid opno, Oid inputtype)
01169 {
01170     bool        result = false;
01171     HeapTuple   tp;
01172     TypeCacheEntry *typentry;
01173 
01174     /*
01175      * For array_eq or record_eq, we can sort if the element or field types
01176      * are all sortable.  We could implement all the checks for that here, but
01177      * the typcache already does that and caches the results too, so let's
01178      * rely on the typcache.
01179      */
01180     if (opno == ARRAY_EQ_OP)
01181     {
01182         typentry = lookup_type_cache(inputtype, TYPECACHE_CMP_PROC);
01183         if (typentry->cmp_proc == F_BTARRAYCMP)
01184             result = true;
01185     }
01186     else if (opno == RECORD_EQ_OP)
01187     {
01188         typentry = lookup_type_cache(inputtype, TYPECACHE_CMP_PROC);
01189         if (typentry->cmp_proc == F_BTRECORDCMP)
01190             result = true;
01191     }
01192     else
01193     {
01194         /* For all other operators, rely on pg_operator.oprcanmerge */
01195         tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
01196         if (HeapTupleIsValid(tp))
01197         {
01198             Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
01199 
01200             result = optup->oprcanmerge;
01201             ReleaseSysCache(tp);
01202         }
01203     }
01204     return result;
01205 }
01206 
01207 /*
01208  * op_hashjoinable
01209  *
01210  * Returns true if the operator is hashjoinable.  (There must be a suitable
01211  * hash opfamily entry for this operator if it is so marked.)
01212  *
01213  * In some cases (currently only array_eq), hashjoinability depends on the
01214  * specific input data type the operator is invoked for, so that must be
01215  * passed as well.  We currently assume that only one input's type is needed
01216  * to check this --- by convention, pass the left input's data type.
01217  */
01218 bool
01219 op_hashjoinable(Oid opno, Oid inputtype)
01220 {
01221     bool        result = false;
01222     HeapTuple   tp;
01223     TypeCacheEntry *typentry;
01224 
01225     /* As in op_mergejoinable, let the typcache handle the hard cases */
01226     /* Eventually we'll need a similar case for record_eq ... */
01227     if (opno == ARRAY_EQ_OP)
01228     {
01229         typentry = lookup_type_cache(inputtype, TYPECACHE_HASH_PROC);
01230         if (typentry->hash_proc == F_HASH_ARRAY)
01231             result = true;
01232     }
01233     else
01234     {
01235         /* For all other operators, rely on pg_operator.oprcanhash */
01236         tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
01237         if (HeapTupleIsValid(tp))
01238         {
01239             Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
01240 
01241             result = optup->oprcanhash;
01242             ReleaseSysCache(tp);
01243         }
01244     }
01245     return result;
01246 }
01247 
01248 /*
01249  * op_strict
01250  *
01251  * Get the proisstrict flag for the operator's underlying function.
01252  */
01253 bool
01254 op_strict(Oid opno)
01255 {
01256     RegProcedure funcid = get_opcode(opno);
01257 
01258     if (funcid == (RegProcedure) InvalidOid)
01259         elog(ERROR, "operator %u does not exist", opno);
01260 
01261     return func_strict((Oid) funcid);
01262 }
01263 
01264 /*
01265  * op_volatile
01266  *
01267  * Get the provolatile flag for the operator's underlying function.
01268  */
01269 char
01270 op_volatile(Oid opno)
01271 {
01272     RegProcedure funcid = get_opcode(opno);
01273 
01274     if (funcid == (RegProcedure) InvalidOid)
01275         elog(ERROR, "operator %u does not exist", opno);
01276 
01277     return func_volatile((Oid) funcid);
01278 }
01279 
01280 /*
01281  * get_commutator
01282  *
01283  *      Returns the corresponding commutator of an operator.
01284  */
01285 Oid
01286 get_commutator(Oid opno)
01287 {
01288     HeapTuple   tp;
01289 
01290     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
01291     if (HeapTupleIsValid(tp))
01292     {
01293         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
01294         Oid         result;
01295 
01296         result = optup->oprcom;
01297         ReleaseSysCache(tp);
01298         return result;
01299     }
01300     else
01301         return InvalidOid;
01302 }
01303 
01304 /*
01305  * get_negator
01306  *
01307  *      Returns the corresponding negator of an operator.
01308  */
01309 Oid
01310 get_negator(Oid opno)
01311 {
01312     HeapTuple   tp;
01313 
01314     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
01315     if (HeapTupleIsValid(tp))
01316     {
01317         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
01318         Oid         result;
01319 
01320         result = optup->oprnegate;
01321         ReleaseSysCache(tp);
01322         return result;
01323     }
01324     else
01325         return InvalidOid;
01326 }
01327 
01328 /*
01329  * get_oprrest
01330  *
01331  *      Returns procedure id for computing selectivity of an operator.
01332  */
01333 RegProcedure
01334 get_oprrest(Oid opno)
01335 {
01336     HeapTuple   tp;
01337 
01338     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
01339     if (HeapTupleIsValid(tp))
01340     {
01341         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
01342         RegProcedure result;
01343 
01344         result = optup->oprrest;
01345         ReleaseSysCache(tp);
01346         return result;
01347     }
01348     else
01349         return (RegProcedure) InvalidOid;
01350 }
01351 
01352 /*
01353  * get_oprjoin
01354  *
01355  *      Returns procedure id for computing selectivity of a join.
01356  */
01357 RegProcedure
01358 get_oprjoin(Oid opno)
01359 {
01360     HeapTuple   tp;
01361 
01362     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
01363     if (HeapTupleIsValid(tp))
01364     {
01365         Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
01366         RegProcedure result;
01367 
01368         result = optup->oprjoin;
01369         ReleaseSysCache(tp);
01370         return result;
01371     }
01372     else
01373         return (RegProcedure) InvalidOid;
01374 }
01375 
01376 /*              ---------- FUNCTION CACHE ----------                     */
01377 
01378 /*
01379  * get_func_name
01380  *    returns the name of the function with the given funcid
01381  *
01382  * Note: returns a palloc'd copy of the string, or NULL if no such function.
01383  */
01384 char *
01385 get_func_name(Oid funcid)
01386 {
01387     HeapTuple   tp;
01388 
01389     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
01390     if (HeapTupleIsValid(tp))
01391     {
01392         Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
01393         char       *result;
01394 
01395         result = pstrdup(NameStr(functup->proname));
01396         ReleaseSysCache(tp);
01397         return result;
01398     }
01399     else
01400         return NULL;
01401 }
01402 
01403 /*
01404  * get_func_namespace
01405  *
01406  *      Returns the pg_namespace OID associated with a given function.
01407  */
01408 Oid
01409 get_func_namespace(Oid funcid)
01410 {
01411     HeapTuple   tp;
01412 
01413     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
01414     if (HeapTupleIsValid(tp))
01415     {
01416         Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
01417         Oid         result;
01418 
01419         result = functup->pronamespace;
01420         ReleaseSysCache(tp);
01421         return result;
01422     }
01423     else
01424         return InvalidOid;
01425 }
01426 
01427 /*
01428  * get_func_rettype
01429  *      Given procedure id, return the function's result type.
01430  */
01431 Oid
01432 get_func_rettype(Oid funcid)
01433 {
01434     HeapTuple   tp;
01435     Oid         result;
01436 
01437     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
01438     if (!HeapTupleIsValid(tp))
01439         elog(ERROR, "cache lookup failed for function %u", funcid);
01440 
01441     result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
01442     ReleaseSysCache(tp);
01443     return result;
01444 }
01445 
01446 /*
01447  * get_func_nargs
01448  *      Given procedure id, return the number of arguments.
01449  */
01450 int
01451 get_func_nargs(Oid funcid)
01452 {
01453     HeapTuple   tp;
01454     int         result;
01455 
01456     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
01457     if (!HeapTupleIsValid(tp))
01458         elog(ERROR, "cache lookup failed for function %u", funcid);
01459 
01460     result = ((Form_pg_proc) GETSTRUCT(tp))->pronargs;
01461     ReleaseSysCache(tp);
01462     return result;
01463 }
01464 
01465 /*
01466  * get_func_signature
01467  *      Given procedure id, return the function's argument and result types.
01468  *      (The return value is the result type.)
01469  *
01470  * The arguments are returned as a palloc'd array.
01471  */
01472 Oid
01473 get_func_signature(Oid funcid, Oid **argtypes, int *nargs)
01474 {
01475     HeapTuple   tp;
01476     Form_pg_proc procstruct;
01477     Oid         result;
01478 
01479     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
01480     if (!HeapTupleIsValid(tp))
01481         elog(ERROR, "cache lookup failed for function %u", funcid);
01482 
01483     procstruct = (Form_pg_proc) GETSTRUCT(tp);
01484 
01485     result = procstruct->prorettype;
01486     *nargs = (int) procstruct->pronargs;
01487     Assert(*nargs == procstruct->proargtypes.dim1);
01488     *argtypes = (Oid *) palloc(*nargs * sizeof(Oid));
01489     memcpy(*argtypes, procstruct->proargtypes.values, *nargs * sizeof(Oid));
01490 
01491     ReleaseSysCache(tp);
01492     return result;
01493 }
01494 
01495 /*
01496  * get_func_retset
01497  *      Given procedure id, return the function's proretset flag.
01498  */
01499 bool
01500 get_func_retset(Oid funcid)
01501 {
01502     HeapTuple   tp;
01503     bool        result;
01504 
01505     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
01506     if (!HeapTupleIsValid(tp))
01507         elog(ERROR, "cache lookup failed for function %u", funcid);
01508 
01509     result = ((Form_pg_proc) GETSTRUCT(tp))->proretset;
01510     ReleaseSysCache(tp);
01511     return result;
01512 }
01513 
01514 /*
01515  * func_strict
01516  *      Given procedure id, return the function's proisstrict flag.
01517  */
01518 bool
01519 func_strict(Oid funcid)
01520 {
01521     HeapTuple   tp;
01522     bool        result;
01523 
01524     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
01525     if (!HeapTupleIsValid(tp))
01526         elog(ERROR, "cache lookup failed for function %u", funcid);
01527 
01528     result = ((Form_pg_proc) GETSTRUCT(tp))->proisstrict;
01529     ReleaseSysCache(tp);
01530     return result;
01531 }
01532 
01533 /*
01534  * func_volatile
01535  *      Given procedure id, return the function's provolatile flag.
01536  */
01537 char
01538 func_volatile(Oid funcid)
01539 {
01540     HeapTuple   tp;
01541     char        result;
01542 
01543     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
01544     if (!HeapTupleIsValid(tp))
01545         elog(ERROR, "cache lookup failed for function %u", funcid);
01546 
01547     result = ((Form_pg_proc) GETSTRUCT(tp))->provolatile;
01548     ReleaseSysCache(tp);
01549     return result;
01550 }
01551 
01552 /*
01553  * get_func_leakproof
01554  *     Given procedure id, return the function's leakproof field.
01555  */
01556 bool
01557 get_func_leakproof(Oid funcid)
01558 {
01559     HeapTuple   tp;
01560     bool        result;
01561 
01562     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
01563     if (!HeapTupleIsValid(tp))
01564         elog(ERROR, "cache lookup failed for function %u", funcid);
01565 
01566     result = ((Form_pg_proc) GETSTRUCT(tp))->proleakproof;
01567     ReleaseSysCache(tp);
01568     return result;
01569 }
01570 
01571 /*
01572  * get_func_cost
01573  *      Given procedure id, return the function's procost field.
01574  */
01575 float4
01576 get_func_cost(Oid funcid)
01577 {
01578     HeapTuple   tp;
01579     float4      result;
01580 
01581     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
01582     if (!HeapTupleIsValid(tp))
01583         elog(ERROR, "cache lookup failed for function %u", funcid);
01584 
01585     result = ((Form_pg_proc) GETSTRUCT(tp))->procost;
01586     ReleaseSysCache(tp);
01587     return result;
01588 }
01589 
01590 /*
01591  * get_func_rows
01592  *      Given procedure id, return the function's prorows field.
01593  */
01594 float4
01595 get_func_rows(Oid funcid)
01596 {
01597     HeapTuple   tp;
01598     float4      result;
01599 
01600     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
01601     if (!HeapTupleIsValid(tp))
01602         elog(ERROR, "cache lookup failed for function %u", funcid);
01603 
01604     result = ((Form_pg_proc) GETSTRUCT(tp))->prorows;
01605     ReleaseSysCache(tp);
01606     return result;
01607 }
01608 
01609 /*              ---------- RELATION CACHE ----------                     */
01610 
01611 /*
01612  * get_relname_relid
01613  *      Given name and namespace of a relation, look up the OID.
01614  *
01615  * Returns InvalidOid if there is no such relation.
01616  */
01617 Oid
01618 get_relname_relid(const char *relname, Oid relnamespace)
01619 {
01620     return GetSysCacheOid2(RELNAMENSP,
01621                            PointerGetDatum(relname),
01622                            ObjectIdGetDatum(relnamespace));
01623 }
01624 
01625 #ifdef NOT_USED
01626 /*
01627  * get_relnatts
01628  *
01629  *      Returns the number of attributes for a given relation.
01630  */
01631 int
01632 get_relnatts(Oid relid)
01633 {
01634     HeapTuple   tp;
01635 
01636     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
01637     if (HeapTupleIsValid(tp))
01638     {
01639         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
01640         int         result;
01641 
01642         result = reltup->relnatts;
01643         ReleaseSysCache(tp);
01644         return result;
01645     }
01646     else
01647         return InvalidAttrNumber;
01648 }
01649 #endif
01650 
01651 /*
01652  * get_rel_name
01653  *      Returns the name of a given relation.
01654  *
01655  * Returns a palloc'd copy of the string, or NULL if no such relation.
01656  *
01657  * NOTE: since relation name is not unique, be wary of code that uses this
01658  * for anything except preparing error messages.
01659  */
01660 char *
01661 get_rel_name(Oid relid)
01662 {
01663     HeapTuple   tp;
01664 
01665     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
01666     if (HeapTupleIsValid(tp))
01667     {
01668         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
01669         char       *result;
01670 
01671         result = pstrdup(NameStr(reltup->relname));
01672         ReleaseSysCache(tp);
01673         return result;
01674     }
01675     else
01676         return NULL;
01677 }
01678 
01679 /*
01680  * get_rel_namespace
01681  *
01682  *      Returns the pg_namespace OID associated with a given relation.
01683  */
01684 Oid
01685 get_rel_namespace(Oid relid)
01686 {
01687     HeapTuple   tp;
01688 
01689     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
01690     if (HeapTupleIsValid(tp))
01691     {
01692         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
01693         Oid         result;
01694 
01695         result = reltup->relnamespace;
01696         ReleaseSysCache(tp);
01697         return result;
01698     }
01699     else
01700         return InvalidOid;
01701 }
01702 
01703 /*
01704  * get_rel_type_id
01705  *
01706  *      Returns the pg_type OID associated with a given relation.
01707  *
01708  * Note: not all pg_class entries have associated pg_type OIDs; so be
01709  * careful to check for InvalidOid result.
01710  */
01711 Oid
01712 get_rel_type_id(Oid relid)
01713 {
01714     HeapTuple   tp;
01715 
01716     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
01717     if (HeapTupleIsValid(tp))
01718     {
01719         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
01720         Oid         result;
01721 
01722         result = reltup->reltype;
01723         ReleaseSysCache(tp);
01724         return result;
01725     }
01726     else
01727         return InvalidOid;
01728 }
01729 
01730 /*
01731  * get_rel_relkind
01732  *
01733  *      Returns the relkind associated with a given relation.
01734  */
01735 char
01736 get_rel_relkind(Oid relid)
01737 {
01738     HeapTuple   tp;
01739 
01740     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
01741     if (HeapTupleIsValid(tp))
01742     {
01743         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
01744         char        result;
01745 
01746         result = reltup->relkind;
01747         ReleaseSysCache(tp);
01748         return result;
01749     }
01750     else
01751         return '\0';
01752 }
01753 
01754 /*
01755  * get_rel_tablespace
01756  *
01757  *      Returns the pg_tablespace OID associated with a given relation.
01758  *
01759  * Note: InvalidOid might mean either that we couldn't find the relation,
01760  * or that it is in the database's default tablespace.
01761  */
01762 Oid
01763 get_rel_tablespace(Oid relid)
01764 {
01765     HeapTuple   tp;
01766 
01767     tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
01768     if (HeapTupleIsValid(tp))
01769     {
01770         Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
01771         Oid         result;
01772 
01773         result = reltup->reltablespace;
01774         ReleaseSysCache(tp);
01775         return result;
01776     }
01777     else
01778         return InvalidOid;
01779 }
01780 
01781 
01782 /*              ---------- TYPE CACHE ----------                         */
01783 
01784 /*
01785  * get_typisdefined
01786  *
01787  *      Given the type OID, determine whether the type is defined
01788  *      (if not, it's only a shell).
01789  */
01790 bool
01791 get_typisdefined(Oid typid)
01792 {
01793     HeapTuple   tp;
01794 
01795     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
01796     if (HeapTupleIsValid(tp))
01797     {
01798         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
01799         bool        result;
01800 
01801         result = typtup->typisdefined;
01802         ReleaseSysCache(tp);
01803         return result;
01804     }
01805     else
01806         return false;
01807 }
01808 
01809 /*
01810  * get_typlen
01811  *
01812  *      Given the type OID, return the length of the type.
01813  */
01814 int16
01815 get_typlen(Oid typid)
01816 {
01817     HeapTuple   tp;
01818 
01819     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
01820     if (HeapTupleIsValid(tp))
01821     {
01822         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
01823         int16       result;
01824 
01825         result = typtup->typlen;
01826         ReleaseSysCache(tp);
01827         return result;
01828     }
01829     else
01830         return 0;
01831 }
01832 
01833 /*
01834  * get_typbyval
01835  *
01836  *      Given the type OID, determine whether the type is returned by value or
01837  *      not.  Returns true if by value, false if by reference.
01838  */
01839 bool
01840 get_typbyval(Oid typid)
01841 {
01842     HeapTuple   tp;
01843 
01844     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
01845     if (HeapTupleIsValid(tp))
01846     {
01847         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
01848         bool        result;
01849 
01850         result = typtup->typbyval;
01851         ReleaseSysCache(tp);
01852         return result;
01853     }
01854     else
01855         return false;
01856 }
01857 
01858 /*
01859  * get_typlenbyval
01860  *
01861  *      A two-fer: given the type OID, return both typlen and typbyval.
01862  *
01863  *      Since both pieces of info are needed to know how to copy a Datum,
01864  *      many places need both.  Might as well get them with one cache lookup
01865  *      instead of two.  Also, this routine raises an error instead of
01866  *      returning a bogus value when given a bad type OID.
01867  */
01868 void
01869 get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
01870 {
01871     HeapTuple   tp;
01872     Form_pg_type typtup;
01873 
01874     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
01875     if (!HeapTupleIsValid(tp))
01876         elog(ERROR, "cache lookup failed for type %u", typid);
01877     typtup = (Form_pg_type) GETSTRUCT(tp);
01878     *typlen = typtup->typlen;
01879     *typbyval = typtup->typbyval;
01880     ReleaseSysCache(tp);
01881 }
01882 
01883 /*
01884  * get_typlenbyvalalign
01885  *
01886  *      A three-fer: given the type OID, return typlen, typbyval, typalign.
01887  */
01888 void
01889 get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
01890                      char *typalign)
01891 {
01892     HeapTuple   tp;
01893     Form_pg_type typtup;
01894 
01895     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
01896     if (!HeapTupleIsValid(tp))
01897         elog(ERROR, "cache lookup failed for type %u", typid);
01898     typtup = (Form_pg_type) GETSTRUCT(tp);
01899     *typlen = typtup->typlen;
01900     *typbyval = typtup->typbyval;
01901     *typalign = typtup->typalign;
01902     ReleaseSysCache(tp);
01903 }
01904 
01905 /*
01906  * getTypeIOParam
01907  *      Given a pg_type row, select the type OID to pass to I/O functions
01908  *
01909  * Formerly, all I/O functions were passed pg_type.typelem as their second
01910  * parameter, but we now have a more complex rule about what to pass.
01911  * This knowledge is intended to be centralized here --- direct references
01912  * to typelem elsewhere in the code are wrong, if they are associated with
01913  * I/O calls and not with actual subscripting operations!  (But see
01914  * bootstrap.c's boot_get_type_io_data() if you need to change this.)
01915  *
01916  * As of PostgreSQL 8.1, output functions receive only the value itself
01917  * and not any auxiliary parameters, so the name of this routine is now
01918  * a bit of a misnomer ... it should be getTypeInputParam.
01919  */
01920 Oid
01921 getTypeIOParam(HeapTuple typeTuple)
01922 {
01923     Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
01924 
01925     /*
01926      * Array types get their typelem as parameter; everybody else gets their
01927      * own type OID as parameter.
01928      */
01929     if (OidIsValid(typeStruct->typelem))
01930         return typeStruct->typelem;
01931     else
01932         return HeapTupleGetOid(typeTuple);
01933 }
01934 
01935 /*
01936  * get_type_io_data
01937  *
01938  *      A six-fer:  given the type OID, return typlen, typbyval, typalign,
01939  *                  typdelim, typioparam, and IO function OID. The IO function
01940  *                  returned is controlled by IOFuncSelector
01941  */
01942 void
01943 get_type_io_data(Oid typid,
01944                  IOFuncSelector which_func,
01945                  int16 *typlen,
01946                  bool *typbyval,
01947                  char *typalign,
01948                  char *typdelim,
01949                  Oid *typioparam,
01950                  Oid *func)
01951 {
01952     HeapTuple   typeTuple;
01953     Form_pg_type typeStruct;
01954 
01955     /*
01956      * In bootstrap mode, pass it off to bootstrap.c.  This hack allows us to
01957      * use array_in and array_out during bootstrap.
01958      */
01959     if (IsBootstrapProcessingMode())
01960     {
01961         Oid         typinput;
01962         Oid         typoutput;
01963 
01964         boot_get_type_io_data(typid,
01965                               typlen,
01966                               typbyval,
01967                               typalign,
01968                               typdelim,
01969                               typioparam,
01970                               &typinput,
01971                               &typoutput);
01972         switch (which_func)
01973         {
01974             case IOFunc_input:
01975                 *func = typinput;
01976                 break;
01977             case IOFunc_output:
01978                 *func = typoutput;
01979                 break;
01980             default:
01981                 elog(ERROR, "binary I/O not supported during bootstrap");
01982                 break;
01983         }
01984         return;
01985     }
01986 
01987     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
01988     if (!HeapTupleIsValid(typeTuple))
01989         elog(ERROR, "cache lookup failed for type %u", typid);
01990     typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
01991 
01992     *typlen = typeStruct->typlen;
01993     *typbyval = typeStruct->typbyval;
01994     *typalign = typeStruct->typalign;
01995     *typdelim = typeStruct->typdelim;
01996     *typioparam = getTypeIOParam(typeTuple);
01997     switch (which_func)
01998     {
01999         case IOFunc_input:
02000             *func = typeStruct->typinput;
02001             break;
02002         case IOFunc_output:
02003             *func = typeStruct->typoutput;
02004             break;
02005         case IOFunc_receive:
02006             *func = typeStruct->typreceive;
02007             break;
02008         case IOFunc_send:
02009             *func = typeStruct->typsend;
02010             break;
02011     }
02012     ReleaseSysCache(typeTuple);
02013 }
02014 
02015 #ifdef NOT_USED
02016 char
02017 get_typalign(Oid typid)
02018 {
02019     HeapTuple   tp;
02020 
02021     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
02022     if (HeapTupleIsValid(tp))
02023     {
02024         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
02025         char        result;
02026 
02027         result = typtup->typalign;
02028         ReleaseSysCache(tp);
02029         return result;
02030     }
02031     else
02032         return 'i';
02033 }
02034 #endif
02035 
02036 char
02037 get_typstorage(Oid typid)
02038 {
02039     HeapTuple   tp;
02040 
02041     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
02042     if (HeapTupleIsValid(tp))
02043     {
02044         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
02045         char        result;
02046 
02047         result = typtup->typstorage;
02048         ReleaseSysCache(tp);
02049         return result;
02050     }
02051     else
02052         return 'p';
02053 }
02054 
02055 /*
02056  * get_typdefault
02057  *    Given a type OID, return the type's default value, if any.
02058  *
02059  *    The result is a palloc'd expression node tree, or NULL if there
02060  *    is no defined default for the datatype.
02061  *
02062  * NB: caller should be prepared to coerce result to correct datatype;
02063  * the returned expression tree might produce something of the wrong type.
02064  */
02065 Node *
02066 get_typdefault(Oid typid)
02067 {
02068     HeapTuple   typeTuple;
02069     Form_pg_type type;
02070     Datum       datum;
02071     bool        isNull;
02072     Node       *expr;
02073 
02074     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
02075     if (!HeapTupleIsValid(typeTuple))
02076         elog(ERROR, "cache lookup failed for type %u", typid);
02077     type = (Form_pg_type) GETSTRUCT(typeTuple);
02078 
02079     /*
02080      * typdefault and typdefaultbin are potentially null, so don't try to
02081      * access 'em as struct fields. Must do it the hard way with
02082      * SysCacheGetAttr.
02083      */
02084     datum = SysCacheGetAttr(TYPEOID,
02085                             typeTuple,
02086                             Anum_pg_type_typdefaultbin,
02087                             &isNull);
02088 
02089     if (!isNull)
02090     {
02091         /* We have an expression default */
02092         expr = stringToNode(TextDatumGetCString(datum));
02093     }
02094     else
02095     {
02096         /* Perhaps we have a plain literal default */
02097         datum = SysCacheGetAttr(TYPEOID,
02098                                 typeTuple,
02099                                 Anum_pg_type_typdefault,
02100                                 &isNull);
02101 
02102         if (!isNull)
02103         {
02104             char       *strDefaultVal;
02105 
02106             /* Convert text datum to C string */
02107             strDefaultVal = TextDatumGetCString(datum);
02108             /* Convert C string to a value of the given type */
02109             datum = OidInputFunctionCall(type->typinput, strDefaultVal,
02110                                          getTypeIOParam(typeTuple), -1);
02111             /* Build a Const node containing the value */
02112             expr = (Node *) makeConst(typid,
02113                                       -1,
02114                                       type->typcollation,
02115                                       type->typlen,
02116                                       datum,
02117                                       false,
02118                                       type->typbyval);
02119             pfree(strDefaultVal);
02120         }
02121         else
02122         {
02123             /* No default */
02124             expr = NULL;
02125         }
02126     }
02127 
02128     ReleaseSysCache(typeTuple);
02129 
02130     return expr;
02131 }
02132 
02133 /*
02134  * getBaseType
02135  *      If the given type is a domain, return its base type;
02136  *      otherwise return the type's own OID.
02137  */
02138 Oid
02139 getBaseType(Oid typid)
02140 {
02141     int32       typmod = -1;
02142 
02143     return getBaseTypeAndTypmod(typid, &typmod);
02144 }
02145 
02146 /*
02147  * getBaseTypeAndTypmod
02148  *      If the given type is a domain, return its base type and typmod;
02149  *      otherwise return the type's own OID, and leave *typmod unchanged.
02150  *
02151  * Note that the "applied typmod" should be -1 for every domain level
02152  * above the bottommost; therefore, if the passed-in typid is indeed
02153  * a domain, *typmod should be -1.
02154  */
02155 Oid
02156 getBaseTypeAndTypmod(Oid typid, int32 *typmod)
02157 {
02158     /*
02159      * We loop to find the bottom base type in a stack of domains.
02160      */
02161     for (;;)
02162     {
02163         HeapTuple   tup;
02164         Form_pg_type typTup;
02165 
02166         tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
02167         if (!HeapTupleIsValid(tup))
02168             elog(ERROR, "cache lookup failed for type %u", typid);
02169         typTup = (Form_pg_type) GETSTRUCT(tup);
02170         if (typTup->typtype != TYPTYPE_DOMAIN)
02171         {
02172             /* Not a domain, so done */
02173             ReleaseSysCache(tup);
02174             break;
02175         }
02176 
02177         Assert(*typmod == -1);
02178         typid = typTup->typbasetype;
02179         *typmod = typTup->typtypmod;
02180 
02181         ReleaseSysCache(tup);
02182     }
02183 
02184     return typid;
02185 }
02186 
02187 /*
02188  * get_typavgwidth
02189  *
02190  *    Given a type OID and a typmod value (pass -1 if typmod is unknown),
02191  *    estimate the average width of values of the type.  This is used by
02192  *    the planner, which doesn't require absolutely correct results;
02193  *    it's OK (and expected) to guess if we don't know for sure.
02194  */
02195 int32
02196 get_typavgwidth(Oid typid, int32 typmod)
02197 {
02198     int         typlen = get_typlen(typid);
02199     int32       maxwidth;
02200 
02201     /*
02202      * Easy if it's a fixed-width type
02203      */
02204     if (typlen > 0)
02205         return typlen;
02206 
02207     /*
02208      * type_maximum_size knows the encoding of typmod for some datatypes;
02209      * don't duplicate that knowledge here.
02210      */
02211     maxwidth = type_maximum_size(typid, typmod);
02212     if (maxwidth > 0)
02213     {
02214         /*
02215          * For BPCHAR, the max width is also the only width.  Otherwise we
02216          * need to guess about the typical data width given the max. A sliding
02217          * scale for percentage of max width seems reasonable.
02218          */
02219         if (typid == BPCHAROID)
02220             return maxwidth;
02221         if (maxwidth <= 32)
02222             return maxwidth;    /* assume full width */
02223         if (maxwidth < 1000)
02224             return 32 + (maxwidth - 32) / 2;    /* assume 50% */
02225 
02226         /*
02227          * Beyond 1000, assume we're looking at something like
02228          * "varchar(10000)" where the limit isn't actually reached often, and
02229          * use a fixed estimate.
02230          */
02231         return 32 + (1000 - 32) / 2;
02232     }
02233 
02234     /*
02235      * Ooops, we have no idea ... wild guess time.
02236      */
02237     return 32;
02238 }
02239 
02240 /*
02241  * get_typtype
02242  *
02243  *      Given the type OID, find if it is a basic type, a complex type, etc.
02244  *      It returns the null char if the cache lookup fails...
02245  */
02246 char
02247 get_typtype(Oid typid)
02248 {
02249     HeapTuple   tp;
02250 
02251     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
02252     if (HeapTupleIsValid(tp))
02253     {
02254         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
02255         char        result;
02256 
02257         result = typtup->typtype;
02258         ReleaseSysCache(tp);
02259         return result;
02260     }
02261     else
02262         return '\0';
02263 }
02264 
02265 /*
02266  * type_is_rowtype
02267  *
02268  *      Convenience function to determine whether a type OID represents
02269  *      a "rowtype" type --- either RECORD or a named composite type.
02270  */
02271 bool
02272 type_is_rowtype(Oid typid)
02273 {
02274     return (typid == RECORDOID || get_typtype(typid) == TYPTYPE_COMPOSITE);
02275 }
02276 
02277 /*
02278  * type_is_enum
02279  *    Returns true if the given type is an enum type.
02280  */
02281 bool
02282 type_is_enum(Oid typid)
02283 {
02284     return (get_typtype(typid) == TYPTYPE_ENUM);
02285 }
02286 
02287 /*
02288  * type_is_range
02289  *    Returns true if the given type is a range type.
02290  */
02291 bool
02292 type_is_range(Oid typid)
02293 {
02294     return (get_typtype(typid) == TYPTYPE_RANGE);
02295 }
02296 
02297 /*
02298  * get_type_category_preferred
02299  *
02300  *      Given the type OID, fetch its category and preferred-type status.
02301  *      Throws error on failure.
02302  */
02303 void
02304 get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
02305 {
02306     HeapTuple   tp;
02307     Form_pg_type typtup;
02308 
02309     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
02310     if (!HeapTupleIsValid(tp))
02311         elog(ERROR, "cache lookup failed for type %u", typid);
02312     typtup = (Form_pg_type) GETSTRUCT(tp);
02313     *typcategory = typtup->typcategory;
02314     *typispreferred = typtup->typispreferred;
02315     ReleaseSysCache(tp);
02316 }
02317 
02318 /*
02319  * get_typ_typrelid
02320  *
02321  *      Given the type OID, get the typrelid (InvalidOid if not a complex
02322  *      type).
02323  */
02324 Oid
02325 get_typ_typrelid(Oid typid)
02326 {
02327     HeapTuple   tp;
02328 
02329     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
02330     if (HeapTupleIsValid(tp))
02331     {
02332         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
02333         Oid         result;
02334 
02335         result = typtup->typrelid;
02336         ReleaseSysCache(tp);
02337         return result;
02338     }
02339     else
02340         return InvalidOid;
02341 }
02342 
02343 /*
02344  * get_element_type
02345  *
02346  *      Given the type OID, get the typelem (InvalidOid if not an array type).
02347  *
02348  * NB: this only considers varlena arrays to be true arrays; InvalidOid is
02349  * returned if the input is a fixed-length array type.
02350  */
02351 Oid
02352 get_element_type(Oid typid)
02353 {
02354     HeapTuple   tp;
02355 
02356     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
02357     if (HeapTupleIsValid(tp))
02358     {
02359         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
02360         Oid         result;
02361 
02362         if (typtup->typlen == -1)
02363             result = typtup->typelem;
02364         else
02365             result = InvalidOid;
02366         ReleaseSysCache(tp);
02367         return result;
02368     }
02369     else
02370         return InvalidOid;
02371 }
02372 
02373 /*
02374  * get_array_type
02375  *
02376  *      Given the type OID, get the corresponding "true" array type.
02377  *      Returns InvalidOid if no array type can be found.
02378  */
02379 Oid
02380 get_array_type(Oid typid)
02381 {
02382     HeapTuple   tp;
02383     Oid         result = InvalidOid;
02384 
02385     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
02386     if (HeapTupleIsValid(tp))
02387     {
02388         result = ((Form_pg_type) GETSTRUCT(tp))->typarray;
02389         ReleaseSysCache(tp);
02390     }
02391     return result;
02392 }
02393 
02394 /*
02395  * get_base_element_type
02396  *      Given the type OID, get the typelem, looking "through" any domain
02397  *      to its underlying array type.
02398  *
02399  * This is equivalent to get_element_type(getBaseType(typid)), but avoids
02400  * an extra cache lookup.  Note that it fails to provide any information
02401  * about the typmod of the array.
02402  */
02403 Oid
02404 get_base_element_type(Oid typid)
02405 {
02406     /*
02407      * We loop to find the bottom base type in a stack of domains.
02408      */
02409     for (;;)
02410     {
02411         HeapTuple   tup;
02412         Form_pg_type typTup;
02413 
02414         tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
02415         if (!HeapTupleIsValid(tup))
02416             break;
02417         typTup = (Form_pg_type) GETSTRUCT(tup);
02418         if (typTup->typtype != TYPTYPE_DOMAIN)
02419         {
02420             /* Not a domain, so stop descending */
02421             Oid         result;
02422 
02423             /* This test must match get_element_type */
02424             if (typTup->typlen == -1)
02425                 result = typTup->typelem;
02426             else
02427                 result = InvalidOid;
02428             ReleaseSysCache(tup);
02429             return result;
02430         }
02431 
02432         typid = typTup->typbasetype;
02433         ReleaseSysCache(tup);
02434     }
02435 
02436     /* Like get_element_type, silently return InvalidOid for bogus input */
02437     return InvalidOid;
02438 }
02439 
02440 /*
02441  * getTypeInputInfo
02442  *
02443  *      Get info needed for converting values of a type to internal form
02444  */
02445 void
02446 getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
02447 {
02448     HeapTuple   typeTuple;
02449     Form_pg_type pt;
02450 
02451     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
02452     if (!HeapTupleIsValid(typeTuple))
02453         elog(ERROR, "cache lookup failed for type %u", type);
02454     pt = (Form_pg_type) GETSTRUCT(typeTuple);
02455 
02456     if (!pt->typisdefined)
02457         ereport(ERROR,
02458                 (errcode(ERRCODE_UNDEFINED_OBJECT),
02459                  errmsg("type %s is only a shell",
02460                         format_type_be(type))));
02461     if (!OidIsValid(pt->typinput))
02462         ereport(ERROR,
02463                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
02464                  errmsg("no input function available for type %s",
02465                         format_type_be(type))));
02466 
02467     *typInput = pt->typinput;
02468     *typIOParam = getTypeIOParam(typeTuple);
02469 
02470     ReleaseSysCache(typeTuple);
02471 }
02472 
02473 /*
02474  * getTypeOutputInfo
02475  *
02476  *      Get info needed for printing values of a type
02477  */
02478 void
02479 getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
02480 {
02481     HeapTuple   typeTuple;
02482     Form_pg_type pt;
02483 
02484     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
02485     if (!HeapTupleIsValid(typeTuple))
02486         elog(ERROR, "cache lookup failed for type %u", type);
02487     pt = (Form_pg_type) GETSTRUCT(typeTuple);
02488 
02489     if (!pt->typisdefined)
02490         ereport(ERROR,
02491                 (errcode(ERRCODE_UNDEFINED_OBJECT),
02492                  errmsg("type %s is only a shell",
02493                         format_type_be(type))));
02494     if (!OidIsValid(pt->typoutput))
02495         ereport(ERROR,
02496                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
02497                  errmsg("no output function available for type %s",
02498                         format_type_be(type))));
02499 
02500     *typOutput = pt->typoutput;
02501     *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
02502 
02503     ReleaseSysCache(typeTuple);
02504 }
02505 
02506 /*
02507  * getTypeBinaryInputInfo
02508  *
02509  *      Get info needed for binary input of values of a type
02510  */
02511 void
02512 getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
02513 {
02514     HeapTuple   typeTuple;
02515     Form_pg_type pt;
02516 
02517     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
02518     if (!HeapTupleIsValid(typeTuple))
02519         elog(ERROR, "cache lookup failed for type %u", type);
02520     pt = (Form_pg_type) GETSTRUCT(typeTuple);
02521 
02522     if (!pt->typisdefined)
02523         ereport(ERROR,
02524                 (errcode(ERRCODE_UNDEFINED_OBJECT),
02525                  errmsg("type %s is only a shell",
02526                         format_type_be(type))));
02527     if (!OidIsValid(pt->typreceive))
02528         ereport(ERROR,
02529                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
02530                  errmsg("no binary input function available for type %s",
02531                         format_type_be(type))));
02532 
02533     *typReceive = pt->typreceive;
02534     *typIOParam = getTypeIOParam(typeTuple);
02535 
02536     ReleaseSysCache(typeTuple);
02537 }
02538 
02539 /*
02540  * getTypeBinaryOutputInfo
02541  *
02542  *      Get info needed for binary output of values of a type
02543  */
02544 void
02545 getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
02546 {
02547     HeapTuple   typeTuple;
02548     Form_pg_type pt;
02549 
02550     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
02551     if (!HeapTupleIsValid(typeTuple))
02552         elog(ERROR, "cache lookup failed for type %u", type);
02553     pt = (Form_pg_type) GETSTRUCT(typeTuple);
02554 
02555     if (!pt->typisdefined)
02556         ereport(ERROR,
02557                 (errcode(ERRCODE_UNDEFINED_OBJECT),
02558                  errmsg("type %s is only a shell",
02559                         format_type_be(type))));
02560     if (!OidIsValid(pt->typsend))
02561         ereport(ERROR,
02562                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
02563                  errmsg("no binary output function available for type %s",
02564                         format_type_be(type))));
02565 
02566     *typSend = pt->typsend;
02567     *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
02568 
02569     ReleaseSysCache(typeTuple);
02570 }
02571 
02572 /*
02573  * get_typmodin
02574  *
02575  *      Given the type OID, return the type's typmodin procedure, if any.
02576  */
02577 Oid
02578 get_typmodin(Oid typid)
02579 {
02580     HeapTuple   tp;
02581 
02582     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
02583     if (HeapTupleIsValid(tp))
02584     {
02585         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
02586         Oid         result;
02587 
02588         result = typtup->typmodin;
02589         ReleaseSysCache(tp);
02590         return result;
02591     }
02592     else
02593         return InvalidOid;
02594 }
02595 
02596 #ifdef NOT_USED
02597 /*
02598  * get_typmodout
02599  *
02600  *      Given the type OID, return the type's typmodout procedure, if any.
02601  */
02602 Oid
02603 get_typmodout(Oid typid)
02604 {
02605     HeapTuple   tp;
02606 
02607     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
02608     if (HeapTupleIsValid(tp))
02609     {
02610         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
02611         Oid         result;
02612 
02613         result = typtup->typmodout;
02614         ReleaseSysCache(tp);
02615         return result;
02616     }
02617     else
02618         return InvalidOid;
02619 }
02620 #endif   /* NOT_USED */
02621 
02622 /*
02623  * get_typcollation
02624  *
02625  *      Given the type OID, return the type's typcollation attribute.
02626  */
02627 Oid
02628 get_typcollation(Oid typid)
02629 {
02630     HeapTuple   tp;
02631 
02632     tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
02633     if (HeapTupleIsValid(tp))
02634     {
02635         Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
02636         Oid         result;
02637 
02638         result = typtup->typcollation;
02639         ReleaseSysCache(tp);
02640         return result;
02641     }
02642     else
02643         return InvalidOid;
02644 }
02645 
02646 
02647 /*
02648  * type_is_collatable
02649  *
02650  *      Return whether the type cares about collations
02651  */
02652 bool
02653 type_is_collatable(Oid typid)
02654 {
02655     return OidIsValid(get_typcollation(typid));
02656 }
02657 
02658 
02659 /*              ---------- STATISTICS CACHE ----------                   */
02660 
02661 /*
02662  * get_attavgwidth
02663  *
02664  *    Given the table and attribute number of a column, get the average
02665  *    width of entries in the column.  Return zero if no data available.
02666  *
02667  * Currently this is only consulted for individual tables, not for inheritance
02668  * trees, so we don't need an "inh" parameter.
02669  *
02670  * Calling a hook at this point looks somewhat strange, but is required
02671  * because the optimizer calls this function without any other way for
02672  * plug-ins to control the result.
02673  */
02674 int32
02675 get_attavgwidth(Oid relid, AttrNumber attnum)
02676 {
02677     HeapTuple   tp;
02678     int32       stawidth;
02679 
02680     if (get_attavgwidth_hook)
02681     {
02682         stawidth = (*get_attavgwidth_hook) (relid, attnum);
02683         if (stawidth > 0)
02684             return stawidth;
02685     }
02686     tp = SearchSysCache3(STATRELATTINH,
02687                          ObjectIdGetDatum(relid),
02688                          Int16GetDatum(attnum),
02689                          BoolGetDatum(false));
02690     if (HeapTupleIsValid(tp))
02691     {
02692         stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
02693         ReleaseSysCache(tp);
02694         if (stawidth > 0)
02695             return stawidth;
02696     }
02697     return 0;
02698 }
02699 
02700 /*
02701  * get_attstatsslot
02702  *
02703  *      Extract the contents of a "slot" of a pg_statistic tuple.
02704  *      Returns TRUE if requested slot type was found, else FALSE.
02705  *
02706  * Unlike other routines in this file, this takes a pointer to an
02707  * already-looked-up tuple in the pg_statistic cache.  We do this since
02708  * most callers will want to extract more than one value from the cache
02709  * entry, and we don't want to repeat the cache lookup unnecessarily.
02710  * Also, this API allows this routine to be used with statistics tuples
02711  * that have been provided by a stats hook and didn't really come from
02712  * pg_statistic.
02713  *
02714  * statstuple: pg_statistics tuple to be examined.
02715  * atttype: type OID of attribute (can be InvalidOid if values == NULL).
02716  * atttypmod: typmod of attribute (can be 0 if values == NULL).
02717  * reqkind: STAKIND code for desired statistics slot kind.
02718  * reqop: STAOP value wanted, or InvalidOid if don't care.
02719  * actualop: if not NULL, *actualop receives the actual STAOP value.
02720  * values, nvalues: if not NULL, the slot's stavalues are extracted.
02721  * numbers, nnumbers: if not NULL, the slot's stanumbers are extracted.
02722  *
02723  * If assigned, values and numbers are set to point to palloc'd arrays.
02724  * If the attribute type is pass-by-reference, the values referenced by
02725  * the values array are themselves palloc'd.  The palloc'd stuff can be
02726  * freed by calling free_attstatsslot.
02727  *
02728  * Note: at present, atttype/atttypmod aren't actually used here at all.
02729  * But the caller must have the correct (or at least binary-compatible)
02730  * type ID to pass to free_attstatsslot later.
02731  */
02732 bool
02733 get_attstatsslot(HeapTuple statstuple,
02734                  Oid atttype, int32 atttypmod,
02735                  int reqkind, Oid reqop,
02736                  Oid *actualop,
02737                  Datum **values, int *nvalues,
02738                  float4 **numbers, int *nnumbers)
02739 {
02740     Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(statstuple);
02741     int         i,
02742                 j;
02743     Datum       val;
02744     bool        isnull;
02745     ArrayType  *statarray;
02746     Oid         arrayelemtype;
02747     int         narrayelem;
02748     HeapTuple   typeTuple;
02749     Form_pg_type typeForm;
02750 
02751     for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
02752     {
02753         if ((&stats->stakind1)[i] == reqkind &&
02754             (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
02755             break;
02756     }
02757     if (i >= STATISTIC_NUM_SLOTS)
02758         return false;           /* not there */
02759 
02760     if (actualop)
02761         *actualop = (&stats->staop1)[i];
02762 
02763     if (values)
02764     {
02765         val = SysCacheGetAttr(STATRELATTINH, statstuple,
02766                               Anum_pg_statistic_stavalues1 + i,
02767                               &isnull);
02768         if (isnull)
02769             elog(ERROR, "stavalues is null");
02770         statarray = DatumGetArrayTypeP(val);
02771 
02772         /*
02773          * Need to get info about the array element type.  We look at the
02774          * actual element type embedded in the array, which might be only
02775          * binary-compatible with the passed-in atttype.  The info we extract
02776          * here should be the same either way, but deconstruct_array is picky
02777          * about having an exact type OID match.
02778          */
02779         arrayelemtype = ARR_ELEMTYPE(statarray);
02780         typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrayelemtype));
02781         if (!HeapTupleIsValid(typeTuple))
02782             elog(ERROR, "cache lookup failed for type %u", arrayelemtype);
02783         typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
02784 
02785         /* Deconstruct array into Datum elements; NULLs not expected */
02786         deconstruct_array(statarray,
02787                           arrayelemtype,
02788                           typeForm->typlen,
02789                           typeForm->typbyval,
02790                           typeForm->typalign,
02791                           values, NULL, nvalues);
02792 
02793         /*
02794          * If the element type is pass-by-reference, we now have a bunch of
02795          * Datums that are pointers into the syscache value.  Copy them to
02796          * avoid problems if syscache decides to drop the entry.
02797          */
02798         if (!typeForm->typbyval)
02799         {
02800             for (j = 0; j < *nvalues; j++)
02801             {
02802                 (*values)[j] = datumCopy((*values)[j],
02803                                          typeForm->typbyval,
02804                                          typeForm->typlen);
02805             }
02806         }
02807 
02808         ReleaseSysCache(typeTuple);
02809 
02810         /*
02811          * Free statarray if it's a detoasted copy.
02812          */
02813         if ((Pointer) statarray != DatumGetPointer(val))
02814             pfree(statarray);
02815     }
02816 
02817     if (numbers)
02818     {
02819         val = SysCacheGetAttr(STATRELATTINH, statstuple,
02820                               Anum_pg_statistic_stanumbers1 + i,
02821                               &isnull);
02822         if (isnull)
02823             elog(ERROR, "stanumbers is null");
02824         statarray = DatumGetArrayTypeP(val);
02825 
02826         /*
02827          * We expect the array to be a 1-D float4 array; verify that. We don't
02828          * need to use deconstruct_array() since the array data is just going
02829          * to look like a C array of float4 values.
02830          */
02831         narrayelem = ARR_DIMS(statarray)[0];
02832         if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
02833             ARR_HASNULL(statarray) ||
02834             ARR_ELEMTYPE(statarray) != FLOAT4OID)
02835             elog(ERROR, "stanumbers is not a 1-D float4 array");
02836         *numbers = (float4 *) palloc(narrayelem * sizeof(float4));
02837         memcpy(*numbers, ARR_DATA_PTR(statarray), narrayelem * sizeof(float4));
02838         *nnumbers = narrayelem;
02839 
02840         /*
02841          * Free statarray if it's a detoasted copy.
02842          */
02843         if ((Pointer) statarray != DatumGetPointer(val))
02844             pfree(statarray);
02845     }
02846 
02847     return true;
02848 }
02849 
02850 /*
02851  * free_attstatsslot
02852  *      Free data allocated by get_attstatsslot
02853  *
02854  * atttype need be valid only if values != NULL.
02855  */
02856 void
02857 free_attstatsslot(Oid atttype,
02858                   Datum *values, int nvalues,
02859                   float4 *numbers, int nnumbers)
02860 {
02861     if (values)
02862     {
02863         if (!get_typbyval(atttype))
02864         {
02865             int         i;
02866 
02867             for (i = 0; i < nvalues; i++)
02868                 pfree(DatumGetPointer(values[i]));
02869         }
02870         pfree(values);
02871     }
02872     if (numbers)
02873         pfree(numbers);
02874 }
02875 
02876 /*              ---------- PG_NAMESPACE CACHE ----------                 */
02877 
02878 /*
02879  * get_namespace_name
02880  *      Returns the name of a given namespace
02881  *
02882  * Returns a palloc'd copy of the string, or NULL if no such namespace.
02883  */
02884 char *
02885 get_namespace_name(Oid nspid)
02886 {
02887     HeapTuple   tp;
02888 
02889     tp = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid));
02890     if (HeapTupleIsValid(tp))
02891     {
02892         Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
02893         char       *result;
02894 
02895         result = pstrdup(NameStr(nsptup->nspname));
02896         ReleaseSysCache(tp);
02897         return result;
02898     }
02899     else
02900         return NULL;
02901 }
02902 
02903 /*              ---------- PG_RANGE CACHE ----------                 */
02904 
02905 /*
02906  * get_range_subtype
02907  *      Returns the subtype of a given range type
02908  *
02909  * Returns InvalidOid if the type is not a range type.
02910  */
02911 Oid
02912 get_range_subtype(Oid rangeOid)
02913 {
02914     HeapTuple   tp;
02915 
02916     tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
02917     if (HeapTupleIsValid(tp))
02918     {
02919         Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
02920         Oid         result;
02921 
02922         result = rngtup->rngsubtype;
02923         ReleaseSysCache(tp);
02924         return result;
02925     }
02926     else
02927         return InvalidOid;
02928 }