Header And Logo

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

namespace.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * namespace.c
00004  *    code to support accessing and searching namespaces
00005  *
00006  * This is separate from pg_namespace.c, which contains the routines that
00007  * directly manipulate the pg_namespace system catalog.  This module
00008  * provides routines associated with defining a "namespace search path"
00009  * and implementing search-path-controlled searches.
00010  *
00011  *
00012  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00013  * Portions Copyright (c) 1994, Regents of the University of California
00014  *
00015  * IDENTIFICATION
00016  *    src/backend/catalog/namespace.c
00017  *
00018  *-------------------------------------------------------------------------
00019  */
00020 #include "postgres.h"
00021 
00022 #include "access/htup_details.h"
00023 #include "access/xact.h"
00024 #include "catalog/dependency.h"
00025 #include "catalog/objectaccess.h"
00026 #include "catalog/pg_authid.h"
00027 #include "catalog/pg_collation.h"
00028 #include "catalog/pg_conversion.h"
00029 #include "catalog/pg_conversion_fn.h"
00030 #include "catalog/pg_namespace.h"
00031 #include "catalog/pg_opclass.h"
00032 #include "catalog/pg_operator.h"
00033 #include "catalog/pg_opfamily.h"
00034 #include "catalog/pg_proc.h"
00035 #include "catalog/pg_ts_config.h"
00036 #include "catalog/pg_ts_dict.h"
00037 #include "catalog/pg_ts_parser.h"
00038 #include "catalog/pg_ts_template.h"
00039 #include "catalog/pg_type.h"
00040 #include "commands/dbcommands.h"
00041 #include "funcapi.h"
00042 #include "mb/pg_wchar.h"
00043 #include "miscadmin.h"
00044 #include "nodes/makefuncs.h"
00045 #include "parser/parse_func.h"
00046 #include "storage/ipc.h"
00047 #include "storage/lmgr.h"
00048 #include "storage/sinval.h"
00049 #include "utils/acl.h"
00050 #include "utils/builtins.h"
00051 #include "utils/catcache.h"
00052 #include "utils/guc.h"
00053 #include "utils/inval.h"
00054 #include "utils/lsyscache.h"
00055 #include "utils/memutils.h"
00056 #include "utils/syscache.h"
00057 
00058 
00059 /*
00060  * The namespace search path is a possibly-empty list of namespace OIDs.
00061  * In addition to the explicit list, implicitly-searched namespaces
00062  * may be included:
00063  *
00064  * 1. If a TEMP table namespace has been initialized in this session, it
00065  * is implicitly searched first.  (The only time this doesn't happen is
00066  * when we are obeying an override search path spec that says not to use the
00067  * temp namespace, or the temp namespace is included in the explicit list.)
00068  *
00069  * 2. The system catalog namespace is always searched.  If the system
00070  * namespace is present in the explicit path then it will be searched in
00071  * the specified order; otherwise it will be searched after TEMP tables and
00072  * *before* the explicit list.  (It might seem that the system namespace
00073  * should be implicitly last, but this behavior appears to be required by
00074  * SQL99.  Also, this provides a way to search the system namespace first
00075  * without thereby making it the default creation target namespace.)
00076  *
00077  * For security reasons, searches using the search path will ignore the temp
00078  * namespace when searching for any object type other than relations and
00079  * types.  (We must allow types since temp tables have rowtypes.)
00080  *
00081  * The default creation target namespace is always the first element of the
00082  * explicit list.  If the explicit list is empty, there is no default target.
00083  *
00084  * The textual specification of search_path can include "$user" to refer to
00085  * the namespace named the same as the current user, if any.  (This is just
00086  * ignored if there is no such namespace.)  Also, it can include "pg_temp"
00087  * to refer to the current backend's temp namespace.  This is usually also
00088  * ignorable if the temp namespace hasn't been set up, but there's a special
00089  * case: if "pg_temp" appears first then it should be the default creation
00090  * target.  We kluge this case a little bit so that the temp namespace isn't
00091  * set up until the first attempt to create something in it.  (The reason for
00092  * klugery is that we can't create the temp namespace outside a transaction,
00093  * but initial GUC processing of search_path happens outside a transaction.)
00094  * activeTempCreationPending is TRUE if "pg_temp" appears first in the string
00095  * but is not reflected in activeCreationNamespace because the namespace isn't
00096  * set up yet.
00097  *
00098  * In bootstrap mode, the search path is set equal to "pg_catalog", so that
00099  * the system namespace is the only one searched or inserted into.
00100  * initdb is also careful to set search_path to "pg_catalog" for its
00101  * post-bootstrap standalone backend runs.  Otherwise the default search
00102  * path is determined by GUC.  The factory default path contains the PUBLIC
00103  * namespace (if it exists), preceded by the user's personal namespace
00104  * (if one exists).
00105  *
00106  * We support a stack of "override" search path settings for use within
00107  * specific sections of backend code.  namespace_search_path is ignored
00108  * whenever the override stack is nonempty.  activeSearchPath is always
00109  * the actually active path; it points either to the search list of the
00110  * topmost stack entry, or to baseSearchPath which is the list derived
00111  * from namespace_search_path.
00112  *
00113  * If baseSearchPathValid is false, then baseSearchPath (and other
00114  * derived variables) need to be recomputed from namespace_search_path.
00115  * We mark it invalid upon an assignment to namespace_search_path or receipt
00116  * of a syscache invalidation event for pg_namespace.  The recomputation
00117  * is done during the next non-overridden lookup attempt.  Note that an
00118  * override spec is never subject to recomputation.
00119  *
00120  * Any namespaces mentioned in namespace_search_path that are not readable
00121  * by the current user ID are simply left out of baseSearchPath; so
00122  * we have to be willing to recompute the path when current userid changes.
00123  * namespaceUser is the userid the path has been computed for.
00124  *
00125  * Note: all data pointed to by these List variables is in TopMemoryContext.
00126  */
00127 
00128 /* These variables define the actually active state: */
00129 
00130 static List *activeSearchPath = NIL;
00131 
00132 /* default place to create stuff; if InvalidOid, no default */
00133 static Oid  activeCreationNamespace = InvalidOid;
00134 
00135 /* if TRUE, activeCreationNamespace is wrong, it should be temp namespace */
00136 static bool activeTempCreationPending = false;
00137 
00138 /* These variables are the values last derived from namespace_search_path: */
00139 
00140 static List *baseSearchPath = NIL;
00141 
00142 static Oid  baseCreationNamespace = InvalidOid;
00143 
00144 static bool baseTempCreationPending = false;
00145 
00146 static Oid  namespaceUser = InvalidOid;
00147 
00148 /* The above four values are valid only if baseSearchPathValid */
00149 static bool baseSearchPathValid = true;
00150 
00151 /* Override requests are remembered in a stack of OverrideStackEntry structs */
00152 
00153 typedef struct
00154 {
00155     List       *searchPath;     /* the desired search path */
00156     Oid         creationNamespace;      /* the desired creation namespace */
00157     int         nestLevel;      /* subtransaction nesting level */
00158 } OverrideStackEntry;
00159 
00160 static List *overrideStack = NIL;
00161 
00162 /*
00163  * myTempNamespace is InvalidOid until and unless a TEMP namespace is set up
00164  * in a particular backend session (this happens when a CREATE TEMP TABLE
00165  * command is first executed).  Thereafter it's the OID of the temp namespace.
00166  *
00167  * myTempToastNamespace is the OID of the namespace for my temp tables' toast
00168  * tables.  It is set when myTempNamespace is, and is InvalidOid before that.
00169  *
00170  * myTempNamespaceSubID shows whether we've created the TEMP namespace in the
00171  * current subtransaction.  The flag propagates up the subtransaction tree,
00172  * so the main transaction will correctly recognize the flag if all
00173  * intermediate subtransactions commit.  When it is InvalidSubTransactionId,
00174  * we either haven't made the TEMP namespace yet, or have successfully
00175  * committed its creation, depending on whether myTempNamespace is valid.
00176  */
00177 static Oid  myTempNamespace = InvalidOid;
00178 
00179 static Oid  myTempToastNamespace = InvalidOid;
00180 
00181 static SubTransactionId myTempNamespaceSubID = InvalidSubTransactionId;
00182 
00183 /*
00184  * This is the user's textual search path specification --- it's the value
00185  * of the GUC variable 'search_path'.
00186  */
00187 char       *namespace_search_path = NULL;
00188 
00189 
00190 /* Local functions */
00191 static void recomputeNamespacePath(void);
00192 static void InitTempTableNamespace(void);
00193 static void RemoveTempRelations(Oid tempNamespaceId);
00194 static void RemoveTempRelationsCallback(int code, Datum arg);
00195 static void NamespaceCallback(Datum arg, int cacheid, uint32 hashvalue);
00196 static bool MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
00197                int **argnumbers);
00198 
00199 /* These don't really need to appear in any header file */
00200 Datum       pg_table_is_visible(PG_FUNCTION_ARGS);
00201 Datum       pg_type_is_visible(PG_FUNCTION_ARGS);
00202 Datum       pg_function_is_visible(PG_FUNCTION_ARGS);
00203 Datum       pg_operator_is_visible(PG_FUNCTION_ARGS);
00204 Datum       pg_opclass_is_visible(PG_FUNCTION_ARGS);
00205 Datum       pg_opfamily_is_visible(PG_FUNCTION_ARGS);
00206 Datum       pg_collation_is_visible(PG_FUNCTION_ARGS);
00207 Datum       pg_conversion_is_visible(PG_FUNCTION_ARGS);
00208 Datum       pg_ts_parser_is_visible(PG_FUNCTION_ARGS);
00209 Datum       pg_ts_dict_is_visible(PG_FUNCTION_ARGS);
00210 Datum       pg_ts_template_is_visible(PG_FUNCTION_ARGS);
00211 Datum       pg_ts_config_is_visible(PG_FUNCTION_ARGS);
00212 Datum       pg_my_temp_schema(PG_FUNCTION_ARGS);
00213 Datum       pg_is_other_temp_schema(PG_FUNCTION_ARGS);
00214 
00215 
00216 /*
00217  * RangeVarGetRelid
00218  *      Given a RangeVar describing an existing relation,
00219  *      select the proper namespace and look up the relation OID.
00220  *
00221  * If the schema or relation is not found, return InvalidOid if missing_ok
00222  * = true, otherwise raise an error.
00223  *
00224  * If nowait = true, throw an error if we'd have to wait for a lock.
00225  *
00226  * Callback allows caller to check permissions or acquire additional locks
00227  * prior to grabbing the relation lock.
00228  */
00229 Oid
00230 RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode,
00231                          bool missing_ok, bool nowait,
00232                        RangeVarGetRelidCallback callback, void *callback_arg)
00233 {
00234     uint64      inval_count;
00235     Oid         relId;
00236     Oid         oldRelId = InvalidOid;
00237     bool        retry = false;
00238 
00239     /*
00240      * We check the catalog name and then ignore it.
00241      */
00242     if (relation->catalogname)
00243     {
00244         if (strcmp(relation->catalogname, get_database_name(MyDatabaseId)) != 0)
00245             ereport(ERROR,
00246                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00247                      errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
00248                             relation->catalogname, relation->schemaname,
00249                             relation->relname)));
00250     }
00251 
00252     /*
00253      * DDL operations can change the results of a name lookup.  Since all such
00254      * operations will generate invalidation messages, we keep track of
00255      * whether any such messages show up while we're performing the operation,
00256      * and retry until either (1) no more invalidation messages show up or (2)
00257      * the answer doesn't change.
00258      *
00259      * But if lockmode = NoLock, then we assume that either the caller is OK
00260      * with the answer changing under them, or that they already hold some
00261      * appropriate lock, and therefore return the first answer we get without
00262      * checking for invalidation messages.  Also, if the requested lock is
00263      * already held, no LockRelationOid will not AcceptInvalidationMessages,
00264      * so we may fail to notice a change.  We could protect against that case
00265      * by calling AcceptInvalidationMessages() before beginning this loop, but
00266      * that would add a significant amount overhead, so for now we don't.
00267      */
00268     for (;;)
00269     {
00270         /*
00271          * Remember this value, so that, after looking up the relation name
00272          * and locking its OID, we can check whether any invalidation messages
00273          * have been processed that might require a do-over.
00274          */
00275         inval_count = SharedInvalidMessageCounter;
00276 
00277         /*
00278          * Some non-default relpersistence value may have been specified.  The
00279          * parser never generates such a RangeVar in simple DML, but it can
00280          * happen in contexts such as "CREATE TEMP TABLE foo (f1 int PRIMARY
00281          * KEY)".  Such a command will generate an added CREATE INDEX
00282          * operation, which must be careful to find the temp table, even when
00283          * pg_temp is not first in the search path.
00284          */
00285         if (relation->relpersistence == RELPERSISTENCE_TEMP)
00286         {
00287             if (!OidIsValid(myTempNamespace))
00288                 relId = InvalidOid;     /* this probably can't happen? */
00289             else
00290             {
00291                 if (relation->schemaname)
00292                 {
00293                     Oid         namespaceId;
00294 
00295                     namespaceId = LookupExplicitNamespace(relation->schemaname, missing_ok);
00296                     /*
00297                      *  For missing_ok, allow a non-existant schema name to
00298                      *  return InvalidOid.
00299                      */
00300                     if (namespaceId != myTempNamespace)
00301                         ereport(ERROR,
00302                                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
00303                                  errmsg("temporary tables cannot specify a schema name")));
00304                 }
00305 
00306                 relId = get_relname_relid(relation->relname, myTempNamespace);
00307             }
00308         }
00309         else if (relation->schemaname)
00310         {
00311             Oid         namespaceId;
00312 
00313             /* use exact schema given */
00314             namespaceId = LookupExplicitNamespace(relation->schemaname, missing_ok);
00315             if (missing_ok && !OidIsValid(namespaceId))
00316                 relId = InvalidOid;
00317             else
00318                 relId = get_relname_relid(relation->relname, namespaceId);
00319         }
00320         else
00321         {
00322             /* search the namespace path */
00323             relId = RelnameGetRelid(relation->relname);
00324         }
00325 
00326         /*
00327          * Invoke caller-supplied callback, if any.
00328          *
00329          * This callback is a good place to check permissions: we haven't
00330          * taken the table lock yet (and it's really best to check permissions
00331          * before locking anything!), but we've gotten far enough to know what
00332          * OID we think we should lock.  Of course, concurrent DDL might
00333          * change things while we're waiting for the lock, but in that case
00334          * the callback will be invoked again for the new OID.
00335          */
00336         if (callback)
00337             callback(relation, relId, oldRelId, callback_arg);
00338 
00339         /*
00340          * If no lock requested, we assume the caller knows what they're
00341          * doing.  They should have already acquired a heavyweight lock on
00342          * this relation earlier in the processing of this same statement, so
00343          * it wouldn't be appropriate to AcceptInvalidationMessages() here, as
00344          * that might pull the rug out from under them.
00345          */
00346         if (lockmode == NoLock)
00347             break;
00348 
00349         /*
00350          * If, upon retry, we get back the same OID we did last time, then the
00351          * invalidation messages we processed did not change the final answer.
00352          * So we're done.
00353          *
00354          * If we got a different OID, we've locked the relation that used to
00355          * have this name rather than the one that does now.  So release the
00356          * lock.
00357          */
00358         if (retry)
00359         {
00360             if (relId == oldRelId)
00361                 break;
00362             if (OidIsValid(oldRelId))
00363                 UnlockRelationOid(oldRelId, lockmode);
00364         }
00365 
00366         /*
00367          * Lock relation.  This will also accept any pending invalidation
00368          * messages.  If we got back InvalidOid, indicating not found, then
00369          * there's nothing to lock, but we accept invalidation messages
00370          * anyway, to flush any negative catcache entries that may be
00371          * lingering.
00372          */
00373         if (!OidIsValid(relId))
00374             AcceptInvalidationMessages();
00375         else if (!nowait)
00376             LockRelationOid(relId, lockmode);
00377         else if (!ConditionalLockRelationOid(relId, lockmode))
00378         {
00379             if (relation->schemaname)
00380                 ereport(ERROR,
00381                         (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
00382                          errmsg("could not obtain lock on relation \"%s.%s\"",
00383                                 relation->schemaname, relation->relname)));
00384             else
00385                 ereport(ERROR,
00386                         (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
00387                          errmsg("could not obtain lock on relation \"%s\"",
00388                                 relation->relname)));
00389         }
00390 
00391         /*
00392          * If no invalidation message were processed, we're done!
00393          */
00394         if (inval_count == SharedInvalidMessageCounter)
00395             break;
00396 
00397         /*
00398          * Something may have changed.  Let's repeat the name lookup, to make
00399          * sure this name still references the same relation it did
00400          * previously.
00401          */
00402         retry = true;
00403         oldRelId = relId;
00404     }
00405 
00406     if (!OidIsValid(relId) && !missing_ok)
00407     {
00408         if (relation->schemaname)
00409             ereport(ERROR,
00410                     (errcode(ERRCODE_UNDEFINED_TABLE),
00411                      errmsg("relation \"%s.%s\" does not exist",
00412                             relation->schemaname, relation->relname)));
00413         else
00414             ereport(ERROR,
00415                     (errcode(ERRCODE_UNDEFINED_TABLE),
00416                      errmsg("relation \"%s\" does not exist",
00417                             relation->relname)));
00418     }
00419     return relId;
00420 }
00421 
00422 /*
00423  * RangeVarGetCreationNamespace
00424  *      Given a RangeVar describing a to-be-created relation,
00425  *      choose which namespace to create it in.
00426  *
00427  * Note: calling this may result in a CommandCounterIncrement operation.
00428  * That will happen on the first request for a temp table in any particular
00429  * backend run; we will need to either create or clean out the temp schema.
00430  */
00431 Oid
00432 RangeVarGetCreationNamespace(const RangeVar *newRelation)
00433 {
00434     Oid         namespaceId;
00435 
00436     /*
00437      * We check the catalog name and then ignore it.
00438      */
00439     if (newRelation->catalogname)
00440     {
00441         if (strcmp(newRelation->catalogname, get_database_name(MyDatabaseId)) != 0)
00442             ereport(ERROR,
00443                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00444                      errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
00445                             newRelation->catalogname, newRelation->schemaname,
00446                             newRelation->relname)));
00447     }
00448 
00449     if (newRelation->schemaname)
00450     {
00451         /* check for pg_temp alias */
00452         if (strcmp(newRelation->schemaname, "pg_temp") == 0)
00453         {
00454             /* Initialize temp namespace if first time through */
00455             if (!OidIsValid(myTempNamespace))
00456                 InitTempTableNamespace();
00457             return myTempNamespace;
00458         }
00459         /* use exact schema given */
00460         namespaceId = get_namespace_oid(newRelation->schemaname, false);
00461         /* we do not check for USAGE rights here! */
00462     }
00463     else if (newRelation->relpersistence == RELPERSISTENCE_TEMP)
00464     {
00465         /* Initialize temp namespace if first time through */
00466         if (!OidIsValid(myTempNamespace))
00467             InitTempTableNamespace();
00468         return myTempNamespace;
00469     }
00470     else
00471     {
00472         /* use the default creation namespace */
00473         recomputeNamespacePath();
00474         if (activeTempCreationPending)
00475         {
00476             /* Need to initialize temp namespace */
00477             InitTempTableNamespace();
00478             return myTempNamespace;
00479         }
00480         namespaceId = activeCreationNamespace;
00481         if (!OidIsValid(namespaceId))
00482             ereport(ERROR,
00483                     (errcode(ERRCODE_UNDEFINED_SCHEMA),
00484                      errmsg("no schema has been selected to create in")));
00485     }
00486 
00487     /* Note: callers will check for CREATE rights when appropriate */
00488 
00489     return namespaceId;
00490 }
00491 
00492 /*
00493  * RangeVarGetAndCheckCreationNamespace
00494  *
00495  * This function returns the OID of the namespace in which a new relation
00496  * with a given name should be created.  If the user does not have CREATE
00497  * permission on the target namespace, this function will instead signal
00498  * an ERROR.
00499  *
00500  * If non-NULL, *existing_oid is set to the OID of any existing relation with
00501  * the same name which already exists in that namespace, or to InvalidOid if
00502  * no such relation exists.
00503  *
00504  * If lockmode != NoLock, the specified lock mode is acquire on the existing
00505  * relation, if any, provided that the current user owns the target relation.
00506  * However, if lockmode != NoLock and the user does not own the target
00507  * relation, we throw an ERROR, as we must not try to lock relations the
00508  * user does not have permissions on.
00509  *
00510  * As a side effect, this function acquires AccessShareLock on the target
00511  * namespace.  Without this, the namespace could be dropped before our
00512  * transaction commits, leaving behind relations with relnamespace pointing
00513  * to a no-longer-exstant namespace.
00514  *
00515  * As a further side-effect, if the select namespace is a temporary namespace,
00516  * we mark the RangeVar as RELPERSISTENCE_TEMP.
00517  */
00518 Oid
00519 RangeVarGetAndCheckCreationNamespace(RangeVar *relation,
00520                                      LOCKMODE lockmode,
00521                                      Oid *existing_relation_id)
00522 {
00523     uint64      inval_count;
00524     Oid         relid;
00525     Oid         oldrelid = InvalidOid;
00526     Oid         nspid;
00527     Oid         oldnspid = InvalidOid;
00528     bool        retry = false;
00529 
00530     /*
00531      * We check the catalog name and then ignore it.
00532      */
00533     if (relation->catalogname)
00534     {
00535         if (strcmp(relation->catalogname, get_database_name(MyDatabaseId)) != 0)
00536             ereport(ERROR,
00537                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00538                      errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
00539                             relation->catalogname, relation->schemaname,
00540                             relation->relname)));
00541     }
00542 
00543     /*
00544      * As in RangeVarGetRelidExtended(), we guard against concurrent DDL
00545      * operations by tracking whether any invalidation messages are processed
00546      * while we're doing the name lookups and acquiring locks.  See comments
00547      * in that function for a more detailed explanation of this logic.
00548      */
00549     for (;;)
00550     {
00551         AclResult   aclresult;
00552 
00553         inval_count = SharedInvalidMessageCounter;
00554 
00555         /* Look up creation namespace and check for existing relation. */
00556         nspid = RangeVarGetCreationNamespace(relation);
00557         Assert(OidIsValid(nspid));
00558         if (existing_relation_id != NULL)
00559             relid = get_relname_relid(relation->relname, nspid);
00560         else
00561             relid = InvalidOid;
00562 
00563         /*
00564          * In bootstrap processing mode, we don't bother with permissions or
00565          * locking.  Permissions might not be working yet, and locking is
00566          * unnecessary.
00567          */
00568         if (IsBootstrapProcessingMode())
00569             break;
00570 
00571         /* Check namespace permissions. */
00572         aclresult = pg_namespace_aclcheck(nspid, GetUserId(), ACL_CREATE);
00573         if (aclresult != ACLCHECK_OK)
00574             aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
00575                            get_namespace_name(nspid));
00576 
00577         if (retry)
00578         {
00579             /* If nothing changed, we're done. */
00580             if (relid == oldrelid && nspid == oldnspid)
00581                 break;
00582             /* If creation namespace has changed, give up old lock. */
00583             if (nspid != oldnspid)
00584                 UnlockDatabaseObject(NamespaceRelationId, oldnspid, 0,
00585                                      AccessShareLock);
00586             /* If name points to something different, give up old lock. */
00587             if (relid != oldrelid && OidIsValid(oldrelid) && lockmode != NoLock)
00588                 UnlockRelationOid(oldrelid, lockmode);
00589         }
00590 
00591         /* Lock namespace. */
00592         if (nspid != oldnspid)
00593             LockDatabaseObject(NamespaceRelationId, nspid, 0, AccessShareLock);
00594 
00595         /* Lock relation, if required if and we have permission. */
00596         if (lockmode != NoLock && OidIsValid(relid))
00597         {
00598             if (!pg_class_ownercheck(relid, GetUserId()))
00599                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
00600                                relation->relname);
00601             if (relid != oldrelid)
00602                 LockRelationOid(relid, lockmode);
00603         }
00604 
00605         /* If no invalidation message were processed, we're done! */
00606         if (inval_count == SharedInvalidMessageCounter)
00607             break;
00608 
00609         /* Something may have changed, so recheck our work. */
00610         retry = true;
00611         oldrelid = relid;
00612         oldnspid = nspid;
00613     }
00614 
00615     RangeVarAdjustRelationPersistence(relation, nspid);
00616     if (existing_relation_id != NULL)
00617         *existing_relation_id = relid;
00618     return nspid;
00619 }
00620 
00621 /*
00622  * Adjust the relpersistence for an about-to-be-created relation based on the
00623  * creation namespace, and throw an error for invalid combinations.
00624  */
00625 void
00626 RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
00627 {
00628     switch (newRelation->relpersistence)
00629     {
00630         case RELPERSISTENCE_TEMP:
00631             if (!isTempOrToastNamespace(nspid))
00632             {
00633                 if (isAnyTempNamespace(nspid))
00634                     ereport(ERROR,
00635                             (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
00636                              errmsg("cannot create relations in temporary schemas of other sessions")));
00637                 else
00638                     ereport(ERROR,
00639                             (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
00640                              errmsg("cannot create temporary relation in non-temporary schema")));
00641             }
00642             break;
00643         case RELPERSISTENCE_PERMANENT:
00644             if (isTempOrToastNamespace(nspid))
00645                 newRelation->relpersistence = RELPERSISTENCE_TEMP;
00646             else if (isAnyTempNamespace(nspid))
00647                 ereport(ERROR,
00648                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
00649                          errmsg("cannot create relations in temporary schemas of other sessions")));
00650             break;
00651         default:
00652             if (isAnyTempNamespace(nspid))
00653                 ereport(ERROR,
00654                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
00655                          errmsg("only temporary relations may be created in temporary schemas")));
00656     }
00657 }
00658 
00659 /*
00660  * RelnameGetRelid
00661  *      Try to resolve an unqualified relation name.
00662  *      Returns OID if relation found in search path, else InvalidOid.
00663  */
00664 Oid
00665 RelnameGetRelid(const char *relname)
00666 {
00667     Oid         relid;
00668     ListCell   *l;
00669 
00670     recomputeNamespacePath();
00671 
00672     foreach(l, activeSearchPath)
00673     {
00674         Oid         namespaceId = lfirst_oid(l);
00675 
00676         relid = get_relname_relid(relname, namespaceId);
00677         if (OidIsValid(relid))
00678             return relid;
00679     }
00680 
00681     /* Not found in path */
00682     return InvalidOid;
00683 }
00684 
00685 
00686 /*
00687  * RelationIsVisible
00688  *      Determine whether a relation (identified by OID) is visible in the
00689  *      current search path.  Visible means "would be found by searching
00690  *      for the unqualified relation name".
00691  */
00692 bool
00693 RelationIsVisible(Oid relid)
00694 {
00695     HeapTuple   reltup;
00696     Form_pg_class relform;
00697     Oid         relnamespace;
00698     bool        visible;
00699 
00700     reltup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
00701     if (!HeapTupleIsValid(reltup))
00702         elog(ERROR, "cache lookup failed for relation %u", relid);
00703     relform = (Form_pg_class) GETSTRUCT(reltup);
00704 
00705     recomputeNamespacePath();
00706 
00707     /*
00708      * Quick check: if it ain't in the path at all, it ain't visible. Items in
00709      * the system namespace are surely in the path and so we needn't even do
00710      * list_member_oid() for them.
00711      */
00712     relnamespace = relform->relnamespace;
00713     if (relnamespace != PG_CATALOG_NAMESPACE &&
00714         !list_member_oid(activeSearchPath, relnamespace))
00715         visible = false;
00716     else
00717     {
00718         /*
00719          * If it is in the path, it might still not be visible; it could be
00720          * hidden by another relation of the same name earlier in the path. So
00721          * we must do a slow check for conflicting relations.
00722          */
00723         char       *relname = NameStr(relform->relname);
00724         ListCell   *l;
00725 
00726         visible = false;
00727         foreach(l, activeSearchPath)
00728         {
00729             Oid         namespaceId = lfirst_oid(l);
00730 
00731             if (namespaceId == relnamespace)
00732             {
00733                 /* Found it first in path */
00734                 visible = true;
00735                 break;
00736             }
00737             if (OidIsValid(get_relname_relid(relname, namespaceId)))
00738             {
00739                 /* Found something else first in path */
00740                 break;
00741             }
00742         }
00743     }
00744 
00745     ReleaseSysCache(reltup);
00746 
00747     return visible;
00748 }
00749 
00750 
00751 /*
00752  * TypenameGetTypid
00753  *      Try to resolve an unqualified datatype name.
00754  *      Returns OID if type found in search path, else InvalidOid.
00755  *
00756  * This is essentially the same as RelnameGetRelid.
00757  */
00758 Oid
00759 TypenameGetTypid(const char *typname)
00760 {
00761     Oid         typid;
00762     ListCell   *l;
00763 
00764     recomputeNamespacePath();
00765 
00766     foreach(l, activeSearchPath)
00767     {
00768         Oid         namespaceId = lfirst_oid(l);
00769 
00770         typid = GetSysCacheOid2(TYPENAMENSP,
00771                                 PointerGetDatum(typname),
00772                                 ObjectIdGetDatum(namespaceId));
00773         if (OidIsValid(typid))
00774             return typid;
00775     }
00776 
00777     /* Not found in path */
00778     return InvalidOid;
00779 }
00780 
00781 /*
00782  * TypeIsVisible
00783  *      Determine whether a type (identified by OID) is visible in the
00784  *      current search path.  Visible means "would be found by searching
00785  *      for the unqualified type name".
00786  */
00787 bool
00788 TypeIsVisible(Oid typid)
00789 {
00790     HeapTuple   typtup;
00791     Form_pg_type typform;
00792     Oid         typnamespace;
00793     bool        visible;
00794 
00795     typtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
00796     if (!HeapTupleIsValid(typtup))
00797         elog(ERROR, "cache lookup failed for type %u", typid);
00798     typform = (Form_pg_type) GETSTRUCT(typtup);
00799 
00800     recomputeNamespacePath();
00801 
00802     /*
00803      * Quick check: if it ain't in the path at all, it ain't visible. Items in
00804      * the system namespace are surely in the path and so we needn't even do
00805      * list_member_oid() for them.
00806      */
00807     typnamespace = typform->typnamespace;
00808     if (typnamespace != PG_CATALOG_NAMESPACE &&
00809         !list_member_oid(activeSearchPath, typnamespace))
00810         visible = false;
00811     else
00812     {
00813         /*
00814          * If it is in the path, it might still not be visible; it could be
00815          * hidden by another type of the same name earlier in the path. So we
00816          * must do a slow check for conflicting types.
00817          */
00818         char       *typname = NameStr(typform->typname);
00819         ListCell   *l;
00820 
00821         visible = false;
00822         foreach(l, activeSearchPath)
00823         {
00824             Oid         namespaceId = lfirst_oid(l);
00825 
00826             if (namespaceId == typnamespace)
00827             {
00828                 /* Found it first in path */
00829                 visible = true;
00830                 break;
00831             }
00832             if (SearchSysCacheExists2(TYPENAMENSP,
00833                                       PointerGetDatum(typname),
00834                                       ObjectIdGetDatum(namespaceId)))
00835             {
00836                 /* Found something else first in path */
00837                 break;
00838             }
00839         }
00840     }
00841 
00842     ReleaseSysCache(typtup);
00843 
00844     return visible;
00845 }
00846 
00847 
00848 /*
00849  * FuncnameGetCandidates
00850  *      Given a possibly-qualified function name and argument count,
00851  *      retrieve a list of the possible matches.
00852  *
00853  * If nargs is -1, we return all functions matching the given name,
00854  * regardless of argument count.  (argnames must be NIL, and expand_variadic
00855  * and expand_defaults must be false, in this case.)
00856  *
00857  * If argnames isn't NIL, we are considering a named- or mixed-notation call,
00858  * and only functions having all the listed argument names will be returned.
00859  * (We assume that length(argnames) <= nargs and all the passed-in names are
00860  * distinct.)  The returned structs will include an argnumbers array showing
00861  * the actual argument index for each logical argument position.
00862  *
00863  * If expand_variadic is true, then variadic functions having the same number
00864  * or fewer arguments will be retrieved, with the variadic argument and any
00865  * additional argument positions filled with the variadic element type.
00866  * nvargs in the returned struct is set to the number of such arguments.
00867  * If expand_variadic is false, variadic arguments are not treated specially,
00868  * and the returned nvargs will always be zero.
00869  *
00870  * If expand_defaults is true, functions that could match after insertion of
00871  * default argument values will also be retrieved.  In this case the returned
00872  * structs could have nargs > passed-in nargs, and ndargs is set to the number
00873  * of additional args (which can be retrieved from the function's
00874  * proargdefaults entry).
00875  *
00876  * It is not possible for nvargs and ndargs to both be nonzero in the same
00877  * list entry, since default insertion allows matches to functions with more
00878  * than nargs arguments while the variadic transformation requires the same
00879  * number or less.
00880  *
00881  * When argnames isn't NIL, the returned args[] type arrays are not ordered
00882  * according to the functions' declarations, but rather according to the call:
00883  * first any positional arguments, then the named arguments, then defaulted
00884  * arguments (if needed and allowed by expand_defaults).  The argnumbers[]
00885  * array can be used to map this back to the catalog information.
00886  * argnumbers[k] is set to the proargtypes index of the k'th call argument.
00887  *
00888  * We search a single namespace if the function name is qualified, else
00889  * all namespaces in the search path.  In the multiple-namespace case,
00890  * we arrange for entries in earlier namespaces to mask identical entries in
00891  * later namespaces.
00892  *
00893  * When expanding variadics, we arrange for non-variadic functions to mask
00894  * variadic ones if the expanded argument list is the same.  It is still
00895  * possible for there to be conflicts between different variadic functions,
00896  * however.
00897  *
00898  * It is guaranteed that the return list will never contain multiple entries
00899  * with identical argument lists.  When expand_defaults is true, the entries
00900  * could have more than nargs positions, but we still guarantee that they are
00901  * distinct in the first nargs positions.  However, if argnames isn't NIL or
00902  * either expand_variadic or expand_defaults is true, there might be multiple
00903  * candidate functions that expand to identical argument lists.  Rather than
00904  * throw error here, we report such situations by returning a single entry
00905  * with oid = 0 that represents a set of such conflicting candidates.
00906  * The caller might end up discarding such an entry anyway, but if it selects
00907  * such an entry it should react as though the call were ambiguous.
00908  */
00909 FuncCandidateList
00910 FuncnameGetCandidates(List *names, int nargs, List *argnames,
00911                       bool expand_variadic, bool expand_defaults)
00912 {
00913     FuncCandidateList resultList = NULL;
00914     bool        any_special = false;
00915     char       *schemaname;
00916     char       *funcname;
00917     Oid         namespaceId;
00918     CatCList   *catlist;
00919     int         i;
00920 
00921     /* check for caller error */
00922     Assert(nargs >= 0 || !(expand_variadic | expand_defaults));
00923 
00924     /* deconstruct the name list */
00925     DeconstructQualifiedName(names, &schemaname, &funcname);
00926 
00927     if (schemaname)
00928     {
00929         /* use exact schema given */
00930         namespaceId = LookupExplicitNamespace(schemaname, false);
00931     }
00932     else
00933     {
00934         /* flag to indicate we need namespace search */
00935         namespaceId = InvalidOid;
00936         recomputeNamespacePath();
00937     }
00938 
00939     /* Search syscache by name only */
00940     catlist = SearchSysCacheList1(PROCNAMEARGSNSP, CStringGetDatum(funcname));
00941 
00942     for (i = 0; i < catlist->n_members; i++)
00943     {
00944         HeapTuple   proctup = &catlist->members[i]->tuple;
00945         Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
00946         int         pronargs = procform->pronargs;
00947         int         effective_nargs;
00948         int         pathpos = 0;
00949         bool        variadic;
00950         bool        use_defaults;
00951         Oid         va_elem_type;
00952         int        *argnumbers = NULL;
00953         FuncCandidateList newResult;
00954 
00955         if (OidIsValid(namespaceId))
00956         {
00957             /* Consider only procs in specified namespace */
00958             if (procform->pronamespace != namespaceId)
00959                 continue;
00960         }
00961         else
00962         {
00963             /*
00964              * Consider only procs that are in the search path and are not in
00965              * the temp namespace.
00966              */
00967             ListCell   *nsp;
00968 
00969             foreach(nsp, activeSearchPath)
00970             {
00971                 if (procform->pronamespace == lfirst_oid(nsp) &&
00972                     procform->pronamespace != myTempNamespace)
00973                     break;
00974                 pathpos++;
00975             }
00976             if (nsp == NULL)
00977                 continue;       /* proc is not in search path */
00978         }
00979 
00980         if (argnames != NIL)
00981         {
00982             /*
00983              * Call uses named or mixed notation
00984              *
00985              * Named or mixed notation can match a variadic function only if
00986              * expand_variadic is off; otherwise there is no way to match the
00987              * presumed-nameless parameters expanded from the variadic array.
00988              */
00989             if (OidIsValid(procform->provariadic) && expand_variadic)
00990                 continue;
00991             va_elem_type = InvalidOid;
00992             variadic = false;
00993 
00994             /*
00995              * Check argument count.
00996              */
00997             Assert(nargs >= 0); /* -1 not supported with argnames */
00998 
00999             if (pronargs > nargs && expand_defaults)
01000             {
01001                 /* Ignore if not enough default expressions */
01002                 if (nargs + procform->pronargdefaults < pronargs)
01003                     continue;
01004                 use_defaults = true;
01005             }
01006             else
01007                 use_defaults = false;
01008 
01009             /* Ignore if it doesn't match requested argument count */
01010             if (pronargs != nargs && !use_defaults)
01011                 continue;
01012 
01013             /* Check for argument name match, generate positional mapping */
01014             if (!MatchNamedCall(proctup, nargs, argnames,
01015                                 &argnumbers))
01016                 continue;
01017 
01018             /* Named argument matching is always "special" */
01019             any_special = true;
01020         }
01021         else
01022         {
01023             /*
01024              * Call uses positional notation
01025              *
01026              * Check if function is variadic, and get variadic element type if
01027              * so.  If expand_variadic is false, we should just ignore
01028              * variadic-ness.
01029              */
01030             if (pronargs <= nargs && expand_variadic)
01031             {
01032                 va_elem_type = procform->provariadic;
01033                 variadic = OidIsValid(va_elem_type);
01034                 any_special |= variadic;
01035             }
01036             else
01037             {
01038                 va_elem_type = InvalidOid;
01039                 variadic = false;
01040             }
01041 
01042             /*
01043              * Check if function can match by using parameter defaults.
01044              */
01045             if (pronargs > nargs && expand_defaults)
01046             {
01047                 /* Ignore if not enough default expressions */
01048                 if (nargs + procform->pronargdefaults < pronargs)
01049                     continue;
01050                 use_defaults = true;
01051                 any_special = true;
01052             }
01053             else
01054                 use_defaults = false;
01055 
01056             /* Ignore if it doesn't match requested argument count */
01057             if (nargs >= 0 && pronargs != nargs && !variadic && !use_defaults)
01058                 continue;
01059         }
01060 
01061         /*
01062          * We must compute the effective argument list so that we can easily
01063          * compare it to earlier results.  We waste a palloc cycle if it gets
01064          * masked by an earlier result, but really that's a pretty infrequent
01065          * case so it's not worth worrying about.
01066          */
01067         effective_nargs = Max(pronargs, nargs);
01068         newResult = (FuncCandidateList)
01069             palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid)
01070                    + effective_nargs * sizeof(Oid));
01071         newResult->pathpos = pathpos;
01072         newResult->oid = HeapTupleGetOid(proctup);
01073         newResult->nargs = effective_nargs;
01074         newResult->argnumbers = argnumbers;
01075         if (argnumbers)
01076         {
01077             /* Re-order the argument types into call's logical order */
01078             Oid        *proargtypes = procform->proargtypes.values;
01079             int         i;
01080 
01081             for (i = 0; i < pronargs; i++)
01082                 newResult->args[i] = proargtypes[argnumbers[i]];
01083         }
01084         else
01085         {
01086             /* Simple positional case, just copy proargtypes as-is */
01087             memcpy(newResult->args, procform->proargtypes.values,
01088                    pronargs * sizeof(Oid));
01089         }
01090         if (variadic)
01091         {
01092             int         i;
01093 
01094             newResult->nvargs = effective_nargs - pronargs + 1;
01095             /* Expand variadic argument into N copies of element type */
01096             for (i = pronargs - 1; i < effective_nargs; i++)
01097                 newResult->args[i] = va_elem_type;
01098         }
01099         else
01100             newResult->nvargs = 0;
01101         newResult->ndargs = use_defaults ? pronargs - nargs : 0;
01102 
01103         /*
01104          * Does it have the same arguments as something we already accepted?
01105          * If so, decide what to do to avoid returning duplicate argument
01106          * lists.  We can skip this check for the single-namespace case if no
01107          * special (named, variadic or defaults) match has been made, since
01108          * then the unique index on pg_proc guarantees all the matches have
01109          * different argument lists.
01110          */
01111         if (resultList != NULL &&
01112             (any_special || !OidIsValid(namespaceId)))
01113         {
01114             /*
01115              * If we have an ordered list from SearchSysCacheList (the normal
01116              * case), then any conflicting proc must immediately adjoin this
01117              * one in the list, so we only need to look at the newest result
01118              * item.  If we have an unordered list, we have to scan the whole
01119              * result list.  Also, if either the current candidate or any
01120              * previous candidate is a special match, we can't assume that
01121              * conflicts are adjacent.
01122              *
01123              * We ignore defaulted arguments in deciding what is a match.
01124              */
01125             FuncCandidateList prevResult;
01126 
01127             if (catlist->ordered && !any_special)
01128             {
01129                 /* ndargs must be 0 if !any_special */
01130                 if (effective_nargs == resultList->nargs &&
01131                     memcmp(newResult->args,
01132                            resultList->args,
01133                            effective_nargs * sizeof(Oid)) == 0)
01134                     prevResult = resultList;
01135                 else
01136                     prevResult = NULL;
01137             }
01138             else
01139             {
01140                 int         cmp_nargs = newResult->nargs - newResult->ndargs;
01141 
01142                 for (prevResult = resultList;
01143                      prevResult;
01144                      prevResult = prevResult->next)
01145                 {
01146                     if (cmp_nargs == prevResult->nargs - prevResult->ndargs &&
01147                         memcmp(newResult->args,
01148                                prevResult->args,
01149                                cmp_nargs * sizeof(Oid)) == 0)
01150                         break;
01151                 }
01152             }
01153 
01154             if (prevResult)
01155             {
01156                 /*
01157                  * We have a match with a previous result.  Decide which one
01158                  * to keep, or mark it ambiguous if we can't decide.  The
01159                  * logic here is preference > 0 means prefer the old result,
01160                  * preference < 0 means prefer the new, preference = 0 means
01161                  * ambiguous.
01162                  */
01163                 int         preference;
01164 
01165                 if (pathpos != prevResult->pathpos)
01166                 {
01167                     /*
01168                      * Prefer the one that's earlier in the search path.
01169                      */
01170                     preference = pathpos - prevResult->pathpos;
01171                 }
01172                 else if (variadic && prevResult->nvargs == 0)
01173                 {
01174                     /*
01175                      * With variadic functions we could have, for example,
01176                      * both foo(numeric) and foo(variadic numeric[]) in the
01177                      * same namespace; if so we prefer the non-variadic match
01178                      * on efficiency grounds.
01179                      */
01180                     preference = 1;
01181                 }
01182                 else if (!variadic && prevResult->nvargs > 0)
01183                 {
01184                     preference = -1;
01185                 }
01186                 else
01187                 {
01188                     /*----------
01189                      * We can't decide.  This can happen with, for example,
01190                      * both foo(numeric, variadic numeric[]) and
01191                      * foo(variadic numeric[]) in the same namespace, or
01192                      * both foo(int) and foo (int, int default something)
01193                      * in the same namespace, or both foo(a int, b text)
01194                      * and foo(b text, a int) in the same namespace.
01195                      *----------
01196                      */
01197                     preference = 0;
01198                 }
01199 
01200                 if (preference > 0)
01201                 {
01202                     /* keep previous result */
01203                     pfree(newResult);
01204                     continue;
01205                 }
01206                 else if (preference < 0)
01207                 {
01208                     /* remove previous result from the list */
01209                     if (prevResult == resultList)
01210                         resultList = prevResult->next;
01211                     else
01212                     {
01213                         FuncCandidateList prevPrevResult;
01214 
01215                         for (prevPrevResult = resultList;
01216                              prevPrevResult;
01217                              prevPrevResult = prevPrevResult->next)
01218                         {
01219                             if (prevResult == prevPrevResult->next)
01220                             {
01221                                 prevPrevResult->next = prevResult->next;
01222                                 break;
01223                             }
01224                         }
01225                         Assert(prevPrevResult); /* assert we found it */
01226                     }
01227                     pfree(prevResult);
01228                     /* fall through to add newResult to list */
01229                 }
01230                 else
01231                 {
01232                     /* mark old result as ambiguous, discard new */
01233                     prevResult->oid = InvalidOid;
01234                     pfree(newResult);
01235                     continue;
01236                 }
01237             }
01238         }
01239 
01240         /*
01241          * Okay to add it to result list
01242          */
01243         newResult->next = resultList;
01244         resultList = newResult;
01245     }
01246 
01247     ReleaseSysCacheList(catlist);
01248 
01249     return resultList;
01250 }
01251 
01252 /*
01253  * MatchNamedCall
01254  *      Given a pg_proc heap tuple and a call's list of argument names,
01255  *      check whether the function could match the call.
01256  *
01257  * The call could match if all supplied argument names are accepted by
01258  * the function, in positions after the last positional argument, and there
01259  * are defaults for all unsupplied arguments.
01260  *
01261  * The number of positional arguments is nargs - list_length(argnames).
01262  * Note caller has already done basic checks on argument count.
01263  *
01264  * On match, return true and fill *argnumbers with a palloc'd array showing
01265  * the mapping from call argument positions to actual function argument
01266  * numbers.  Defaulted arguments are included in this map, at positions
01267  * after the last supplied argument.
01268  */
01269 static bool
01270 MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
01271                int **argnumbers)
01272 {
01273     Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
01274     int         pronargs = procform->pronargs;
01275     int         numposargs = nargs - list_length(argnames);
01276     int         pronallargs;
01277     Oid        *p_argtypes;
01278     char      **p_argnames;
01279     char       *p_argmodes;
01280     bool        arggiven[FUNC_MAX_ARGS];
01281     bool        isnull;
01282     int         ap;             /* call args position */
01283     int         pp;             /* proargs position */
01284     ListCell   *lc;
01285 
01286     Assert(argnames != NIL);
01287     Assert(numposargs >= 0);
01288     Assert(nargs <= pronargs);
01289 
01290     /* Ignore this function if its proargnames is null */
01291     (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proargnames,
01292                            &isnull);
01293     if (isnull)
01294         return false;
01295 
01296     /* OK, let's extract the argument names and types */
01297     pronallargs = get_func_arg_info(proctup,
01298                                     &p_argtypes, &p_argnames, &p_argmodes);
01299     Assert(p_argnames != NULL);
01300 
01301     /* initialize state for matching */
01302     *argnumbers = (int *) palloc(pronargs * sizeof(int));
01303     memset(arggiven, false, pronargs * sizeof(bool));
01304 
01305     /* there are numposargs positional args before the named args */
01306     for (ap = 0; ap < numposargs; ap++)
01307     {
01308         (*argnumbers)[ap] = ap;
01309         arggiven[ap] = true;
01310     }
01311 
01312     /* now examine the named args */
01313     foreach(lc, argnames)
01314     {
01315         char       *argname = (char *) lfirst(lc);
01316         bool        found;
01317         int         i;
01318 
01319         pp = 0;
01320         found = false;
01321         for (i = 0; i < pronallargs; i++)
01322         {
01323             /* consider only input parameters */
01324             if (p_argmodes &&
01325                 (p_argmodes[i] != FUNC_PARAM_IN &&
01326                  p_argmodes[i] != FUNC_PARAM_INOUT &&
01327                  p_argmodes[i] != FUNC_PARAM_VARIADIC))
01328                 continue;
01329             if (p_argnames[i] && strcmp(p_argnames[i], argname) == 0)
01330             {
01331                 /* fail if argname matches a positional argument */
01332                 if (arggiven[pp])
01333                     return false;
01334                 arggiven[pp] = true;
01335                 (*argnumbers)[ap] = pp;
01336                 found = true;
01337                 break;
01338             }
01339             /* increase pp only for input parameters */
01340             pp++;
01341         }
01342         /* if name isn't in proargnames, fail */
01343         if (!found)
01344             return false;
01345         ap++;
01346     }
01347 
01348     Assert(ap == nargs);        /* processed all actual parameters */
01349 
01350     /* Check for default arguments */
01351     if (nargs < pronargs)
01352     {
01353         int         first_arg_with_default = pronargs - procform->pronargdefaults;
01354 
01355         for (pp = numposargs; pp < pronargs; pp++)
01356         {
01357             if (arggiven[pp])
01358                 continue;
01359             /* fail if arg not given and no default available */
01360             if (pp < first_arg_with_default)
01361                 return false;
01362             (*argnumbers)[ap++] = pp;
01363         }
01364     }
01365 
01366     Assert(ap == pronargs);     /* processed all function parameters */
01367 
01368     return true;
01369 }
01370 
01371 /*
01372  * FunctionIsVisible
01373  *      Determine whether a function (identified by OID) is visible in the
01374  *      current search path.  Visible means "would be found by searching
01375  *      for the unqualified function name with exact argument matches".
01376  */
01377 bool
01378 FunctionIsVisible(Oid funcid)
01379 {
01380     HeapTuple   proctup;
01381     Form_pg_proc procform;
01382     Oid         pronamespace;
01383     bool        visible;
01384 
01385     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
01386     if (!HeapTupleIsValid(proctup))
01387         elog(ERROR, "cache lookup failed for function %u", funcid);
01388     procform = (Form_pg_proc) GETSTRUCT(proctup);
01389 
01390     recomputeNamespacePath();
01391 
01392     /*
01393      * Quick check: if it ain't in the path at all, it ain't visible. Items in
01394      * the system namespace are surely in the path and so we needn't even do
01395      * list_member_oid() for them.
01396      */
01397     pronamespace = procform->pronamespace;
01398     if (pronamespace != PG_CATALOG_NAMESPACE &&
01399         !list_member_oid(activeSearchPath, pronamespace))
01400         visible = false;
01401     else
01402     {
01403         /*
01404          * If it is in the path, it might still not be visible; it could be
01405          * hidden by another proc of the same name and arguments earlier in
01406          * the path.  So we must do a slow check to see if this is the same
01407          * proc that would be found by FuncnameGetCandidates.
01408          */
01409         char       *proname = NameStr(procform->proname);
01410         int         nargs = procform->pronargs;
01411         FuncCandidateList clist;
01412 
01413         visible = false;
01414 
01415         clist = FuncnameGetCandidates(list_make1(makeString(proname)),
01416                                       nargs, NIL, false, false);
01417 
01418         for (; clist; clist = clist->next)
01419         {
01420             if (memcmp(clist->args, procform->proargtypes.values,
01421                        nargs * sizeof(Oid)) == 0)
01422             {
01423                 /* Found the expected entry; is it the right proc? */
01424                 visible = (clist->oid == funcid);
01425                 break;
01426             }
01427         }
01428     }
01429 
01430     ReleaseSysCache(proctup);
01431 
01432     return visible;
01433 }
01434 
01435 
01436 /*
01437  * OpernameGetOprid
01438  *      Given a possibly-qualified operator name and exact input datatypes,
01439  *      look up the operator.  Returns InvalidOid if not found.
01440  *
01441  * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
01442  * a postfix op.
01443  *
01444  * If the operator name is not schema-qualified, it is sought in the current
01445  * namespace search path.
01446  */
01447 Oid
01448 OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
01449 {
01450     char       *schemaname;
01451     char       *opername;
01452     CatCList   *catlist;
01453     ListCell   *l;
01454 
01455     /* deconstruct the name list */
01456     DeconstructQualifiedName(names, &schemaname, &opername);
01457 
01458     if (schemaname)
01459     {
01460         /* search only in exact schema given */
01461         Oid         namespaceId;
01462         HeapTuple   opertup;
01463 
01464         namespaceId = LookupExplicitNamespace(schemaname, false);
01465         opertup = SearchSysCache4(OPERNAMENSP,
01466                                   CStringGetDatum(opername),
01467                                   ObjectIdGetDatum(oprleft),
01468                                   ObjectIdGetDatum(oprright),
01469                                   ObjectIdGetDatum(namespaceId));
01470         if (HeapTupleIsValid(opertup))
01471         {
01472             Oid         result = HeapTupleGetOid(opertup);
01473 
01474             ReleaseSysCache(opertup);
01475             return result;
01476         }
01477         return InvalidOid;
01478     }
01479 
01480     /* Search syscache by name and argument types */
01481     catlist = SearchSysCacheList3(OPERNAMENSP,
01482                                   CStringGetDatum(opername),
01483                                   ObjectIdGetDatum(oprleft),
01484                                   ObjectIdGetDatum(oprright));
01485 
01486     if (catlist->n_members == 0)
01487     {
01488         /* no hope, fall out early */
01489         ReleaseSysCacheList(catlist);
01490         return InvalidOid;
01491     }
01492 
01493     /*
01494      * We have to find the list member that is first in the search path, if
01495      * there's more than one.  This doubly-nested loop looks ugly, but in
01496      * practice there should usually be few catlist members.
01497      */
01498     recomputeNamespacePath();
01499 
01500     foreach(l, activeSearchPath)
01501     {
01502         Oid         namespaceId = lfirst_oid(l);
01503         int         i;
01504 
01505         if (namespaceId == myTempNamespace)
01506             continue;           /* do not look in temp namespace */
01507 
01508         for (i = 0; i < catlist->n_members; i++)
01509         {
01510             HeapTuple   opertup = &catlist->members[i]->tuple;
01511             Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
01512 
01513             if (operform->oprnamespace == namespaceId)
01514             {
01515                 Oid         result = HeapTupleGetOid(opertup);
01516 
01517                 ReleaseSysCacheList(catlist);
01518                 return result;
01519             }
01520         }
01521     }
01522 
01523     ReleaseSysCacheList(catlist);
01524     return InvalidOid;
01525 }
01526 
01527 /*
01528  * OpernameGetCandidates
01529  *      Given a possibly-qualified operator name and operator kind,
01530  *      retrieve a list of the possible matches.
01531  *
01532  * If oprkind is '\0', we return all operators matching the given name,
01533  * regardless of arguments.
01534  *
01535  * We search a single namespace if the operator name is qualified, else
01536  * all namespaces in the search path.  The return list will never contain
01537  * multiple entries with identical argument lists --- in the multiple-
01538  * namespace case, we arrange for entries in earlier namespaces to mask
01539  * identical entries in later namespaces.
01540  *
01541  * The returned items always have two args[] entries --- one or the other
01542  * will be InvalidOid for a prefix or postfix oprkind.  nargs is 2, too.
01543  */
01544 FuncCandidateList
01545 OpernameGetCandidates(List *names, char oprkind)
01546 {
01547     FuncCandidateList resultList = NULL;
01548     char       *resultSpace = NULL;
01549     int         nextResult = 0;
01550     char       *schemaname;
01551     char       *opername;
01552     Oid         namespaceId;
01553     CatCList   *catlist;
01554     int         i;
01555 
01556     /* deconstruct the name list */
01557     DeconstructQualifiedName(names, &schemaname, &opername);
01558 
01559     if (schemaname)
01560     {
01561         /* use exact schema given */
01562         namespaceId = LookupExplicitNamespace(schemaname, false);
01563     }
01564     else
01565     {
01566         /* flag to indicate we need namespace search */
01567         namespaceId = InvalidOid;
01568         recomputeNamespacePath();
01569     }
01570 
01571     /* Search syscache by name only */
01572     catlist = SearchSysCacheList1(OPERNAMENSP, CStringGetDatum(opername));
01573 
01574     /*
01575      * In typical scenarios, most if not all of the operators found by the
01576      * catcache search will end up getting returned; and there can be quite a
01577      * few, for common operator names such as '=' or '+'.  To reduce the time
01578      * spent in palloc, we allocate the result space as an array large enough
01579      * to hold all the operators.  The original coding of this routine did a
01580      * separate palloc for each operator, but profiling revealed that the
01581      * pallocs used an unreasonably large fraction of parsing time.
01582      */
01583 #define SPACE_PER_OP MAXALIGN(sizeof(struct _FuncCandidateList) + sizeof(Oid))
01584 
01585     if (catlist->n_members > 0)
01586         resultSpace = palloc(catlist->n_members * SPACE_PER_OP);
01587 
01588     for (i = 0; i < catlist->n_members; i++)
01589     {
01590         HeapTuple   opertup = &catlist->members[i]->tuple;
01591         Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
01592         int         pathpos = 0;
01593         FuncCandidateList newResult;
01594 
01595         /* Ignore operators of wrong kind, if specific kind requested */
01596         if (oprkind && operform->oprkind != oprkind)
01597             continue;
01598 
01599         if (OidIsValid(namespaceId))
01600         {
01601             /* Consider only opers in specified namespace */
01602             if (operform->oprnamespace != namespaceId)
01603                 continue;
01604             /* No need to check args, they must all be different */
01605         }
01606         else
01607         {
01608             /*
01609              * Consider only opers that are in the search path and are not in
01610              * the temp namespace.
01611              */
01612             ListCell   *nsp;
01613 
01614             foreach(nsp, activeSearchPath)
01615             {
01616                 if (operform->oprnamespace == lfirst_oid(nsp) &&
01617                     operform->oprnamespace != myTempNamespace)
01618                     break;
01619                 pathpos++;
01620             }
01621             if (nsp == NULL)
01622                 continue;       /* oper is not in search path */
01623 
01624             /*
01625              * Okay, it's in the search path, but does it have the same
01626              * arguments as something we already accepted?  If so, keep only
01627              * the one that appears earlier in the search path.
01628              *
01629              * If we have an ordered list from SearchSysCacheList (the normal
01630              * case), then any conflicting oper must immediately adjoin this
01631              * one in the list, so we only need to look at the newest result
01632              * item.  If we have an unordered list, we have to scan the whole
01633              * result list.
01634              */
01635             if (resultList)
01636             {
01637                 FuncCandidateList prevResult;
01638 
01639                 if (catlist->ordered)
01640                 {
01641                     if (operform->oprleft == resultList->args[0] &&
01642                         operform->oprright == resultList->args[1])
01643                         prevResult = resultList;
01644                     else
01645                         prevResult = NULL;
01646                 }
01647                 else
01648                 {
01649                     for (prevResult = resultList;
01650                          prevResult;
01651                          prevResult = prevResult->next)
01652                     {
01653                         if (operform->oprleft == prevResult->args[0] &&
01654                             operform->oprright == prevResult->args[1])
01655                             break;
01656                     }
01657                 }
01658                 if (prevResult)
01659                 {
01660                     /* We have a match with a previous result */
01661                     Assert(pathpos != prevResult->pathpos);
01662                     if (pathpos > prevResult->pathpos)
01663                         continue;       /* keep previous result */
01664                     /* replace previous result */
01665                     prevResult->pathpos = pathpos;
01666                     prevResult->oid = HeapTupleGetOid(opertup);
01667                     continue;   /* args are same, of course */
01668                 }
01669             }
01670         }
01671 
01672         /*
01673          * Okay to add it to result list
01674          */
01675         newResult = (FuncCandidateList) (resultSpace + nextResult);
01676         nextResult += SPACE_PER_OP;
01677 
01678         newResult->pathpos = pathpos;
01679         newResult->oid = HeapTupleGetOid(opertup);
01680         newResult->nargs = 2;
01681         newResult->nvargs = 0;
01682         newResult->ndargs = 0;
01683         newResult->argnumbers = NULL;
01684         newResult->args[0] = operform->oprleft;
01685         newResult->args[1] = operform->oprright;
01686         newResult->next = resultList;
01687         resultList = newResult;
01688     }
01689 
01690     ReleaseSysCacheList(catlist);
01691 
01692     return resultList;
01693 }
01694 
01695 /*
01696  * OperatorIsVisible
01697  *      Determine whether an operator (identified by OID) is visible in the
01698  *      current search path.  Visible means "would be found by searching
01699  *      for the unqualified operator name with exact argument matches".
01700  */
01701 bool
01702 OperatorIsVisible(Oid oprid)
01703 {
01704     HeapTuple   oprtup;
01705     Form_pg_operator oprform;
01706     Oid         oprnamespace;
01707     bool        visible;
01708 
01709     oprtup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid));
01710     if (!HeapTupleIsValid(oprtup))
01711         elog(ERROR, "cache lookup failed for operator %u", oprid);
01712     oprform = (Form_pg_operator) GETSTRUCT(oprtup);
01713 
01714     recomputeNamespacePath();
01715 
01716     /*
01717      * Quick check: if it ain't in the path at all, it ain't visible. Items in
01718      * the system namespace are surely in the path and so we needn't even do
01719      * list_member_oid() for them.
01720      */
01721     oprnamespace = oprform->oprnamespace;
01722     if (oprnamespace != PG_CATALOG_NAMESPACE &&
01723         !list_member_oid(activeSearchPath, oprnamespace))
01724         visible = false;
01725     else
01726     {
01727         /*
01728          * If it is in the path, it might still not be visible; it could be
01729          * hidden by another operator of the same name and arguments earlier
01730          * in the path.  So we must do a slow check to see if this is the same
01731          * operator that would be found by OpernameGetOprId.
01732          */
01733         char       *oprname = NameStr(oprform->oprname);
01734 
01735         visible = (OpernameGetOprid(list_make1(makeString(oprname)),
01736                                     oprform->oprleft, oprform->oprright)
01737                    == oprid);
01738     }
01739 
01740     ReleaseSysCache(oprtup);
01741 
01742     return visible;
01743 }
01744 
01745 
01746 /*
01747  * OpclassnameGetOpcid
01748  *      Try to resolve an unqualified index opclass name.
01749  *      Returns OID if opclass found in search path, else InvalidOid.
01750  *
01751  * This is essentially the same as TypenameGetTypid, but we have to have
01752  * an extra argument for the index AM OID.
01753  */
01754 Oid
01755 OpclassnameGetOpcid(Oid amid, const char *opcname)
01756 {
01757     Oid         opcid;
01758     ListCell   *l;
01759 
01760     recomputeNamespacePath();
01761 
01762     foreach(l, activeSearchPath)
01763     {
01764         Oid         namespaceId = lfirst_oid(l);
01765 
01766         if (namespaceId == myTempNamespace)
01767             continue;           /* do not look in temp namespace */
01768 
01769         opcid = GetSysCacheOid3(CLAAMNAMENSP,
01770                                 ObjectIdGetDatum(amid),
01771                                 PointerGetDatum(opcname),
01772                                 ObjectIdGetDatum(namespaceId));
01773         if (OidIsValid(opcid))
01774             return opcid;
01775     }
01776 
01777     /* Not found in path */
01778     return InvalidOid;
01779 }
01780 
01781 /*
01782  * OpclassIsVisible
01783  *      Determine whether an opclass (identified by OID) is visible in the
01784  *      current search path.  Visible means "would be found by searching
01785  *      for the unqualified opclass name".
01786  */
01787 bool
01788 OpclassIsVisible(Oid opcid)
01789 {
01790     HeapTuple   opctup;
01791     Form_pg_opclass opcform;
01792     Oid         opcnamespace;
01793     bool        visible;
01794 
01795     opctup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcid));
01796     if (!HeapTupleIsValid(opctup))
01797         elog(ERROR, "cache lookup failed for opclass %u", opcid);
01798     opcform = (Form_pg_opclass) GETSTRUCT(opctup);
01799 
01800     recomputeNamespacePath();
01801 
01802     /*
01803      * Quick check: if it ain't in the path at all, it ain't visible. Items in
01804      * the system namespace are surely in the path and so we needn't even do
01805      * list_member_oid() for them.
01806      */
01807     opcnamespace = opcform->opcnamespace;
01808     if (opcnamespace != PG_CATALOG_NAMESPACE &&
01809         !list_member_oid(activeSearchPath, opcnamespace))
01810         visible = false;
01811     else
01812     {
01813         /*
01814          * If it is in the path, it might still not be visible; it could be
01815          * hidden by another opclass of the same name earlier in the path. So
01816          * we must do a slow check to see if this opclass would be found by
01817          * OpclassnameGetOpcid.
01818          */
01819         char       *opcname = NameStr(opcform->opcname);
01820 
01821         visible = (OpclassnameGetOpcid(opcform->opcmethod, opcname) == opcid);
01822     }
01823 
01824     ReleaseSysCache(opctup);
01825 
01826     return visible;
01827 }
01828 
01829 /*
01830  * OpfamilynameGetOpfid
01831  *      Try to resolve an unqualified index opfamily name.
01832  *      Returns OID if opfamily found in search path, else InvalidOid.
01833  *
01834  * This is essentially the same as TypenameGetTypid, but we have to have
01835  * an extra argument for the index AM OID.
01836  */
01837 Oid
01838 OpfamilynameGetOpfid(Oid amid, const char *opfname)
01839 {
01840     Oid         opfid;
01841     ListCell   *l;
01842 
01843     recomputeNamespacePath();
01844 
01845     foreach(l, activeSearchPath)
01846     {
01847         Oid         namespaceId = lfirst_oid(l);
01848 
01849         if (namespaceId == myTempNamespace)
01850             continue;           /* do not look in temp namespace */
01851 
01852         opfid = GetSysCacheOid3(OPFAMILYAMNAMENSP,
01853                                 ObjectIdGetDatum(amid),
01854                                 PointerGetDatum(opfname),
01855                                 ObjectIdGetDatum(namespaceId));
01856         if (OidIsValid(opfid))
01857             return opfid;
01858     }
01859 
01860     /* Not found in path */
01861     return InvalidOid;
01862 }
01863 
01864 /*
01865  * OpfamilyIsVisible
01866  *      Determine whether an opfamily (identified by OID) is visible in the
01867  *      current search path.  Visible means "would be found by searching
01868  *      for the unqualified opfamily name".
01869  */
01870 bool
01871 OpfamilyIsVisible(Oid opfid)
01872 {
01873     HeapTuple   opftup;
01874     Form_pg_opfamily opfform;
01875     Oid         opfnamespace;
01876     bool        visible;
01877 
01878     opftup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
01879     if (!HeapTupleIsValid(opftup))
01880         elog(ERROR, "cache lookup failed for opfamily %u", opfid);
01881     opfform = (Form_pg_opfamily) GETSTRUCT(opftup);
01882 
01883     recomputeNamespacePath();
01884 
01885     /*
01886      * Quick check: if it ain't in the path at all, it ain't visible. Items in
01887      * the system namespace are surely in the path and so we needn't even do
01888      * list_member_oid() for them.
01889      */
01890     opfnamespace = opfform->opfnamespace;
01891     if (opfnamespace != PG_CATALOG_NAMESPACE &&
01892         !list_member_oid(activeSearchPath, opfnamespace))
01893         visible = false;
01894     else
01895     {
01896         /*
01897          * If it is in the path, it might still not be visible; it could be
01898          * hidden by another opfamily of the same name earlier in the path. So
01899          * we must do a slow check to see if this opfamily would be found by
01900          * OpfamilynameGetOpfid.
01901          */
01902         char       *opfname = NameStr(opfform->opfname);
01903 
01904         visible = (OpfamilynameGetOpfid(opfform->opfmethod, opfname) == opfid);
01905     }
01906 
01907     ReleaseSysCache(opftup);
01908 
01909     return visible;
01910 }
01911 
01912 /*
01913  * CollationGetCollid
01914  *      Try to resolve an unqualified collation name.
01915  *      Returns OID if collation found in search path, else InvalidOid.
01916  */
01917 Oid
01918 CollationGetCollid(const char *collname)
01919 {
01920     int32       dbencoding = GetDatabaseEncoding();
01921     ListCell   *l;
01922 
01923     recomputeNamespacePath();
01924 
01925     foreach(l, activeSearchPath)
01926     {
01927         Oid         namespaceId = lfirst_oid(l);
01928         Oid         collid;
01929 
01930         if (namespaceId == myTempNamespace)
01931             continue;           /* do not look in temp namespace */
01932 
01933         /* Check for database-encoding-specific entry */
01934         collid = GetSysCacheOid3(COLLNAMEENCNSP,
01935                                  PointerGetDatum(collname),
01936                                  Int32GetDatum(dbencoding),
01937                                  ObjectIdGetDatum(namespaceId));
01938         if (OidIsValid(collid))
01939             return collid;
01940 
01941         /* Check for any-encoding entry */
01942         collid = GetSysCacheOid3(COLLNAMEENCNSP,
01943                                  PointerGetDatum(collname),
01944                                  Int32GetDatum(-1),
01945                                  ObjectIdGetDatum(namespaceId));
01946         if (OidIsValid(collid))
01947             return collid;
01948     }
01949 
01950     /* Not found in path */
01951     return InvalidOid;
01952 }
01953 
01954 /*
01955  * CollationIsVisible
01956  *      Determine whether a collation (identified by OID) is visible in the
01957  *      current search path.  Visible means "would be found by searching
01958  *      for the unqualified collation name".
01959  */
01960 bool
01961 CollationIsVisible(Oid collid)
01962 {
01963     HeapTuple   colltup;
01964     Form_pg_collation collform;
01965     Oid         collnamespace;
01966     bool        visible;
01967 
01968     colltup = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
01969     if (!HeapTupleIsValid(colltup))
01970         elog(ERROR, "cache lookup failed for collation %u", collid);
01971     collform = (Form_pg_collation) GETSTRUCT(colltup);
01972 
01973     recomputeNamespacePath();
01974 
01975     /*
01976      * Quick check: if it ain't in the path at all, it ain't visible. Items in
01977      * the system namespace are surely in the path and so we needn't even do
01978      * list_member_oid() for them.
01979      */
01980     collnamespace = collform->collnamespace;
01981     if (collnamespace != PG_CATALOG_NAMESPACE &&
01982         !list_member_oid(activeSearchPath, collnamespace))
01983         visible = false;
01984     else
01985     {
01986         /*
01987          * If it is in the path, it might still not be visible; it could be
01988          * hidden by another conversion of the same name earlier in the path.
01989          * So we must do a slow check to see if this conversion would be found
01990          * by CollationGetCollid.
01991          */
01992         char       *collname = NameStr(collform->collname);
01993 
01994         visible = (CollationGetCollid(collname) == collid);
01995     }
01996 
01997     ReleaseSysCache(colltup);
01998 
01999     return visible;
02000 }
02001 
02002 
02003 /*
02004  * ConversionGetConid
02005  *      Try to resolve an unqualified conversion name.
02006  *      Returns OID if conversion found in search path, else InvalidOid.
02007  *
02008  * This is essentially the same as RelnameGetRelid.
02009  */
02010 Oid
02011 ConversionGetConid(const char *conname)
02012 {
02013     Oid         conid;
02014     ListCell   *l;
02015 
02016     recomputeNamespacePath();
02017 
02018     foreach(l, activeSearchPath)
02019     {
02020         Oid         namespaceId = lfirst_oid(l);
02021 
02022         if (namespaceId == myTempNamespace)
02023             continue;           /* do not look in temp namespace */
02024 
02025         conid = GetSysCacheOid2(CONNAMENSP,
02026                                 PointerGetDatum(conname),
02027                                 ObjectIdGetDatum(namespaceId));
02028         if (OidIsValid(conid))
02029             return conid;
02030     }
02031 
02032     /* Not found in path */
02033     return InvalidOid;
02034 }
02035 
02036 /*
02037  * ConversionIsVisible
02038  *      Determine whether a conversion (identified by OID) is visible in the
02039  *      current search path.  Visible means "would be found by searching
02040  *      for the unqualified conversion name".
02041  */
02042 bool
02043 ConversionIsVisible(Oid conid)
02044 {
02045     HeapTuple   contup;
02046     Form_pg_conversion conform;
02047     Oid         connamespace;
02048     bool        visible;
02049 
02050     contup = SearchSysCache1(CONVOID, ObjectIdGetDatum(conid));
02051     if (!HeapTupleIsValid(contup))
02052         elog(ERROR, "cache lookup failed for conversion %u", conid);
02053     conform = (Form_pg_conversion) GETSTRUCT(contup);
02054 
02055     recomputeNamespacePath();
02056 
02057     /*
02058      * Quick check: if it ain't in the path at all, it ain't visible. Items in
02059      * the system namespace are surely in the path and so we needn't even do
02060      * list_member_oid() for them.
02061      */
02062     connamespace = conform->connamespace;
02063     if (connamespace != PG_CATALOG_NAMESPACE &&
02064         !list_member_oid(activeSearchPath, connamespace))
02065         visible = false;
02066     else
02067     {
02068         /*
02069          * If it is in the path, it might still not be visible; it could be
02070          * hidden by another conversion of the same name earlier in the path.
02071          * So we must do a slow check to see if this conversion would be found
02072          * by ConversionGetConid.
02073          */
02074         char       *conname = NameStr(conform->conname);
02075 
02076         visible = (ConversionGetConid(conname) == conid);
02077     }
02078 
02079     ReleaseSysCache(contup);
02080 
02081     return visible;
02082 }
02083 
02084 /*
02085  * get_ts_parser_oid - find a TS parser by possibly qualified name
02086  *
02087  * If not found, returns InvalidOid if missing_ok, else throws error
02088  */
02089 Oid
02090 get_ts_parser_oid(List *names, bool missing_ok)
02091 {
02092     char       *schemaname;
02093     char       *parser_name;
02094     Oid         namespaceId;
02095     Oid         prsoid = InvalidOid;
02096     ListCell   *l;
02097 
02098     /* deconstruct the name list */
02099     DeconstructQualifiedName(names, &schemaname, &parser_name);
02100 
02101     if (schemaname)
02102     {
02103         /* use exact schema given */
02104         namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
02105         if (missing_ok && !OidIsValid(namespaceId))
02106             prsoid = InvalidOid;
02107         else
02108             prsoid = GetSysCacheOid2(TSPARSERNAMENSP,
02109                                      PointerGetDatum(parser_name),
02110                                      ObjectIdGetDatum(namespaceId));
02111     }
02112     else
02113     {
02114         /* search for it in search path */
02115         recomputeNamespacePath();
02116 
02117         foreach(l, activeSearchPath)
02118         {
02119             namespaceId = lfirst_oid(l);
02120 
02121             if (namespaceId == myTempNamespace)
02122                 continue;       /* do not look in temp namespace */
02123 
02124             prsoid = GetSysCacheOid2(TSPARSERNAMENSP,
02125                                      PointerGetDatum(parser_name),
02126                                      ObjectIdGetDatum(namespaceId));
02127             if (OidIsValid(prsoid))
02128                 break;
02129         }
02130     }
02131 
02132     if (!OidIsValid(prsoid) && !missing_ok)
02133         ereport(ERROR,
02134                 (errcode(ERRCODE_UNDEFINED_OBJECT),
02135                  errmsg("text search parser \"%s\" does not exist",
02136                         NameListToString(names))));
02137 
02138     return prsoid;
02139 }
02140 
02141 /*
02142  * TSParserIsVisible
02143  *      Determine whether a parser (identified by OID) is visible in the
02144  *      current search path.  Visible means "would be found by searching
02145  *      for the unqualified parser name".
02146  */
02147 bool
02148 TSParserIsVisible(Oid prsId)
02149 {
02150     HeapTuple   tup;
02151     Form_pg_ts_parser form;
02152     Oid         namespace;
02153     bool        visible;
02154 
02155     tup = SearchSysCache1(TSPARSEROID, ObjectIdGetDatum(prsId));
02156     if (!HeapTupleIsValid(tup))
02157         elog(ERROR, "cache lookup failed for text search parser %u", prsId);
02158     form = (Form_pg_ts_parser) GETSTRUCT(tup);
02159 
02160     recomputeNamespacePath();
02161 
02162     /*
02163      * Quick check: if it ain't in the path at all, it ain't visible. Items in
02164      * the system namespace are surely in the path and so we needn't even do
02165      * list_member_oid() for them.
02166      */
02167     namespace = form->prsnamespace;
02168     if (namespace != PG_CATALOG_NAMESPACE &&
02169         !list_member_oid(activeSearchPath, namespace))
02170         visible = false;
02171     else
02172     {
02173         /*
02174          * If it is in the path, it might still not be visible; it could be
02175          * hidden by another parser of the same name earlier in the path. So
02176          * we must do a slow check for conflicting parsers.
02177          */
02178         char       *name = NameStr(form->prsname);
02179         ListCell   *l;
02180 
02181         visible = false;
02182         foreach(l, activeSearchPath)
02183         {
02184             Oid         namespaceId = lfirst_oid(l);
02185 
02186             if (namespaceId == myTempNamespace)
02187                 continue;       /* do not look in temp namespace */
02188 
02189             if (namespaceId == namespace)
02190             {
02191                 /* Found it first in path */
02192                 visible = true;
02193                 break;
02194             }
02195             if (SearchSysCacheExists2(TSPARSERNAMENSP,
02196                                       PointerGetDatum(name),
02197                                       ObjectIdGetDatum(namespaceId)))
02198             {
02199                 /* Found something else first in path */
02200                 break;
02201             }
02202         }
02203     }
02204 
02205     ReleaseSysCache(tup);
02206 
02207     return visible;
02208 }
02209 
02210 /*
02211  * get_ts_dict_oid - find a TS dictionary by possibly qualified name
02212  *
02213  * If not found, returns InvalidOid if failOK, else throws error
02214  */
02215 Oid
02216 get_ts_dict_oid(List *names, bool missing_ok)
02217 {
02218     char       *schemaname;
02219     char       *dict_name;
02220     Oid         namespaceId;
02221     Oid         dictoid = InvalidOid;
02222     ListCell   *l;
02223 
02224     /* deconstruct the name list */
02225     DeconstructQualifiedName(names, &schemaname, &dict_name);
02226 
02227     if (schemaname)
02228     {
02229         /* use exact schema given */
02230         namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
02231         if (missing_ok && !OidIsValid(namespaceId))
02232             dictoid = InvalidOid;
02233         else
02234             dictoid = GetSysCacheOid2(TSDICTNAMENSP,
02235                                       PointerGetDatum(dict_name),
02236                                       ObjectIdGetDatum(namespaceId));
02237     }
02238     else
02239     {
02240         /* search for it in search path */
02241         recomputeNamespacePath();
02242 
02243         foreach(l, activeSearchPath)
02244         {
02245             namespaceId = lfirst_oid(l);
02246 
02247             if (namespaceId == myTempNamespace)
02248                 continue;       /* do not look in temp namespace */
02249 
02250             dictoid = GetSysCacheOid2(TSDICTNAMENSP,
02251                                       PointerGetDatum(dict_name),
02252                                       ObjectIdGetDatum(namespaceId));
02253             if (OidIsValid(dictoid))
02254                 break;
02255         }
02256     }
02257 
02258     if (!OidIsValid(dictoid) && !missing_ok)
02259         ereport(ERROR,
02260                 (errcode(ERRCODE_UNDEFINED_OBJECT),
02261                  errmsg("text search dictionary \"%s\" does not exist",
02262                         NameListToString(names))));
02263 
02264     return dictoid;
02265 }
02266 
02267 /*
02268  * TSDictionaryIsVisible
02269  *      Determine whether a dictionary (identified by OID) is visible in the
02270  *      current search path.  Visible means "would be found by searching
02271  *      for the unqualified dictionary name".
02272  */
02273 bool
02274 TSDictionaryIsVisible(Oid dictId)
02275 {
02276     HeapTuple   tup;
02277     Form_pg_ts_dict form;
02278     Oid         namespace;
02279     bool        visible;
02280 
02281     tup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));
02282     if (!HeapTupleIsValid(tup))
02283         elog(ERROR, "cache lookup failed for text search dictionary %u",
02284              dictId);
02285     form = (Form_pg_ts_dict) GETSTRUCT(tup);
02286 
02287     recomputeNamespacePath();
02288 
02289     /*
02290      * Quick check: if it ain't in the path at all, it ain't visible. Items in
02291      * the system namespace are surely in the path and so we needn't even do
02292      * list_member_oid() for them.
02293      */
02294     namespace = form->dictnamespace;
02295     if (namespace != PG_CATALOG_NAMESPACE &&
02296         !list_member_oid(activeSearchPath, namespace))
02297         visible = false;
02298     else
02299     {
02300         /*
02301          * If it is in the path, it might still not be visible; it could be
02302          * hidden by another dictionary of the same name earlier in the path.
02303          * So we must do a slow check for conflicting dictionaries.
02304          */
02305         char       *name = NameStr(form->dictname);
02306         ListCell   *l;
02307 
02308         visible = false;
02309         foreach(l, activeSearchPath)
02310         {
02311             Oid         namespaceId = lfirst_oid(l);
02312 
02313             if (namespaceId == myTempNamespace)
02314                 continue;       /* do not look in temp namespace */
02315 
02316             if (namespaceId == namespace)
02317             {
02318                 /* Found it first in path */
02319                 visible = true;
02320                 break;
02321             }
02322             if (SearchSysCacheExists2(TSDICTNAMENSP,
02323                                       PointerGetDatum(name),
02324                                       ObjectIdGetDatum(namespaceId)))
02325             {
02326                 /* Found something else first in path */
02327                 break;
02328             }
02329         }
02330     }
02331 
02332     ReleaseSysCache(tup);
02333 
02334     return visible;
02335 }
02336 
02337 /*
02338  * get_ts_template_oid - find a TS template by possibly qualified name
02339  *
02340  * If not found, returns InvalidOid if missing_ok, else throws error
02341  */
02342 Oid
02343 get_ts_template_oid(List *names, bool missing_ok)
02344 {
02345     char       *schemaname;
02346     char       *template_name;
02347     Oid         namespaceId;
02348     Oid         tmploid = InvalidOid;
02349     ListCell   *l;
02350 
02351     /* deconstruct the name list */
02352     DeconstructQualifiedName(names, &schemaname, &template_name);
02353 
02354     if (schemaname)
02355     {
02356         /* use exact schema given */
02357         namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
02358         if (missing_ok && !OidIsValid(namespaceId))
02359             tmploid = InvalidOid;
02360         else
02361             tmploid = GetSysCacheOid2(TSTEMPLATENAMENSP,
02362                                       PointerGetDatum(template_name),
02363                                       ObjectIdGetDatum(namespaceId));
02364     }
02365     else
02366     {
02367         /* search for it in search path */
02368         recomputeNamespacePath();
02369 
02370         foreach(l, activeSearchPath)
02371         {
02372             namespaceId = lfirst_oid(l);
02373 
02374             if (namespaceId == myTempNamespace)
02375                 continue;       /* do not look in temp namespace */
02376 
02377             tmploid = GetSysCacheOid2(TSTEMPLATENAMENSP,
02378                                       PointerGetDatum(template_name),
02379                                       ObjectIdGetDatum(namespaceId));
02380             if (OidIsValid(tmploid))
02381                 break;
02382         }
02383     }
02384 
02385     if (!OidIsValid(tmploid) && !missing_ok)
02386         ereport(ERROR,
02387                 (errcode(ERRCODE_UNDEFINED_OBJECT),
02388                  errmsg("text search template \"%s\" does not exist",
02389                         NameListToString(names))));
02390 
02391     return tmploid;
02392 }
02393 
02394 /*
02395  * TSTemplateIsVisible
02396  *      Determine whether a template (identified by OID) is visible in the
02397  *      current search path.  Visible means "would be found by searching
02398  *      for the unqualified template name".
02399  */
02400 bool
02401 TSTemplateIsVisible(Oid tmplId)
02402 {
02403     HeapTuple   tup;
02404     Form_pg_ts_template form;
02405     Oid         namespace;
02406     bool        visible;
02407 
02408     tup = SearchSysCache1(TSTEMPLATEOID, ObjectIdGetDatum(tmplId));
02409     if (!HeapTupleIsValid(tup))
02410         elog(ERROR, "cache lookup failed for text search template %u", tmplId);
02411     form = (Form_pg_ts_template) GETSTRUCT(tup);
02412 
02413     recomputeNamespacePath();
02414 
02415     /*
02416      * Quick check: if it ain't in the path at all, it ain't visible. Items in
02417      * the system namespace are surely in the path and so we needn't even do
02418      * list_member_oid() for them.
02419      */
02420     namespace = form->tmplnamespace;
02421     if (namespace != PG_CATALOG_NAMESPACE &&
02422         !list_member_oid(activeSearchPath, namespace))
02423         visible = false;
02424     else
02425     {
02426         /*
02427          * If it is in the path, it might still not be visible; it could be
02428          * hidden by another template of the same name earlier in the path. So
02429          * we must do a slow check for conflicting templates.
02430          */
02431         char       *name = NameStr(form->tmplname);
02432         ListCell   *l;
02433 
02434         visible = false;
02435         foreach(l, activeSearchPath)
02436         {
02437             Oid         namespaceId = lfirst_oid(l);
02438 
02439             if (namespaceId == myTempNamespace)
02440                 continue;       /* do not look in temp namespace */
02441 
02442             if (namespaceId == namespace)
02443             {
02444                 /* Found it first in path */
02445                 visible = true;
02446                 break;
02447             }
02448             if (SearchSysCacheExists2(TSTEMPLATENAMENSP,
02449                                       PointerGetDatum(name),
02450                                       ObjectIdGetDatum(namespaceId)))
02451             {
02452                 /* Found something else first in path */
02453                 break;
02454             }
02455         }
02456     }
02457 
02458     ReleaseSysCache(tup);
02459 
02460     return visible;
02461 }
02462 
02463 /*
02464  * get_ts_config_oid - find a TS config by possibly qualified name
02465  *
02466  * If not found, returns InvalidOid if missing_ok, else throws error
02467  */
02468 Oid
02469 get_ts_config_oid(List *names, bool missing_ok)
02470 {
02471     char       *schemaname;
02472     char       *config_name;
02473     Oid         namespaceId;
02474     Oid         cfgoid = InvalidOid;
02475     ListCell   *l;
02476 
02477     /* deconstruct the name list */
02478     DeconstructQualifiedName(names, &schemaname, &config_name);
02479 
02480     if (schemaname)
02481     {
02482         /* use exact schema given */
02483         namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
02484         if (missing_ok && !OidIsValid(namespaceId))
02485             cfgoid = InvalidOid;
02486         else
02487             cfgoid = GetSysCacheOid2(TSCONFIGNAMENSP,
02488                                      PointerGetDatum(config_name),
02489                                      ObjectIdGetDatum(namespaceId));
02490     }
02491     else
02492     {
02493         /* search for it in search path */
02494         recomputeNamespacePath();
02495 
02496         foreach(l, activeSearchPath)
02497         {
02498             namespaceId = lfirst_oid(l);
02499 
02500             if (namespaceId == myTempNamespace)
02501                 continue;       /* do not look in temp namespace */
02502 
02503             cfgoid = GetSysCacheOid2(TSCONFIGNAMENSP,
02504                                      PointerGetDatum(config_name),
02505                                      ObjectIdGetDatum(namespaceId));
02506             if (OidIsValid(cfgoid))
02507                 break;
02508         }
02509     }
02510 
02511     if (!OidIsValid(cfgoid) && !missing_ok)
02512         ereport(ERROR,
02513                 (errcode(ERRCODE_UNDEFINED_OBJECT),
02514                  errmsg("text search configuration \"%s\" does not exist",
02515                         NameListToString(names))));
02516 
02517     return cfgoid;
02518 }
02519 
02520 /*
02521  * TSConfigIsVisible
02522  *      Determine whether a text search configuration (identified by OID)
02523  *      is visible in the current search path.  Visible means "would be found
02524  *      by searching for the unqualified text search configuration name".
02525  */
02526 bool
02527 TSConfigIsVisible(Oid cfgid)
02528 {
02529     HeapTuple   tup;
02530     Form_pg_ts_config form;
02531     Oid         namespace;
02532     bool        visible;
02533 
02534     tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid));
02535     if (!HeapTupleIsValid(tup))
02536         elog(ERROR, "cache lookup failed for text search configuration %u",
02537              cfgid);
02538     form = (Form_pg_ts_config) GETSTRUCT(tup);
02539 
02540     recomputeNamespacePath();
02541 
02542     /*
02543      * Quick check: if it ain't in the path at all, it ain't visible. Items in
02544      * the system namespace are surely in the path and so we needn't even do
02545      * list_member_oid() for them.
02546      */
02547     namespace = form->cfgnamespace;
02548     if (namespace != PG_CATALOG_NAMESPACE &&
02549         !list_member_oid(activeSearchPath, namespace))
02550         visible = false;
02551     else
02552     {
02553         /*
02554          * If it is in the path, it might still not be visible; it could be
02555          * hidden by another configuration of the same name earlier in the
02556          * path. So we must do a slow check for conflicting configurations.
02557          */
02558         char       *name = NameStr(form->cfgname);
02559         ListCell   *l;
02560 
02561         visible = false;
02562         foreach(l, activeSearchPath)
02563         {
02564             Oid         namespaceId = lfirst_oid(l);
02565 
02566             if (namespaceId == myTempNamespace)
02567                 continue;       /* do not look in temp namespace */
02568 
02569             if (namespaceId == namespace)
02570             {
02571                 /* Found it first in path */
02572                 visible = true;
02573                 break;
02574             }
02575             if (SearchSysCacheExists2(TSCONFIGNAMENSP,
02576                                       PointerGetDatum(name),
02577                                       ObjectIdGetDatum(namespaceId)))
02578             {
02579                 /* Found something else first in path */
02580                 break;
02581             }
02582         }
02583     }
02584 
02585     ReleaseSysCache(tup);
02586 
02587     return visible;
02588 }
02589 
02590 
02591 /*
02592  * DeconstructQualifiedName
02593  *      Given a possibly-qualified name expressed as a list of String nodes,
02594  *      extract the schema name and object name.
02595  *
02596  * *nspname_p is set to NULL if there is no explicit schema name.
02597  */
02598 void
02599 DeconstructQualifiedName(List *names,
02600                          char **nspname_p,
02601                          char **objname_p)
02602 {
02603     char       *catalogname;
02604     char       *schemaname = NULL;
02605     char       *objname = NULL;
02606 
02607     switch (list_length(names))
02608     {
02609         case 1:
02610             objname = strVal(linitial(names));
02611             break;
02612         case 2:
02613             schemaname = strVal(linitial(names));
02614             objname = strVal(lsecond(names));
02615             break;
02616         case 3:
02617             catalogname = strVal(linitial(names));
02618             schemaname = strVal(lsecond(names));
02619             objname = strVal(lthird(names));
02620 
02621             /*
02622              * We check the catalog name and then ignore it.
02623              */
02624             if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0)
02625                 ereport(ERROR,
02626                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02627                   errmsg("cross-database references are not implemented: %s",
02628                          NameListToString(names))));
02629             break;
02630         default:
02631             ereport(ERROR,
02632                     (errcode(ERRCODE_SYNTAX_ERROR),
02633                 errmsg("improper qualified name (too many dotted names): %s",
02634                        NameListToString(names))));
02635             break;
02636     }
02637 
02638     *nspname_p = schemaname;
02639     *objname_p = objname;
02640 }
02641 
02642 /*
02643  * LookupNamespaceNoError
02644  *      Look up a schema name.
02645  *
02646  * Returns the namespace OID, or InvalidOid if not found.
02647  *
02648  * Note this does NOT perform any permissions check --- callers are
02649  * responsible for being sure that an appropriate check is made.
02650  * In the majority of cases LookupExplicitNamespace is preferable.
02651  */
02652 Oid
02653 LookupNamespaceNoError(const char *nspname)
02654 {
02655     /* check for pg_temp alias */
02656     if (strcmp(nspname, "pg_temp") == 0)
02657     {
02658         if (OidIsValid(myTempNamespace))
02659         {
02660             InvokeNamespaceSearchHook(myTempNamespace, true);
02661             return myTempNamespace;
02662         }
02663 
02664         /*
02665          * Since this is used only for looking up existing objects, there is
02666          * no point in trying to initialize the temp namespace here; and doing
02667          * so might create problems for some callers. Just report "not found".
02668          */
02669         return InvalidOid;
02670     }
02671 
02672     return get_namespace_oid(nspname, true);
02673 }
02674 
02675 /*
02676  * LookupExplicitNamespace
02677  *      Process an explicitly-specified schema name: look up the schema
02678  *      and verify we have USAGE (lookup) rights in it.
02679  *
02680  * Returns the namespace OID
02681  */
02682 Oid
02683 LookupExplicitNamespace(const char *nspname, bool missing_ok)
02684 {
02685     Oid         namespaceId;
02686     AclResult   aclresult;
02687 
02688     /* check for pg_temp alias */
02689     if (strcmp(nspname, "pg_temp") == 0)
02690     {
02691         if (OidIsValid(myTempNamespace))
02692             return myTempNamespace;
02693 
02694         /*
02695          * Since this is used only for looking up existing objects, there is
02696          * no point in trying to initialize the temp namespace here; and doing
02697          * so might create problems for some callers --- just fall through.
02698          */
02699     }
02700 
02701     namespaceId = get_namespace_oid(nspname, missing_ok);
02702     if (missing_ok && !OidIsValid(namespaceId))
02703         return InvalidOid;
02704     
02705     aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
02706     if (aclresult != ACLCHECK_OK)
02707         aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
02708                        nspname);
02709     /* Schema search hook for this lookup */
02710     InvokeNamespaceSearchHook(namespaceId, true);
02711 
02712     return namespaceId;
02713 }
02714 
02715 /*
02716  * LookupCreationNamespace
02717  *      Look up the schema and verify we have CREATE rights on it.
02718  *
02719  * This is just like LookupExplicitNamespace except for the different
02720  * permission check, and that we are willing to create pg_temp if needed.
02721  *
02722  * Note: calling this may result in a CommandCounterIncrement operation,
02723  * if we have to create or clean out the temp namespace.
02724  */
02725 Oid
02726 LookupCreationNamespace(const char *nspname)
02727 {
02728     Oid         namespaceId;
02729     AclResult   aclresult;
02730 
02731     /* check for pg_temp alias */
02732     if (strcmp(nspname, "pg_temp") == 0)
02733     {
02734         /* Initialize temp namespace if first time through */
02735         if (!OidIsValid(myTempNamespace))
02736             InitTempTableNamespace();
02737         return myTempNamespace;
02738     }
02739 
02740     namespaceId = get_namespace_oid(nspname, false);
02741 
02742     aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
02743     if (aclresult != ACLCHECK_OK)
02744         aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
02745                        nspname);
02746 
02747     return namespaceId;
02748 }
02749 
02750 /*
02751  * Common checks on switching namespaces.
02752  *
02753  * We complain if (1) the old and new namespaces are the same, (2) either the
02754  * old or new namespaces is a temporary schema (or temporary toast schema), or
02755  * (3) either the old or new namespaces is the TOAST schema.
02756  */
02757 void
02758 CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid, Oid objid)
02759 {
02760     if (oldNspOid == nspOid)
02761         ereport(ERROR,
02762                 (classid == RelationRelationId ?
02763                  errcode(ERRCODE_DUPLICATE_TABLE) :
02764                  classid == ProcedureRelationId ?
02765                  errcode(ERRCODE_DUPLICATE_FUNCTION) :
02766                  errcode(ERRCODE_DUPLICATE_OBJECT),
02767                  errmsg("%s is already in schema \"%s\"",
02768                         getObjectDescriptionOids(classid, objid),
02769                         get_namespace_name(nspOid))));
02770 
02771     /* disallow renaming into or out of temp schemas */
02772     if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
02773         ereport(ERROR,
02774                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02775             errmsg("cannot move objects into or out of temporary schemas")));
02776 
02777     /* same for TOAST schema */
02778     if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
02779         ereport(ERROR,
02780                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02781                  errmsg("cannot move objects into or out of TOAST schema")));
02782 }
02783 
02784 /*
02785  * QualifiedNameGetCreationNamespace
02786  *      Given a possibly-qualified name for an object (in List-of-Values
02787  *      format), determine what namespace the object should be created in.
02788  *      Also extract and return the object name (last component of list).
02789  *
02790  * Note: this does not apply any permissions check.  Callers must check
02791  * for CREATE rights on the selected namespace when appropriate.
02792  *
02793  * Note: calling this may result in a CommandCounterIncrement operation,
02794  * if we have to create or clean out the temp namespace.
02795  */
02796 Oid
02797 QualifiedNameGetCreationNamespace(List *names, char **objname_p)
02798 {
02799     char       *schemaname;
02800     Oid         namespaceId;
02801 
02802     /* deconstruct the name list */
02803     DeconstructQualifiedName(names, &schemaname, objname_p);
02804 
02805     if (schemaname)
02806     {
02807         /* check for pg_temp alias */
02808         if (strcmp(schemaname, "pg_temp") == 0)
02809         {
02810             /* Initialize temp namespace if first time through */
02811             if (!OidIsValid(myTempNamespace))
02812                 InitTempTableNamespace();
02813             return myTempNamespace;
02814         }
02815         /* use exact schema given */
02816         namespaceId = get_namespace_oid(schemaname, false);
02817         /* we do not check for USAGE rights here! */
02818     }
02819     else
02820     {
02821         /* use the default creation namespace */
02822         recomputeNamespacePath();
02823         if (activeTempCreationPending)
02824         {
02825             /* Need to initialize temp namespace */
02826             InitTempTableNamespace();
02827             return myTempNamespace;
02828         }
02829         namespaceId = activeCreationNamespace;
02830         if (!OidIsValid(namespaceId))
02831             ereport(ERROR,
02832                     (errcode(ERRCODE_UNDEFINED_SCHEMA),
02833                      errmsg("no schema has been selected to create in")));
02834     }
02835 
02836     return namespaceId;
02837 }
02838 
02839 /*
02840  * get_namespace_oid - given a namespace name, look up the OID
02841  *
02842  * If missing_ok is false, throw an error if namespace name not found.  If
02843  * true, just return InvalidOid.
02844  */
02845 Oid
02846 get_namespace_oid(const char *nspname, bool missing_ok)
02847 {
02848     Oid         oid;
02849 
02850     oid = GetSysCacheOid1(NAMESPACENAME, CStringGetDatum(nspname));
02851     if (!OidIsValid(oid) && !missing_ok)
02852         ereport(ERROR,
02853                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
02854                  errmsg("schema \"%s\" does not exist", nspname)));
02855 
02856     return oid;
02857 }
02858 
02859 /*
02860  * makeRangeVarFromNameList
02861  *      Utility routine to convert a qualified-name list into RangeVar form.
02862  */
02863 RangeVar *
02864 makeRangeVarFromNameList(List *names)
02865 {
02866     RangeVar   *rel = makeRangeVar(NULL, NULL, -1);
02867 
02868     switch (list_length(names))
02869     {
02870         case 1:
02871             rel->relname = strVal(linitial(names));
02872             break;
02873         case 2:
02874             rel->schemaname = strVal(linitial(names));
02875             rel->relname = strVal(lsecond(names));
02876             break;
02877         case 3:
02878             rel->catalogname = strVal(linitial(names));
02879             rel->schemaname = strVal(lsecond(names));
02880             rel->relname = strVal(lthird(names));
02881             break;
02882         default:
02883             ereport(ERROR,
02884                     (errcode(ERRCODE_SYNTAX_ERROR),
02885                  errmsg("improper relation name (too many dotted names): %s",
02886                         NameListToString(names))));
02887             break;
02888     }
02889 
02890     return rel;
02891 }
02892 
02893 /*
02894  * NameListToString
02895  *      Utility routine to convert a qualified-name list into a string.
02896  *
02897  * This is used primarily to form error messages, and so we do not quote
02898  * the list elements, for the sake of legibility.
02899  *
02900  * In most scenarios the list elements should always be Value strings,
02901  * but we also allow A_Star for the convenience of ColumnRef processing.
02902  */
02903 char *
02904 NameListToString(List *names)
02905 {
02906     StringInfoData string;
02907     ListCell   *l;
02908 
02909     initStringInfo(&string);
02910 
02911     foreach(l, names)
02912     {
02913         Node       *name = (Node *) lfirst(l);
02914 
02915         if (l != list_head(names))
02916             appendStringInfoChar(&string, '.');
02917 
02918         if (IsA(name, String))
02919             appendStringInfoString(&string, strVal(name));
02920         else if (IsA(name, A_Star))
02921             appendStringInfoString(&string, "*");
02922         else
02923             elog(ERROR, "unexpected node type in name list: %d",
02924                  (int) nodeTag(name));
02925     }
02926 
02927     return string.data;
02928 }
02929 
02930 /*
02931  * NameListToQuotedString
02932  *      Utility routine to convert a qualified-name list into a string.
02933  *
02934  * Same as above except that names will be double-quoted where necessary,
02935  * so the string could be re-parsed (eg, by textToQualifiedNameList).
02936  */
02937 char *
02938 NameListToQuotedString(List *names)
02939 {
02940     StringInfoData string;
02941     ListCell   *l;
02942 
02943     initStringInfo(&string);
02944 
02945     foreach(l, names)
02946     {
02947         if (l != list_head(names))
02948             appendStringInfoChar(&string, '.');
02949         appendStringInfoString(&string, quote_identifier(strVal(lfirst(l))));
02950     }
02951 
02952     return string.data;
02953 }
02954 
02955 /*
02956  * isTempNamespace - is the given namespace my temporary-table namespace?
02957  */
02958 bool
02959 isTempNamespace(Oid namespaceId)
02960 {
02961     if (OidIsValid(myTempNamespace) && myTempNamespace == namespaceId)
02962         return true;
02963     return false;
02964 }
02965 
02966 /*
02967  * isTempToastNamespace - is the given namespace my temporary-toast-table
02968  *      namespace?
02969  */
02970 bool
02971 isTempToastNamespace(Oid namespaceId)
02972 {
02973     if (OidIsValid(myTempToastNamespace) && myTempToastNamespace == namespaceId)
02974         return true;
02975     return false;
02976 }
02977 
02978 /*
02979  * isTempOrToastNamespace - is the given namespace my temporary-table
02980  *      namespace or my temporary-toast-table namespace?
02981  */
02982 bool
02983 isTempOrToastNamespace(Oid namespaceId)
02984 {
02985     if (OidIsValid(myTempNamespace) &&
02986      (myTempNamespace == namespaceId || myTempToastNamespace == namespaceId))
02987         return true;
02988     return false;
02989 }
02990 
02991 /*
02992  * isAnyTempNamespace - is the given namespace a temporary-table namespace
02993  * (either my own, or another backend's)?  Temporary-toast-table namespaces
02994  * are included, too.
02995  */
02996 bool
02997 isAnyTempNamespace(Oid namespaceId)
02998 {
02999     bool        result;
03000     char       *nspname;
03001 
03002     /* True if the namespace name starts with "pg_temp_" or "pg_toast_temp_" */
03003     nspname = get_namespace_name(namespaceId);
03004     if (!nspname)
03005         return false;           /* no such namespace? */
03006     result = (strncmp(nspname, "pg_temp_", 8) == 0) ||
03007         (strncmp(nspname, "pg_toast_temp_", 14) == 0);
03008     pfree(nspname);
03009     return result;
03010 }
03011 
03012 /*
03013  * isOtherTempNamespace - is the given namespace some other backend's
03014  * temporary-table namespace (including temporary-toast-table namespaces)?
03015  *
03016  * Note: for most purposes in the C code, this function is obsolete.  Use
03017  * RELATION_IS_OTHER_TEMP() instead to detect non-local temp relations.
03018  */
03019 bool
03020 isOtherTempNamespace(Oid namespaceId)
03021 {
03022     /* If it's my own temp namespace, say "false" */
03023     if (isTempOrToastNamespace(namespaceId))
03024         return false;
03025     /* Else, if it's any temp namespace, say "true" */
03026     return isAnyTempNamespace(namespaceId);
03027 }
03028 
03029 /*
03030  * GetTempNamespaceBackendId - if the given namespace is a temporary-table
03031  * namespace (either my own, or another backend's), return the BackendId
03032  * that owns it.  Temporary-toast-table namespaces are included, too.
03033  * If it isn't a temp namespace, return InvalidBackendId.
03034  */
03035 int
03036 GetTempNamespaceBackendId(Oid namespaceId)
03037 {
03038     int         result;
03039     char       *nspname;
03040 
03041     /* See if the namespace name starts with "pg_temp_" or "pg_toast_temp_" */
03042     nspname = get_namespace_name(namespaceId);
03043     if (!nspname)
03044         return InvalidBackendId;    /* no such namespace? */
03045     if (strncmp(nspname, "pg_temp_", 8) == 0)
03046         result = atoi(nspname + 8);
03047     else if (strncmp(nspname, "pg_toast_temp_", 14) == 0)
03048         result = atoi(nspname + 14);
03049     else
03050         result = InvalidBackendId;
03051     pfree(nspname);
03052     return result;
03053 }
03054 
03055 /*
03056  * GetTempToastNamespace - get the OID of my temporary-toast-table namespace,
03057  * which must already be assigned.  (This is only used when creating a toast
03058  * table for a temp table, so we must have already done InitTempTableNamespace)
03059  */
03060 Oid
03061 GetTempToastNamespace(void)
03062 {
03063     Assert(OidIsValid(myTempToastNamespace));
03064     return myTempToastNamespace;
03065 }
03066 
03067 
03068 /*
03069  * GetOverrideSearchPath - fetch current search path definition in form
03070  * used by PushOverrideSearchPath.
03071  *
03072  * The result structure is allocated in the specified memory context
03073  * (which might or might not be equal to CurrentMemoryContext); but any
03074  * junk created by revalidation calculations will be in CurrentMemoryContext.
03075  */
03076 OverrideSearchPath *
03077 GetOverrideSearchPath(MemoryContext context)
03078 {
03079     OverrideSearchPath *result;
03080     List       *schemas;
03081     MemoryContext oldcxt;
03082 
03083     recomputeNamespacePath();
03084 
03085     oldcxt = MemoryContextSwitchTo(context);
03086 
03087     result = (OverrideSearchPath *) palloc0(sizeof(OverrideSearchPath));
03088     schemas = list_copy(activeSearchPath);
03089     while (schemas && linitial_oid(schemas) != activeCreationNamespace)
03090     {
03091         if (linitial_oid(schemas) == myTempNamespace)
03092             result->addTemp = true;
03093         else
03094         {
03095             Assert(linitial_oid(schemas) == PG_CATALOG_NAMESPACE);
03096             result->addCatalog = true;
03097         }
03098         schemas = list_delete_first(schemas);
03099     }
03100     result->schemas = schemas;
03101 
03102     MemoryContextSwitchTo(oldcxt);
03103 
03104     return result;
03105 }
03106 
03107 /*
03108  * CopyOverrideSearchPath - copy the specified OverrideSearchPath.
03109  *
03110  * The result structure is allocated in CurrentMemoryContext.
03111  */
03112 OverrideSearchPath *
03113 CopyOverrideSearchPath(OverrideSearchPath *path)
03114 {
03115     OverrideSearchPath *result;
03116 
03117     result = (OverrideSearchPath *) palloc(sizeof(OverrideSearchPath));
03118     result->schemas = list_copy(path->schemas);
03119     result->addCatalog = path->addCatalog;
03120     result->addTemp = path->addTemp;
03121 
03122     return result;
03123 }
03124 
03125 /*
03126  * OverrideSearchPathMatchesCurrent - does path match current setting?
03127  */
03128 bool
03129 OverrideSearchPathMatchesCurrent(OverrideSearchPath *path)
03130 {
03131     /* Easiest way to do this is GetOverrideSearchPath() and compare */
03132     bool        result;
03133     OverrideSearchPath *cur;
03134 
03135     cur = GetOverrideSearchPath(CurrentMemoryContext);
03136     if (path->addCatalog == cur->addCatalog &&
03137         path->addTemp == cur->addTemp &&
03138         equal(path->schemas, cur->schemas))
03139         result = true;
03140     else
03141         result = false;
03142     list_free(cur->schemas);
03143     pfree(cur);
03144     return result;
03145 }
03146 
03147 /*
03148  * PushOverrideSearchPath - temporarily override the search path
03149  *
03150  * We allow nested overrides, hence the push/pop terminology.  The GUC
03151  * search_path variable is ignored while an override is active.
03152  *
03153  * It's possible that newpath->useTemp is set but there is no longer any
03154  * active temp namespace, if the path was saved during a transaction that
03155  * created a temp namespace and was later rolled back.  In that case we just
03156  * ignore useTemp.  A plausible alternative would be to create a new temp
03157  * namespace, but for existing callers that's not necessary because an empty
03158  * temp namespace wouldn't affect their results anyway.
03159  *
03160  * It's also worth noting that other schemas listed in newpath might not
03161  * exist anymore either.  We don't worry about this because OIDs that match
03162  * no existing namespace will simply not produce any hits during searches.
03163  */
03164 void
03165 PushOverrideSearchPath(OverrideSearchPath *newpath)
03166 {
03167     OverrideStackEntry *entry;
03168     List       *oidlist;
03169     Oid         firstNS;
03170     MemoryContext oldcxt;
03171 
03172     /*
03173      * Copy the list for safekeeping, and insert implicitly-searched
03174      * namespaces as needed.  This code should track recomputeNamespacePath.
03175      */
03176     oldcxt = MemoryContextSwitchTo(TopMemoryContext);
03177 
03178     oidlist = list_copy(newpath->schemas);
03179 
03180     /*
03181      * Remember the first member of the explicit list.
03182      */
03183     if (oidlist == NIL)
03184         firstNS = InvalidOid;
03185     else
03186         firstNS = linitial_oid(oidlist);
03187 
03188     /*
03189      * Add any implicitly-searched namespaces to the list.  Note these go on
03190      * the front, not the back; also notice that we do not check USAGE
03191      * permissions for these.
03192      */
03193     if (newpath->addCatalog)
03194         oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist);
03195 
03196     if (newpath->addTemp && OidIsValid(myTempNamespace))
03197         oidlist = lcons_oid(myTempNamespace, oidlist);
03198 
03199     /*
03200      * Build the new stack entry, then insert it at the head of the list.
03201      */
03202     entry = (OverrideStackEntry *) palloc(sizeof(OverrideStackEntry));
03203     entry->searchPath = oidlist;
03204     entry->creationNamespace = firstNS;
03205     entry->nestLevel = GetCurrentTransactionNestLevel();
03206 
03207     overrideStack = lcons(entry, overrideStack);
03208 
03209     /* And make it active. */
03210     activeSearchPath = entry->searchPath;
03211     activeCreationNamespace = entry->creationNamespace;
03212     activeTempCreationPending = false;  /* XXX is this OK? */
03213 
03214     MemoryContextSwitchTo(oldcxt);
03215 }
03216 
03217 /*
03218  * PopOverrideSearchPath - undo a previous PushOverrideSearchPath
03219  *
03220  * Any push during a (sub)transaction will be popped automatically at abort.
03221  * But it's caller error if a push isn't popped in normal control flow.
03222  */
03223 void
03224 PopOverrideSearchPath(void)
03225 {
03226     OverrideStackEntry *entry;
03227 
03228     /* Sanity checks. */
03229     if (overrideStack == NIL)
03230         elog(ERROR, "bogus PopOverrideSearchPath call");
03231     entry = (OverrideStackEntry *) linitial(overrideStack);
03232     if (entry->nestLevel != GetCurrentTransactionNestLevel())
03233         elog(ERROR, "bogus PopOverrideSearchPath call");
03234 
03235     /* Pop the stack and free storage. */
03236     overrideStack = list_delete_first(overrideStack);
03237     list_free(entry->searchPath);
03238     pfree(entry);
03239 
03240     /* Activate the next level down. */
03241     if (overrideStack)
03242     {
03243         entry = (OverrideStackEntry *) linitial(overrideStack);
03244         activeSearchPath = entry->searchPath;
03245         activeCreationNamespace = entry->creationNamespace;
03246         activeTempCreationPending = false;      /* XXX is this OK? */
03247     }
03248     else
03249     {
03250         /* If not baseSearchPathValid, this is useless but harmless */
03251         activeSearchPath = baseSearchPath;
03252         activeCreationNamespace = baseCreationNamespace;
03253         activeTempCreationPending = baseTempCreationPending;
03254     }
03255 }
03256 
03257 
03258 /*
03259  * get_collation_oid - find a collation by possibly qualified name
03260  */
03261 Oid
03262 get_collation_oid(List *name, bool missing_ok)
03263 {
03264     char       *schemaname;
03265     char       *collation_name;
03266     int32       dbencoding = GetDatabaseEncoding();
03267     Oid         namespaceId;
03268     Oid         colloid;
03269     ListCell   *l;
03270 
03271     /* deconstruct the name list */
03272     DeconstructQualifiedName(name, &schemaname, &collation_name);
03273 
03274     if (schemaname)
03275     {
03276         /* use exact schema given */
03277         namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
03278         if (missing_ok && !OidIsValid(namespaceId))
03279             return InvalidOid;
03280 
03281         /* first try for encoding-specific entry, then any-encoding */
03282         colloid = GetSysCacheOid3(COLLNAMEENCNSP,
03283                                   PointerGetDatum(collation_name),
03284                                   Int32GetDatum(dbencoding),
03285                                   ObjectIdGetDatum(namespaceId));
03286         if (OidIsValid(colloid))
03287             return colloid;
03288         colloid = GetSysCacheOid3(COLLNAMEENCNSP,
03289                                   PointerGetDatum(collation_name),
03290                                   Int32GetDatum(-1),
03291                                   ObjectIdGetDatum(namespaceId));
03292         if (OidIsValid(colloid))
03293             return colloid;
03294     }
03295     else
03296     {
03297         /* search for it in search path */
03298         recomputeNamespacePath();
03299 
03300         foreach(l, activeSearchPath)
03301         {
03302             namespaceId = lfirst_oid(l);
03303 
03304             if (namespaceId == myTempNamespace)
03305                 continue;       /* do not look in temp namespace */
03306 
03307             colloid = GetSysCacheOid3(COLLNAMEENCNSP,
03308                                       PointerGetDatum(collation_name),
03309                                       Int32GetDatum(dbencoding),
03310                                       ObjectIdGetDatum(namespaceId));
03311             if (OidIsValid(colloid))
03312                 return colloid;
03313             colloid = GetSysCacheOid3(COLLNAMEENCNSP,
03314                                       PointerGetDatum(collation_name),
03315                                       Int32GetDatum(-1),
03316                                       ObjectIdGetDatum(namespaceId));
03317             if (OidIsValid(colloid))
03318                 return colloid;
03319         }
03320     }
03321 
03322     /* Not found in path */
03323     if (!missing_ok)
03324         ereport(ERROR,
03325                 (errcode(ERRCODE_UNDEFINED_OBJECT),
03326                  errmsg("collation \"%s\" for encoding \"%s\" does not exist",
03327                         NameListToString(name), GetDatabaseEncodingName())));
03328     return InvalidOid;
03329 }
03330 
03331 /*
03332  * get_conversion_oid - find a conversion by possibly qualified name
03333  */
03334 Oid
03335 get_conversion_oid(List *name, bool missing_ok)
03336 {
03337     char       *schemaname;
03338     char       *conversion_name;
03339     Oid         namespaceId;
03340     Oid         conoid = InvalidOid;
03341     ListCell   *l;
03342 
03343     /* deconstruct the name list */
03344     DeconstructQualifiedName(name, &schemaname, &conversion_name);
03345 
03346     if (schemaname)
03347     {
03348         /* use exact schema given */
03349         namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
03350         if (missing_ok && !OidIsValid(namespaceId))
03351             conoid = InvalidOid;
03352         else
03353             conoid = GetSysCacheOid2(CONNAMENSP,
03354                                      PointerGetDatum(conversion_name),
03355                                      ObjectIdGetDatum(namespaceId));
03356     }
03357     else
03358     {
03359         /* search for it in search path */
03360         recomputeNamespacePath();
03361 
03362         foreach(l, activeSearchPath)
03363         {
03364             namespaceId = lfirst_oid(l);
03365 
03366             if (namespaceId == myTempNamespace)
03367                 continue;       /* do not look in temp namespace */
03368 
03369             conoid = GetSysCacheOid2(CONNAMENSP,
03370                                      PointerGetDatum(conversion_name),
03371                                      ObjectIdGetDatum(namespaceId));
03372             if (OidIsValid(conoid))
03373                 return conoid;
03374         }
03375     }
03376 
03377     /* Not found in path */
03378     if (!OidIsValid(conoid) && !missing_ok)
03379         ereport(ERROR,
03380                 (errcode(ERRCODE_UNDEFINED_OBJECT),
03381                  errmsg("conversion \"%s\" does not exist",
03382                         NameListToString(name))));
03383     return conoid;
03384 }
03385 
03386 /*
03387  * FindDefaultConversionProc - find default encoding conversion proc
03388  */
03389 Oid
03390 FindDefaultConversionProc(int32 for_encoding, int32 to_encoding)
03391 {
03392     Oid         proc;
03393     ListCell   *l;
03394 
03395     recomputeNamespacePath();
03396 
03397     foreach(l, activeSearchPath)
03398     {
03399         Oid         namespaceId = lfirst_oid(l);
03400 
03401         if (namespaceId == myTempNamespace)
03402             continue;           /* do not look in temp namespace */
03403 
03404         proc = FindDefaultConversion(namespaceId, for_encoding, to_encoding);
03405         if (OidIsValid(proc))
03406             return proc;
03407     }
03408 
03409     /* Not found in path */
03410     return InvalidOid;
03411 }
03412 
03413 /*
03414  * recomputeNamespacePath - recompute path derived variables if needed.
03415  */
03416 static void
03417 recomputeNamespacePath(void)
03418 {
03419     Oid         roleid = GetUserId();
03420     char       *rawname;
03421     List       *namelist;
03422     List       *oidlist;
03423     List       *newpath;
03424     ListCell   *l;
03425     bool        temp_missing;
03426     Oid         firstNS;
03427     MemoryContext oldcxt;
03428 
03429     /* Do nothing if an override search spec is active. */
03430     if (overrideStack)
03431         return;
03432 
03433     /* Do nothing if path is already valid. */
03434     if (baseSearchPathValid && namespaceUser == roleid)
03435         return;
03436 
03437     /* Need a modifiable copy of namespace_search_path string */
03438     rawname = pstrdup(namespace_search_path);
03439 
03440     /* Parse string into list of identifiers */
03441     if (!SplitIdentifierString(rawname, ',', &namelist))
03442     {
03443         /* syntax error in name list */
03444         /* this should not happen if GUC checked check_search_path */
03445         elog(ERROR, "invalid list syntax");
03446     }
03447 
03448     /*
03449      * Convert the list of names to a list of OIDs.  If any names are not
03450      * recognizable or we don't have read access, just leave them out of the
03451      * list.  (We can't raise an error, since the search_path setting has
03452      * already been accepted.)  Don't make duplicate entries, either.
03453      */
03454     oidlist = NIL;
03455     temp_missing = false;
03456     foreach(l, namelist)
03457     {
03458         char       *curname = (char *) lfirst(l);
03459         Oid         namespaceId;
03460 
03461         if (strcmp(curname, "$user") == 0)
03462         {
03463             /* $user --- substitute namespace matching user name, if any */
03464             HeapTuple   tuple;
03465 
03466             tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
03467             if (HeapTupleIsValid(tuple))
03468             {
03469                 char       *rname;
03470 
03471                 rname = NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname);
03472                 namespaceId = get_namespace_oid(rname, true);
03473                 ReleaseSysCache(tuple);
03474                 if (OidIsValid(namespaceId) &&
03475                     !list_member_oid(oidlist, namespaceId) &&
03476                     pg_namespace_aclcheck(namespaceId, roleid,
03477                                           ACL_USAGE) == ACLCHECK_OK &&
03478                     InvokeNamespaceSearchHook(namespaceId, false))
03479                     oidlist = lappend_oid(oidlist, namespaceId);
03480             }
03481         }
03482         else if (strcmp(curname, "pg_temp") == 0)
03483         {
03484             /* pg_temp --- substitute temp namespace, if any */
03485             if (OidIsValid(myTempNamespace))
03486             {
03487                 if (!list_member_oid(oidlist, myTempNamespace) &&
03488                     InvokeNamespaceSearchHook(myTempNamespace, false))
03489                     oidlist = lappend_oid(oidlist, myTempNamespace);
03490             }
03491             else
03492             {
03493                 /* If it ought to be the creation namespace, set flag */
03494                 if (oidlist == NIL)
03495                     temp_missing = true;
03496             }
03497         }
03498         else
03499         {
03500             /* normal namespace reference */
03501             namespaceId = get_namespace_oid(curname, true);
03502             if (OidIsValid(namespaceId) &&
03503                 !list_member_oid(oidlist, namespaceId) &&
03504                 pg_namespace_aclcheck(namespaceId, roleid,
03505                                       ACL_USAGE) == ACLCHECK_OK &&
03506                 InvokeNamespaceSearchHook(namespaceId, false))
03507                 oidlist = lappend_oid(oidlist, namespaceId);
03508         }
03509     }
03510 
03511     /*
03512      * Remember the first member of the explicit list.  (Note: this is
03513      * nominally wrong if temp_missing, but we need it anyway to distinguish
03514      * explicit from implicit mention of pg_catalog.)
03515      */
03516     if (oidlist == NIL)
03517         firstNS = InvalidOid;
03518     else
03519         firstNS = linitial_oid(oidlist);
03520 
03521     /*
03522      * Add any implicitly-searched namespaces to the list.  Note these go on
03523      * the front, not the back; also notice that we do not check USAGE
03524      * permissions for these.
03525      */
03526     if (!list_member_oid(oidlist, PG_CATALOG_NAMESPACE))
03527         oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist);
03528 
03529     if (OidIsValid(myTempNamespace) &&
03530         !list_member_oid(oidlist, myTempNamespace))
03531         oidlist = lcons_oid(myTempNamespace, oidlist);
03532 
03533     /*
03534      * Now that we've successfully built the new list of namespace OIDs, save
03535      * it in permanent storage.
03536      */
03537     oldcxt = MemoryContextSwitchTo(TopMemoryContext);
03538     newpath = list_copy(oidlist);
03539     MemoryContextSwitchTo(oldcxt);
03540 
03541     /* Now safe to assign to state variables. */
03542     list_free(baseSearchPath);
03543     baseSearchPath = newpath;
03544     baseCreationNamespace = firstNS;
03545     baseTempCreationPending = temp_missing;
03546 
03547     /* Mark the path valid. */
03548     baseSearchPathValid = true;
03549     namespaceUser = roleid;
03550 
03551     /* And make it active. */
03552     activeSearchPath = baseSearchPath;
03553     activeCreationNamespace = baseCreationNamespace;
03554     activeTempCreationPending = baseTempCreationPending;
03555 
03556     /* Clean up. */
03557     pfree(rawname);
03558     list_free(namelist);
03559     list_free(oidlist);
03560 }
03561 
03562 /*
03563  * InitTempTableNamespace
03564  *      Initialize temp table namespace on first use in a particular backend
03565  */
03566 static void
03567 InitTempTableNamespace(void)
03568 {
03569     char        namespaceName[NAMEDATALEN];
03570     Oid         namespaceId;
03571     Oid         toastspaceId;
03572 
03573     Assert(!OidIsValid(myTempNamespace));
03574 
03575     /*
03576      * First, do permission check to see if we are authorized to make temp
03577      * tables.  We use a nonstandard error message here since "databasename:
03578      * permission denied" might be a tad cryptic.
03579      *
03580      * Note that ACL_CREATE_TEMP rights are rechecked in pg_namespace_aclmask;
03581      * that's necessary since current user ID could change during the session.
03582      * But there's no need to make the namespace in the first place until a
03583      * temp table creation request is made by someone with appropriate rights.
03584      */
03585     if (pg_database_aclcheck(MyDatabaseId, GetUserId(),
03586                              ACL_CREATE_TEMP) != ACLCHECK_OK)
03587         ereport(ERROR,
03588                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
03589                  errmsg("permission denied to create temporary tables in database \"%s\"",
03590                         get_database_name(MyDatabaseId))));
03591 
03592     /*
03593      * Do not allow a Hot Standby slave session to make temp tables.  Aside
03594      * from problems with modifying the system catalogs, there is a naming
03595      * conflict: pg_temp_N belongs to the session with BackendId N on the
03596      * master, not to a slave session with the same BackendId.  We should not
03597      * be able to get here anyway due to XactReadOnly checks, but let's just
03598      * make real sure.  Note that this also backstops various operations that
03599      * allow XactReadOnly transactions to modify temp tables; they'd need
03600      * RecoveryInProgress checks if not for this.
03601      */
03602     if (RecoveryInProgress())
03603         ereport(ERROR,
03604                 (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
03605                  errmsg("cannot create temporary tables during recovery")));
03606 
03607     snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId);
03608 
03609     namespaceId = get_namespace_oid(namespaceName, true);
03610     if (!OidIsValid(namespaceId))
03611     {
03612         /*
03613          * First use of this temp namespace in this database; create it. The
03614          * temp namespaces are always owned by the superuser.  We leave their
03615          * permissions at default --- i.e., no access except to superuser ---
03616          * to ensure that unprivileged users can't peek at other backends'
03617          * temp tables.  This works because the places that access the temp
03618          * namespace for my own backend skip permissions checks on it.
03619          */
03620         namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID,
03621                                       true);
03622         /* Advance command counter to make namespace visible */
03623         CommandCounterIncrement();
03624     }
03625     else
03626     {
03627         /*
03628          * If the namespace already exists, clean it out (in case the former
03629          * owner crashed without doing so).
03630          */
03631         RemoveTempRelations(namespaceId);
03632     }
03633 
03634     /*
03635      * If the corresponding toast-table namespace doesn't exist yet, create
03636      * it. (We assume there is no need to clean it out if it does exist, since
03637      * dropping a parent table should make its toast table go away.)
03638      */
03639     snprintf(namespaceName, sizeof(namespaceName), "pg_toast_temp_%d",
03640              MyBackendId);
03641 
03642     toastspaceId = get_namespace_oid(namespaceName, true);
03643     if (!OidIsValid(toastspaceId))
03644     {
03645         toastspaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID,
03646                                        true);
03647         /* Advance command counter to make namespace visible */
03648         CommandCounterIncrement();
03649     }
03650 
03651     /*
03652      * Okay, we've prepared the temp namespace ... but it's not committed yet,
03653      * so all our work could be undone by transaction rollback.  Set flag for
03654      * AtEOXact_Namespace to know what to do.
03655      */
03656     myTempNamespace = namespaceId;
03657     myTempToastNamespace = toastspaceId;
03658 
03659     /* It should not be done already. */
03660     AssertState(myTempNamespaceSubID == InvalidSubTransactionId);
03661     myTempNamespaceSubID = GetCurrentSubTransactionId();
03662 
03663     baseSearchPathValid = false;    /* need to rebuild list */
03664 }
03665 
03666 /*
03667  * End-of-transaction cleanup for namespaces.
03668  */
03669 void
03670 AtEOXact_Namespace(bool isCommit)
03671 {
03672     /*
03673      * If we abort the transaction in which a temp namespace was selected,
03674      * we'll have to do any creation or cleanout work over again.  So, just
03675      * forget the namespace entirely until next time.  On the other hand, if
03676      * we commit then register an exit callback to clean out the temp tables
03677      * at backend shutdown.  (We only want to register the callback once per
03678      * session, so this is a good place to do it.)
03679      */
03680     if (myTempNamespaceSubID != InvalidSubTransactionId)
03681     {
03682         if (isCommit)
03683             on_shmem_exit(RemoveTempRelationsCallback, 0);
03684         else
03685         {
03686             myTempNamespace = InvalidOid;
03687             myTempToastNamespace = InvalidOid;
03688             baseSearchPathValid = false;        /* need to rebuild list */
03689         }
03690         myTempNamespaceSubID = InvalidSubTransactionId;
03691     }
03692 
03693     /*
03694      * Clean up if someone failed to do PopOverrideSearchPath
03695      */
03696     if (overrideStack)
03697     {
03698         if (isCommit)
03699             elog(WARNING, "leaked override search path");
03700         while (overrideStack)
03701         {
03702             OverrideStackEntry *entry;
03703 
03704             entry = (OverrideStackEntry *) linitial(overrideStack);
03705             overrideStack = list_delete_first(overrideStack);
03706             list_free(entry->searchPath);
03707             pfree(entry);
03708         }
03709         /* If not baseSearchPathValid, this is useless but harmless */
03710         activeSearchPath = baseSearchPath;
03711         activeCreationNamespace = baseCreationNamespace;
03712         activeTempCreationPending = baseTempCreationPending;
03713     }
03714 }
03715 
03716 /*
03717  * AtEOSubXact_Namespace
03718  *
03719  * At subtransaction commit, propagate the temp-namespace-creation
03720  * flag to the parent subtransaction.
03721  *
03722  * At subtransaction abort, forget the flag if we set it up.
03723  */
03724 void
03725 AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid,
03726                       SubTransactionId parentSubid)
03727 {
03728     OverrideStackEntry *entry;
03729 
03730     if (myTempNamespaceSubID == mySubid)
03731     {
03732         if (isCommit)
03733             myTempNamespaceSubID = parentSubid;
03734         else
03735         {
03736             myTempNamespaceSubID = InvalidSubTransactionId;
03737             /* TEMP namespace creation failed, so reset state */
03738             myTempNamespace = InvalidOid;
03739             myTempToastNamespace = InvalidOid;
03740             baseSearchPathValid = false;        /* need to rebuild list */
03741         }
03742     }
03743 
03744     /*
03745      * Clean up if someone failed to do PopOverrideSearchPath
03746      */
03747     while (overrideStack)
03748     {
03749         entry = (OverrideStackEntry *) linitial(overrideStack);
03750         if (entry->nestLevel < GetCurrentTransactionNestLevel())
03751             break;
03752         if (isCommit)
03753             elog(WARNING, "leaked override search path");
03754         overrideStack = list_delete_first(overrideStack);
03755         list_free(entry->searchPath);
03756         pfree(entry);
03757     }
03758 
03759     /* Activate the next level down. */
03760     if (overrideStack)
03761     {
03762         entry = (OverrideStackEntry *) linitial(overrideStack);
03763         activeSearchPath = entry->searchPath;
03764         activeCreationNamespace = entry->creationNamespace;
03765         activeTempCreationPending = false;      /* XXX is this OK? */
03766     }
03767     else
03768     {
03769         /* If not baseSearchPathValid, this is useless but harmless */
03770         activeSearchPath = baseSearchPath;
03771         activeCreationNamespace = baseCreationNamespace;
03772         activeTempCreationPending = baseTempCreationPending;
03773     }
03774 }
03775 
03776 /*
03777  * Remove all relations in the specified temp namespace.
03778  *
03779  * This is called at backend shutdown (if we made any temp relations).
03780  * It is also called when we begin using a pre-existing temp namespace,
03781  * in order to clean out any relations that might have been created by
03782  * a crashed backend.
03783  */
03784 static void
03785 RemoveTempRelations(Oid tempNamespaceId)
03786 {
03787     ObjectAddress object;
03788 
03789     /*
03790      * We want to get rid of everything in the target namespace, but not the
03791      * namespace itself (deleting it only to recreate it later would be a
03792      * waste of cycles).  We do this by finding everything that has a
03793      * dependency on the namespace.
03794      */
03795     object.classId = NamespaceRelationId;
03796     object.objectId = tempNamespaceId;
03797     object.objectSubId = 0;
03798 
03799     deleteWhatDependsOn(&object, false);
03800 }
03801 
03802 /*
03803  * Callback to remove temp relations at backend exit.
03804  */
03805 static void
03806 RemoveTempRelationsCallback(int code, Datum arg)
03807 {
03808     if (OidIsValid(myTempNamespace))    /* should always be true */
03809     {
03810         /* Need to ensure we have a usable transaction. */
03811         AbortOutOfAnyTransaction();
03812         StartTransactionCommand();
03813 
03814         RemoveTempRelations(myTempNamespace);
03815 
03816         CommitTransactionCommand();
03817     }
03818 }
03819 
03820 /*
03821  * Remove all temp tables from the temporary namespace.
03822  */
03823 void
03824 ResetTempTableNamespace(void)
03825 {
03826     if (OidIsValid(myTempNamespace))
03827         RemoveTempRelations(myTempNamespace);
03828 }
03829 
03830 
03831 /*
03832  * Routines for handling the GUC variable 'search_path'.
03833  */
03834 
03835 /* check_hook: validate new search_path value */
03836 bool
03837 check_search_path(char **newval, void **extra, GucSource source)
03838 {
03839     char       *rawname;
03840     List       *namelist;
03841 
03842     /* Need a modifiable copy of string */
03843     rawname = pstrdup(*newval);
03844 
03845     /* Parse string into list of identifiers */
03846     if (!SplitIdentifierString(rawname, ',', &namelist))
03847     {
03848         /* syntax error in name list */
03849         GUC_check_errdetail("List syntax is invalid.");
03850         pfree(rawname);
03851         list_free(namelist);
03852         return false;
03853     }
03854 
03855     /*
03856      * We used to try to check that the named schemas exist, but there are
03857      * many valid use-cases for having search_path settings that include
03858      * schemas that don't exist; and often, we are not inside a transaction
03859      * here and so can't consult the system catalogs anyway.  So now, the only
03860      * requirement is syntactic validity of the identifier list.
03861      */
03862 
03863     pfree(rawname);
03864     list_free(namelist);
03865 
03866     return true;
03867 }
03868 
03869 /* assign_hook: do extra actions as needed */
03870 void
03871 assign_search_path(const char *newval, void *extra)
03872 {
03873     /*
03874      * We mark the path as needing recomputation, but don't do anything until
03875      * it's needed.  This avoids trying to do database access during GUC
03876      * initialization, or outside a transaction.
03877      */
03878     baseSearchPathValid = false;
03879 }
03880 
03881 /*
03882  * InitializeSearchPath: initialize module during InitPostgres.
03883  *
03884  * This is called after we are up enough to be able to do catalog lookups.
03885  */
03886 void
03887 InitializeSearchPath(void)
03888 {
03889     if (IsBootstrapProcessingMode())
03890     {
03891         /*
03892          * In bootstrap mode, the search path must be 'pg_catalog' so that
03893          * tables are created in the proper namespace; ignore the GUC setting.
03894          */
03895         MemoryContext oldcxt;
03896 
03897         oldcxt = MemoryContextSwitchTo(TopMemoryContext);
03898         baseSearchPath = list_make1_oid(PG_CATALOG_NAMESPACE);
03899         MemoryContextSwitchTo(oldcxt);
03900         baseCreationNamespace = PG_CATALOG_NAMESPACE;
03901         baseTempCreationPending = false;
03902         baseSearchPathValid = true;
03903         namespaceUser = GetUserId();
03904         activeSearchPath = baseSearchPath;
03905         activeCreationNamespace = baseCreationNamespace;
03906         activeTempCreationPending = baseTempCreationPending;
03907     }
03908     else
03909     {
03910         /*
03911          * In normal mode, arrange for a callback on any syscache invalidation
03912          * of pg_namespace rows.
03913          */
03914         CacheRegisterSyscacheCallback(NAMESPACEOID,
03915                                       NamespaceCallback,
03916                                       (Datum) 0);
03917         /* Force search path to be recomputed on next use */
03918         baseSearchPathValid = false;
03919     }
03920 }
03921 
03922 /*
03923  * NamespaceCallback
03924  *      Syscache inval callback function
03925  */
03926 static void
03927 NamespaceCallback(Datum arg, int cacheid, uint32 hashvalue)
03928 {
03929     /* Force search path to be recomputed on next use */
03930     baseSearchPathValid = false;
03931 }
03932 
03933 /*
03934  * Fetch the active search path. The return value is a palloc'ed list
03935  * of OIDs; the caller is responsible for freeing this storage as
03936  * appropriate.
03937  *
03938  * The returned list includes the implicitly-prepended namespaces only if
03939  * includeImplicit is true.
03940  *
03941  * Note: calling this may result in a CommandCounterIncrement operation,
03942  * if we have to create or clean out the temp namespace.
03943  */
03944 List *
03945 fetch_search_path(bool includeImplicit)
03946 {
03947     List       *result;
03948 
03949     recomputeNamespacePath();
03950 
03951     /*
03952      * If the temp namespace should be first, force it to exist.  This is so
03953      * that callers can trust the result to reflect the actual default
03954      * creation namespace.  It's a bit bogus to do this here, since
03955      * current_schema() is supposedly a stable function without side-effects,
03956      * but the alternatives seem worse.
03957      */
03958     if (activeTempCreationPending)
03959     {
03960         InitTempTableNamespace();
03961         recomputeNamespacePath();
03962     }
03963 
03964     result = list_copy(activeSearchPath);
03965     if (!includeImplicit)
03966     {
03967         while (result && linitial_oid(result) != activeCreationNamespace)
03968             result = list_delete_first(result);
03969     }
03970 
03971     return result;
03972 }
03973 
03974 /*
03975  * Fetch the active search path into a caller-allocated array of OIDs.
03976  * Returns the number of path entries.  (If this is more than sarray_len,
03977  * then the data didn't fit and is not all stored.)
03978  *
03979  * The returned list always includes the implicitly-prepended namespaces,
03980  * but never includes the temp namespace.  (This is suitable for existing
03981  * users, which would want to ignore the temp namespace anyway.)  This
03982  * definition allows us to not worry about initializing the temp namespace.
03983  */
03984 int
03985 fetch_search_path_array(Oid *sarray, int sarray_len)
03986 {
03987     int         count = 0;
03988     ListCell   *l;
03989 
03990     recomputeNamespacePath();
03991 
03992     foreach(l, activeSearchPath)
03993     {
03994         Oid         namespaceId = lfirst_oid(l);
03995 
03996         if (namespaceId == myTempNamespace)
03997             continue;           /* do not include temp namespace */
03998 
03999         if (count < sarray_len)
04000             sarray[count] = namespaceId;
04001         count++;
04002     }
04003 
04004     return count;
04005 }
04006 
04007 
04008 /*
04009  * Export the FooIsVisible functions as SQL-callable functions.
04010  *
04011  * Note: as of Postgres 8.4, these will silently return NULL if called on
04012  * a nonexistent object OID, rather than failing.  This is to avoid race
04013  * condition errors when a query that's scanning a catalog using an MVCC
04014  * snapshot uses one of these functions.  The underlying IsVisible functions
04015  * operate on SnapshotNow semantics and so might see the object as already
04016  * gone when it's still visible to the MVCC snapshot.  (There is no race
04017  * condition in the current coding because we don't accept sinval messages
04018  * between the SearchSysCacheExists test and the subsequent lookup.)
04019  */
04020 
04021 Datum
04022 pg_table_is_visible(PG_FUNCTION_ARGS)
04023 {
04024     Oid         oid = PG_GETARG_OID(0);
04025 
04026     if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(oid)))
04027         PG_RETURN_NULL();
04028 
04029     PG_RETURN_BOOL(RelationIsVisible(oid));
04030 }
04031 
04032 Datum
04033 pg_type_is_visible(PG_FUNCTION_ARGS)
04034 {
04035     Oid         oid = PG_GETARG_OID(0);
04036 
04037     if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(oid)))
04038         PG_RETURN_NULL();
04039 
04040     PG_RETURN_BOOL(TypeIsVisible(oid));
04041 }
04042 
04043 Datum
04044 pg_function_is_visible(PG_FUNCTION_ARGS)
04045 {
04046     Oid         oid = PG_GETARG_OID(0);
04047 
04048     if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(oid)))
04049         PG_RETURN_NULL();
04050 
04051     PG_RETURN_BOOL(FunctionIsVisible(oid));
04052 }
04053 
04054 Datum
04055 pg_operator_is_visible(PG_FUNCTION_ARGS)
04056 {
04057     Oid         oid = PG_GETARG_OID(0);
04058 
04059     if (!SearchSysCacheExists1(OPEROID, ObjectIdGetDatum(oid)))
04060         PG_RETURN_NULL();
04061 
04062     PG_RETURN_BOOL(OperatorIsVisible(oid));
04063 }
04064 
04065 Datum
04066 pg_opclass_is_visible(PG_FUNCTION_ARGS)
04067 {
04068     Oid         oid = PG_GETARG_OID(0);
04069 
04070     if (!SearchSysCacheExists1(CLAOID, ObjectIdGetDatum(oid)))
04071         PG_RETURN_NULL();
04072 
04073     PG_RETURN_BOOL(OpclassIsVisible(oid));
04074 }
04075 
04076 Datum
04077 pg_opfamily_is_visible(PG_FUNCTION_ARGS)
04078 {
04079     Oid         oid = PG_GETARG_OID(0);
04080 
04081     if (!SearchSysCacheExists1(OPFAMILYOID, ObjectIdGetDatum(oid)))
04082         PG_RETURN_NULL();
04083 
04084     PG_RETURN_BOOL(OpfamilyIsVisible(oid));
04085 }
04086 
04087 Datum
04088 pg_collation_is_visible(PG_FUNCTION_ARGS)
04089 {
04090     Oid         oid = PG_GETARG_OID(0);
04091 
04092     if (!SearchSysCacheExists1(COLLOID, ObjectIdGetDatum(oid)))
04093         PG_RETURN_NULL();
04094 
04095     PG_RETURN_BOOL(CollationIsVisible(oid));
04096 }
04097 
04098 Datum
04099 pg_conversion_is_visible(PG_FUNCTION_ARGS)
04100 {
04101     Oid         oid = PG_GETARG_OID(0);
04102 
04103     if (!SearchSysCacheExists1(CONVOID, ObjectIdGetDatum(oid)))
04104         PG_RETURN_NULL();
04105 
04106     PG_RETURN_BOOL(ConversionIsVisible(oid));
04107 }
04108 
04109 Datum
04110 pg_ts_parser_is_visible(PG_FUNCTION_ARGS)
04111 {
04112     Oid         oid = PG_GETARG_OID(0);
04113 
04114     if (!SearchSysCacheExists1(TSPARSEROID, ObjectIdGetDatum(oid)))
04115         PG_RETURN_NULL();
04116 
04117     PG_RETURN_BOOL(TSParserIsVisible(oid));
04118 }
04119 
04120 Datum
04121 pg_ts_dict_is_visible(PG_FUNCTION_ARGS)
04122 {
04123     Oid         oid = PG_GETARG_OID(0);
04124 
04125     if (!SearchSysCacheExists1(TSDICTOID, ObjectIdGetDatum(oid)))
04126         PG_RETURN_NULL();
04127 
04128     PG_RETURN_BOOL(TSDictionaryIsVisible(oid));
04129 }
04130 
04131 Datum
04132 pg_ts_template_is_visible(PG_FUNCTION_ARGS)
04133 {
04134     Oid         oid = PG_GETARG_OID(0);
04135 
04136     if (!SearchSysCacheExists1(TSTEMPLATEOID, ObjectIdGetDatum(oid)))
04137         PG_RETURN_NULL();
04138 
04139     PG_RETURN_BOOL(TSTemplateIsVisible(oid));
04140 }
04141 
04142 Datum
04143 pg_ts_config_is_visible(PG_FUNCTION_ARGS)
04144 {
04145     Oid         oid = PG_GETARG_OID(0);
04146 
04147     if (!SearchSysCacheExists1(TSCONFIGOID, ObjectIdGetDatum(oid)))
04148         PG_RETURN_NULL();
04149 
04150     PG_RETURN_BOOL(TSConfigIsVisible(oid));
04151 }
04152 
04153 Datum
04154 pg_my_temp_schema(PG_FUNCTION_ARGS)
04155 {
04156     PG_RETURN_OID(myTempNamespace);
04157 }
04158 
04159 Datum
04160 pg_is_other_temp_schema(PG_FUNCTION_ARGS)
04161 {
04162     Oid         oid = PG_GETARG_OID(0);
04163 
04164     PG_RETURN_BOOL(isOtherTempNamespace(oid));
04165 }