LCOV - code coverage report
Current view: top level - src/backend/catalog - namespace.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 1152 1366 84.3 %
Date: 2019-11-22 07:06:56 Functions: 78 91 85.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * namespace.c
       4             :  *    code to support accessing and searching namespaces
       5             :  *
       6             :  * This is separate from pg_namespace.c, which contains the routines that
       7             :  * directly manipulate the pg_namespace system catalog.  This module
       8             :  * provides routines associated with defining a "namespace search path"
       9             :  * and implementing search-path-controlled searches.
      10             :  *
      11             :  *
      12             :  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
      13             :  * Portions Copyright (c) 1994, Regents of the University of California
      14             :  *
      15             :  * IDENTIFICATION
      16             :  *    src/backend/catalog/namespace.c
      17             :  *
      18             :  *-------------------------------------------------------------------------
      19             :  */
      20             : #include "postgres.h"
      21             : 
      22             : #include "access/htup_details.h"
      23             : #include "access/parallel.h"
      24             : #include "access/xact.h"
      25             : #include "access/xlog.h"
      26             : #include "catalog/dependency.h"
      27             : #include "catalog/objectaccess.h"
      28             : #include "catalog/pg_authid.h"
      29             : #include "catalog/pg_collation.h"
      30             : #include "catalog/pg_conversion.h"
      31             : #include "catalog/pg_namespace.h"
      32             : #include "catalog/pg_opclass.h"
      33             : #include "catalog/pg_operator.h"
      34             : #include "catalog/pg_opfamily.h"
      35             : #include "catalog/pg_proc.h"
      36             : #include "catalog/pg_statistic_ext.h"
      37             : #include "catalog/pg_ts_config.h"
      38             : #include "catalog/pg_ts_dict.h"
      39             : #include "catalog/pg_ts_parser.h"
      40             : #include "catalog/pg_ts_template.h"
      41             : #include "catalog/pg_type.h"
      42             : #include "commands/dbcommands.h"
      43             : #include "funcapi.h"
      44             : #include "mb/pg_wchar.h"
      45             : #include "miscadmin.h"
      46             : #include "nodes/makefuncs.h"
      47             : #include "parser/parse_func.h"
      48             : #include "storage/ipc.h"
      49             : #include "storage/lmgr.h"
      50             : #include "storage/sinvaladt.h"
      51             : #include "utils/acl.h"
      52             : #include "utils/builtins.h"
      53             : #include "utils/catcache.h"
      54             : #include "utils/guc.h"
      55             : #include "utils/inval.h"
      56             : #include "utils/lsyscache.h"
      57             : #include "utils/memutils.h"
      58             : #include "utils/syscache.h"
      59             : #include "utils/varlena.h"
      60             : 
      61             : 
      62             : /*
      63             :  * The namespace search path is a possibly-empty list of namespace OIDs.
      64             :  * In addition to the explicit list, implicitly-searched namespaces
      65             :  * may be included:
      66             :  *
      67             :  * 1. If a TEMP table namespace has been initialized in this session, it
      68             :  * is implicitly searched first.  (The only time this doesn't happen is
      69             :  * when we are obeying an override search path spec that says not to use the
      70             :  * temp namespace, or the temp namespace is included in the explicit list.)
      71             :  *
      72             :  * 2. The system catalog namespace is always searched.  If the system
      73             :  * namespace is present in the explicit path then it will be searched in
      74             :  * the specified order; otherwise it will be searched after TEMP tables and
      75             :  * *before* the explicit list.  (It might seem that the system namespace
      76             :  * should be implicitly last, but this behavior appears to be required by
      77             :  * SQL99.  Also, this provides a way to search the system namespace first
      78             :  * without thereby making it the default creation target namespace.)
      79             :  *
      80             :  * For security reasons, searches using the search path will ignore the temp
      81             :  * namespace when searching for any object type other than relations and
      82             :  * types.  (We must allow types since temp tables have rowtypes.)
      83             :  *
      84             :  * The default creation target namespace is always the first element of the
      85             :  * explicit list.  If the explicit list is empty, there is no default target.
      86             :  *
      87             :  * The textual specification of search_path can include "$user" to refer to
      88             :  * the namespace named the same as the current user, if any.  (This is just
      89             :  * ignored if there is no such namespace.)  Also, it can include "pg_temp"
      90             :  * to refer to the current backend's temp namespace.  This is usually also
      91             :  * ignorable if the temp namespace hasn't been set up, but there's a special
      92             :  * case: if "pg_temp" appears first then it should be the default creation
      93             :  * target.  We kluge this case a little bit so that the temp namespace isn't
      94             :  * set up until the first attempt to create something in it.  (The reason for
      95             :  * klugery is that we can't create the temp namespace outside a transaction,
      96             :  * but initial GUC processing of search_path happens outside a transaction.)
      97             :  * activeTempCreationPending is true if "pg_temp" appears first in the string
      98             :  * but is not reflected in activeCreationNamespace because the namespace isn't
      99             :  * set up yet.
     100             :  *
     101             :  * In bootstrap mode, the search path is set equal to "pg_catalog", so that
     102             :  * the system namespace is the only one searched or inserted into.
     103             :  * initdb is also careful to set search_path to "pg_catalog" for its
     104             :  * post-bootstrap standalone backend runs.  Otherwise the default search
     105             :  * path is determined by GUC.  The factory default path contains the PUBLIC
     106             :  * namespace (if it exists), preceded by the user's personal namespace
     107             :  * (if one exists).
     108             :  *
     109             :  * We support a stack of "override" search path settings for use within
     110             :  * specific sections of backend code.  namespace_search_path is ignored
     111             :  * whenever the override stack is nonempty.  activeSearchPath is always
     112             :  * the actually active path; it points either to the search list of the
     113             :  * topmost stack entry, or to baseSearchPath which is the list derived
     114             :  * from namespace_search_path.
     115             :  *
     116             :  * If baseSearchPathValid is false, then baseSearchPath (and other
     117             :  * derived variables) need to be recomputed from namespace_search_path.
     118             :  * We mark it invalid upon an assignment to namespace_search_path or receipt
     119             :  * of a syscache invalidation event for pg_namespace.  The recomputation
     120             :  * is done during the next non-overridden lookup attempt.  Note that an
     121             :  * override spec is never subject to recomputation.
     122             :  *
     123             :  * Any namespaces mentioned in namespace_search_path that are not readable
     124             :  * by the current user ID are simply left out of baseSearchPath; so
     125             :  * we have to be willing to recompute the path when current userid changes.
     126             :  * namespaceUser is the userid the path has been computed for.
     127             :  *
     128             :  * Note: all data pointed to by these List variables is in TopMemoryContext.
     129             :  */
     130             : 
     131             : /* These variables define the actually active state: */
     132             : 
     133             : static List *activeSearchPath = NIL;
     134             : 
     135             : /* default place to create stuff; if InvalidOid, no default */
     136             : static Oid  activeCreationNamespace = InvalidOid;
     137             : 
     138             : /* if true, activeCreationNamespace is wrong, it should be temp namespace */
     139             : static bool activeTempCreationPending = false;
     140             : 
     141             : /* These variables are the values last derived from namespace_search_path: */
     142             : 
     143             : static List *baseSearchPath = NIL;
     144             : 
     145             : static Oid  baseCreationNamespace = InvalidOid;
     146             : 
     147             : static bool baseTempCreationPending = false;
     148             : 
     149             : static Oid  namespaceUser = InvalidOid;
     150             : 
     151             : /* The above four values are valid only if baseSearchPathValid */
     152             : static bool baseSearchPathValid = true;
     153             : 
     154             : /* Override requests are remembered in a stack of OverrideStackEntry structs */
     155             : 
     156             : typedef struct
     157             : {
     158             :     List       *searchPath;     /* the desired search path */
     159             :     Oid         creationNamespace;  /* the desired creation namespace */
     160             :     int         nestLevel;      /* subtransaction nesting level */
     161             : } OverrideStackEntry;
     162             : 
     163             : static List *overrideStack = NIL;
     164             : 
     165             : /*
     166             :  * myTempNamespace is InvalidOid until and unless a TEMP namespace is set up
     167             :  * in a particular backend session (this happens when a CREATE TEMP TABLE
     168             :  * command is first executed).  Thereafter it's the OID of the temp namespace.
     169             :  *
     170             :  * myTempToastNamespace is the OID of the namespace for my temp tables' toast
     171             :  * tables.  It is set when myTempNamespace is, and is InvalidOid before that.
     172             :  *
     173             :  * myTempNamespaceSubID shows whether we've created the TEMP namespace in the
     174             :  * current subtransaction.  The flag propagates up the subtransaction tree,
     175             :  * so the main transaction will correctly recognize the flag if all
     176             :  * intermediate subtransactions commit.  When it is InvalidSubTransactionId,
     177             :  * we either haven't made the TEMP namespace yet, or have successfully
     178             :  * committed its creation, depending on whether myTempNamespace is valid.
     179             :  */
     180             : static Oid  myTempNamespace = InvalidOid;
     181             : 
     182             : static Oid  myTempToastNamespace = InvalidOid;
     183             : 
     184             : static SubTransactionId myTempNamespaceSubID = InvalidSubTransactionId;
     185             : 
     186             : /*
     187             :  * This is the user's textual search path specification --- it's the value
     188             :  * of the GUC variable 'search_path'.
     189             :  */
     190             : char       *namespace_search_path = NULL;
     191             : 
     192             : 
     193             : /* Local functions */
     194             : static void recomputeNamespacePath(void);
     195             : static void AccessTempTableNamespace(bool force);
     196             : static void InitTempTableNamespace(void);
     197             : static void RemoveTempRelations(Oid tempNamespaceId);
     198             : static void RemoveTempRelationsCallback(int code, Datum arg);
     199             : static void NamespaceCallback(Datum arg, int cacheid, uint32 hashvalue);
     200             : static bool MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
     201             :                            int **argnumbers);
     202             : 
     203             : 
     204             : /*
     205             :  * RangeVarGetRelidExtended
     206             :  *      Given a RangeVar describing an existing relation,
     207             :  *      select the proper namespace and look up the relation OID.
     208             :  *
     209             :  * If the schema or relation is not found, return InvalidOid if flags contains
     210             :  * RVR_MISSING_OK, otherwise raise an error.
     211             :  *
     212             :  * If flags contains RVR_NOWAIT, throw an error if we'd have to wait for a
     213             :  * lock.
     214             :  *
     215             :  * If flags contains RVR_SKIP_LOCKED, return InvalidOid if we'd have to wait
     216             :  * for a lock.
     217             :  *
     218             :  * flags cannot contain both RVR_NOWAIT and RVR_SKIP_LOCKED.
     219             :  *
     220             :  * Note that if RVR_MISSING_OK and RVR_SKIP_LOCKED are both specified, a
     221             :  * return value of InvalidOid could either mean the relation is missing or it
     222             :  * could not be locked.
     223             :  *
     224             :  * Callback allows caller to check permissions or acquire additional locks
     225             :  * prior to grabbing the relation lock.
     226             :  */
     227             : Oid
     228      578734 : RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode,
     229             :                          uint32 flags,
     230             :                          RangeVarGetRelidCallback callback, void *callback_arg)
     231             : {
     232             :     uint64      inval_count;
     233             :     Oid         relId;
     234      578734 :     Oid         oldRelId = InvalidOid;
     235      578734 :     bool        retry = false;
     236      578734 :     bool        missing_ok = (flags & RVR_MISSING_OK) != 0;
     237             : 
     238             :     /* verify that flags do no conflict */
     239             :     Assert(!((flags & RVR_NOWAIT) && (flags & RVR_SKIP_LOCKED)));
     240             : 
     241             :     /*
     242             :      * We check the catalog name and then ignore it.
     243             :      */
     244      578734 :     if (relation->catalogname)
     245             :     {
     246          52 :         if (strcmp(relation->catalogname, get_database_name(MyDatabaseId)) != 0)
     247          52 :             ereport(ERROR,
     248             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     249             :                      errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
     250             :                             relation->catalogname, relation->schemaname,
     251             :                             relation->relname)));
     252             :     }
     253             : 
     254             :     /*
     255             :      * DDL operations can change the results of a name lookup.  Since all such
     256             :      * operations will generate invalidation messages, we keep track of
     257             :      * whether any such messages show up while we're performing the operation,
     258             :      * and retry until either (1) no more invalidation messages show up or (2)
     259             :      * the answer doesn't change.
     260             :      *
     261             :      * But if lockmode = NoLock, then we assume that either the caller is OK
     262             :      * with the answer changing under them, or that they already hold some
     263             :      * appropriate lock, and therefore return the first answer we get without
     264             :      * checking for invalidation messages.  Also, if the requested lock is
     265             :      * already held, LockRelationOid will not AcceptInvalidationMessages, so
     266             :      * we may fail to notice a change.  We could protect against that case by
     267             :      * calling AcceptInvalidationMessages() before beginning this loop, but
     268             :      * that would add a significant amount overhead, so for now we don't.
     269             :      */
     270             :     for (;;)
     271             :     {
     272             :         /*
     273             :          * Remember this value, so that, after looking up the relation name
     274             :          * and locking its OID, we can check whether any invalidation messages
     275             :          * have been processed that might require a do-over.
     276             :          */
     277      580514 :         inval_count = SharedInvalidMessageCounter;
     278             : 
     279             :         /*
     280             :          * Some non-default relpersistence value may have been specified.  The
     281             :          * parser never generates such a RangeVar in simple DML, but it can
     282             :          * happen in contexts such as "CREATE TEMP TABLE foo (f1 int PRIMARY
     283             :          * KEY)".  Such a command will generate an added CREATE INDEX
     284             :          * operation, which must be careful to find the temp table, even when
     285             :          * pg_temp is not first in the search path.
     286             :          */
     287      579598 :         if (relation->relpersistence == RELPERSISTENCE_TEMP)
     288             :         {
     289         376 :             if (!OidIsValid(myTempNamespace))
     290           0 :                 relId = InvalidOid; /* this probably can't happen? */
     291             :             else
     292             :             {
     293         376 :                 if (relation->schemaname)
     294             :                 {
     295             :                     Oid         namespaceId;
     296             : 
     297           8 :                     namespaceId = LookupExplicitNamespace(relation->schemaname, missing_ok);
     298             : 
     299             :                     /*
     300             :                      * For missing_ok, allow a non-existent schema name to
     301             :                      * return InvalidOid.
     302             :                      */
     303           8 :                     if (namespaceId != myTempNamespace)
     304           0 :                         ereport(ERROR,
     305             :                                 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
     306             :                                  errmsg("temporary tables cannot specify a schema name")));
     307             :                 }
     308             : 
     309         376 :                 relId = get_relname_relid(relation->relname, myTempNamespace);
     310             :             }
     311             :         }
     312      579222 :         else if (relation->schemaname)
     313             :         {
     314             :             Oid         namespaceId;
     315             : 
     316             :             /* use exact schema given */
     317      149414 :             namespaceId = LookupExplicitNamespace(relation->schemaname, missing_ok);
     318      149340 :             if (missing_ok && !OidIsValid(namespaceId))
     319          50 :                 relId = InvalidOid;
     320             :             else
     321      149290 :                 relId = get_relname_relid(relation->relname, namespaceId);
     322             :         }
     323             :         else
     324             :         {
     325             :             /* search the namespace path */
     326      429808 :             relId = RelnameGetRelid(relation->relname);
     327             :         }
     328             : 
     329             :         /*
     330             :          * Invoke caller-supplied callback, if any.
     331             :          *
     332             :          * This callback is a good place to check permissions: we haven't
     333             :          * taken the table lock yet (and it's really best to check permissions
     334             :          * before locking anything!), but we've gotten far enough to know what
     335             :          * OID we think we should lock.  Of course, concurrent DDL might
     336             :          * change things while we're waiting for the lock, but in that case
     337             :          * the callback will be invoked again for the new OID.
     338             :          */
     339      579524 :         if (callback)
     340       37160 :             callback(relation, relId, oldRelId, callback_arg);
     341             : 
     342             :         /*
     343             :          * If no lock requested, we assume the caller knows what they're
     344             :          * doing.  They should have already acquired a heavyweight lock on
     345             :          * this relation earlier in the processing of this same statement, so
     346             :          * it wouldn't be appropriate to AcceptInvalidationMessages() here, as
     347             :          * that might pull the rug out from under them.
     348             :          */
     349      579396 :         if (lockmode == NoLock)
     350      103636 :             break;
     351             : 
     352             :         /*
     353             :          * If, upon retry, we get back the same OID we did last time, then the
     354             :          * invalidation messages we processed did not change the final answer.
     355             :          * So we're done.
     356             :          *
     357             :          * If we got a different OID, we've locked the relation that used to
     358             :          * have this name rather than the one that does now.  So release the
     359             :          * lock.
     360             :          */
     361      475760 :         if (retry)
     362             :         {
     363         916 :             if (relId == oldRelId)
     364         916 :                 break;
     365           0 :             if (OidIsValid(oldRelId))
     366           0 :                 UnlockRelationOid(oldRelId, lockmode);
     367             :         }
     368             : 
     369             :         /*
     370             :          * Lock relation.  This will also accept any pending invalidation
     371             :          * messages.  If we got back InvalidOid, indicating not found, then
     372             :          * there's nothing to lock, but we accept invalidation messages
     373             :          * anyway, to flush any negative catcache entries that may be
     374             :          * lingering.
     375             :          */
     376      474844 :         if (!OidIsValid(relId))
     377        1254 :             AcceptInvalidationMessages();
     378      473590 :         else if (!(flags & (RVR_NOWAIT | RVR_SKIP_LOCKED)))
     379      473186 :             LockRelationOid(relId, lockmode);
     380         404 :         else if (!ConditionalLockRelationOid(relId, lockmode))
     381             :         {
     382          12 :             int         elevel = (flags & RVR_SKIP_LOCKED) ? DEBUG1 : ERROR;
     383             : 
     384          12 :             if (relation->schemaname)
     385           0 :                 ereport(elevel,
     386             :                         (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
     387             :                          errmsg("could not obtain lock on relation \"%s.%s\"",
     388             :                                 relation->schemaname, relation->relname)));
     389             :             else
     390          12 :                 ereport(elevel,
     391             :                         (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
     392             :                          errmsg("could not obtain lock on relation \"%s\"",
     393             :                                 relation->relname)));
     394             : 
     395           8 :             return InvalidOid;
     396             :         }
     397             : 
     398             :         /*
     399             :          * If no invalidation message were processed, we're done!
     400             :          */
     401      474820 :         if (inval_count == SharedInvalidMessageCounter)
     402      473904 :             break;
     403             : 
     404             :         /*
     405             :          * Something may have changed.  Let's repeat the name lookup, to make
     406             :          * sure this name still references the same relation it did
     407             :          * previously.
     408             :          */
     409         916 :         retry = true;
     410         916 :         oldRelId = relId;
     411             :     }
     412             : 
     413      578456 :     if (!OidIsValid(relId))
     414             :     {
     415        1294 :         int         elevel = missing_ok ? DEBUG1 : ERROR;
     416             : 
     417        1294 :         if (relation->schemaname)
     418         150 :             ereport(elevel,
     419             :                     (errcode(ERRCODE_UNDEFINED_TABLE),
     420             :                      errmsg("relation \"%s.%s\" does not exist",
     421             :                             relation->schemaname, relation->relname)));
     422             :         else
     423        1144 :             ereport(elevel,
     424             :                     (errcode(ERRCODE_UNDEFINED_TABLE),
     425             :                      errmsg("relation \"%s\" does not exist",
     426             :                             relation->relname)));
     427             :     }
     428      578154 :     return relId;
     429             : }
     430             : 
     431             : /*
     432             :  * RangeVarGetCreationNamespace
     433             :  *      Given a RangeVar describing a to-be-created relation,
     434             :  *      choose which namespace to create it in.
     435             :  *
     436             :  * Note: calling this may result in a CommandCounterIncrement operation.
     437             :  * That will happen on the first request for a temp table in any particular
     438             :  * backend run; we will need to either create or clean out the temp schema.
     439             :  */
     440             : Oid
     441      127900 : RangeVarGetCreationNamespace(const RangeVar *newRelation)
     442             : {
     443             :     Oid         namespaceId;
     444             : 
     445             :     /*
     446             :      * We check the catalog name and then ignore it.
     447             :      */
     448      127900 :     if (newRelation->catalogname)
     449             :     {
     450           0 :         if (strcmp(newRelation->catalogname, get_database_name(MyDatabaseId)) != 0)
     451           0 :             ereport(ERROR,
     452             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     453             :                      errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
     454             :                             newRelation->catalogname, newRelation->schemaname,
     455             :                             newRelation->relname)));
     456             :     }
     457             : 
     458      127900 :     if (newRelation->schemaname)
     459             :     {
     460             :         /* check for pg_temp alias */
     461       22318 :         if (strcmp(newRelation->schemaname, "pg_temp") == 0)
     462             :         {
     463             :             /* Initialize temp namespace */
     464          40 :             AccessTempTableNamespace(false);
     465          40 :             return myTempNamespace;
     466             :         }
     467             :         /* use exact schema given */
     468       22278 :         namespaceId = get_namespace_oid(newRelation->schemaname, false);
     469             :         /* we do not check for USAGE rights here! */
     470             :     }
     471      105582 :     else if (newRelation->relpersistence == RELPERSISTENCE_TEMP)
     472             :     {
     473             :         /* Initialize temp namespace */
     474        4364 :         AccessTempTableNamespace(false);
     475        4364 :         return myTempNamespace;
     476             :     }
     477             :     else
     478             :     {
     479             :         /* use the default creation namespace */
     480      101218 :         recomputeNamespacePath();
     481      101218 :         if (activeTempCreationPending)
     482             :         {
     483             :             /* Need to initialize temp namespace */
     484           0 :             AccessTempTableNamespace(true);
     485           0 :             return myTempNamespace;
     486             :         }
     487      101218 :         namespaceId = activeCreationNamespace;
     488      101218 :         if (!OidIsValid(namespaceId))
     489           0 :             ereport(ERROR,
     490             :                     (errcode(ERRCODE_UNDEFINED_SCHEMA),
     491             :                      errmsg("no schema has been selected to create in")));
     492             :     }
     493             : 
     494             :     /* Note: callers will check for CREATE rights when appropriate */
     495             : 
     496      123496 :     return namespaceId;
     497             : }
     498             : 
     499             : /*
     500             :  * RangeVarGetAndCheckCreationNamespace
     501             :  *
     502             :  * This function returns the OID of the namespace in which a new relation
     503             :  * with a given name should be created.  If the user does not have CREATE
     504             :  * permission on the target namespace, this function will instead signal
     505             :  * an ERROR.
     506             :  *
     507             :  * If non-NULL, *existing_relation_id is set to the OID of any existing relation
     508             :  * with the same name which already exists in that namespace, or to InvalidOid
     509             :  * if no such relation exists.
     510             :  *
     511             :  * If lockmode != NoLock, the specified lock mode is acquired on the existing
     512             :  * relation, if any, provided that the current user owns the target relation.
     513             :  * However, if lockmode != NoLock and the user does not own the target
     514             :  * relation, we throw an ERROR, as we must not try to lock relations the
     515             :  * user does not have permissions on.
     516             :  *
     517             :  * As a side effect, this function acquires AccessShareLock on the target
     518             :  * namespace.  Without this, the namespace could be dropped before our
     519             :  * transaction commits, leaving behind relations with relnamespace pointing
     520             :  * to a no-longer-existent namespace.
     521             :  *
     522             :  * As a further side-effect, if the selected namespace is a temporary namespace,
     523             :  * we mark the RangeVar as RELPERSISTENCE_TEMP.
     524             :  */
     525             : Oid
     526      126928 : RangeVarGetAndCheckCreationNamespace(RangeVar *relation,
     527             :                                      LOCKMODE lockmode,
     528             :                                      Oid *existing_relation_id)
     529             : {
     530             :     uint64      inval_count;
     531             :     Oid         relid;
     532      126928 :     Oid         oldrelid = InvalidOid;
     533             :     Oid         nspid;
     534      126928 :     Oid         oldnspid = InvalidOid;
     535      126928 :     bool        retry = false;
     536             : 
     537             :     /*
     538             :      * We check the catalog name and then ignore it.
     539             :      */
     540      126928 :     if (relation->catalogname)
     541             :     {
     542           0 :         if (strcmp(relation->catalogname, get_database_name(MyDatabaseId)) != 0)
     543           0 :             ereport(ERROR,
     544             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     545             :                      errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
     546             :                             relation->catalogname, relation->schemaname,
     547             :                             relation->relname)));
     548             :     }
     549             : 
     550             :     /*
     551             :      * As in RangeVarGetRelidExtended(), we guard against concurrent DDL
     552             :      * operations by tracking whether any invalidation messages are processed
     553             :      * while we're doing the name lookups and acquiring locks.  See comments
     554             :      * in that function for a more detailed explanation of this logic.
     555             :      */
     556             :     for (;;)
     557         408 :     {
     558             :         AclResult   aclresult;
     559             : 
     560      127336 :         inval_count = SharedInvalidMessageCounter;
     561             : 
     562             :         /* Look up creation namespace and check for existing relation. */
     563      127336 :         nspid = RangeVarGetCreationNamespace(relation);
     564             :         Assert(OidIsValid(nspid));
     565      127336 :         if (existing_relation_id != NULL)
     566       62588 :             relid = get_relname_relid(relation->relname, nspid);
     567             :         else
     568       64748 :             relid = InvalidOid;
     569             : 
     570             :         /*
     571             :          * In bootstrap processing mode, we don't bother with permissions or
     572             :          * locking.  Permissions might not be working yet, and locking is
     573             :          * unnecessary.
     574             :          */
     575      127336 :         if (IsBootstrapProcessingMode())
     576           0 :             break;
     577             : 
     578             :         /* Check namespace permissions. */
     579      127336 :         aclresult = pg_namespace_aclcheck(nspid, GetUserId(), ACL_CREATE);
     580      127336 :         if (aclresult != ACLCHECK_OK)
     581           0 :             aclcheck_error(aclresult, OBJECT_SCHEMA,
     582           0 :                            get_namespace_name(nspid));
     583             : 
     584      127336 :         if (retry)
     585             :         {
     586             :             /* If nothing changed, we're done. */
     587         408 :             if (relid == oldrelid && nspid == oldnspid)
     588         408 :                 break;
     589             :             /* If creation namespace has changed, give up old lock. */
     590           0 :             if (nspid != oldnspid)
     591           0 :                 UnlockDatabaseObject(NamespaceRelationId, oldnspid, 0,
     592             :                                      AccessShareLock);
     593             :             /* If name points to something different, give up old lock. */
     594           0 :             if (relid != oldrelid && OidIsValid(oldrelid) && lockmode != NoLock)
     595           0 :                 UnlockRelationOid(oldrelid, lockmode);
     596             :         }
     597             : 
     598             :         /* Lock namespace. */
     599      126928 :         if (nspid != oldnspid)
     600      126928 :             LockDatabaseObject(NamespaceRelationId, nspid, 0, AccessShareLock);
     601             : 
     602             :         /* Lock relation, if required if and we have permission. */
     603      126928 :         if (lockmode != NoLock && OidIsValid(relid))
     604             :         {
     605         126 :             if (!pg_class_ownercheck(relid, GetUserId()))
     606           0 :                 aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relid)),
     607           0 :                                relation->relname);
     608         126 :             if (relid != oldrelid)
     609         126 :                 LockRelationOid(relid, lockmode);
     610             :         }
     611             : 
     612             :         /* If no invalidation message were processed, we're done! */
     613      126928 :         if (inval_count == SharedInvalidMessageCounter)
     614      126520 :             break;
     615             : 
     616             :         /* Something may have changed, so recheck our work. */
     617         408 :         retry = true;
     618         408 :         oldrelid = relid;
     619         408 :         oldnspid = nspid;
     620             :     }
     621             : 
     622      126928 :     RangeVarAdjustRelationPersistence(relation, nspid);
     623      126912 :     if (existing_relation_id != NULL)
     624       62272 :         *existing_relation_id = relid;
     625      126912 :     return nspid;
     626             : }
     627             : 
     628             : /*
     629             :  * Adjust the relpersistence for an about-to-be-created relation based on the
     630             :  * creation namespace, and throw an error for invalid combinations.
     631             :  */
     632             : void
     633      127890 : RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
     634             : {
     635      127890 :     switch (newRelation->relpersistence)
     636             :     {
     637             :         case RELPERSISTENCE_TEMP:
     638        4358 :             if (!isTempOrTempToastNamespace(nspid))
     639             :             {
     640          12 :                 if (isAnyTempNamespace(nspid))
     641           0 :                     ereport(ERROR,
     642             :                             (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
     643             :                              errmsg("cannot create relations in temporary schemas of other sessions")));
     644             :                 else
     645          12 :                     ereport(ERROR,
     646             :                             (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
     647             :                              errmsg("cannot create temporary relation in non-temporary schema")));
     648             :             }
     649        4346 :             break;
     650             :         case RELPERSISTENCE_PERMANENT:
     651      123386 :             if (isTempOrTempToastNamespace(nspid))
     652          42 :                 newRelation->relpersistence = RELPERSISTENCE_TEMP;
     653      123344 :             else if (isAnyTempNamespace(nspid))
     654           0 :                 ereport(ERROR,
     655             :                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
     656             :                          errmsg("cannot create relations in temporary schemas of other sessions")));
     657      123386 :             break;
     658             :         default:
     659         146 :             if (isAnyTempNamespace(nspid))
     660           4 :                 ereport(ERROR,
     661             :                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
     662             :                          errmsg("only temporary relations may be created in temporary schemas")));
     663             :     }
     664      127874 : }
     665             : 
     666             : /*
     667             :  * RelnameGetRelid
     668             :  *      Try to resolve an unqualified relation name.
     669             :  *      Returns OID if relation found in search path, else InvalidOid.
     670             :  */
     671             : Oid
     672      429864 : RelnameGetRelid(const char *relname)
     673             : {
     674             :     Oid         relid;
     675             :     ListCell   *l;
     676             : 
     677      429864 :     recomputeNamespacePath();
     678             : 
     679      755026 :     foreach(l, activeSearchPath)
     680             :     {
     681      753876 :         Oid         namespaceId = lfirst_oid(l);
     682             : 
     683      753876 :         relid = get_relname_relid(relname, namespaceId);
     684      753876 :         if (OidIsValid(relid))
     685      428714 :             return relid;
     686             :     }
     687             : 
     688             :     /* Not found in path */
     689        1150 :     return InvalidOid;
     690             : }
     691             : 
     692             : 
     693             : /*
     694             :  * RelationIsVisible
     695             :  *      Determine whether a relation (identified by OID) is visible in the
     696             :  *      current search path.  Visible means "would be found by searching
     697             :  *      for the unqualified relation name".
     698             :  */
     699             : bool
     700      129718 : RelationIsVisible(Oid relid)
     701             : {
     702             :     HeapTuple   reltup;
     703             :     Form_pg_class relform;
     704             :     Oid         relnamespace;
     705             :     bool        visible;
     706             : 
     707      129718 :     reltup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
     708      129718 :     if (!HeapTupleIsValid(reltup))
     709           0 :         elog(ERROR, "cache lookup failed for relation %u", relid);
     710      129718 :     relform = (Form_pg_class) GETSTRUCT(reltup);
     711             : 
     712      129718 :     recomputeNamespacePath();
     713             : 
     714             :     /*
     715             :      * Quick check: if it ain't in the path at all, it ain't visible. Items in
     716             :      * the system namespace are surely in the path and so we needn't even do
     717             :      * list_member_oid() for them.
     718             :      */
     719      129718 :     relnamespace = relform->relnamespace;
     720      240850 :     if (relnamespace != PG_CATALOG_NAMESPACE &&
     721      111132 :         !list_member_oid(activeSearchPath, relnamespace))
     722       43966 :         visible = false;
     723             :     else
     724             :     {
     725             :         /*
     726             :          * If it is in the path, it might still not be visible; it could be
     727             :          * hidden by another relation of the same name earlier in the path. So
     728             :          * we must do a slow check for conflicting relations.
     729             :          */
     730       85752 :         char       *relname = NameStr(relform->relname);
     731             :         ListCell   *l;
     732             : 
     733       85752 :         visible = false;
     734      162744 :         foreach(l, activeSearchPath)
     735             :         {
     736      162744 :             Oid         namespaceId = lfirst_oid(l);
     737             : 
     738      162744 :             if (namespaceId == relnamespace)
     739             :             {
     740             :                 /* Found it first in path */
     741       85752 :                 visible = true;
     742       85752 :                 break;
     743             :             }
     744       76992 :             if (OidIsValid(get_relname_relid(relname, namespaceId)))
     745             :             {
     746             :                 /* Found something else first in path */
     747           0 :                 break;
     748             :             }
     749             :         }
     750             :     }
     751             : 
     752      129718 :     ReleaseSysCache(reltup);
     753             : 
     754      129718 :     return visible;
     755             : }
     756             : 
     757             : 
     758             : /*
     759             :  * TypenameGetTypid
     760             :  *      Wrapper for binary compatibility.
     761             :  */
     762             : Oid
     763           0 : TypenameGetTypid(const char *typname)
     764             : {
     765           0 :     return TypenameGetTypidExtended(typname, true);
     766             : }
     767             : 
     768             : /*
     769             :  * TypenameGetTypidExtended
     770             :  *      Try to resolve an unqualified datatype name.
     771             :  *      Returns OID if type found in search path, else InvalidOid.
     772             :  *
     773             :  * This is essentially the same as RelnameGetRelid.
     774             :  */
     775             : Oid
     776      437528 : TypenameGetTypidExtended(const char *typname, bool temp_ok)
     777             : {
     778             :     Oid         typid;
     779             :     ListCell   *l;
     780             : 
     781      437528 :     recomputeNamespacePath();
     782             : 
     783      980922 :     foreach(l, activeSearchPath)
     784             :     {
     785      952244 :         Oid         namespaceId = lfirst_oid(l);
     786             : 
     787      952244 :         if (!temp_ok && namespaceId == myTempNamespace)
     788        5530 :             continue;           /* do not look in temp namespace */
     789             : 
     790      946714 :         typid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
     791             :                                 PointerGetDatum(typname),
     792             :                                 ObjectIdGetDatum(namespaceId));
     793      946714 :         if (OidIsValid(typid))
     794      408850 :             return typid;
     795             :     }
     796             : 
     797             :     /* Not found in path */
     798       28678 :     return InvalidOid;
     799             : }
     800             : 
     801             : /*
     802             :  * TypeIsVisible
     803             :  *      Determine whether a type (identified by OID) is visible in the
     804             :  *      current search path.  Visible means "would be found by searching
     805             :  *      for the unqualified type name".
     806             :  */
     807             : bool
     808      335122 : TypeIsVisible(Oid typid)
     809             : {
     810             :     HeapTuple   typtup;
     811             :     Form_pg_type typform;
     812             :     Oid         typnamespace;
     813             :     bool        visible;
     814             : 
     815      335122 :     typtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
     816      335122 :     if (!HeapTupleIsValid(typtup))
     817           0 :         elog(ERROR, "cache lookup failed for type %u", typid);
     818      335122 :     typform = (Form_pg_type) GETSTRUCT(typtup);
     819             : 
     820      335122 :     recomputeNamespacePath();
     821             : 
     822             :     /*
     823             :      * Quick check: if it ain't in the path at all, it ain't visible. Items in
     824             :      * the system namespace are surely in the path and so we needn't even do
     825             :      * list_member_oid() for them.
     826             :      */
     827      335122 :     typnamespace = typform->typnamespace;
     828      382868 :     if (typnamespace != PG_CATALOG_NAMESPACE &&
     829       47746 :         !list_member_oid(activeSearchPath, typnamespace))
     830        9204 :         visible = false;
     831             :     else
     832             :     {
     833             :         /*
     834             :          * If it is in the path, it might still not be visible; it could be
     835             :          * hidden by another type of the same name earlier in the path. So we
     836             :          * must do a slow check for conflicting types.
     837             :          */
     838      325918 :         char       *typname = NameStr(typform->typname);
     839             :         ListCell   *l;
     840             : 
     841      325918 :         visible = false;
     842      372508 :         foreach(l, activeSearchPath)
     843             :         {
     844      372508 :             Oid         namespaceId = lfirst_oid(l);
     845             : 
     846      372508 :             if (namespaceId == typnamespace)
     847             :             {
     848             :                 /* Found it first in path */
     849      325918 :                 visible = true;
     850      325918 :                 break;
     851             :             }
     852       46590 :             if (SearchSysCacheExists2(TYPENAMENSP,
     853             :                                       PointerGetDatum(typname),
     854             :                                       ObjectIdGetDatum(namespaceId)))
     855             :             {
     856             :                 /* Found something else first in path */
     857           0 :                 break;
     858             :             }
     859             :         }
     860             :     }
     861             : 
     862      335122 :     ReleaseSysCache(typtup);
     863             : 
     864      335122 :     return visible;
     865             : }
     866             : 
     867             : 
     868             : /*
     869             :  * FuncnameGetCandidates
     870             :  *      Given a possibly-qualified function name and argument count,
     871             :  *      retrieve a list of the possible matches.
     872             :  *
     873             :  * If nargs is -1, we return all functions matching the given name,
     874             :  * regardless of argument count.  (argnames must be NIL, and expand_variadic
     875             :  * and expand_defaults must be false, in this case.)
     876             :  *
     877             :  * If argnames isn't NIL, we are considering a named- or mixed-notation call,
     878             :  * and only functions having all the listed argument names will be returned.
     879             :  * (We assume that length(argnames) <= nargs and all the passed-in names are
     880             :  * distinct.)  The returned structs will include an argnumbers array showing
     881             :  * the actual argument index for each logical argument position.
     882             :  *
     883             :  * If expand_variadic is true, then variadic functions having the same number
     884             :  * or fewer arguments will be retrieved, with the variadic argument and any
     885             :  * additional argument positions filled with the variadic element type.
     886             :  * nvargs in the returned struct is set to the number of such arguments.
     887             :  * If expand_variadic is false, variadic arguments are not treated specially,
     888             :  * and the returned nvargs will always be zero.
     889             :  *
     890             :  * If expand_defaults is true, functions that could match after insertion of
     891             :  * default argument values will also be retrieved.  In this case the returned
     892             :  * structs could have nargs > passed-in nargs, and ndargs is set to the number
     893             :  * of additional args (which can be retrieved from the function's
     894             :  * proargdefaults entry).
     895             :  *
     896             :  * It is not possible for nvargs and ndargs to both be nonzero in the same
     897             :  * list entry, since default insertion allows matches to functions with more
     898             :  * than nargs arguments while the variadic transformation requires the same
     899             :  * number or less.
     900             :  *
     901             :  * When argnames isn't NIL, the returned args[] type arrays are not ordered
     902             :  * according to the functions' declarations, but rather according to the call:
     903             :  * first any positional arguments, then the named arguments, then defaulted
     904             :  * arguments (if needed and allowed by expand_defaults).  The argnumbers[]
     905             :  * array can be used to map this back to the catalog information.
     906             :  * argnumbers[k] is set to the proargtypes index of the k'th call argument.
     907             :  *
     908             :  * We search a single namespace if the function name is qualified, else
     909             :  * all namespaces in the search path.  In the multiple-namespace case,
     910             :  * we arrange for entries in earlier namespaces to mask identical entries in
     911             :  * later namespaces.
     912             :  *
     913             :  * When expanding variadics, we arrange for non-variadic functions to mask
     914             :  * variadic ones if the expanded argument list is the same.  It is still
     915             :  * possible for there to be conflicts between different variadic functions,
     916             :  * however.
     917             :  *
     918             :  * It is guaranteed that the return list will never contain multiple entries
     919             :  * with identical argument lists.  When expand_defaults is true, the entries
     920             :  * could have more than nargs positions, but we still guarantee that they are
     921             :  * distinct in the first nargs positions.  However, if argnames isn't NIL or
     922             :  * either expand_variadic or expand_defaults is true, there might be multiple
     923             :  * candidate functions that expand to identical argument lists.  Rather than
     924             :  * throw error here, we report such situations by returning a single entry
     925             :  * with oid = 0 that represents a set of such conflicting candidates.
     926             :  * The caller might end up discarding such an entry anyway, but if it selects
     927             :  * such an entry it should react as though the call were ambiguous.
     928             :  *
     929             :  * If missing_ok is true, an empty list (NULL) is returned if the name was
     930             :  * schema- qualified with a schema that does not exist.  Likewise if no
     931             :  * candidate is found for other reasons.
     932             :  */
     933             : FuncCandidateList
     934      444336 : FuncnameGetCandidates(List *names, int nargs, List *argnames,
     935             :                       bool expand_variadic, bool expand_defaults,
     936             :                       bool missing_ok)
     937             : {
     938      444336 :     FuncCandidateList resultList = NULL;
     939      444336 :     bool        any_special = false;
     940             :     char       *schemaname;
     941             :     char       *funcname;
     942             :     Oid         namespaceId;
     943             :     CatCList   *catlist;
     944             :     int         i;
     945             : 
     946             :     /* check for caller error */
     947             :     Assert(nargs >= 0 || !(expand_variadic | expand_defaults));
     948             : 
     949             :     /* deconstruct the name list */
     950      444336 :     DeconstructQualifiedName(names, &schemaname, &funcname);
     951             : 
     952      444312 :     if (schemaname)
     953             :     {
     954             :         /* use exact schema given */
     955      142404 :         namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
     956      142396 :         if (!OidIsValid(namespaceId))
     957          16 :             return NULL;
     958             :     }
     959             :     else
     960             :     {
     961             :         /* flag to indicate we need namespace search */
     962      301908 :         namespaceId = InvalidOid;
     963      301908 :         recomputeNamespacePath();
     964             :     }
     965             : 
     966             :     /* Search syscache by name only */
     967      444288 :     catlist = SearchSysCacheList1(PROCNAMEARGSNSP, CStringGetDatum(funcname));
     968             : 
     969     1375810 :     for (i = 0; i < catlist->n_members; i++)
     970             :     {
     971      931522 :         HeapTuple   proctup = &catlist->members[i]->tuple;
     972      931522 :         Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
     973      931522 :         int         pronargs = procform->pronargs;
     974             :         int         effective_nargs;
     975      931522 :         int         pathpos = 0;
     976             :         bool        variadic;
     977             :         bool        use_defaults;
     978             :         Oid         va_elem_type;
     979      931522 :         int        *argnumbers = NULL;
     980             :         FuncCandidateList newResult;
     981             : 
     982      931522 :         if (OidIsValid(namespaceId))
     983             :         {
     984             :             /* Consider only procs in specified namespace */
     985      243586 :             if (procform->pronamespace != namespaceId)
     986      264690 :                 continue;
     987             :         }
     988             :         else
     989             :         {
     990             :             /*
     991             :              * Consider only procs that are in the search path and are not in
     992             :              * the temp namespace.
     993             :              */
     994             :             ListCell   *nsp;
     995             : 
     996     1101798 :             foreach(nsp, activeSearchPath)
     997             :             {
     998     1786804 :                 if (procform->pronamespace == lfirst_oid(nsp) &&
     999      686480 :                     procform->pronamespace != myTempNamespace)
    1000      686462 :                     break;
    1001      413862 :                 pathpos++;
    1002             :             }
    1003      687936 :             if (nsp == NULL)
    1004        1474 :                 continue;       /* proc is not in search path */
    1005             :         }
    1006             : 
    1007      929680 :         if (argnames != NIL)
    1008             :         {
    1009             :             /*
    1010             :              * Call uses named or mixed notation
    1011             :              *
    1012             :              * Named or mixed notation can match a variadic function only if
    1013             :              * expand_variadic is off; otherwise there is no way to match the
    1014             :              * presumed-nameless parameters expanded from the variadic array.
    1015             :              */
    1016         502 :             if (OidIsValid(procform->provariadic) && expand_variadic)
    1017           0 :                 continue;
    1018         502 :             va_elem_type = InvalidOid;
    1019         502 :             variadic = false;
    1020             : 
    1021             :             /*
    1022             :              * Check argument count.
    1023             :              */
    1024             :             Assert(nargs >= 0); /* -1 not supported with argnames */
    1025             : 
    1026         502 :             if (pronargs > nargs && expand_defaults)
    1027             :             {
    1028             :                 /* Ignore if not enough default expressions */
    1029         396 :                 if (nargs + procform->pronargdefaults < pronargs)
    1030           0 :                     continue;
    1031         396 :                 use_defaults = true;
    1032             :             }
    1033             :             else
    1034         106 :                 use_defaults = false;
    1035             : 
    1036             :             /* Ignore if it doesn't match requested argument count */
    1037         502 :             if (pronargs != nargs && !use_defaults)
    1038           0 :                 continue;
    1039             : 
    1040             :             /* Check for argument name match, generate positional mapping */
    1041         502 :             if (!MatchNamedCall(proctup, nargs, argnames,
    1042             :                                 &argnumbers))
    1043          12 :                 continue;
    1044             : 
    1045             :             /* Named argument matching is always "special" */
    1046         490 :             any_special = true;
    1047             :         }
    1048             :         else
    1049             :         {
    1050             :             /*
    1051             :              * Call uses positional notation
    1052             :              *
    1053             :              * Check if function is variadic, and get variadic element type if
    1054             :              * so.  If expand_variadic is false, we should just ignore
    1055             :              * variadic-ness.
    1056             :              */
    1057      929178 :             if (pronargs <= nargs && expand_variadic)
    1058             :             {
    1059      627300 :                 va_elem_type = procform->provariadic;
    1060      627300 :                 variadic = OidIsValid(va_elem_type);
    1061      627300 :                 any_special |= variadic;
    1062             :             }
    1063             :             else
    1064             :             {
    1065      301878 :                 va_elem_type = InvalidOid;
    1066      301878 :                 variadic = false;
    1067             :             }
    1068             : 
    1069             :             /*
    1070             :              * Check if function can match by using parameter defaults.
    1071             :              */
    1072      929178 :             if (pronargs > nargs && expand_defaults)
    1073             :             {
    1074             :                 /* Ignore if not enough default expressions */
    1075      218076 :                 if (nargs + procform->pronargdefaults < pronargs)
    1076      215930 :                     continue;
    1077        2146 :                 use_defaults = true;
    1078        2146 :                 any_special = true;
    1079             :             }
    1080             :             else
    1081      711102 :                 use_defaults = false;
    1082             : 
    1083             :             /* Ignore if it doesn't match requested argument count */
    1084      713248 :             if (nargs >= 0 && pronargs != nargs && !variadic && !use_defaults)
    1085       46492 :                 continue;
    1086             :         }
    1087             : 
    1088             :         /*
    1089             :          * We must compute the effective argument list so that we can easily
    1090             :          * compare it to earlier results.  We waste a palloc cycle if it gets
    1091             :          * masked by an earlier result, but really that's a pretty infrequent
    1092             :          * case so it's not worth worrying about.
    1093             :          */
    1094      667246 :         effective_nargs = Max(pronargs, nargs);
    1095      667246 :         newResult = (FuncCandidateList)
    1096      667246 :             palloc(offsetof(struct _FuncCandidateList, args) +
    1097             :                    effective_nargs * sizeof(Oid));
    1098      667246 :         newResult->pathpos = pathpos;
    1099      667246 :         newResult->oid = procform->oid;
    1100      667246 :         newResult->nargs = effective_nargs;
    1101      667246 :         newResult->argnumbers = argnumbers;
    1102      667246 :         if (argnumbers)
    1103             :         {
    1104             :             /* Re-order the argument types into call's logical order */
    1105         490 :             Oid        *proargtypes = procform->proargtypes.values;
    1106             :             int         i;
    1107             : 
    1108        2404 :             for (i = 0; i < pronargs; i++)
    1109        1914 :                 newResult->args[i] = proargtypes[argnumbers[i]];
    1110             :         }
    1111             :         else
    1112             :         {
    1113             :             /* Simple positional case, just copy proargtypes as-is */
    1114      666756 :             memcpy(newResult->args, procform->proargtypes.values,
    1115             :                    pronargs * sizeof(Oid));
    1116             :         }
    1117      667246 :         if (variadic)
    1118             :         {
    1119             :             int         i;
    1120             : 
    1121        1608 :             newResult->nvargs = effective_nargs - pronargs + 1;
    1122             :             /* Expand variadic argument into N copies of element type */
    1123        5336 :             for (i = pronargs - 1; i < effective_nargs; i++)
    1124        3728 :                 newResult->args[i] = va_elem_type;
    1125             :         }
    1126             :         else
    1127      665638 :             newResult->nvargs = 0;
    1128      667246 :         newResult->ndargs = use_defaults ? pronargs - nargs : 0;
    1129             : 
    1130             :         /*
    1131             :          * Does it have the same arguments as something we already accepted?
    1132             :          * If so, decide what to do to avoid returning duplicate argument
    1133             :          * lists.  We can skip this check for the single-namespace case if no
    1134             :          * special (named, variadic or defaults) match has been made, since
    1135             :          * then the unique index on pg_proc guarantees all the matches have
    1136             :          * different argument lists.
    1137             :          */
    1138      667246 :         if (resultList != NULL &&
    1139      225864 :             (any_special || !OidIsValid(namespaceId)))
    1140             :         {
    1141             :             /*
    1142             :              * If we have an ordered list from SearchSysCacheList (the normal
    1143             :              * case), then any conflicting proc must immediately adjoin this
    1144             :              * one in the list, so we only need to look at the newest result
    1145             :              * item.  If we have an unordered list, we have to scan the whole
    1146             :              * result list.  Also, if either the current candidate or any
    1147             :              * previous candidate is a special match, we can't assume that
    1148             :              * conflicts are adjacent.
    1149             :              *
    1150             :              * We ignore defaulted arguments in deciding what is a match.
    1151             :              */
    1152             :             FuncCandidateList prevResult;
    1153             : 
    1154      179160 :             if (catlist->ordered && !any_special)
    1155             :             {
    1156             :                 /* ndargs must be 0 if !any_special */
    1157      537264 :                 if (effective_nargs == resultList->nargs &&
    1158      358176 :                     memcmp(newResult->args,
    1159      179088 :                            resultList->args,
    1160             :                            effective_nargs * sizeof(Oid)) == 0)
    1161           2 :                     prevResult = resultList;
    1162             :                 else
    1163      179086 :                     prevResult = NULL;
    1164             :             }
    1165             :             else
    1166             :             {
    1167          72 :                 int         cmp_nargs = newResult->nargs - newResult->ndargs;
    1168             : 
    1169         168 :                 for (prevResult = resultList;
    1170             :                      prevResult;
    1171          24 :                      prevResult = prevResult->next)
    1172             :                 {
    1173         144 :                     if (cmp_nargs == prevResult->nargs - prevResult->ndargs &&
    1174         144 :                         memcmp(newResult->args,
    1175          72 :                                prevResult->args,
    1176             :                                cmp_nargs * sizeof(Oid)) == 0)
    1177          48 :                         break;
    1178             :                 }
    1179             :             }
    1180             : 
    1181      179160 :             if (prevResult)
    1182             :             {
    1183             :                 /*
    1184             :                  * We have a match with a previous result.  Decide which one
    1185             :                  * to keep, or mark it ambiguous if we can't decide.  The
    1186             :                  * logic here is preference > 0 means prefer the old result,
    1187             :                  * preference < 0 means prefer the new, preference = 0 means
    1188             :                  * ambiguous.
    1189             :                  */
    1190             :                 int         preference;
    1191             : 
    1192          50 :                 if (pathpos != prevResult->pathpos)
    1193             :                 {
    1194             :                     /*
    1195             :                      * Prefer the one that's earlier in the search path.
    1196             :                      */
    1197           2 :                     preference = pathpos - prevResult->pathpos;
    1198             :                 }
    1199          48 :                 else if (variadic && prevResult->nvargs == 0)
    1200             :                 {
    1201             :                     /*
    1202             :                      * With variadic functions we could have, for example,
    1203             :                      * both foo(numeric) and foo(variadic numeric[]) in the
    1204             :                      * same namespace; if so we prefer the non-variadic match
    1205             :                      * on efficiency grounds.
    1206             :                      */
    1207          20 :                     preference = 1;
    1208             :                 }
    1209          28 :                 else if (!variadic && prevResult->nvargs > 0)
    1210             :                 {
    1211           4 :                     preference = -1;
    1212             :                 }
    1213             :                 else
    1214             :                 {
    1215             :                     /*----------
    1216             :                      * We can't decide.  This can happen with, for example,
    1217             :                      * both foo(numeric, variadic numeric[]) and
    1218             :                      * foo(variadic numeric[]) in the same namespace, or
    1219             :                      * both foo(int) and foo (int, int default something)
    1220             :                      * in the same namespace, or both foo(a int, b text)
    1221             :                      * and foo(b text, a int) in the same namespace.
    1222             :                      *----------
    1223             :                      */
    1224          24 :                     preference = 0;
    1225             :                 }
    1226             : 
    1227          50 :                 if (preference > 0)
    1228             :                 {
    1229             :                     /* keep previous result */
    1230          22 :                     pfree(newResult);
    1231          22 :                     continue;
    1232             :                 }
    1233          28 :                 else if (preference < 0)
    1234             :                 {
    1235             :                     /* remove previous result from the list */
    1236           4 :                     if (prevResult == resultList)
    1237           4 :                         resultList = prevResult->next;
    1238             :                     else
    1239             :                     {
    1240             :                         FuncCandidateList prevPrevResult;
    1241             : 
    1242           0 :                         for (prevPrevResult = resultList;
    1243             :                              prevPrevResult;
    1244           0 :                              prevPrevResult = prevPrevResult->next)
    1245             :                         {
    1246           0 :                             if (prevResult == prevPrevResult->next)
    1247             :                             {
    1248           0 :                                 prevPrevResult->next = prevResult->next;
    1249           0 :                                 break;
    1250             :                             }
    1251             :                         }
    1252             :                         Assert(prevPrevResult); /* assert we found it */
    1253             :                     }
    1254           4 :                     pfree(prevResult);
    1255             :                     /* fall through to add newResult to list */
    1256             :                 }
    1257             :                 else
    1258             :                 {
    1259             :                     /* mark old result as ambiguous, discard new */
    1260          24 :                     prevResult->oid = InvalidOid;
    1261          24 :                     pfree(newResult);
    1262          24 :                     continue;
    1263             :                 }
    1264             :             }
    1265             :         }
    1266             : 
    1267             :         /*
    1268             :          * Okay to add it to result list
    1269             :          */
    1270      667200 :         newResult->next = resultList;
    1271      667200 :         resultList = newResult;
    1272             :     }
    1273             : 
    1274      444288 :     ReleaseSysCacheList(catlist);
    1275             : 
    1276      444288 :     return resultList;
    1277             : }
    1278             : 
    1279             : /*
    1280             :  * MatchNamedCall
    1281             :  *      Given a pg_proc heap tuple and a call's list of argument names,
    1282             :  *      check whether the function could match the call.
    1283             :  *
    1284             :  * The call could match if all supplied argument names are accepted by
    1285             :  * the function, in positions after the last positional argument, and there
    1286             :  * are defaults for all unsupplied arguments.
    1287             :  *
    1288             :  * The number of positional arguments is nargs - list_length(argnames).
    1289             :  * Note caller has already done basic checks on argument count.
    1290             :  *
    1291             :  * On match, return true and fill *argnumbers with a palloc'd array showing
    1292             :  * the mapping from call argument positions to actual function argument
    1293             :  * numbers.  Defaulted arguments are included in this map, at positions
    1294             :  * after the last supplied argument.
    1295             :  */
    1296             : static bool
    1297         502 : MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
    1298             :                int **argnumbers)
    1299             : {
    1300         502 :     Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
    1301         502 :     int         pronargs = procform->pronargs;
    1302         502 :     int         numposargs = nargs - list_length(argnames);
    1303             :     int         pronallargs;
    1304             :     Oid        *p_argtypes;
    1305             :     char      **p_argnames;
    1306             :     char       *p_argmodes;
    1307             :     bool        arggiven[FUNC_MAX_ARGS];
    1308             :     bool        isnull;
    1309             :     int         ap;             /* call args position */
    1310             :     int         pp;             /* proargs position */
    1311             :     ListCell   *lc;
    1312             : 
    1313             :     Assert(argnames != NIL);
    1314             :     Assert(numposargs >= 0);
    1315             :     Assert(nargs <= pronargs);
    1316             : 
    1317             :     /* Ignore this function if its proargnames is null */
    1318         502 :     (void) SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proargnames,
    1319             :                            &isnull);
    1320         502 :     if (isnull)
    1321           0 :         return false;
    1322             : 
    1323             :     /* OK, let's extract the argument names and types */
    1324         502 :     pronallargs = get_func_arg_info(proctup,
    1325             :                                     &p_argtypes, &p_argnames, &p_argmodes);
    1326             :     Assert(p_argnames != NULL);
    1327             : 
    1328             :     /* initialize state for matching */
    1329         502 :     *argnumbers = (int *) palloc(pronargs * sizeof(int));
    1330         502 :     memset(arggiven, false, pronargs * sizeof(bool));
    1331             : 
    1332             :     /* there are numposargs positional args before the named args */
    1333        1102 :     for (ap = 0; ap < numposargs; ap++)
    1334             :     {
    1335         600 :         (*argnumbers)[ap] = ap;
    1336         600 :         arggiven[ap] = true;
    1337             :     }
    1338             : 
    1339             :     /* now examine the named args */
    1340        1254 :     foreach(lc, argnames)
    1341             :     {
    1342         760 :         char       *argname = (char *) lfirst(lc);
    1343             :         bool        found;
    1344             :         int         i;
    1345             : 
    1346         760 :         pp = 0;
    1347         760 :         found = false;
    1348        2336 :         for (i = 0; i < pronallargs; i++)
    1349             :         {
    1350             :             /* consider only input parameters */
    1351        2678 :             if (p_argmodes &&
    1352         432 :                 (p_argmodes[i] != FUNC_PARAM_IN &&
    1353         118 :                  p_argmodes[i] != FUNC_PARAM_INOUT &&
    1354          32 :                  p_argmodes[i] != FUNC_PARAM_VARIADIC))
    1355          32 :                 continue;
    1356        2300 :             if (p_argnames[i] && strcmp(p_argnames[i], argname) == 0)
    1357             :             {
    1358             :                 /* fail if argname matches a positional argument */
    1359         756 :                 if (arggiven[pp])
    1360          12 :                     return false;
    1361         752 :                 arggiven[pp] = true;
    1362         752 :                 (*argnumbers)[ap] = pp;
    1363         752 :                 found = true;
    1364         752 :                 break;
    1365             :             }
    1366             :             /* increase pp only for input parameters */
    1367        1544 :             pp++;
    1368             :         }
    1369             :         /* if name isn't in proargnames, fail */
    1370         756 :         if (!found)
    1371           4 :             return false;
    1372         752 :         ap++;
    1373             :     }
    1374             : 
    1375             :     Assert(ap == nargs);        /* processed all actual parameters */
    1376             : 
    1377             :     /* Check for default arguments */
    1378         494 :     if (nargs < pronargs)
    1379             :     {
    1380         388 :         int         first_arg_with_default = pronargs - procform->pronargdefaults;
    1381             : 
    1382        1482 :         for (pp = numposargs; pp < pronargs; pp++)
    1383             :         {
    1384        1098 :             if (arggiven[pp])
    1385         512 :                 continue;
    1386             :             /* fail if arg not given and no default available */
    1387         586 :             if (pp < first_arg_with_default)
    1388           4 :                 return false;
    1389         582 :             (*argnumbers)[ap++] = pp;
    1390             :         }
    1391             :     }
    1392             : 
    1393             :     Assert(ap == pronargs);     /* processed all function parameters */
    1394             : 
    1395         490 :     return true;
    1396             : }
    1397             : 
    1398             : /*
    1399             :  * FunctionIsVisible
    1400             :  *      Determine whether a function (identified by OID) is visible in the
    1401             :  *      current search path.  Visible means "would be found by searching
    1402             :  *      for the unqualified function name with exact argument matches".
    1403             :  */
    1404             : bool
    1405       13830 : FunctionIsVisible(Oid funcid)
    1406             : {
    1407             :     HeapTuple   proctup;
    1408             :     Form_pg_proc procform;
    1409             :     Oid         pronamespace;
    1410             :     bool        visible;
    1411             : 
    1412       13830 :     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1413       13830 :     if (!HeapTupleIsValid(proctup))
    1414           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
    1415       13830 :     procform = (Form_pg_proc) GETSTRUCT(proctup);
    1416             : 
    1417       13830 :     recomputeNamespacePath();
    1418             : 
    1419             :     /*
    1420             :      * Quick check: if it ain't in the path at all, it ain't visible. Items in
    1421             :      * the system namespace are surely in the path and so we needn't even do
    1422             :      * list_member_oid() for them.
    1423             :      */
    1424       13830 :     pronamespace = procform->pronamespace;
    1425       19944 :     if (pronamespace != PG_CATALOG_NAMESPACE &&
    1426        6114 :         !list_member_oid(activeSearchPath, pronamespace))
    1427         430 :         visible = false;
    1428             :     else
    1429             :     {
    1430             :         /*
    1431             :          * If it is in the path, it might still not be visible; it could be
    1432             :          * hidden by another proc of the same name and arguments earlier in
    1433             :          * the path.  So we must do a slow check to see if this is the same
    1434             :          * proc that would be found by FuncnameGetCandidates.
    1435             :          */
    1436       13400 :         char       *proname = NameStr(procform->proname);
    1437       13400 :         int         nargs = procform->pronargs;
    1438             :         FuncCandidateList clist;
    1439             : 
    1440       13400 :         visible = false;
    1441             : 
    1442       13400 :         clist = FuncnameGetCandidates(list_make1(makeString(proname)),
    1443             :                                       nargs, NIL, false, false, false);
    1444             : 
    1445       21076 :         for (; clist; clist = clist->next)
    1446             :         {
    1447       21070 :             if (memcmp(clist->args, procform->proargtypes.values,
    1448             :                        nargs * sizeof(Oid)) == 0)
    1449             :             {
    1450             :                 /* Found the expected entry; is it the right proc? */
    1451       13394 :                 visible = (clist->oid == funcid);
    1452       13394 :                 break;
    1453             :             }
    1454             :         }
    1455             :     }
    1456             : 
    1457       13830 :     ReleaseSysCache(proctup);
    1458             : 
    1459       13830 :     return visible;
    1460             : }
    1461             : 
    1462             : 
    1463             : /*
    1464             :  * OpernameGetOprid
    1465             :  *      Given a possibly-qualified operator name and exact input datatypes,
    1466             :  *      look up the operator.  Returns InvalidOid if not found.
    1467             :  *
    1468             :  * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
    1469             :  * a postfix op.
    1470             :  *
    1471             :  * If the operator name is not schema-qualified, it is sought in the current
    1472             :  * namespace search path.  If the name is schema-qualified and the given
    1473             :  * schema does not exist, InvalidOid is returned.
    1474             :  */
    1475             : Oid
    1476       57956 : OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
    1477             : {
    1478             :     char       *schemaname;
    1479             :     char       *opername;
    1480             :     CatCList   *catlist;
    1481             :     ListCell   *l;
    1482             : 
    1483             :     /* deconstruct the name list */
    1484       57956 :     DeconstructQualifiedName(names, &schemaname, &opername);
    1485             : 
    1486       57956 :     if (schemaname)
    1487             :     {
    1488             :         /* search only in exact schema given */
    1489             :         Oid         namespaceId;
    1490             : 
    1491        1170 :         namespaceId = LookupExplicitNamespace(schemaname, true);
    1492        1170 :         if (OidIsValid(namespaceId))
    1493             :         {
    1494             :             HeapTuple   opertup;
    1495             : 
    1496        1158 :             opertup = SearchSysCache4(OPERNAMENSP,
    1497             :                                       CStringGetDatum(opername),
    1498             :                                       ObjectIdGetDatum(oprleft),
    1499             :                                       ObjectIdGetDatum(oprright),
    1500             :                                       ObjectIdGetDatum(namespaceId));
    1501        1158 :             if (HeapTupleIsValid(opertup))
    1502             :             {
    1503         696 :                 Form_pg_operator operclass = (Form_pg_operator) GETSTRUCT(opertup);
    1504         696 :                 Oid         result = operclass->oid;
    1505             : 
    1506         696 :                 ReleaseSysCache(opertup);
    1507         696 :                 return result;
    1508             :             }
    1509             :         }
    1510             : 
    1511         474 :         return InvalidOid;
    1512             :     }
    1513             : 
    1514             :     /* Search syscache by name and argument types */
    1515       56786 :     catlist = SearchSysCacheList3(OPERNAMENSP,
    1516             :                                   CStringGetDatum(opername),
    1517             :                                   ObjectIdGetDatum(oprleft),
    1518             :                                   ObjectIdGetDatum(oprright));
    1519             : 
    1520       56786 :     if (catlist->n_members == 0)
    1521             :     {
    1522             :         /* no hope, fall out early */
    1523       15054 :         ReleaseSysCacheList(catlist);
    1524       15054 :         return InvalidOid;
    1525             :     }
    1526             : 
    1527             :     /*
    1528             :      * We have to find the list member that is first in the search path, if
    1529             :      * there's more than one.  This doubly-nested loop looks ugly, but in
    1530             :      * practice there should usually be few catlist members.
    1531             :      */
    1532       41732 :     recomputeNamespacePath();
    1533             : 
    1534       58288 :     foreach(l, activeSearchPath)
    1535             :     {
    1536       58270 :         Oid         namespaceId = lfirst_oid(l);
    1537             :         int         i;
    1538             : 
    1539       58270 :         if (namespaceId == myTempNamespace)
    1540       13106 :             continue;           /* do not look in temp namespace */
    1541             : 
    1542       48638 :         for (i = 0; i < catlist->n_members; i++)
    1543             :         {
    1544       45188 :             HeapTuple   opertup = &catlist->members[i]->tuple;
    1545       45188 :             Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
    1546             : 
    1547       45188 :             if (operform->oprnamespace == namespaceId)
    1548             :             {
    1549       41714 :                 Oid         result = operform->oid;
    1550             : 
    1551       41714 :                 ReleaseSysCacheList(catlist);
    1552       41714 :                 return result;
    1553             :             }
    1554             :         }
    1555             :     }
    1556             : 
    1557          18 :     ReleaseSysCacheList(catlist);
    1558          18 :     return InvalidOid;
    1559             : }
    1560             : 
    1561             : /*
    1562             :  * OpernameGetCandidates
    1563             :  *      Given a possibly-qualified operator name and operator kind,
    1564             :  *      retrieve a list of the possible matches.
    1565             :  *
    1566             :  * If oprkind is '\0', we return all operators matching the given name,
    1567             :  * regardless of arguments.
    1568             :  *
    1569             :  * We search a single namespace if the operator name is qualified, else
    1570             :  * all namespaces in the search path.  The return list will never contain
    1571             :  * multiple entries with identical argument lists --- in the multiple-
    1572             :  * namespace case, we arrange for entries in earlier namespaces to mask
    1573             :  * identical entries in later namespaces.
    1574             :  *
    1575             :  * The returned items always have two args[] entries --- one or the other
    1576             :  * will be InvalidOid for a prefix or postfix oprkind.  nargs is 2, too.
    1577             :  */
    1578             : FuncCandidateList
    1579       14214 : OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)
    1580             : {
    1581       14214 :     FuncCandidateList resultList = NULL;
    1582       14214 :     char       *resultSpace = NULL;
    1583       14214 :     int         nextResult = 0;
    1584             :     char       *schemaname;
    1585             :     char       *opername;
    1586             :     Oid         namespaceId;
    1587             :     CatCList   *catlist;
    1588             :     int         i;
    1589             : 
    1590             :     /* deconstruct the name list */
    1591       14214 :     DeconstructQualifiedName(names, &schemaname, &opername);
    1592             : 
    1593       14214 :     if (schemaname)
    1594             :     {
    1595             :         /* use exact schema given */
    1596         468 :         namespaceId = LookupExplicitNamespace(schemaname, missing_schema_ok);
    1597         464 :         if (missing_schema_ok && !OidIsValid(namespaceId))
    1598           4 :             return NULL;
    1599             :     }
    1600             :     else
    1601             :     {
    1602             :         /* flag to indicate we need namespace search */
    1603       13746 :         namespaceId = InvalidOid;
    1604       13746 :         recomputeNamespacePath();
    1605             :     }
    1606             : 
    1607             :     /* Search syscache by name only */
    1608       14206 :     catlist = SearchSysCacheList1(OPERNAMENSP, CStringGetDatum(opername));
    1609             : 
    1610             :     /*
    1611             :      * In typical scenarios, most if not all of the operators found by the
    1612             :      * catcache search will end up getting returned; and there can be quite a
    1613             :      * few, for common operator names such as '=' or '+'.  To reduce the time
    1614             :      * spent in palloc, we allocate the result space as an array large enough
    1615             :      * to hold all the operators.  The original coding of this routine did a
    1616             :      * separate palloc for each operator, but profiling revealed that the
    1617             :      * pallocs used an unreasonably large fraction of parsing time.
    1618             :      */
    1619             : #define SPACE_PER_OP MAXALIGN(offsetof(struct _FuncCandidateList, args) + \
    1620             :                               2 * sizeof(Oid))
    1621             : 
    1622       14206 :     if (catlist->n_members > 0)
    1623       14198 :         resultSpace = palloc(catlist->n_members * SPACE_PER_OP);
    1624             : 
    1625      635688 :     for (i = 0; i < catlist->n_members; i++)
    1626             :     {
    1627      621482 :         HeapTuple   opertup = &catlist->members[i]->tuple;
    1628      621482 :         Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
    1629      621482 :         int         pathpos = 0;
    1630             :         FuncCandidateList newResult;
    1631             : 
    1632             :         /* Ignore operators of wrong kind, if specific kind requested */
    1633      621482 :         if (oprkind && operform->oprkind != oprkind)
    1634        5910 :             continue;
    1635             : 
    1636      615572 :         if (OidIsValid(namespaceId))
    1637             :         {
    1638             :             /* Consider only opers in specified namespace */
    1639       12080 :             if (operform->oprnamespace != namespaceId)
    1640          28 :                 continue;
    1641             :             /* No need to check args, they must all be different */
    1642             :         }
    1643             :         else
    1644             :         {
    1645             :             /*
    1646             :              * Consider only opers that are in the search path and are not in
    1647             :              * the temp namespace.
    1648             :              */
    1649             :             ListCell   *nsp;
    1650             : 
    1651      905376 :             foreach(nsp, activeSearchPath)
    1652             :             {
    1653     1508412 :                 if (operform->oprnamespace == lfirst_oid(nsp) &&
    1654      603264 :                     operform->oprnamespace != myTempNamespace)
    1655      603264 :                     break;
    1656      301884 :                 pathpos++;
    1657             :             }
    1658      603492 :             if (nsp == NULL)
    1659         228 :                 continue;       /* oper is not in search path */
    1660             : 
    1661             :             /*
    1662             :              * Okay, it's in the search path, but does it have the same
    1663             :              * arguments as something we already accepted?  If so, keep only
    1664             :              * the one that appears earlier in the search path.
    1665             :              *
    1666             :              * If we have an ordered list from SearchSysCacheList (the normal
    1667             :              * case), then any conflicting oper must immediately adjoin this
    1668             :              * one in the list, so we only need to look at the newest result
    1669             :              * item.  If we have an unordered list, we have to scan the whole
    1670             :              * result list.
    1671             :              */
    1672      603264 :             if (resultList)
    1673             :             {
    1674             :                 FuncCandidateList prevResult;
    1675             : 
    1676      589526 :                 if (catlist->ordered)
    1677             :                 {
    1678      758494 :                     if (operform->oprleft == resultList->args[0] &&
    1679      168968 :                         operform->oprright == resultList->args[1])
    1680           0 :                         prevResult = resultList;
    1681             :                     else
    1682      589526 :                         prevResult = NULL;
    1683             :                 }
    1684             :                 else
    1685             :                 {
    1686           0 :                     for (prevResult = resultList;
    1687             :                          prevResult;
    1688           0 :                          prevResult = prevResult->next)
    1689             :                     {
    1690           0 :                         if (operform->oprleft == prevResult->args[0] &&
    1691           0 :                             operform->oprright == prevResult->args[1])
    1692           0 :                             break;
    1693             :                     }
    1694             :                 }
    1695      589526 :                 if (prevResult)
    1696             :                 {
    1697             :                     /* We have a match with a previous result */
    1698             :                     Assert(pathpos != prevResult->pathpos);
    1699           0 :                     if (pathpos > prevResult->pathpos)
    1700           0 :                         continue;   /* keep previous result */
    1701             :                     /* replace previous result */
    1702           0 :                     prevResult->pathpos = pathpos;
    1703           0 :                     prevResult->oid = operform->oid;
    1704           0 :                     continue;   /* args are same, of course */
    1705             :                 }
    1706             :             }
    1707             :         }
    1708             : 
    1709             :         /*
    1710             :          * Okay to add it to result list
    1711             :          */
    1712      615316 :         newResult = (FuncCandidateList) (resultSpace + nextResult);
    1713      615316 :         nextResult += SPACE_PER_OP;
    1714             : 
    1715      615316 :         newResult->pathpos = pathpos;
    1716      615316 :         newResult->oid = operform->oid;
    1717      615316 :         newResult->nargs = 2;
    1718      615316 :         newResult->nvargs = 0;
    1719      615316 :         newResult->ndargs = 0;
    1720      615316 :         newResult->argnumbers = NULL;
    1721      615316 :         newResult->args[0] = operform->oprleft;
    1722      615316 :         newResult->args[1] = operform->oprright;
    1723      615316 :         newResult->next = resultList;
    1724      615316 :         resultList = newResult;
    1725             :     }
    1726             : 
    1727       14206 :     ReleaseSysCacheList(catlist);
    1728             : 
    1729       14206 :     return resultList;
    1730             : }
    1731             : 
    1732             : /*
    1733             :  * OperatorIsVisible
    1734             :  *      Determine whether an operator (identified by OID) is visible in the
    1735             :  *      current search path.  Visible means "would be found by searching
    1736             :  *      for the unqualified operator name with exact argument matches".
    1737             :  */
    1738             : bool
    1739        3576 : OperatorIsVisible(Oid oprid)
    1740             : {
    1741             :     HeapTuple   oprtup;
    1742             :     Form_pg_operator oprform;
    1743             :     Oid         oprnamespace;
    1744             :     bool        visible;
    1745             : 
    1746        3576 :     oprtup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid));
    1747        3576 :     if (!HeapTupleIsValid(oprtup))
    1748           0 :         elog(ERROR, "cache lookup failed for operator %u", oprid);
    1749        3576 :     oprform = (Form_pg_operator) GETSTRUCT(oprtup);
    1750             : 
    1751        3576 :     recomputeNamespacePath();
    1752             : 
    1753             :     /*
    1754             :      * Quick check: if it ain't in the path at all, it ain't visible. Items in
    1755             :      * the system namespace are surely in the path and so we needn't even do
    1756             :      * list_member_oid() for them.
    1757             :      */
    1758        3576 :     oprnamespace = oprform->oprnamespace;
    1759        4920 :     if (oprnamespace != PG_CATALOG_NAMESPACE &&
    1760        1344 :         !list_member_oid(activeSearchPath, oprnamespace))
    1761         242 :         visible = false;
    1762             :     else
    1763             :     {
    1764             :         /*
    1765             :          * If it is in the path, it might still not be visible; it could be
    1766             :          * hidden by another operator of the same name and arguments earlier
    1767             :          * in the path.  So we must do a slow check to see if this is the same
    1768             :          * operator that would be found by OpernameGetOprid.
    1769             :          */
    1770        3334 :         char       *oprname = NameStr(oprform->oprname);
    1771             : 
    1772        3334 :         visible = (OpernameGetOprid(list_make1(makeString(oprname)),
    1773             :                                     oprform->oprleft, oprform->oprright)
    1774             :                    == oprid);
    1775             :     }
    1776             : 
    1777        3576 :     ReleaseSysCache(oprtup);
    1778             : 
    1779        3576 :     return visible;
    1780             : }
    1781             : 
    1782             : 
    1783             : /*
    1784             :  * OpclassnameGetOpcid
    1785             :  *      Try to resolve an unqualified index opclass name.
    1786             :  *      Returns OID if opclass found in search path, else InvalidOid.
    1787             :  *
    1788             :  * This is essentially the same as TypenameGetTypid, but we have to have
    1789             :  * an extra argument for the index AM OID.
    1790             :  */
    1791             : Oid
    1792       63076 : OpclassnameGetOpcid(Oid amid, const char *opcname)
    1793             : {
    1794             :     Oid         opcid;
    1795             :     ListCell   *l;
    1796             : 
    1797       63076 :     recomputeNamespacePath();
    1798             : 
    1799       63450 :     foreach(l, activeSearchPath)
    1800             :     {
    1801       63434 :         Oid         namespaceId = lfirst_oid(l);
    1802             : 
    1803       63434 :         if (namespaceId == myTempNamespace)
    1804          98 :             continue;           /* do not look in temp namespace */
    1805             : 
    1806       63336 :         opcid = GetSysCacheOid3(CLAAMNAMENSP, Anum_pg_opclass_oid,
    1807             :                                 ObjectIdGetDatum(amid),
    1808             :                                 PointerGetDatum(opcname),
    1809             :                                 ObjectIdGetDatum(namespaceId));
    1810       63336 :         if (OidIsValid(opcid))
    1811       63060 :             return opcid;
    1812             :     }
    1813             : 
    1814             :     /* Not found in path */
    1815          16 :     return InvalidOid;
    1816             : }
    1817             : 
    1818             : /*
    1819             :  * OpclassIsVisible
    1820             :  *      Determine whether an opclass (identified by OID) is visible in the
    1821             :  *      current search path.  Visible means "would be found by searching
    1822             :  *      for the unqualified opclass name".
    1823             :  */
    1824             : bool
    1825         168 : OpclassIsVisible(Oid opcid)
    1826             : {
    1827             :     HeapTuple   opctup;
    1828             :     Form_pg_opclass opcform;
    1829             :     Oid         opcnamespace;
    1830             :     bool        visible;
    1831             : 
    1832         168 :     opctup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcid));
    1833         168 :     if (!HeapTupleIsValid(opctup))
    1834           0 :         elog(ERROR, "cache lookup failed for opclass %u", opcid);
    1835         168 :     opcform = (Form_pg_opclass) GETSTRUCT(opctup);
    1836             : 
    1837         168 :     recomputeNamespacePath();
    1838             : 
    1839             :     /*
    1840             :      * Quick check: if it ain't in the path at all, it ain't visible. Items in
    1841             :      * the system namespace are surely in the path and so we needn't even do
    1842             :      * list_member_oid() for them.
    1843             :      */
    1844         168 :     opcnamespace = opcform->opcnamespace;
    1845         280 :     if (opcnamespace != PG_CATALOG_NAMESPACE &&
    1846         112 :         !list_member_oid(activeSearchPath, opcnamespace))
    1847          20 :         visible = false;
    1848             :     else
    1849             :     {
    1850             :         /*
    1851             :          * If it is in the path, it might still not be visible; it could be
    1852             :          * hidden by another opclass of the same name earlier in the path. So
    1853             :          * we must do a slow check to see if this opclass would be found by
    1854             :          * OpclassnameGetOpcid.
    1855             :          */
    1856         148 :         char       *opcname = NameStr(opcform->opcname);
    1857             : 
    1858         148 :         visible = (OpclassnameGetOpcid(opcform->opcmethod, opcname) == opcid);
    1859             :     }
    1860             : 
    1861         168 :     ReleaseSysCache(opctup);
    1862             : 
    1863         168 :     return visible;
    1864             : }
    1865             : 
    1866             : /*
    1867             :  * OpfamilynameGetOpfid
    1868             :  *      Try to resolve an unqualified index opfamily name.
    1869             :  *      Returns OID if opfamily found in search path, else InvalidOid.
    1870             :  *
    1871             :  * This is essentially the same as TypenameGetTypid, but we have to have
    1872             :  * an extra argument for the index AM OID.
    1873             :  */
    1874             : Oid
    1875        1566 : OpfamilynameGetOpfid(Oid amid, const char *opfname)
    1876             : {
    1877             :     Oid         opfid;
    1878             :     ListCell   *l;
    1879             : 
    1880        1566 :     recomputeNamespacePath();
    1881             : 
    1882        3082 :     foreach(l, activeSearchPath)
    1883             :     {
    1884        3074 :         Oid         namespaceId = lfirst_oid(l);
    1885             : 
    1886        3074 :         if (namespaceId == myTempNamespace)
    1887          48 :             continue;           /* do not look in temp namespace */
    1888             : 
    1889        3026 :         opfid = GetSysCacheOid3(OPFAMILYAMNAMENSP, Anum_pg_opfamily_oid,
    1890             :                                 ObjectIdGetDatum(amid),
    1891             :                                 PointerGetDatum(opfname),
    1892             :                                 ObjectIdGetDatum(namespaceId));
    1893        3026 :         if (OidIsValid(opfid))
    1894        1558 :             return opfid;
    1895             :     }
    1896             : 
    1897             :     /* Not found in path */
    1898           8 :     return InvalidOid;
    1899             : }
    1900             : 
    1901             : /*
    1902             :  * OpfamilyIsVisible
    1903             :  *      Determine whether an opfamily (identified by OID) is visible in the
    1904             :  *      current search path.  Visible means "would be found by searching
    1905             :  *      for the unqualified opfamily name".
    1906             :  */
    1907             : bool
    1908        1234 : OpfamilyIsVisible(Oid opfid)
    1909             : {
    1910             :     HeapTuple   opftup;
    1911             :     Form_pg_opfamily opfform;
    1912             :     Oid         opfnamespace;
    1913             :     bool        visible;
    1914             : 
    1915        1234 :     opftup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
    1916        1234 :     if (!HeapTupleIsValid(opftup))
    1917           0 :         elog(ERROR, "cache lookup failed for opfamily %u", opfid);
    1918        1234 :     opfform = (Form_pg_opfamily) GETSTRUCT(opftup);
    1919             : 
    1920        1234 :     recomputeNamespacePath();
    1921             : 
    1922             :     /*
    1923             :      * Quick check: if it ain't in the path at all, it ain't visible. Items in
    1924             :      * the system namespace are surely in the path and so we needn't even do
    1925             :      * list_member_oid() for them.
    1926             :      */
    1927        1234 :     opfnamespace = opfform->opfnamespace;
    1928        2452 :     if (opfnamespace != PG_CATALOG_NAMESPACE &&
    1929        1218 :         !list_member_oid(activeSearchPath, opfnamespace))
    1930         156 :         visible = false;
    1931             :     else
    1932             :     {
    1933             :         /*
    1934             :          * If it is in the path, it might still not be visible; it could be
    1935             :          * hidden by another opfamily of the same name earlier in the path. So
    1936             :          * we must do a slow check to see if this opfamily would be found by
    1937             :          * OpfamilynameGetOpfid.
    1938             :          */
    1939        1078 :         char       *opfname = NameStr(opfform->opfname);
    1940             : 
    1941        1078 :         visible = (OpfamilynameGetOpfid(opfform->opfmethod, opfname) == opfid);
    1942             :     }
    1943             : 
    1944        1234 :     ReleaseSysCache(opftup);
    1945             : 
    1946        1234 :     return visible;
    1947             : }
    1948             : 
    1949             : /*
    1950             :  * lookup_collation
    1951             :  *      If there's a collation of the given name/namespace, and it works
    1952             :  *      with the given encoding, return its OID.  Else return InvalidOid.
    1953             :  */
    1954             : static Oid
    1955        3840 : lookup_collation(const char *collname, Oid collnamespace, int32 encoding)
    1956             : {
    1957             :     Oid         collid;
    1958             :     HeapTuple   colltup;
    1959             :     Form_pg_collation collform;
    1960             : 
    1961             :     /* Check for encoding-specific entry (exact match) */
    1962        3840 :     collid = GetSysCacheOid3(COLLNAMEENCNSP, Anum_pg_collation_oid,
    1963             :                              PointerGetDatum(collname),
    1964             :                              Int32GetDatum(encoding),
    1965             :                              ObjectIdGetDatum(collnamespace));
    1966        3840 :     if (OidIsValid(collid))
    1967          24 :         return collid;
    1968             : 
    1969             :     /*
    1970             :      * Check for any-encoding entry.  This takes a bit more work: while libc
    1971             :      * collations with collencoding = -1 do work with all encodings, ICU
    1972             :      * collations only work with certain encodings, so we have to check that
    1973             :      * aspect before deciding it's a match.
    1974             :      */
    1975        3816 :     colltup = SearchSysCache3(COLLNAMEENCNSP,
    1976             :                               PointerGetDatum(collname),
    1977             :                               Int32GetDatum(-1),
    1978             :                               ObjectIdGetDatum(collnamespace));
    1979        3816 :     if (!HeapTupleIsValid(colltup))
    1980          40 :         return InvalidOid;
    1981        3776 :     collform = (Form_pg_collation) GETSTRUCT(colltup);
    1982        3776 :     if (collform->collprovider == COLLPROVIDER_ICU)
    1983             :     {
    1984           0 :         if (is_encoding_supported_by_icu(encoding))
    1985           0 :             collid = collform->oid;
    1986             :         else
    1987           0 :             collid = InvalidOid;
    1988             :     }
    1989             :     else
    1990             :     {
    1991        3776 :         collid = collform->oid;
    1992             :     }
    1993        3776 :     ReleaseSysCache(colltup);
    1994        3776 :     return collid;
    1995             : }
    1996             : 
    1997             : /*
    1998             :  * CollationGetCollid
    1999             :  *      Try to resolve an unqualified collation name.
    2000             :  *      Returns OID if collation found in search path, else InvalidOid.
    2001             :  *
    2002             :  * Note that this will only find collations that work with the current
    2003             :  * database's encoding.
    2004             :  */
    2005             : Oid
    2006         172 : CollationGetCollid(const char *collname)
    2007             : {
    2008         172 :     int32       dbencoding = GetDatabaseEncoding();
    2009             :     ListCell   *l;
    2010             : 
    2011         172 :     recomputeNamespacePath();
    2012             : 
    2013         252 :     foreach(l, activeSearchPath)
    2014             :     {
    2015         252 :         Oid         namespaceId = lfirst_oid(l);
    2016             :         Oid         collid;
    2017             : 
    2018         252 :         if (namespaceId == myTempNamespace)
    2019          68 :             continue;           /* do not look in temp namespace */
    2020             : 
    2021         184 :         collid = lookup_collation(collname, namespaceId, dbencoding);
    2022         184 :         if (OidIsValid(collid))
    2023         172 :             return collid;
    2024             :     }
    2025             : 
    2026             :     /* Not found in path */
    2027           0 :     return InvalidOid;
    2028             : }
    2029             : 
    2030             : /*
    2031             :  * CollationIsVisible
    2032             :  *      Determine whether a collation (identified by OID) is visible in the
    2033             :  *      current search path.  Visible means "would be found by searching
    2034             :  *      for the unqualified collation name".
    2035             :  *
    2036             :  * Note that only collations that work with the current database's encoding
    2037             :  * will be considered visible.
    2038             :  */
    2039             : bool
    2040         172 : CollationIsVisible(Oid collid)
    2041             : {
    2042             :     HeapTuple   colltup;
    2043             :     Form_pg_collation collform;
    2044             :     Oid         collnamespace;
    2045             :     bool        visible;
    2046             : 
    2047         172 :     colltup = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
    2048         172 :     if (!HeapTupleIsValid(colltup))
    2049           0 :         elog(ERROR, "cache lookup failed for collation %u", collid);
    2050         172 :     collform = (Form_pg_collation) GETSTRUCT(colltup);
    2051             : 
    2052         172 :     recomputeNamespacePath();
    2053             : 
    2054             :     /*
    2055             :      * Quick check: if it ain't in the path at all, it ain't visible. Items in
    2056             :      * the system namespace are surely in the path and so we needn't even do
    2057             :      * list_member_oid() for them.
    2058             :      */
    2059         172 :     collnamespace = collform->collnamespace;
    2060         184 :     if (collnamespace != PG_CATALOG_NAMESPACE &&
    2061          12 :         !list_member_oid(activeSearchPath, collnamespace))
    2062           0 :         visible = false;
    2063             :     else
    2064             :     {
    2065             :         /*
    2066             :          * If it is in the path, it might still not be visible; it could be
    2067             :          * hidden by another collation of the same name earlier in the path,
    2068             :          * or it might not work with the current DB encoding.  So we must do a
    2069             :          * slow check to see if this collation would be found by
    2070             :          * CollationGetCollid.
    2071             :          */
    2072         172 :         char       *collname = NameStr(collform->collname);
    2073             : 
    2074         172 :         visible = (CollationGetCollid(collname) == collid);
    2075             :     }
    2076             : 
    2077         172 :     ReleaseSysCache(colltup);
    2078             : 
    2079         172 :     return visible;
    2080             : }
    2081             : 
    2082             : 
    2083             : /*
    2084             :  * ConversionGetConid
    2085             :  *      Try to resolve an unqualified conversion name.
    2086             :  *      Returns OID if conversion found in search path, else InvalidOid.
    2087             :  *
    2088             :  * This is essentially the same as RelnameGetRelid.
    2089             :  */
    2090             : Oid
    2091          12 : ConversionGetConid(const char *conname)
    2092             : {
    2093             :     Oid         conid;
    2094             :     ListCell   *l;
    2095             : 
    2096          12 :     recomputeNamespacePath();
    2097             : 
    2098          24 :     foreach(l, activeSearchPath)
    2099             :     {
    2100          24 :         Oid         namespaceId = lfirst_oid(l);
    2101             : 
    2102          24 :         if (namespaceId == myTempNamespace)
    2103           0 :             continue;           /* do not look in temp namespace */
    2104             : 
    2105          24 :         conid = GetSysCacheOid2(CONNAMENSP, Anum_pg_conversion_oid,
    2106             :                                 PointerGetDatum(conname),
    2107             :                                 ObjectIdGetDatum(namespaceId));
    2108          24 :         if (OidIsValid(conid))
    2109          12 :             return conid;
    2110             :     }
    2111             : 
    2112             :     /* Not found in path */
    2113           0 :     return InvalidOid;
    2114             : }
    2115             : 
    2116             : /*
    2117             :  * ConversionIsVisible
    2118             :  *      Determine whether a conversion (identified by OID) is visible in the
    2119             :  *      current search path.  Visible means "would be found by searching
    2120             :  *      for the unqualified conversion name".
    2121             :  */
    2122             : bool
    2123          20 : ConversionIsVisible(Oid conid)
    2124             : {
    2125             :     HeapTuple   contup;
    2126             :     Form_pg_conversion conform;
    2127             :     Oid         connamespace;
    2128             :     bool        visible;
    2129             : 
    2130          20 :     contup = SearchSysCache1(CONVOID, ObjectIdGetDatum(conid));
    2131          20 :     if (!HeapTupleIsValid(contup))
    2132           0 :         elog(ERROR, "cache lookup failed for conversion %u", conid);
    2133          20 :     conform = (Form_pg_conversion) GETSTRUCT(contup);
    2134             : 
    2135          20 :     recomputeNamespacePath();
    2136             : 
    2137             :     /*
    2138             :      * Quick check: if it ain't in the path at all, it ain't visible. Items in
    2139             :      * the system namespace are surely in the path and so we needn't even do
    2140             :      * list_member_oid() for them.
    2141             :      */
    2142          20 :     connamespace = conform->connamespace;
    2143          40 :     if (connamespace != PG_CATALOG_NAMESPACE &&
    2144          20 :         !list_member_oid(activeSearchPath, connamespace))
    2145           8 :         visible = false;
    2146             :     else
    2147             :     {
    2148             :         /*
    2149             :          * If it is in the path, it might still not be visible; it could be
    2150             :          * hidden by another conversion of the same name earlier in the path.
    2151             :          * So we must do a slow check to see if this conversion would be found
    2152             :          * by ConversionGetConid.
    2153             :          */
    2154          12 :         char       *conname = NameStr(conform->conname);
    2155             : 
    2156          12 :         visible = (ConversionGetConid(conname) == conid);
    2157             :     }
    2158             : 
    2159          20 :     ReleaseSysCache(contup);
    2160             : 
    2161          20 :     return visible;
    2162             : }
    2163             : 
    2164             : /*
    2165             :  * get_statistics_object_oid - find a statistics object by possibly qualified name
    2166             :  *
    2167             :  * If not found, returns InvalidOid if missing_ok, else throws error
    2168             :  */
    2169             : Oid
    2170         110 : get_statistics_object_oid(List *names, bool missing_ok)
    2171             : {
    2172             :     char       *schemaname;
    2173             :     char       *stats_name;
    2174             :     Oid         namespaceId;
    2175         110 :     Oid         stats_oid = InvalidOid;
    2176             :     ListCell   *l;
    2177             : 
    2178             :     /* deconstruct the name list */
    2179         110 :     DeconstructQualifiedName(names, &schemaname, &stats_name);
    2180             : 
    2181         110 :     if (schemaname)
    2182             :     {
    2183             :         /* use exact schema given */
    2184          22 :         namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
    2185          22 :         if (missing_ok && !OidIsValid(namespaceId))
    2186           0 :             stats_oid = InvalidOid;
    2187             :         else
    2188          22 :             stats_oid = GetSysCacheOid2(STATEXTNAMENSP, Anum_pg_statistic_ext_oid,
    2189             :                                         PointerGetDatum(stats_name),
    2190             :                                         ObjectIdGetDatum(namespaceId));
    2191             :     }
    2192             :     else
    2193             :     {
    2194             :         /* search for it in search path */
    2195          88 :         recomputeNamespacePath();
    2196             : 
    2197         184 :         foreach(l, activeSearchPath)
    2198             :         {
    2199         176 :             namespaceId = lfirst_oid(l);
    2200             : 
    2201         176 :             if (namespaceId == myTempNamespace)
    2202           0 :                 continue;       /* do not look in temp namespace */
    2203         176 :             stats_oid = GetSysCacheOid2(STATEXTNAMENSP, Anum_pg_statistic_ext_oid,
    2204             :                                         PointerGetDatum(stats_name),
    2205             :                                         ObjectIdGetDatum(namespaceId));
    2206         176 :             if (OidIsValid(stats_oid))
    2207          80 :                 break;
    2208             :         }
    2209             :     }
    2210             : 
    2211         110 :     if (!OidIsValid(stats_oid) && !missing_ok)
    2212           4 :         ereport(ERROR,
    2213             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2214             :                  errmsg("statistics object \"%s\" does not exist",
    2215             :                         NameListToString(names))));
    2216             : 
    2217         106 :     return stats_oid;
    2218             : }
    2219             : 
    2220             : /*
    2221             :  * StatisticsObjIsVisible
    2222             :  *      Determine whether a statistics object (identified by OID) is visible in
    2223             :  *      the current search path.  Visible means "would be found by searching
    2224             :  *      for the unqualified statistics object name".
    2225             :  */
    2226             : bool
    2227          72 : StatisticsObjIsVisible(Oid relid)
    2228             : {
    2229             :     HeapTuple   stxtup;
    2230             :     Form_pg_statistic_ext stxform;
    2231             :     Oid         stxnamespace;
    2232             :     bool        visible;
    2233             : 
    2234          72 :     stxtup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(relid));
    2235          72 :     if (!HeapTupleIsValid(stxtup))
    2236           0 :         elog(ERROR, "cache lookup failed for statistics object %u", relid);
    2237          72 :     stxform = (Form_pg_statistic_ext) GETSTRUCT(stxtup);
    2238             : 
    2239          72 :     recomputeNamespacePath();
    2240             : 
    2241             :     /*
    2242             :      * Quick check: if it ain't in the path at all, it ain't visible. Items in
    2243             :      * the system namespace are surely in the path and so we needn't even do
    2244             :      * list_member_oid() for them.
    2245             :      */
    2246          72 :     stxnamespace = stxform->stxnamespace;
    2247         144 :     if (stxnamespace != PG_CATALOG_NAMESPACE &&
    2248          72 :         !list_member_oid(activeSearchPath, stxnamespace))
    2249          28 :         visible = false;
    2250             :     else
    2251             :     {
    2252             :         /*
    2253             :          * If it is in the path, it might still not be visible; it could be
    2254             :          * hidden by another statistics object of the same name earlier in the
    2255             :          * path. So we must do a slow check for conflicting objects.
    2256             :          */
    2257          44 :         char       *stxname = NameStr(stxform->stxname);
    2258             :         ListCell   *l;
    2259             : 
    2260          44 :         visible = false;
    2261          88 :         foreach(l, activeSearchPath)
    2262             :         {
    2263          88 :             Oid         namespaceId = lfirst_oid(l);
    2264             : 
    2265          88 :             if (namespaceId == stxnamespace)
    2266             :             {
    2267             :                 /* Found it first in path */
    2268          44 :                 visible = true;
    2269          44 :                 break;
    2270             :             }
    2271          44 :             if (SearchSysCacheExists2(STATEXTNAMENSP,
    2272             :                                       PointerGetDatum(stxname),
    2273             :                                       ObjectIdGetDatum(namespaceId)))
    2274             :             {
    2275             :                 /* Found something else first in path */
    2276           0 :                 break;
    2277             :             }
    2278             :         }
    2279             :     }
    2280             : 
    2281          72 :     ReleaseSysCache(stxtup);
    2282             : 
    2283          72 :     return visible;
    2284             : }
    2285             : 
    2286             : /*
    2287             :  * get_ts_parser_oid - find a TS parser by possibly qualified name
    2288             :  *
    2289             :  * If not found, returns InvalidOid if missing_ok, else throws error
    2290             :  */
    2291             : Oid
    2292        7174 : get_ts_parser_oid(List *names, bool missing_ok)
    2293             : {
    2294             :     char       *schemaname;
    2295             :     char       *parser_name;
    2296             :     Oid         namespaceId;
    2297        7174 :     Oid         prsoid = InvalidOid;
    2298             :     ListCell   *l;
    2299             : 
    2300             :     /* deconstruct the name list */
    2301        7174 :     DeconstructQualifiedName(names, &schemaname, &parser_name);
    2302             : 
    2303        7166 :     if (schemaname)
    2304             :     {
    2305             :         /* use exact schema given */
    2306          34 :         namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
    2307          34 :         if (missing_ok && !OidIsValid(namespaceId))
    2308           4 :             prsoid = InvalidOid;
    2309             :         else
    2310          30 :             prsoid = GetSysCacheOid2(TSPARSERNAMENSP, Anum_pg_ts_parser_oid,
    2311             :                                      PointerGetDatum(parser_name),
    2312             :                                      ObjectIdGetDatum(namespaceId));
    2313             :     }
    2314             :     else
    2315             :     {
    2316             :         /* search for it in search path */
    2317        7132 :         recomputeNamespacePath();
    2318             : 
    2319       14272 :         foreach(l, activeSearchPath)
    2320             :         {
    2321       14256 :             namespaceId = lfirst_oid(l);
    2322             : 
    2323       14256 :             if (namespaceId == myTempNamespace)
    2324        7084 :                 continue;       /* do not look in temp namespace */
    2325             : 
    2326        7172 :             prsoid = GetSysCacheOid2(TSPARSERNAMENSP, Anum_pg_ts_parser_oid,
    2327             :                                      PointerGetDatum(parser_name),
    2328             :                                      ObjectIdGetDatum(namespaceId));
    2329        7172 :             if (OidIsValid(prsoid))
    2330        7116 :                 break;
    2331             :         }
    2332             :     }
    2333             : 
    2334        7166 :     if (!OidIsValid(prsoid) && !missing_ok)
    2335          20 :         ereport(ERROR,
    2336             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2337             :                  errmsg("text search parser \"%s\" does not exist",
    2338             :                         NameListToString(names))));
    2339             : 
    2340        7146 :     return prsoid;
    2341             : }
    2342             : 
    2343             : /*
    2344             :  * TSParserIsVisible
    2345             :  *      Determine whether a parser (identified by OID) is visible in the
    2346             :  *      current search path.  Visible means "would be found by searching
    2347             :  *      for the unqualified parser name".
    2348             :  */
    2349             : bool
    2350          20 : TSParserIsVisible(Oid prsId)
    2351             : {
    2352             :     HeapTuple   tup;
    2353             :     Form_pg_ts_parser form;
    2354             :     Oid         namespace;
    2355             :     bool        visible;
    2356             : 
    2357          20 :     tup = SearchSysCache1(TSPARSEROID, ObjectIdGetDatum(prsId));
    2358          20 :     if (!HeapTupleIsValid(tup))
    2359           0 :         elog(ERROR, "cache lookup failed for text search parser %u", prsId);
    2360          20 :     form = (Form_pg_ts_parser) GETSTRUCT(tup);
    2361             : 
    2362          20 :     recomputeNamespacePath();
    2363             : 
    2364             :     /*
    2365             :      * Quick check: if it ain't in the path at all, it ain't visible. Items in
    2366             :      * the system namespace are surely in the path and so we needn't even do
    2367             :      * list_member_oid() for them.
    2368             :      */
    2369          20 :     namespace = form->prsnamespace;
    2370          40 :     if (namespace != PG_CATALOG_NAMESPACE &&
    2371          20 :         !list_member_oid(activeSearchPath, namespace))
    2372           8 :         visible = false;
    2373             :     else
    2374             :     {
    2375             :         /*
    2376             :          * If it is in the path, it might still not be visible; it could be
    2377             :          * hidden by another parser of the same name earlier in the path. So
    2378             :          * we must do a slow check for conflicting parsers.
    2379             :          */
    2380          12 :         char       *name = NameStr(form->prsname);
    2381             :         ListCell   *l;
    2382             : 
    2383          12 :         visible = false;
    2384          24 :         foreach(l, activeSearchPath)
    2385             :         {
    2386          24 :             Oid         namespaceId = lfirst_oid(l);
    2387             : 
    2388          24 :             if (namespaceId == myTempNamespace)
    2389           0 :                 continue;       /* do not look in temp namespace */
    2390             : 
    2391          24 :             if (namespaceId == namespace)
    2392             :             {
    2393             :                 /* Found it first in path */
    2394          12 :                 visible = true;
    2395          12 :                 break;
    2396             :             }
    2397          12 :             if (SearchSysCacheExists2(TSPARSERNAMENSP,
    2398             :                                       PointerGetDatum(name),
    2399             :                                       ObjectIdGetDatum(namespaceId)))
    2400             :             {
    2401             :                 /* Found something else first in path */
    2402           0 :                 break;
    2403             :             }
    2404             :         }
    2405             :     }
    2406             : 
    2407          20 :     ReleaseSysCache(tup);
    2408             : 
    2409          20 :     return visible;
    2410             : }
    2411             : 
    2412             : /*
    2413             :  * get_ts_dict_oid - find a TS dictionary by possibly qualified name
    2414             :  *
    2415             :  * If not found, returns InvalidOid if missing_ok, else throws error
    2416             :  */
    2417             : Oid
    2418       29188 : get_ts_dict_oid(List *names, bool missing_ok)
    2419             : {
    2420             :     char       *schemaname;
    2421             :     char       *dict_name;
    2422             :     Oid         namespaceId;
    2423       29188 :     Oid         dictoid = InvalidOid;
    2424             :     ListCell   *l;
    2425             : 
    2426             :     /* deconstruct the name list */
    2427       29188 :     DeconstructQualifiedName(names, &schemaname, &dict_name);
    2428             : 
    2429       29180 :     if (schemaname)
    2430             :     {
    2431             :         /* use exact schema given */
    2432          94 :         namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
    2433          94 :         if (missing_ok && !OidIsValid(namespaceId))
    2434           4 :             dictoid = InvalidOid;
    2435             :         else
    2436          90 :             dictoid = GetSysCacheOid2(TSDICTNAMENSP, Anum_pg_ts_dict_oid,
    2437             :                                       PointerGetDatum(dict_name),
    2438             :                                       ObjectIdGetDatum(namespaceId));
    2439             :     }
    2440             :     else
    2441             :     {
    2442             :         /* search for it in search path */
    2443       29086 :         recomputeNamespacePath();
    2444             : 
    2445       58002 :         foreach(l, activeSearchPath)
    2446             :         {
    2447       57986 :             namespaceId = lfirst_oid(l);
    2448             : 
    2449       57986 :             if (namespaceId == myTempNamespace)
    2450       28336 :                 continue;       /* do not look in temp namespace */
    2451             : 
    2452       29650 :             dictoid = GetSysCacheOid2(TSDICTNAMENSP, Anum_pg_ts_dict_oid,
    2453             :                                       PointerGetDatum(dict_name),
    2454             :                                       ObjectIdGetDatum(namespaceId));
    2455       29650 :             if (OidIsValid(dictoid))
    2456       29070 :                 break;
    2457             :         }
    2458             :     }
    2459             : 
    2460       29180 :     if (!OidIsValid(dictoid) && !missing_ok)
    2461          20 :         ereport(ERROR,
    2462             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2463             :                  errmsg("text search dictionary \"%s\" does not exist",
    2464             :                         NameListToString(names))));
    2465             : 
    2466       29160 :     return dictoid;
    2467             : }
    2468             : 
    2469             : /*
    2470             :  * TSDictionaryIsVisible
    2471             :  *      Determine whether a dictionary (identified by OID) is visible in the
    2472             :  *      current search path.  Visible means "would be found by searching
    2473             :  *      for the unqualified dictionary name".
    2474             :  */
    2475             : bool
    2476        1614 : TSDictionaryIsVisible(Oid dictId)
    2477             : {
    2478             :     HeapTuple   tup;
    2479             :     Form_pg_ts_dict form;
    2480             :     Oid         namespace;
    2481             :     bool        visible;
    2482             : 
    2483        1614 :     tup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));
    2484        1614 :     if (!HeapTupleIsValid(tup))
    2485           0 :         elog(ERROR, "cache lookup failed for text search dictionary %u",
    2486             :              dictId);
    2487        1614 :     form = (Form_pg_ts_dict) GETSTRUCT(tup);
    2488             : 
    2489        1614 :     recomputeNamespacePath();
    2490             : 
    2491             :     /*
    2492             :      * Quick check: if it ain't in the path at all, it ain't visible. Items in
    2493             :      * the system namespace are surely in the path and so we needn't even do
    2494             :      * list_member_oid() for them.
    2495             :      */
    2496        1614 :     namespace = form->dictnamespace;
    2497        1800 :     if (namespace != PG_CATALOG_NAMESPACE &&
    2498         186 :         !list_member_oid(activeSearchPath, namespace))
    2499         170 :         visible = false;
    2500             :     else
    2501             :     {
    2502             :         /*
    2503             :          * If it is in the path, it might still not be visible; it could be
    2504             :          * hidden by another dictionary of the same name earlier in the path.
    2505             :          * So we must do a slow check for conflicting dictionaries.
    2506             :          */
    2507        1444 :         char       *name = NameStr(form->dictname);
    2508             :         ListCell   *l;
    2509             : 
    2510        1444 :         visible = false;
    2511        1460 :         foreach(l, activeSearchPath)
    2512             :         {
    2513        1460 :             Oid         namespaceId = lfirst_oid(l);
    2514             : 
    2515        1460 :             if (namespaceId == myTempNamespace)
    2516           0 :                 continue;       /* do not look in temp namespace */
    2517             : 
    2518        1460 :             if (namespaceId == namespace)
    2519             :             {
    2520             :                 /* Found it first in path */
    2521        1444 :                 visible = true;
    2522        1444 :                 break;
    2523             :             }
    2524          16 :             if (SearchSysCacheExists2(TSDICTNAMENSP,
    2525             :                                       PointerGetDatum(name),
    2526             :                                       ObjectIdGetDatum(namespaceId)))
    2527             :             {
    2528             :                 /* Found something else first in path */
    2529           0 :                 break;
    2530             :             }
    2531             :         }
    2532             :     }
    2533             : 
    2534        1614 :     ReleaseSysCache(tup);
    2535             : 
    2536        1614 :     return visible;
    2537             : }
    2538             : 
    2539             : /*
    2540             :  * get_ts_template_oid - find a TS template by possibly qualified name
    2541             :  *
    2542             :  * If not found, returns InvalidOid if missing_ok, else throws error
    2543             :  */
    2544             : Oid
    2545        7578 : get_ts_template_oid(List *names, bool missing_ok)
    2546             : {
    2547             :     char       *schemaname;
    2548             :     char       *template_name;
    2549             :     Oid         namespaceId;
    2550        7578 :     Oid         tmploid = InvalidOid;
    2551             :     ListCell   *l;
    2552             : 
    2553             :     /* deconstruct the name list */
    2554        7578 :     DeconstructQualifiedName(names, &schemaname, &template_name);
    2555             : 
    2556        7570 :     if (schemaname)
    2557             :     {
    2558             :         /* use exact schema given */
    2559          44 :         namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
    2560          44 :         if (missing_ok && !OidIsValid(namespaceId))
    2561           4 :             tmploid = InvalidOid;
    2562             :         else
    2563          40 :             tmploid = GetSysCacheOid2(TSTEMPLATENAMENSP, Anum_pg_ts_template_oid,
    2564             :                                       PointerGetDatum(template_name),
    2565             :                                       ObjectIdGetDatum(namespaceId));
    2566             :     }
    2567             :     else
    2568             :     {
    2569             :         /* search for it in search path */
    2570        7526 :         recomputeNamespacePath();
    2571             : 
    2572       14990 :         foreach(l, activeSearchPath)
    2573             :         {
    2574       14974 :             namespaceId = lfirst_oid(l);
    2575             : 
    2576       14974 :             if (namespaceId == myTempNamespace)
    2577        7406 :                 continue;       /* do not look in temp namespace */
    2578             : 
    2579        7568 :             tmploid = GetSysCacheOid2(TSTEMPLATENAMENSP, Anum_pg_ts_template_oid,
    2580             :                                       PointerGetDatum(template_name),
    2581             :                                       ObjectIdGetDatum(namespaceId));
    2582        7568 :             if (OidIsValid(tmploid))
    2583        7510 :                 break;
    2584             :         }
    2585             :     }
    2586             : 
    2587        7570 :     if (!OidIsValid(tmploid) && !missing_ok)
    2588          20 :         ereport(ERROR,
    2589             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2590             :                  errmsg("text search template \"%s\" does not exist",
    2591             :                         NameListToString(names))));
    2592             : 
    2593        7550 :     return tmploid;
    2594             : }
    2595             : 
    2596             : /*
    2597             :  * TSTemplateIsVisible
    2598             :  *      Determine whether a template (identified by OID) is visible in the
    2599             :  *      current search path.  Visible means "would be found by searching
    2600             :  *      for the unqualified template name".
    2601             :  */
    2602             : bool
    2603          20 : TSTemplateIsVisible(Oid tmplId)
    2604             : {
    2605             :     HeapTuple   tup;
    2606             :     Form_pg_ts_template form;
    2607             :     Oid         namespace;
    2608             :     bool        visible;
    2609             : 
    2610          20 :     tup = SearchSysCache1(TSTEMPLATEOID, ObjectIdGetDatum(tmplId));
    2611          20 :     if (!HeapTupleIsValid(tup))
    2612           0 :         elog(ERROR, "cache lookup failed for text search template %u", tmplId);
    2613          20 :     form = (Form_pg_ts_template) GETSTRUCT(tup);
    2614             : 
    2615          20 :     recomputeNamespacePath();
    2616             : 
    2617             :     /*
    2618             :      * Quick check: if it ain't in the path at all, it ain't visible. Items in
    2619             :      * the system namespace are surely in the path and so we needn't even do
    2620             :      * list_member_oid() for them.
    2621             :      */
    2622          20 :     namespace = form->tmplnamespace;
    2623          40 :     if (namespace != PG_CATALOG_NAMESPACE &&
    2624          20 :         !list_member_oid(activeSearchPath, namespace))
    2625           8 :         visible = false;
    2626             :     else
    2627             :     {
    2628             :         /*
    2629             :          * If it is in the path, it might still not be visible; it could be
    2630             :          * hidden by another template of the same name earlier in the path. So
    2631             :          * we must do a slow check for conflicting templates.
    2632             :          */
    2633          12 :         char       *name = NameStr(form->tmplname);
    2634             :         ListCell   *l;
    2635             : 
    2636          12 :         visible = false;
    2637          24 :         foreach(l, activeSearchPath)
    2638             :         {
    2639          24 :             Oid         namespaceId = lfirst_oid(l);
    2640             : 
    2641          24 :             if (namespaceId == myTempNamespace)
    2642           0 :                 continue;       /* do not look in temp namespace */
    2643             : 
    2644          24 :             if (namespaceId == namespace)
    2645             :             {
    2646             :                 /* Found it first in path */
    2647          12 :                 visible = true;
    2648          12 :                 break;
    2649             :             }
    2650          12 :             if (SearchSysCacheExists2(TSTEMPLATENAMENSP,
    2651             :                                       PointerGetDatum(name),
    2652             :                                       ObjectIdGetDatum(namespaceId)))
    2653             :             {
    2654             :                 /* Found something else first in path */
    2655           0 :                 break;
    2656             :             }
    2657             :         }
    2658             :     }
    2659             : 
    2660          20 :     ReleaseSysCache(tup);
    2661             : 
    2662          20 :     return visible;
    2663             : }
    2664             : 
    2665             : /*
    2666             :  * get_ts_config_oid - find a TS config by possibly qualified name
    2667             :  *
    2668             :  * If not found, returns InvalidOid if missing_ok, else throws error
    2669             :  */
    2670             : Oid
    2671       32890 : get_ts_config_oid(List *names, bool missing_ok)
    2672             : {
    2673             :     char       *schemaname;
    2674             :     char       *config_name;
    2675             :     Oid         namespaceId;
    2676       32890 :     Oid         cfgoid = InvalidOid;
    2677             :     ListCell   *l;
    2678             : 
    2679             :     /* deconstruct the name list */
    2680       32890 :     DeconstructQualifiedName(names, &schemaname, &config_name);
    2681             : 
    2682       32882 :     if (schemaname)
    2683             :     {
    2684             :         /* use exact schema given */
    2685        3260 :         namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
    2686        3260 :         if (missing_ok && !OidIsValid(namespaceId))
    2687           4 :             cfgoid = InvalidOid;
    2688             :         else
    2689        3256 :             cfgoid = GetSysCacheOid2(TSCONFIGNAMENSP, Anum_pg_ts_config_oid,
    2690             :                                      PointerGetDatum(config_name),
    2691             :                                      ObjectIdGetDatum(namespaceId));
    2692             :     }
    2693             :     else
    2694             :     {
    2695             :         /* search for it in search path */
    2696       29622 :         recomputeNamespacePath();
    2697             : 
    2698       58664 :         foreach(l, activeSearchPath)
    2699             :         {
    2700       58630 :             namespaceId = lfirst_oid(l);
    2701             : 
    2702       58630 :             if (namespaceId == myTempNamespace)
    2703       28796 :                 continue;       /* do not look in temp namespace */
    2704             : 
    2705       29834 :             cfgoid = GetSysCacheOid2(TSCONFIGNAMENSP, Anum_pg_ts_config_oid,
    2706             :                                      PointerGetDatum(config_name),
    2707             :                                      ObjectIdGetDatum(namespaceId));
    2708       29834 :             if (OidIsValid(cfgoid))
    2709       29588 :                 break;
    2710             :         }
    2711             :     }
    2712             : 
    2713       32882 :     if (!OidIsValid(cfgoid) && !missing_ok)
    2714          20 :         ereport(ERROR,
    2715             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2716             :                  errmsg("text search configuration \"%s\" does not exist",
    2717             :                         NameListToString(names))));
    2718             : 
    2719       32862 :     return cfgoid;
    2720             : }
    2721             : 
    2722             : /*
    2723             :  * TSConfigIsVisible
    2724             :  *      Determine whether a text search configuration (identified by OID)
    2725             :  *      is visible in the current search path.  Visible means "would be found
    2726             :  *      by searching for the unqualified text search configuration name".
    2727             :  */
    2728             : bool
    2729          24 : TSConfigIsVisible(Oid cfgid)
    2730             : {
    2731             :     HeapTuple   tup;
    2732             :     Form_pg_ts_config form;
    2733             :     Oid         namespace;
    2734             :     bool        visible;
    2735             : 
    2736          24 :     tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid));
    2737          24 :     if (!HeapTupleIsValid(tup))
    2738           0 :         elog(ERROR, "cache lookup failed for text search configuration %u",
    2739             :              cfgid);
    2740          24 :     form = (Form_pg_ts_config) GETSTRUCT(tup);
    2741             : 
    2742          24 :     recomputeNamespacePath();
    2743             : 
    2744             :     /*
    2745             :      * Quick check: if it ain't in the path at all, it ain't visible. Items in
    2746             :      * the system namespace are surely in the path and so we needn't even do
    2747             :      * list_member_oid() for them.
    2748             :      */
    2749          24 :     namespace = form->cfgnamespace;
    2750          48 :     if (namespace != PG_CATALOG_NAMESPACE &&
    2751          24 :         !list_member_oid(activeSearchPath, namespace))
    2752           8 :         visible = false;
    2753             :     else
    2754             :     {
    2755             :         /*
    2756             :          * If it is in the path, it might still not be visible; it could be
    2757             :          * hidden by another configuration of the same name earlier in the
    2758             :          * path. So we must do a slow check for conflicting configurations.
    2759             :          */
    2760          16 :         char       *name = NameStr(form->cfgname);
    2761             :         ListCell   *l;
    2762             : 
    2763          16 :         visible = false;
    2764          32 :         foreach(l, activeSearchPath)
    2765             :         {
    2766          32 :             Oid         namespaceId = lfirst_oid(l);
    2767             : 
    2768          32 :             if (namespaceId == myTempNamespace)
    2769           0 :                 continue;       /* do not look in temp namespace */
    2770             : 
    2771          32 :             if (namespaceId == namespace)
    2772             :             {
    2773             :                 /* Found it first in path */
    2774          16 :                 visible = true;
    2775          16 :                 break;
    2776             :             }
    2777          16 :             if (SearchSysCacheExists2(TSCONFIGNAMENSP,
    2778             :                                       PointerGetDatum(name),
    2779             :                                       ObjectIdGetDatum(namespaceId)))
    2780             :             {
    2781             :                 /* Found something else first in path */
    2782           0 :                 break;
    2783             :             }
    2784             :         }
    2785             :     }
    2786             : 
    2787          24 :     ReleaseSysCache(tup);
    2788             : 
    2789          24 :     return visible;
    2790             : }
    2791             : 
    2792             : 
    2793             : /*
    2794             :  * DeconstructQualifiedName
    2795             :  *      Given a possibly-qualified name expressed as a list of String nodes,
    2796             :  *      extract the schema name and object name.
    2797             :  *
    2798             :  * *nspname_p is set to NULL if there is no explicit schema name.
    2799             :  */
    2800             : void
    2801     1906812 : DeconstructQualifiedName(List *names,
    2802             :                          char **nspname_p,
    2803             :                          char **objname_p)
    2804             : {
    2805             :     char       *catalogname;
    2806     1906812 :     char       *schemaname = NULL;
    2807     1906812 :     char       *objname = NULL;
    2808             : 
    2809     1906812 :     switch (list_length(names))
    2810             :     {
    2811             :         case 1:
    2812     1551842 :             objname = strVal(linitial(names));
    2813     1551842 :             break;
    2814             :         case 2:
    2815      354906 :             schemaname = strVal(linitial(names));
    2816      354906 :             objname = strVal(lsecond(names));
    2817      354906 :             break;
    2818             :         case 3:
    2819          64 :             catalogname = strVal(linitial(names));
    2820          64 :             schemaname = strVal(lsecond(names));
    2821          64 :             objname = strVal(lthird(names));
    2822             : 
    2823             :             /*
    2824             :              * We check the catalog name and then ignore it.
    2825             :              */
    2826          64 :             if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0)
    2827          64 :                 ereport(ERROR,
    2828             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2829             :                          errmsg("cross-database references are not implemented: %s",
    2830             :                                 NameListToString(names))));
    2831           0 :             break;
    2832             :         default:
    2833           0 :             ereport(ERROR,
    2834             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    2835             :                      errmsg("improper qualified name (too many dotted names): %s",
    2836             :                             NameListToString(names))));
    2837             :             break;
    2838             :     }
    2839             : 
    2840     1906748 :     *nspname_p = schemaname;
    2841     1906748 :     *objname_p = objname;
    2842     1906748 : }
    2843             : 
    2844             : /*
    2845             :  * LookupNamespaceNoError
    2846             :  *      Look up a schema name.
    2847             :  *
    2848             :  * Returns the namespace OID, or InvalidOid if not found.
    2849             :  *
    2850             :  * Note this does NOT perform any permissions check --- callers are
    2851             :  * responsible for being sure that an appropriate check is made.
    2852             :  * In the majority of cases LookupExplicitNamespace is preferable.
    2853             :  */
    2854             : Oid
    2855         200 : LookupNamespaceNoError(const char *nspname)
    2856             : {
    2857             :     /* check for pg_temp alias */
    2858         200 :     if (strcmp(nspname, "pg_temp") == 0)
    2859             :     {
    2860           0 :         if (OidIsValid(myTempNamespace))
    2861             :         {
    2862           0 :             InvokeNamespaceSearchHook(myTempNamespace, true);
    2863           0 :             return myTempNamespace;
    2864             :         }
    2865             : 
    2866             :         /*
    2867             :          * Since this is used only for looking up existing objects, there is
    2868             :          * no point in trying to initialize the temp namespace here; and doing
    2869             :          * so might create problems for some callers. Just report "not found".
    2870             :          */
    2871           0 :         return InvalidOid;
    2872             :     }
    2873             : 
    2874         200 :     return get_namespace_oid(nspname, true);
    2875             : }
    2876             : 
    2877             : /*
    2878             :  * LookupExplicitNamespace
    2879             :  *      Process an explicitly-specified schema name: look up the schema
    2880             :  *      and verify we have USAGE (lookup) rights in it.
    2881             :  *
    2882             :  * Returns the namespace OID
    2883             :  */
    2884             : Oid
    2885      503142 : LookupExplicitNamespace(const char *nspname, bool missing_ok)
    2886             : {
    2887             :     Oid         namespaceId;
    2888             :     AclResult   aclresult;
    2889             : 
    2890             :     /* check for pg_temp alias */
    2891      503142 :     if (strcmp(nspname, "pg_temp") == 0)
    2892             :     {
    2893         292 :         if (OidIsValid(myTempNamespace))
    2894         292 :             return myTempNamespace;
    2895             : 
    2896             :         /*
    2897             :          * Since this is used only for looking up existing objects, there is
    2898             :          * no point in trying to initialize the temp namespace here; and doing
    2899             :          * so might create problems for some callers --- just fall through.
    2900             :          */
    2901             :     }
    2902             : 
    2903      502850 :     namespaceId = get_namespace_oid(nspname, missing_ok);
    2904      502762 :     if (missing_ok && !OidIsValid(namespaceId))
    2905         178 :         return InvalidOid;
    2906             : 
    2907      502584 :     aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
    2908      502584 :     if (aclresult != ACLCHECK_OK)
    2909           6 :         aclcheck_error(aclresult, OBJECT_SCHEMA,
    2910             :                        nspname);
    2911             :     /* Schema search hook for this lookup */
    2912      502578 :     InvokeNamespaceSearchHook(namespaceId, true);
    2913             : 
    2914      502578 :     return namespaceId;
    2915             : }
    2916             : 
    2917             : /*
    2918             :  * LookupCreationNamespace
    2919             :  *      Look up the schema and verify we have CREATE rights on it.
    2920             :  *
    2921             :  * This is just like LookupExplicitNamespace except for the different
    2922             :  * permission check, and that we are willing to create pg_temp if needed.
    2923             :  *
    2924             :  * Note: calling this may result in a CommandCounterIncrement operation,
    2925             :  * if we have to create or clean out the temp namespace.
    2926             :  */
    2927             : Oid
    2928         262 : LookupCreationNamespace(const char *nspname)
    2929             : {
    2930             :     Oid         namespaceId;
    2931             :     AclResult   aclresult;
    2932             : 
    2933             :     /* check for pg_temp alias */
    2934         262 :     if (strcmp(nspname, "pg_temp") == 0)
    2935             :     {
    2936             :         /* Initialize temp namespace */
    2937          50 :         AccessTempTableNamespace(false);
    2938          50 :         return myTempNamespace;
    2939             :     }
    2940             : 
    2941         212 :     namespaceId = get_namespace_oid(nspname, false);
    2942             : 
    2943         210 :     aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
    2944         210 :     if (aclresult != ACLCHECK_OK)
    2945           0 :         aclcheck_error(aclresult, OBJECT_SCHEMA,
    2946             :                        nspname);
    2947             : 
    2948         210 :     return namespaceId;
    2949             : }
    2950             : 
    2951             : /*
    2952             :  * Common checks on switching namespaces.
    2953             :  *
    2954             :  * We complain if either the old or new namespaces is a temporary schema
    2955             :  * (or temporary toast schema), or if either the old or new namespaces is the
    2956             :  * TOAST schema.
    2957             :  */
    2958             : void
    2959         326 : CheckSetNamespace(Oid oldNspOid, Oid nspOid)
    2960             : {
    2961             :     /* disallow renaming into or out of temp schemas */
    2962         326 :     if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
    2963           0 :         ereport(ERROR,
    2964             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2965             :                  errmsg("cannot move objects into or out of temporary schemas")));
    2966             : 
    2967             :     /* same for TOAST schema */
    2968         326 :     if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
    2969           0 :         ereport(ERROR,
    2970             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2971             :                  errmsg("cannot move objects into or out of TOAST schema")));
    2972         326 : }
    2973             : 
    2974             : /*
    2975             :  * QualifiedNameGetCreationNamespace
    2976             :  *      Given a possibly-qualified name for an object (in List-of-Values
    2977             :  *      format), determine what namespace the object should be created in.
    2978             :  *      Also extract and return the object name (last component of list).
    2979             :  *
    2980             :  * Note: this does not apply any permissions check.  Callers must check
    2981             :  * for CREATE rights on the selected namespace when appropriate.
    2982             :  *
    2983             :  * Note: calling this may result in a CommandCounterIncrement operation,
    2984             :  * if we have to create or clean out the temp namespace.
    2985             :  */
    2986             : Oid
    2987       41810 : QualifiedNameGetCreationNamespace(List *names, char **objname_p)
    2988             : {
    2989             :     char       *schemaname;
    2990             :     Oid         namespaceId;
    2991             : 
    2992             :     /* deconstruct the name list */
    2993       41810 :     DeconstructQualifiedName(names, &schemaname, objname_p);
    2994             : 
    2995       41810 :     if (schemaname)
    2996             :     {
    2997             :         /* check for pg_temp alias */
    2998        1238 :         if (strcmp(schemaname, "pg_temp") == 0)
    2999             :         {
    3000             :             /* Initialize temp namespace */
    3001         278 :             AccessTempTableNamespace(false);
    3002         278 :             return myTempNamespace;
    3003             :         }
    3004             :         /* use exact schema given */
    3005         960 :         namespaceId = get_namespace_oid(schemaname, false);
    3006             :         /* we do not check for USAGE rights here! */
    3007             :     }
    3008             :     else
    3009             :     {
    3010             :         /* use the default creation namespace */
    3011       40572 :         recomputeNamespacePath();
    3012       40572 :         if (activeTempCreationPending)
    3013             :         {
    3014             :             /* Need to initialize temp namespace */
    3015           0 :             AccessTempTableNamespace(true);
    3016           0 :             return myTempNamespace;
    3017             :         }
    3018       40572 :         namespaceId = activeCreationNamespace;
    3019       40572 :         if (!OidIsValid(namespaceId))
    3020           0 :             ereport(ERROR,
    3021             :                     (errcode(ERRCODE_UNDEFINED_SCHEMA),
    3022             :                      errmsg("no schema has been selected to create in")));
    3023             :     }
    3024             : 
    3025       41532 :     return namespaceId;
    3026             : }
    3027             : 
    3028             : /*
    3029             :  * get_namespace_oid - given a namespace name, look up the OID
    3030             :  *
    3031             :  * If missing_ok is false, throw an error if namespace name not found.  If
    3032             :  * true, just return InvalidOid.
    3033             :  */
    3034             : Oid
    3035      549316 : get_namespace_oid(const char *nspname, bool missing_ok)
    3036             : {
    3037             :     Oid         oid;
    3038             : 
    3039      549316 :     oid = GetSysCacheOid1(NAMESPACENAME, Anum_pg_namespace_oid,
    3040             :                           CStringGetDatum(nspname));
    3041      549316 :     if (!OidIsValid(oid) && !missing_ok)
    3042         118 :         ereport(ERROR,
    3043             :                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
    3044             :                  errmsg("schema \"%s\" does not exist", nspname)));
    3045             : 
    3046      549198 :     return oid;
    3047             : }
    3048             : 
    3049             : /*
    3050             :  * makeRangeVarFromNameList
    3051             :  *      Utility routine to convert a qualified-name list into RangeVar form.
    3052             :  */
    3053             : RangeVar *
    3054       37578 : makeRangeVarFromNameList(List *names)
    3055             : {
    3056       37578 :     RangeVar   *rel = makeRangeVar(NULL, NULL, -1);
    3057             : 
    3058       37578 :     switch (list_length(names))
    3059             :     {
    3060             :         case 1:
    3061       23204 :             rel->relname = strVal(linitial(names));
    3062       23204 :             break;
    3063             :         case 2:
    3064       14322 :             rel->schemaname = strVal(linitial(names));
    3065       14322 :             rel->relname = strVal(lsecond(names));
    3066       14322 :             break;
    3067             :         case 3:
    3068          52 :             rel->catalogname = strVal(linitial(names));
    3069          52 :             rel->schemaname = strVal(lsecond(names));
    3070          52 :             rel->relname = strVal(lthird(names));
    3071          52 :             break;
    3072             :         default:
    3073           0 :             ereport(ERROR,
    3074             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    3075             :                      errmsg("improper relation name (too many dotted names): %s",
    3076             :                             NameListToString(names))));
    3077             :             break;
    3078             :     }
    3079             : 
    3080       37578 :     return rel;
    3081             : }
    3082             : 
    3083             : /*
    3084             :  * NameListToString
    3085             :  *      Utility routine to convert a qualified-name list into a string.
    3086             :  *
    3087             :  * This is used primarily to form error messages, and so we do not quote
    3088             :  * the list elements, for the sake of legibility.
    3089             :  *
    3090             :  * In most scenarios the list elements should always be Value strings,
    3091             :  * but we also allow A_Star for the convenience of ColumnRef processing.
    3092             :  */
    3093             : char *
    3094         892 : NameListToString(List *names)
    3095             : {
    3096             :     StringInfoData string;
    3097             :     ListCell   *l;
    3098             : 
    3099         892 :     initStringInfo(&string);
    3100             : 
    3101        2008 :     foreach(l, names)
    3102             :     {
    3103        1116 :         Node       *name = (Node *) lfirst(l);
    3104             : 
    3105        1116 :         if (l != list_head(names))
    3106         224 :             appendStringInfoChar(&string, '.');
    3107             : 
    3108        1116 :         if (IsA(name, String))
    3109        1116 :             appendStringInfoString(&string, strVal(name));
    3110           0 :         else if (IsA(name, A_Star))
    3111           0 :             appendStringInfoChar(&string, '*');
    3112             :         else
    3113           0 :             elog(ERROR, "unexpected node type in name list: %d",
    3114             :                  (int) nodeTag(name));
    3115             :     }
    3116             : 
    3117         892 :     return string.data;
    3118             : }
    3119             : 
    3120             : /*
    3121             :  * NameListToQuotedString
    3122             :  *      Utility routine to convert a qualified-name list into a string.
    3123             :  *
    3124             :  * Same as above except that names will be double-quoted where necessary,
    3125             :  * so the string could be re-parsed (eg, by textToQualifiedNameList).
    3126             :  */
    3127             : char *
    3128           0 : NameListToQuotedString(List *names)
    3129             : {
    3130             :     StringInfoData string;
    3131             :     ListCell   *l;
    3132             : 
    3133           0 :     initStringInfo(&string);
    3134             : 
    3135           0 :     foreach(l, names)
    3136             :     {
    3137           0 :         if (l != list_head(names))
    3138           0 :             appendStringInfoChar(&string, '.');
    3139           0 :         appendStringInfoString(&string, quote_identifier(strVal(lfirst(l))));
    3140             :     }
    3141             : 
    3142           0 :     return string.data;
    3143             : }
    3144             : 
    3145             : /*
    3146             :  * isTempNamespace - is the given namespace my temporary-table namespace?
    3147             :  */
    3148             : bool
    3149       23572 : isTempNamespace(Oid namespaceId)
    3150             : {
    3151       23572 :     if (OidIsValid(myTempNamespace) && myTempNamespace == namespaceId)
    3152         384 :         return true;
    3153       23188 :     return false;
    3154             : }
    3155             : 
    3156             : /*
    3157             :  * isTempToastNamespace - is the given namespace my temporary-toast-table
    3158             :  *      namespace?
    3159             :  */
    3160             : bool
    3161     7324582 : isTempToastNamespace(Oid namespaceId)
    3162             : {
    3163     7324582 :     if (OidIsValid(myTempToastNamespace) && myTempToastNamespace == namespaceId)
    3164        2280 :         return true;
    3165     7322302 :     return false;
    3166             : }
    3167             : 
    3168             : /*
    3169             :  * isTempOrTempToastNamespace - is the given namespace my temporary-table
    3170             :  *      namespace or my temporary-toast-table namespace?
    3171             :  */
    3172             : bool
    3173      170026 : isTempOrTempToastNamespace(Oid namespaceId)
    3174             : {
    3175      248294 :     if (OidIsValid(myTempNamespace) &&
    3176      140030 :         (myTempNamespace == namespaceId || myTempToastNamespace == namespaceId))
    3177       24256 :         return true;
    3178      145770 :     return false;
    3179             : }
    3180             : 
    3181             : /*
    3182             :  * isAnyTempNamespace - is the given namespace a temporary-table namespace
    3183             :  * (either my own, or another backend's)?  Temporary-toast-table namespaces
    3184             :  * are included, too.
    3185             :  */
    3186             : bool
    3187      129358 : isAnyTempNamespace(Oid namespaceId)
    3188             : {
    3189             :     bool        result;
    3190             :     char       *nspname;
    3191             : 
    3192             :     /* True if the namespace name starts with "pg_temp_" or "pg_toast_temp_" */
    3193      129358 :     nspname = get_namespace_name(namespaceId);
    3194      129358 :     if (!nspname)
    3195           0 :         return false;           /* no such namespace? */
    3196      257680 :     result = (strncmp(nspname, "pg_temp_", 8) == 0) ||
    3197      128322 :         (strncmp(nspname, "pg_toast_temp_", 14) == 0);
    3198      129358 :     pfree(nspname);
    3199      129358 :     return result;
    3200             : }
    3201             : 
    3202             : /*
    3203             :  * isOtherTempNamespace - is the given namespace some other backend's
    3204             :  * temporary-table namespace (including temporary-toast-table namespaces)?
    3205             :  *
    3206             :  * Note: for most purposes in the C code, this function is obsolete.  Use
    3207             :  * RELATION_IS_OTHER_TEMP() instead to detect non-local temp relations.
    3208             :  */
    3209             : bool
    3210        3758 : isOtherTempNamespace(Oid namespaceId)
    3211             : {
    3212             :     /* If it's my own temp namespace, say "false" */
    3213        3758 :     if (isTempOrTempToastNamespace(namespaceId))
    3214           8 :         return false;
    3215             :     /* Else, if it's any temp namespace, say "true" */
    3216        3750 :     return isAnyTempNamespace(namespaceId);
    3217             : }
    3218             : 
    3219             : /*
    3220             :  * isTempNamespaceInUse - is the given namespace owned and actively used
    3221             :  * by a backend?
    3222             :  *
    3223             :  * Note: this can be used while scanning relations in pg_class to detect
    3224             :  * orphaned temporary tables or namespaces with a backend connected to a
    3225             :  * given database.  The result may be out of date quickly, so the caller
    3226             :  * must be careful how to handle this information.
    3227             :  */
    3228             : bool
    3229           0 : isTempNamespaceInUse(Oid namespaceId)
    3230             : {
    3231             :     PGPROC     *proc;
    3232             :     int         backendId;
    3233             : 
    3234             :     Assert(OidIsValid(MyDatabaseId));
    3235             : 
    3236           0 :     backendId = GetTempNamespaceBackendId(namespaceId);
    3237             : 
    3238           0 :     if (backendId == InvalidBackendId ||
    3239           0 :         backendId == MyBackendId)
    3240           0 :         return false;
    3241             : 
    3242             :     /* Is the backend alive? */
    3243           0 :     proc = BackendIdGetProc(backendId);
    3244           0 :     if (proc == NULL)
    3245           0 :         return false;
    3246             : 
    3247             :     /* Is the backend connected to the same database we are looking at? */
    3248           0 :     if (proc->databaseId != MyDatabaseId)
    3249           0 :         return false;
    3250             : 
    3251             :     /* Does the backend own the temporary namespace? */
    3252           0 :     if (proc->tempNamespaceId != namespaceId)
    3253           0 :         return false;
    3254             : 
    3255             :     /* all good to go */
    3256           0 :     return true;
    3257             : }
    3258             : 
    3259             : /*
    3260             :  * GetTempNamespaceBackendId - if the given namespace is a temporary-table
    3261             :  * namespace (either my own, or another backend's), return the BackendId
    3262             :  * that owns it.  Temporary-toast-table namespaces are included, too.
    3263             :  * If it isn't a temp namespace, return InvalidBackendId.
    3264             :  */
    3265             : int
    3266          34 : GetTempNamespaceBackendId(Oid namespaceId)
    3267             : {
    3268             :     int         result;
    3269             :     char       *nspname;
    3270             : 
    3271             :     /* See if the namespace name starts with "pg_temp_" or "pg_toast_temp_" */
    3272          34 :     nspname = get_namespace_name(namespaceId);
    3273          34 :     if (!nspname)
    3274           0 :         return InvalidBackendId;    /* no such namespace? */
    3275          34 :     if (strncmp(nspname, "pg_temp_", 8) == 0)
    3276          34 :         result = atoi(nspname + 8);
    3277           0 :     else if (strncmp(nspname, "pg_toast_temp_", 14) == 0)
    3278           0 :         result = atoi(nspname + 14);
    3279             :     else
    3280           0 :         result = InvalidBackendId;
    3281          34 :     pfree(nspname);
    3282          34 :     return result;
    3283             : }
    3284             : 
    3285             : /*
    3286             :  * GetTempToastNamespace - get the OID of my temporary-toast-table namespace,
    3287             :  * which must already be assigned.  (This is only used when creating a toast
    3288             :  * table for a temp table, so we must have already done InitTempTableNamespace)
    3289             :  */
    3290             : Oid
    3291        1112 : GetTempToastNamespace(void)
    3292             : {
    3293             :     Assert(OidIsValid(myTempToastNamespace));
    3294        1112 :     return myTempToastNamespace;
    3295             : }
    3296             : 
    3297             : 
    3298             : /*
    3299             :  * GetTempNamespaceState - fetch status of session's temporary namespace
    3300             :  *
    3301             :  * This is used for conveying state to a parallel worker, and is not meant
    3302             :  * for general-purpose access.
    3303             :  */
    3304             : void
    3305         446 : GetTempNamespaceState(Oid *tempNamespaceId, Oid *tempToastNamespaceId)
    3306             : {
    3307             :     /* Return namespace OIDs, or 0 if session has not created temp namespace */
    3308         446 :     *tempNamespaceId = myTempNamespace;
    3309         446 :     *tempToastNamespaceId = myTempToastNamespace;
    3310         446 : }
    3311             : 
    3312             : /*
    3313             :  * SetTempNamespaceState - set status of session's temporary namespace
    3314             :  *
    3315             :  * This is used for conveying state to a parallel worker, and is not meant for
    3316             :  * general-purpose access.  By transferring these namespace OIDs to workers,
    3317             :  * we ensure they will have the same notion of the search path as their leader
    3318             :  * does.
    3319             :  */
    3320             : void
    3321        1520 : SetTempNamespaceState(Oid tempNamespaceId, Oid tempToastNamespaceId)
    3322             : {
    3323             :     /* Worker should not have created its own namespaces ... */
    3324             :     Assert(myTempNamespace == InvalidOid);
    3325             :     Assert(myTempToastNamespace == InvalidOid);
    3326             :     Assert(myTempNamespaceSubID == InvalidSubTransactionId);
    3327             : 
    3328             :     /* Assign same namespace OIDs that leader has */
    3329        1520 :     myTempNamespace = tempNamespaceId;
    3330        1520 :     myTempToastNamespace = tempToastNamespaceId;
    3331             : 
    3332             :     /*
    3333             :      * It's fine to leave myTempNamespaceSubID == InvalidSubTransactionId.
    3334             :      * Even if the namespace is new so far as the leader is concerned, it's
    3335             :      * not new to the worker, and we certainly wouldn't want the worker trying
    3336             :      * to destroy it.
    3337             :      */
    3338             : 
    3339        1520 :     baseSearchPathValid = false;    /* may need to rebuild list */
    3340        1520 : }
    3341             : 
    3342             : 
    3343             : /*
    3344             :  * GetOverrideSearchPath - fetch current search path definition in form
    3345             :  * used by PushOverrideSearchPath.
    3346             :  *
    3347             :  * The result structure is allocated in the specified memory context
    3348             :  * (which might or might not be equal to CurrentMemoryContext); but any
    3349             :  * junk created by revalidation calculations will be in CurrentMemoryContext.
    3350             :  */
    3351             : OverrideSearchPath *
    3352       32062 : GetOverrideSearchPath(MemoryContext context)
    3353             : {
    3354             :     OverrideSearchPath *result;
    3355             :     List       *schemas;
    3356             :     MemoryContext oldcxt;
    3357             : 
    3358       32062 :     recomputeNamespacePath();
    3359             : 
    3360       32062 :     oldcxt = MemoryContextSwitchTo(context);
    3361             : 
    3362       32062 :     result = (OverrideSearchPath *) palloc0(sizeof(OverrideSearchPath));
    3363       32062 :     schemas = list_copy(activeSearchPath);
    3364      100322 :     while (schemas && linitial_oid(schemas) != activeCreationNamespace)
    3365             :     {
    3366       36198 :         if (linitial_oid(schemas) == myTempNamespace)
    3367        6036 :             result->addTemp = true;
    3368             :         else
    3369             :         {
    3370             :             Assert(linitial_oid(schemas) == PG_CATALOG_NAMESPACE);
    3371       30162 :             result->addCatalog = true;
    3372             :         }
    3373       36198 :         schemas = list_delete_first(schemas);
    3374             :     }
    3375       32062 :     result->schemas = schemas;
    3376             : 
    3377       32062 :     MemoryContextSwitchTo(oldcxt);
    3378             : 
    3379       32062 :     return result;
    3380             : }
    3381             : 
    3382             : /*
    3383             :  * CopyOverrideSearchPath - copy the specified OverrideSearchPath.
    3384             :  *
    3385             :  * The result structure is allocated in CurrentMemoryContext.
    3386             :  */
    3387             : OverrideSearchPath *
    3388           0 : CopyOverrideSearchPath(OverrideSearchPath *path)
    3389             : {
    3390             :     OverrideSearchPath *result;
    3391             : 
    3392           0 :     result = (OverrideSearchPath *) palloc(sizeof(OverrideSearchPath));
    3393           0 :     result->schemas = list_copy(path->schemas);
    3394           0 :     result->addCatalog = path->addCatalog;
    3395           0 :     result->addTemp = path->addTemp;
    3396             : 
    3397           0 :     return result;
    3398             : }
    3399             : 
    3400             : /*
    3401             :  * OverrideSearchPathMatchesCurrent - does path match current setting?
    3402             :  */
    3403             : bool
    3404      222144 : OverrideSearchPathMatchesCurrent(OverrideSearchPath *path)
    3405             : {
    3406             :     ListCell   *lc,
    3407             :                *lcp;
    3408             : 
    3409      222144 :     recomputeNamespacePath();
    3410             : 
    3411             :     /* We scan down the activeSearchPath to see if it matches the input. */
    3412      222144 :     lc = list_head(activeSearchPath);
    3413             : 
    3414             :     /* If path->addTemp, first item should be my temp namespace. */
    3415      222144 :     if (path->addTemp)
    3416             :     {
    3417       17932 :         if (lc && lfirst_oid(lc) == myTempNamespace)
    3418       17932 :             lc = lnext(activeSearchPath, lc);
    3419             :         else
    3420           0 :             return false;
    3421             :     }
    3422             :     /* If path->addCatalog, next item should be pg_catalog. */
    3423      222144 :     if (path->addCatalog)
    3424             :     {
    3425      217346 :         if (lc && lfirst_oid(lc) == PG_CATALOG_NAMESPACE)
    3426      217316 :             lc = lnext(activeSearchPath, lc);
    3427             :         else
    3428          30 :             return false;
    3429             :     }
    3430             :     /* We should now be looking at the activeCreationNamespace. */
    3431      222114 :     if (activeCreationNamespace != (lc ? lfirst_oid(lc) : InvalidOid))
    3432           0 :         return false;
    3433             :     /* The remainder of activeSearchPath should match path->schemas. */
    3434      887256 :     foreach(lcp, path->schemas)
    3435             :     {
    3436      221520 :         if (lc && lfirst_oid(lc) == lfirst_oid(lcp))
    3437      221514 :             lc = lnext(activeSearchPath, lc);
    3438             :         else
    3439           6 :             return false;
    3440             :     }
    3441      222108 :     if (lc)
    3442           0 :         return false;
    3443      222108 :     return true;
    3444             : }
    3445             : 
    3446             : /*
    3447             :  * PushOverrideSearchPath - temporarily override the search path
    3448             :  *
    3449             :  * We allow nested overrides, hence the push/pop terminology.  The GUC
    3450             :  * search_path variable is ignored while an override is active.
    3451             :  *
    3452             :  * It's possible that newpath->useTemp is set but there is no longer any
    3453             :  * active temp namespace, if the path was saved during a transaction that
    3454             :  * created a temp namespace and was later rolled back.  In that case we just
    3455             :  * ignore useTemp.  A plausible alternative would be to create a new temp
    3456             :  * namespace, but for existing callers that's not necessary because an empty
    3457             :  * temp namespace wouldn't affect their results anyway.
    3458             :  *
    3459             :  * It's also worth noting that other schemas listed in newpath might not
    3460             :  * exist anymore either.  We don't worry about this because OIDs that match
    3461             :  * no existing namespace will simply not produce any hits during searches.
    3462             :  */
    3463             : void
    3464         640 : PushOverrideSearchPath(OverrideSearchPath *newpath)
    3465             : {
    3466             :     OverrideStackEntry *entry;
    3467             :     List       *oidlist;
    3468             :     Oid         firstNS;
    3469             :     MemoryContext oldcxt;
    3470             : 
    3471             :     /*
    3472             :      * Copy the list for safekeeping, and insert implicitly-searched
    3473             :      * namespaces as needed.  This code should track recomputeNamespacePath.
    3474             :      */
    3475         640 :     oldcxt = MemoryContextSwitchTo(TopMemoryContext);
    3476             : 
    3477         640 :     oidlist = list_copy(newpath->schemas);
    3478             : 
    3479             :     /*
    3480             :      * Remember the first member of the explicit list.
    3481             :      */
    3482         640 :     if (oidlist == NIL)
    3483           0 :         firstNS = InvalidOid;
    3484             :     else
    3485         640 :         firstNS = linitial_oid(oidlist);
    3486             : 
    3487             :     /*
    3488             :      * Add any implicitly-searched namespaces to the list.  Note these go on
    3489             :      * the front, not the back; also notice that we do not check USAGE
    3490             :      * permissions for these.
    3491             :      */
    3492         640 :     if (newpath->addCatalog)
    3493         318 :         oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist);
    3494             : 
    3495         640 :     if (newpath->addTemp && OidIsValid(myTempNamespace))
    3496         410 :         oidlist = lcons_oid(myTempNamespace, oidlist);
    3497             : 
    3498             :     /*
    3499             :      * Build the new stack entry, then insert it at the head of the list.
    3500             :      */
    3501         640 :     entry = (OverrideStackEntry *) palloc(sizeof(OverrideStackEntry));
    3502         640 :     entry->searchPath = oidlist;
    3503         640 :     entry->creationNamespace = firstNS;
    3504         640 :     entry->nestLevel = GetCurrentTransactionNestLevel();
    3505             : 
    3506         640 :     overrideStack = lcons(entry, overrideStack);
    3507             : 
    3508             :     /* And make it active. */
    3509         640 :     activeSearchPath = entry->searchPath;
    3510         640 :     activeCreationNamespace = entry->creationNamespace;
    3511         640 :     activeTempCreationPending = false;  /* XXX is this OK? */
    3512             : 
    3513         640 :     MemoryContextSwitchTo(oldcxt);
    3514         640 : }
    3515             : 
    3516             : /*
    3517             :  * PopOverrideSearchPath - undo a previous PushOverrideSearchPath
    3518             :  *
    3519             :  * Any push during a (sub)transaction will be popped automatically at abort.
    3520             :  * But it's caller error if a push isn't popped in normal control flow.
    3521             :  */
    3522             : void
    3523         636 : PopOverrideSearchPath(void)
    3524             : {
    3525             :     OverrideStackEntry *entry;
    3526             : 
    3527             :     /* Sanity checks. */
    3528         636 :     if (overrideStack == NIL)
    3529           0 :         elog(ERROR, "bogus PopOverrideSearchPath call");
    3530         636 :     entry = (OverrideStackEntry *) linitial(overrideStack);
    3531         636 :     if (entry->nestLevel != GetCurrentTransactionNestLevel())
    3532           0 :         elog(ERROR, "bogus PopOverrideSearchPath call");
    3533             : 
    3534             :     /* Pop the stack and free storage. */
    3535         636 :     overrideStack = list_delete_first(overrideStack);
    3536         636 :     list_free(entry->searchPath);
    3537         636 :     pfree(entry);
    3538             : 
    3539             :     /* Activate the next level down. */
    3540         636 :     if (overrideStack)
    3541             :     {
    3542           0 :         entry = (OverrideStackEntry *) linitial(overrideStack);
    3543           0 :         activeSearchPath = entry->searchPath;
    3544           0 :         activeCreationNamespace = entry->creationNamespace;
    3545           0 :         activeTempCreationPending = false;  /* XXX is this OK? */
    3546             :     }
    3547             :     else
    3548             :     {
    3549             :         /* If not baseSearchPathValid, this is useless but harmless */
    3550         636 :         activeSearchPath = baseSearchPath;
    3551         636 :         activeCreationNamespace = baseCreationNamespace;
    3552         636 :         activeTempCreationPending = baseTempCreationPending;
    3553             :     }
    3554         636 : }
    3555             : 
    3556             : 
    3557             : /*
    3558             :  * get_collation_oid - find a collation by possibly qualified name
    3559             :  *
    3560             :  * Note that this will only find collations that work with the current
    3561             :  * database's encoding.
    3562             :  */
    3563             : Oid
    3564        3636 : get_collation_oid(List *name, bool missing_ok)
    3565             : {
    3566             :     char       *schemaname;
    3567             :     char       *collation_name;
    3568        3636 :     int32       dbencoding = GetDatabaseEncoding();
    3569             :     Oid         namespaceId;
    3570             :     Oid         colloid;
    3571             :     ListCell   *l;
    3572             : 
    3573             :     /* deconstruct the name list */
    3574        3636 :     DeconstructQualifiedName(name, &schemaname, &collation_name);
    3575             : 
    3576        3636 :     if (schemaname)
    3577             :     {
    3578             :         /* use exact schema given */
    3579        2230 :         namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
    3580        2230 :         if (missing_ok && !OidIsValid(namespaceId))
    3581           4 :             return InvalidOid;
    3582             : 
    3583        2226 :         colloid = lookup_collation(collation_name, namespaceId, dbencoding);
    3584        2226 :         if (OidIsValid(colloid))
    3585        2226 :             return colloid;
    3586             :     }
    3587             :     else
    3588             :     {
    3589             :         /* search for it in search path */
    3590        1406 :         recomputeNamespacePath();
    3591             : 
    3592        2262 :         foreach(l, activeSearchPath)
    3593             :         {
    3594        2258 :             namespaceId = lfirst_oid(l);
    3595             : 
    3596        2258 :             if (namespaceId == myTempNamespace)
    3597         828 :                 continue;       /* do not look in temp namespace */
    3598             : 
    3599        1430 :             colloid = lookup_collation(collation_name, namespaceId, dbencoding);
    3600        1430 :             if (OidIsValid(colloid))
    3601        1402 :                 return colloid;
    3602             :         }
    3603             :     }
    3604             : 
    3605             :     /* Not found in path */
    3606           4 :     if (!missing_ok)
    3607           0 :         ereport(ERROR,
    3608             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    3609             :                  errmsg("collation \"%s\" for encoding \"%s\" does not exist",
    3610             :                         NameListToString(name), GetDatabaseEncodingName())));
    3611           4 :     return InvalidOid;
    3612             : }
    3613             : 
    3614             : /*
    3615             :  * get_conversion_oid - find a conversion by possibly qualified name
    3616             :  */
    3617             : Oid
    3618         118 : get_conversion_oid(List *name, bool missing_ok)
    3619             : {
    3620             :     char       *schemaname;
    3621             :     char       *conversion_name;
    3622             :     Oid         namespaceId;
    3623         118 :     Oid         conoid = InvalidOid;
    3624             :     ListCell   *l;
    3625             : 
    3626             :     /* deconstruct the name list */
    3627         118 :     DeconstructQualifiedName(name, &schemaname, &conversion_name);
    3628             : 
    3629         110 :     if (schemaname)
    3630             :     {
    3631             :         /* use exact schema given */
    3632          26 :         namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
    3633          26 :         if (missing_ok && !OidIsValid(namespaceId))
    3634           4 :             conoid = InvalidOid;
    3635             :         else
    3636          22 :             conoid = GetSysCacheOid2(CONNAMENSP, Anum_pg_conversion_oid,
    3637             :                                      PointerGetDatum(conversion_name),
    3638             :                                      ObjectIdGetDatum(namespaceId));
    3639             :     }
    3640             :     else
    3641             :     {
    3642             :         /* search for it in search path */
    3643          84 :         recomputeNamespacePath();
    3644             : 
    3645         188 :         foreach(l, activeSearchPath)
    3646             :         {
    3647         168 :             namespaceId = lfirst_oid(l);
    3648             : 
    3649         168 :             if (namespaceId == myTempNamespace)
    3650           0 :                 continue;       /* do not look in temp namespace */
    3651             : 
    3652         168 :             conoid = GetSysCacheOid2(CONNAMENSP, Anum_pg_conversion_oid,
    3653             :                                      PointerGetDatum(conversion_name),
    3654             :                                      ObjectIdGetDatum(namespaceId));
    3655         168 :             if (OidIsValid(conoid))
    3656          64 :                 return conoid;
    3657             :         }
    3658             :     }
    3659             : 
    3660             :     /* Not found in path */
    3661          46 :     if (!OidIsValid(conoid) && !missing_ok)
    3662          24 :         ereport(ERROR,
    3663             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    3664             :                  errmsg("conversion \"%s\" does not exist",
    3665             :                         NameListToString(name))));
    3666          22 :     return conoid;
    3667             : }
    3668             : 
    3669             : /*
    3670             :  * FindDefaultConversionProc - find default encoding conversion proc
    3671             :  */
    3672             : Oid
    3673         524 : FindDefaultConversionProc(int32 for_encoding, int32 to_encoding)
    3674             : {
    3675             :     Oid         proc;
    3676             :     ListCell   *l;
    3677             : 
    3678         524 :     recomputeNamespacePath();
    3679             : 
    3680         524 :     foreach(l, activeSearchPath)
    3681             :     {
    3682         524 :         Oid         namespaceId = lfirst_oid(l);
    3683             : 
    3684         524 :         if (namespaceId == myTempNamespace)
    3685           0 :             continue;           /* do not look in temp namespace */
    3686             : 
    3687         524 :         proc = FindDefaultConversion(namespaceId, for_encoding, to_encoding);
    3688         524 :         if (OidIsValid(proc))
    3689         524 :             return proc;
    3690             :     }
    3691             : 
    3692             :     /* Not found in path */
    3693           0 :     return InvalidOid;
    3694             : }
    3695             : 
    3696             : /*
    3697             :  * recomputeNamespacePath - recompute path derived variables if needed.
    3698             :  */
    3699             : static void
    3700     2810036 : recomputeNamespacePath(void)
    3701             : {
    3702     2810036 :     Oid         roleid = GetUserId();
    3703             :     char       *rawname;
    3704             :     List       *namelist;
    3705             :     List       *oidlist;
    3706             :     List       *newpath;
    3707             :     ListCell   *l;
    3708             :     bool        temp_missing;
    3709             :     Oid         firstNS;
    3710             :     MemoryContext oldcxt;
    3711             : 
    3712             :     /* Do nothing if an override search spec is active. */
    3713     2810036 :     if (overrideStack)
    3714     2798412 :         return;
    3715             : 
    3716             :     /* Do nothing if path is already valid. */
    3717     2809954 :     if (baseSearchPathValid && namespaceUser == roleid)
    3718     2798248 :         return;
    3719             : 
    3720             :     /* Need a modifiable copy of namespace_search_path string */
    3721       11706 :     rawname = pstrdup(namespace_search_path);
    3722             : 
    3723             :     /* Parse string into list of identifiers */
    3724       11706 :     if (!SplitIdentifierString(rawname, ',', &namelist))
    3725             :     {
    3726             :         /* syntax error in name list */
    3727             :         /* this should not happen if GUC checked check_search_path */
    3728           0 :         elog(ERROR, "invalid list syntax");
    3729             :     }
    3730             : 
    3731             :     /*
    3732             :      * Convert the list of names to a list of OIDs.  If any names are not
    3733             :      * recognizable or we don't have read access, just leave them out of the
    3734             :      * list.  (We can't raise an error, since the search_path setting has
    3735             :      * already been accepted.)  Don't make duplicate entries, either.
    3736             :      */
    3737       11706 :     oidlist = NIL;
    3738       11706 :     temp_missing = false;
    3739       30830 :     foreach(l, namelist)
    3740             :     {
    3741       19124 :         char       *curname = (char *) lfirst(l);
    3742             :         Oid         namespaceId;
    3743             : 
    3744       19124 :         if (strcmp(curname, "$user") == 0)
    3745             :         {
    3746             :             /* $user --- substitute namespace matching user name, if any */
    3747             :             HeapTuple   tuple;
    3748             : 
    3749        7548 :             tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
    3750        7548 :             if (HeapTupleIsValid(tuple))
    3751             :             {
    3752             :                 char       *rname;
    3753             : 
    3754        7548 :                 rname = NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname);
    3755        7548 :                 namespaceId = get_namespace_oid(rname, true);
    3756        7548 :                 ReleaseSysCache(tuple);
    3757        7548 :                 if (OidIsValid(namespaceId) &&
    3758           0 :                     !list_member_oid(oidlist, namespaceId) &&
    3759           0 :                     pg_namespace_aclcheck(namespaceId, roleid,
    3760           0 :                                           ACL_USAGE) == ACLCHECK_OK &&
    3761           0 :                     InvokeNamespaceSearchHook(namespaceId, false))
    3762           0 :                     oidlist = lappend_oid(oidlist, namespaceId);
    3763             :             }
    3764             :         }
    3765       11576 :         else if (strcmp(curname, "pg_temp") == 0)
    3766             :         {
    3767             :             /* pg_temp --- substitute temp namespace, if any */
    3768          20 :             if (OidIsValid(myTempNamespace))
    3769             :             {
    3770          32 :                 if (!list_member_oid(oidlist, myTempNamespace) &&
    3771          16 :                     InvokeNamespaceSearchHook(myTempNamespace, false))
    3772          16 :                     oidlist = lappend_oid(oidlist, myTempNamespace);
    3773             :             }
    3774             :             else
    3775             :             {
    3776             :                 /* If it ought to be the creation namespace, set flag */
    3777           4 :                 if (oidlist == NIL)
    3778           4 :                     temp_missing = true;
    3779             :             }
    3780             :         }
    3781             :         else
    3782             :         {
    3783             :             /* normal namespace reference */
    3784       11556 :             namespaceId = get_namespace_oid(curname, true);
    3785       23076 :             if (OidIsValid(namespaceId) &&
    3786       23024 :                 !list_member_oid(oidlist, namespaceId) &&
    3787       11504 :                 pg_namespace_aclcheck(namespaceId, roleid,
    3788       11504 :                                       ACL_USAGE) == ACLCHECK_OK &&
    3789       11504 :                 InvokeNamespaceSearchHook(namespaceId, false))
    3790       11504 :                 oidlist = lappend_oid(oidlist, namespaceId);
    3791             :         }
    3792             :     }
    3793             : 
    3794             :     /*
    3795             :      * Remember the first member of the explicit list.  (Note: this is
    3796             :      * nominally wrong if temp_missing, but we need it anyway to distinguish
    3797             :      * explicit from implicit mention of pg_catalog.)
    3798             :      */
    3799       11706 :     if (oidlist == NIL)
    3800         380 :         firstNS = InvalidOid;
    3801             :     else
    3802       11326 :         firstNS = linitial_oid(oidlist);
    3803             : 
    3804             :     /*
    3805             :      * Add any implicitly-searched namespaces to the list.  Note these go on
    3806             :      * the front, not the back; also notice that we do not check USAGE
    3807             :      * permissions for these.
    3808             :      */
    3809       11706 :     if (!list_member_oid(oidlist, PG_CATALOG_NAMESPACE))
    3810        9702 :         oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist);
    3811             : 
    3812       15088 :     if (OidIsValid(myTempNamespace) &&
    3813        3382 :         !list_member_oid(oidlist, myTempNamespace))
    3814        3366 :         oidlist = lcons_oid(myTempNamespace, oidlist);
    3815             : 
    3816             :     /*
    3817             :      * Now that we've successfully built the new list of namespace OIDs, save
    3818             :      * it in permanent storage.
    3819             :      */
    3820       11706 :     oldcxt = MemoryContextSwitchTo(TopMemoryContext);
    3821       11706 :     newpath = list_copy(oidlist);
    3822       11706 :     MemoryContextSwitchTo(oldcxt);
    3823             : 
    3824             :     /* Now safe to assign to state variables. */
    3825       11706 :     list_free(baseSearchPath);
    3826       11706 :     baseSearchPath = newpath;
    3827       11706 :     baseCreationNamespace = firstNS;
    3828       11706 :     baseTempCreationPending = temp_missing;
    3829             : 
    3830             :     /* Mark the path valid. */
    3831       11706 :     baseSearchPathValid = true;
    3832       11706 :     namespaceUser = roleid;
    3833             : 
    3834             :     /* And make it active. */
    3835       11706 :     activeSearchPath = baseSearchPath;
    3836       11706 :     activeCreationNamespace = baseCreationNamespace;
    3837       11706 :     activeTempCreationPending = baseTempCreationPending;
    3838             : 
    3839             :     /* Clean up. */
    3840       11706 :     pfree(rawname);
    3841       11706 :     list_free(namelist);
    3842       11706 :     list_free(oidlist);
    3843             : }
    3844             : 
    3845             : /*
    3846             :  * AccessTempTableNamespace
    3847             :  *      Provide access to a temporary namespace, potentially creating it
    3848             :  *      if not present yet.  This routine registers if the namespace gets
    3849             :  *      in use in this transaction.  'force' can be set to true to allow
    3850             :  *      the caller to enforce the creation of the temporary namespace for
    3851             :  *      use in this backend, which happens if its creation is pending.
    3852             :  */
    3853             : static void
    3854        4736 : AccessTempTableNamespace(bool force)
    3855             : {
    3856             :     /*
    3857             :      * Make note that this temporary namespace has been accessed in this
    3858             :      * transaction.
    3859             :      */
    3860        4736 :     MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
    3861             : 
    3862             :     /*
    3863             :      * If the caller attempting to access a temporary schema expects the
    3864             :      * creation of the namespace to be pending and should be enforced, then go
    3865             :      * through the creation.
    3866             :      */
    3867        4736 :     if (!force && OidIsValid(myTempNamespace))
    3868        4112 :         return;
    3869             : 
    3870             :     /*
    3871             :      * The temporary tablespace does not exist yet and is wanted, so
    3872             :      * initialize it.
    3873             :      */
    3874         624 :     InitTempTableNamespace();
    3875             : }
    3876             : 
    3877             : /*
    3878             :  * InitTempTableNamespace
    3879             :  *      Initialize temp table namespace on first use in a particular backend
    3880             :  */
    3881             : static void
    3882         624 : InitTempTableNamespace(void)
    3883             : {
    3884             :     char        namespaceName[NAMEDATALEN];
    3885             :     Oid         namespaceId;
    3886             :     Oid         toastspaceId;
    3887             : 
    3888             :     Assert(!OidIsValid(myTempNamespace));
    3889             : 
    3890             :     /*
    3891             :      * First, do permission check to see if we are authorized to make temp
    3892             :      * tables.  We use a nonstandard error message here since "databasename:
    3893             :      * permission denied" might be a tad cryptic.
    3894             :      *
    3895             :      * Note that ACL_CREATE_TEMP rights are rechecked in pg_namespace_aclmask;
    3896             :      * that's necessary since current user ID could change during the session.
    3897             :      * But there's no need to make the namespace in the first place until a
    3898             :      * temp table creation request is made by someone with appropriate rights.
    3899             :      */
    3900         624 :     if (pg_database_aclcheck(MyDatabaseId, GetUserId(),
    3901             :                              ACL_CREATE_TEMP) != ACLCHECK_OK)
    3902           0 :         ereport(ERROR,
    3903             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    3904             :                  errmsg("permission denied to create temporary tables in database \"%s\"",
    3905             :                         get_database_name(MyDatabaseId))));
    3906             : 
    3907             :     /*
    3908             :      * Do not allow a Hot Standby session to make temp tables.  Aside from
    3909             :      * problems with modifying the system catalogs, there is a naming
    3910             :      * conflict: pg_temp_N belongs to the session with BackendId N on the
    3911             :      * master, not to a hot standby session with the same BackendId.  We
    3912             :      * should not be able to get here anyway due to XactReadOnly checks, but
    3913             :      * let's just make real sure.  Note that this also backstops various
    3914             :      * operations that allow XactReadOnly transactions to modify temp tables;
    3915             :      * they'd need RecoveryInProgress checks if not for this.
    3916             :      */
    3917         624 :     if (RecoveryInProgress())
    3918           0 :         ereport(ERROR,
    3919             :                 (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
    3920             :                  errmsg("cannot create temporary tables during recovery")));
    3921             : 
    3922             :     /* Parallel workers can't create temporary tables, either. */
    3923         624 :     if (IsParallelWorker())
    3924           0 :         ereport(ERROR,
    3925             :                 (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
    3926             :                  errmsg("cannot create temporary tables during a parallel operation")));
    3927             : 
    3928         624 :     snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId);
    3929             : 
    3930         624 :     namespaceId = get_namespace_oid(namespaceName, true);
    3931         624 :     if (!OidIsValid(namespaceId))
    3932             :     {
    3933             :         /*
    3934             :          * First use of this temp namespace in this database; create it. The
    3935             :          * temp namespaces are always owned by the superuser.  We leave their
    3936             :          * permissions at default --- i.e., no access except to superuser ---
    3937             :          * to ensure that unprivileged users can't peek at other backends'
    3938             :          * temp tables.  This works because the places that access the temp
    3939             :          * namespace for my own backend skip permissions checks on it.
    3940             :          */
    3941         414 :         namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID,
    3942             :                                       true);
    3943             :         /* Advance command counter to make namespace visible */
    3944         414 :         CommandCounterIncrement();
    3945             :     }
    3946             :     else
    3947             :     {
    3948             :         /*
    3949             :          * If the namespace already exists, clean it out (in case the former
    3950             :          * owner crashed without doing so).
    3951             :          */
    3952         210 :         RemoveTempRelations(namespaceId);
    3953             :     }
    3954             : 
    3955             :     /*
    3956             :      * If the corresponding toast-table namespace doesn't exist yet, create
    3957             :      * it. (We assume there is no need to clean it out if it does exist, since
    3958             :      * dropping a parent table should make its toast table go away.)
    3959             :      */
    3960         624 :     snprintf(namespaceName, sizeof(namespaceName), "pg_toast_temp_%d",
    3961             :              MyBackendId);
    3962             : 
    3963         624 :     toastspaceId = get_namespace_oid(namespaceName, true);
    3964         624 :     if (!OidIsValid(toastspaceId))
    3965             :     {
    3966         414 :         toastspaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID,
    3967             :                                        true);
    3968             :         /* Advance command counter to make namespace visible */
    3969         414 :         CommandCounterIncrement();
    3970             :     }
    3971             : 
    3972             :     /*
    3973             :      * Okay, we've prepared the temp namespace ... but it's not committed yet,
    3974             :      * so all our work could be undone by transaction rollback.  Set flag for
    3975             :      * AtEOXact_Namespace to know what to do.
    3976             :      */
    3977         624 :     myTempNamespace = namespaceId;
    3978         624 :     myTempToastNamespace = toastspaceId;
    3979             : 
    3980             :     /*
    3981             :      * Mark MyProc as owning this namespace which other processes can use to
    3982             :      * decide if a temporary namespace is in use or not.  We assume that
    3983             :      * assignment of namespaceId is an atomic operation.  Even if it is not,
    3984             :      * the temporary relation which resulted in the creation of this temporary
    3985             :      * namespace is still locked until the current transaction commits, and
    3986             :      * its pg_namespace row is not visible yet.  However it does not matter:
    3987             :      * this flag makes the namespace as being in use, so no objects created on
    3988             :      * it would be removed concurrently.
    3989             :      */
    3990         624 :     MyProc->tempNamespaceId = namespaceId;
    3991             : 
    3992             :     /* It should not be done already. */
    3993             :     AssertState(myTempNamespaceSubID == InvalidSubTransactionId);
    3994         624 :     myTempNamespaceSubID = GetCurrentSubTransactionId();
    3995             : 
    3996         624 :     baseSearchPathValid = false;    /* need to rebuild list */
    3997         624 : }
    3998             : 
    3999             : /*
    4000             :  * End-of-transaction cleanup for namespaces.
    4001             :  */
    4002             : void
    4003      458796 : AtEOXact_Namespace(bool isCommit, bool parallel)
    4004             : {
    4005             :     /*
    4006             :      * If we abort the transaction in which a temp namespace was selected,
    4007             :      * we'll have to do any creation or cleanout work over again.  So, just
    4008             :      * forget the namespace entirely until next time.  On the other hand, if
    4009             :      * we commit then register an exit callback to clean out the temp tables
    4010             :      * at backend shutdown.  (We only want to register the callback once per
    4011             :      * session, so this is a good place to do it.)
    4012             :      */
    4013      458796 :     if (myTempNamespaceSubID != InvalidSubTransactionId && !parallel)
    4014             :     {
    4015         622 :         if (isCommit)
    4016         612 :             before_shmem_exit(RemoveTempRelationsCallback, 0);
    4017             :         else
    4018             :         {
    4019          10 :             myTempNamespace = InvalidOid;
    4020          10 :             myTempToastNamespace = InvalidOid;
    4021          10 :             baseSearchPathValid = false;    /* need to rebuild list */
    4022             : 
    4023             :             /*
    4024             :              * Reset the temporary namespace flag in MyProc.  We assume that
    4025             :              * this operation is atomic.
    4026             :              *
    4027             :              * Because this transaction is aborting, the pg_namespace row is
    4028             :              * not visible to anyone else anyway, but that doesn't matter:
    4029             :              * it's not a problem if objects contained in this namespace are
    4030             :              * removed concurrently.
    4031             :              */
    4032          10 :             MyProc->tempNamespaceId = InvalidOid;
    4033             :         }
    4034         622 :         myTempNamespaceSubID = InvalidSubTransactionId;
    4035             :     }
    4036             : 
    4037             :     /*
    4038             :      * Clean up if someone failed to do PopOverrideSearchPath
    4039             :      */
    4040      458796 :     if (overrideStack)
    4041             :     {
    4042           4 :         if (isCommit)
    4043           0 :             elog(WARNING, "leaked override search path");
    4044          12 :         while (overrideStack)
    4045             :         {
    4046             :             OverrideStackEntry *entry;
    4047             : 
    4048           4 :             entry = (OverrideStackEntry *) linitial(overrideStack);
    4049           4 :             overrideStack = list_delete_first(overrideStack);
    4050           4 :             list_free(entry->searchPath);
    4051           4 :             pfree(entry);
    4052             :         }
    4053             :         /* If not baseSearchPathValid, this is useless but harmless */
    4054           4 :         activeSearchPath = baseSearchPath;
    4055           4 :         activeCreationNamespace = baseCreationNamespace;
    4056           4 :         activeTempCreationPending = baseTempCreationPending;
    4057             :     }
    4058      458796 : }
    4059             : 
    4060             : /*
    4061             :  * AtEOSubXact_Namespace
    4062             :  *
    4063             :  * At subtransaction commit, propagate the temp-namespace-creation
    4064             :  * flag to the parent subtransaction.
    4065             :  *
    4066             :  * At subtransaction abort, forget the flag if we set it up.
    4067             :  */
    4068             : void
    4069        7350 : AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid,
    4070             :                       SubTransactionId parentSubid)
    4071             : {
    4072             :     OverrideStackEntry *entry;
    4073             : 
    4074        7350 :     if (myTempNamespaceSubID == mySubid)
    4075             :     {
    4076           8 :         if (isCommit)
    4077           6 :             myTempNamespaceSubID = parentSubid;
    4078             :         else
    4079             :         {
    4080           2 :             myTempNamespaceSubID = InvalidSubTransactionId;
    4081             :             /* TEMP namespace creation failed, so reset state */
    4082           2 :             myTempNamespace = InvalidOid;
    4083           2 :             myTempToastNamespace = InvalidOid;
    4084           2 :             baseSearchPathValid = false;    /* need to rebuild list */
    4085             : 
    4086             :             /*
    4087             :              * Reset the temporary namespace flag in MyProc.  We assume that
    4088             :              * this operation is atomic.
    4089             :              *
    4090             :              * Because this subtransaction is aborting, the pg_namespace row
    4091             :              * is not visible to anyone else anyway, but that doesn't matter:
    4092             :              * it's not a problem if objects contained in this namespace are
    4093             :              * removed concurrently.
    4094             :              */
    4095           2 :             MyProc->tempNamespaceId = InvalidOid;
    4096             :         }
    4097             :     }
    4098             : 
    4099             :     /*
    4100             :      * Clean up if someone failed to do PopOverrideSearchPath
    4101             :      */
    4102       14700 :     while (overrideStack)
    4103             :     {
    4104           0 :         entry = (OverrideStackEntry *) linitial(overrideStack);
    4105           0 :         if (entry->nestLevel < GetCurrentTransactionNestLevel())
    4106           0 :             break;
    4107           0 :         if (isCommit)
    4108           0 :             elog(WARNING, "leaked override search path");
    4109           0 :         overrideStack = list_delete_first(overrideStack);
    4110           0 :         list_free(entry->searchPath);
    4111           0 :         pfree(entry);
    4112             :     }
    4113             : 
    4114             :     /* Activate the next level down. */
    4115        7350 :     if (overrideStack)
    4116             :     {
    4117           0 :         entry = (OverrideStackEntry *) linitial(overrideStack);
    4118           0 :         activeSearchPath = entry->searchPath;
    4119           0 :         activeCreationNamespace = entry->creationNamespace;
    4120           0 :         activeTempCreationPending = false;  /* XXX is this OK? */
    4121             :     }
    4122             :     else
    4123             :     {
    4124             :         /* If not baseSearchPathValid, this is useless but harmless */
    4125        7350 :         activeSearchPath = baseSearchPath;
    4126        7350 :         activeCreationNamespace = baseCreationNamespace;
    4127        7350 :         activeTempCreationPending = baseTempCreationPending;
    4128             :     }
    4129        7350 : }
    4130             : 
    4131             : /*
    4132             :  * Remove all relations in the specified temp namespace.
    4133             :  *
    4134             :  * This is called at backend shutdown (if we made any temp relations).
    4135             :  * It is also called when we begin using a pre-existing temp namespace,
    4136             :  * in order to clean out any relations that might have been created by
    4137             :  * a crashed backend.
    4138             :  */
    4139             : static void
    4140         830 : RemoveTempRelations(Oid tempNamespaceId)
    4141             : {
    4142             :     ObjectAddress object;
    4143             : 
    4144             :     /*
    4145             :      * We want to get rid of everything in the target namespace, but not the
    4146             :      * namespace itself (deleting it only to recreate it later would be a
    4147             :      * waste of cycles).  Hence, specify SKIP_ORIGINAL.  It's also an INTERNAL
    4148             :      * deletion, and we want to not drop any extensions that might happen to
    4149             :      * own temp objects.
    4150             :      */
    4151         830 :     object.classId = NamespaceRelationId;
    4152         830 :     object.objectId = tempNamespaceId;
    4153         830 :     object.objectSubId = 0;
    4154             : 
    4155         830 :     performDeletion(&object, DROP_CASCADE,
    4156             :                     PERFORM_DELETION_INTERNAL |
    4157             :                     PERFORM_DELETION_QUIETLY |
    4158             :                     PERFORM_DELETION_SKIP_ORIGINAL |
    4159             :                     PERFORM_DELETION_SKIP_EXTENSIONS);
    4160         830 : }
    4161             : 
    4162             : /*
    4163             :  * Callback to remove temp relations at backend exit.
    4164             :  */
    4165             : static void
    4166         612 : RemoveTempRelationsCallback(int code, Datum arg)
    4167             : {
    4168         612 :     if (OidIsValid(myTempNamespace))    /* should always be true */
    4169             :     {
    4170             :         /* Need to ensure we have a usable transaction. */
    4171         612 :         AbortOutOfAnyTransaction();
    4172         612 :         StartTransactionCommand();
    4173             : 
    4174         612 :         RemoveTempRelations(myTempNamespace);
    4175             : 
    4176         612 :         CommitTransactionCommand();
    4177             :     }
    4178         612 : }
    4179             : 
    4180             : /*
    4181             :  * Remove all temp tables from the temporary namespace.
    4182             :  */
    4183             : void
    4184           8 : ResetTempTableNamespace(void)
    4185             : {
    4186           8 :     if (OidIsValid(myTempNamespace))
    4187           8 :         RemoveTempRelations(myTempNamespace);
    4188           8 : }
    4189             : 
    4190             : 
    4191             : /*
    4192             :  * Routines for handling the GUC variable 'search_path'.
    4193             :  */
    4194             : 
    4195             : /* check_hook: validate new search_path value */
    4196             : bool
    4197        5158 : check_search_path(char **newval, void **extra, GucSource source)
    4198             : {
    4199             :     char       *rawname;
    4200             :     List       *namelist;
    4201             : 
    4202             :     /* Need a modifiable copy of string */
    4203        5158 :     rawname = pstrdup(*newval);
    4204             : 
    4205             :     /* Parse string into list of identifiers */
    4206        5158 :     if (!SplitIdentifierString(rawname, ',', &namelist))
    4207             :     {
    4208             :         /* syntax error in name list */
    4209           0 :         GUC_check_errdetail("List syntax is invalid.");
    4210           0 :         pfree(rawname);
    4211           0 :         list_free(namelist);
    4212           0 :         return false;
    4213             :     }
    4214             : 
    4215             :     /*
    4216             :      * We used to try to check that the named schemas exist, but there are
    4217             :      * many valid use-cases for having search_path settings that include
    4218             :      * schemas that don't exist; and often, we are not inside a transaction
    4219             :      * here and so can't consult the system catalogs anyway.  So now, the only
    4220             :      * requirement is syntactic validity of the identifier list.
    4221             :      */
    4222             : 
    4223        5158 :     pfree(rawname);
    4224        5158 :     list_free(namelist);
    4225             : 
    4226        5158 :     return true;
    4227             : }
    4228             : 
    4229             : /* assign_hook: do extra actions as needed */
    4230             : void
    4231        6004 : assign_search_path(const char *newval, void *extra)
    4232             : {
    4233             :     /*
    4234             :      * We mark the path as needing recomputation, but don't do anything until
    4235             :      * it's needed.  This avoids trying to do database access during GUC
    4236             :      * initialization, or outside a transaction.
    4237             :      */
    4238        6004 :     baseSearchPathValid = false;
    4239        6004 : }
    4240             : 
    4241             : /*
    4242             :  * InitializeSearchPath: initialize module during InitPostgres.
    4243             :  *
    4244             :  * This is called after we are up enough to be able to do catalog lookups.
    4245             :  */
    4246             : void
    4247        8834 : InitializeSearchPath(void)
    4248             : {
    4249        8834 :     if (IsBootstrapProcessingMode())
    4250             :     {
    4251             :         /*
    4252             :          * In bootstrap mode, the search path must be 'pg_catalog' so that
    4253             :          * tables are created in the proper namespace; ignore the GUC setting.
    4254             :          */
    4255             :         MemoryContext oldcxt;
    4256             : 
    4257         322 :         oldcxt = MemoryContextSwitchTo(TopMemoryContext);
    4258         322 :         baseSearchPath = list_make1_oid(PG_CATALOG_NAMESPACE);
    4259         322 :         MemoryContextSwitchTo(oldcxt);
    4260         322 :         baseCreationNamespace = PG_CATALOG_NAMESPACE;
    4261         322 :         baseTempCreationPending = false;
    4262         322 :         baseSearchPathValid = true;
    4263         322 :         namespaceUser = GetUserId();
    4264         322 :         activeSearchPath = baseSearchPath;
    4265         322 :         activeCreationNamespace = baseCreationNamespace;
    4266         322 :         activeTempCreationPending = baseTempCreationPending;
    4267             :     }
    4268             :     else
    4269             :     {
    4270             :         /*
    4271             :          * In normal mode, arrange for a callback on any syscache invalidation
    4272             :          * of pg_namespace rows.
    4273             :          */
    4274        8512 :         CacheRegisterSyscacheCallback(NAMESPACEOID,
    4275             :                                       NamespaceCallback,
    4276             :                                       (Datum) 0);
    4277             :         /* Force search path to be recomputed on next use */
    4278        8512 :         baseSearchPathValid = false;
    4279             :     }
    4280        8834 : }
    4281             : 
    4282             : /*
    4283             :  * NamespaceCallback
    4284             :  *      Syscache inval callback function
    4285             :  */
    4286             : static void
    4287        9062 : NamespaceCallback(Datum arg, int cacheid, uint32 hashvalue)
    4288             : {
    4289             :     /* Force search path to be recomputed on next use */
    4290        9062 :     baseSearchPathValid = false;
    4291        9062 : }
    4292             : 
    4293             : /*
    4294             :  * Fetch the active search path. The return value is a palloc'ed list
    4295             :  * of OIDs; the caller is responsible for freeing this storage as
    4296             :  * appropriate.
    4297             :  *
    4298             :  * The returned list includes the implicitly-prepended namespaces only if
    4299             :  * includeImplicit is true.
    4300             :  *
    4301             :  * Note: calling this may result in a CommandCounterIncrement operation,
    4302             :  * if we have to create or clean out the temp namespace.
    4303             :  */
    4304             : List *
    4305         436 : fetch_search_path(bool includeImplicit)
    4306             : {
    4307             :     List       *result;
    4308             : 
    4309         436 :     recomputeNamespacePath();
    4310             : 
    4311             :     /*
    4312             :      * If the temp namespace should be first, force it to exist.  This is so
    4313             :      * that callers can trust the result to reflect the actual default
    4314             :      * creation namespace.  It's a bit bogus to do this here, since
    4315             :      * current_schema() is supposedly a stable function without side-effects,
    4316             :      * but the alternatives seem worse.
    4317             :      */
    4318         436 :     if (activeTempCreationPending)
    4319             :     {
    4320           4 :         AccessTempTableNamespace(true);
    4321           4 :         recomputeNamespacePath();
    4322             :     }
    4323             : 
    4324         436 :     result = list_copy(activeSearchPath);
    4325         436 :     if (!includeImplicit)
    4326             :     {
    4327         956 :         while (result && linitial_oid(result) != activeCreationNamespace)
    4328         324 :             result = list_delete_first(result);
    4329             :     }
    4330             : 
    4331         436 :     return result;
    4332             : }
    4333             : 
    4334             : /*
    4335             :  * Fetch the active search path into a caller-allocated array of OIDs.
    4336             :  * Returns the number of path entries.  (If this is more than sarray_len,
    4337             :  * then the data didn't fit and is not all stored.)
    4338             :  *
    4339             :  * The returned list always includes the implicitly-prepended namespaces,
    4340             :  * but never includes the temp namespace.  (This is suitable for existing
    4341             :  * users, which would want to ignore the temp namespace anyway.)  This
    4342             :  * definition allows us to not worry about initializing the temp namespace.
    4343             :  */
    4344             : int
    4345      562938 : fetch_search_path_array(Oid *sarray, int sarray_len)
    4346             : {
    4347      562938 :     int         count = 0;
    4348             :     ListCell   *l;
    4349             : 
    4350      562938 :     recomputeNamespacePath();
    4351             : 
    4352     1670624 :     foreach(l, activeSearchPath)
    4353             :     {
    4354     1107686 :         Oid         namespaceId = lfirst_oid(l);
    4355             : 
    4356     1107686 :         if (namespaceId == myTempNamespace)
    4357      216478 :             continue;           /* do not include temp namespace */
    4358             : 
    4359      891208 :         if (count < sarray_len)
    4360      891208 :             sarray[count] = namespaceId;
    4361      891208 :         count++;
    4362             :     }
    4363             : 
    4364      562938 :     return count;
    4365             : }
    4366             : 
    4367             : 
    4368             : /*
    4369             :  * Export the FooIsVisible functions as SQL-callable functions.
    4370             :  *
    4371             :  * Note: as of Postgres 8.4, these will silently return NULL if called on
    4372             :  * a nonexistent object OID, rather than failing.  This is to avoid race
    4373             :  * condition errors when a query that's scanning a catalog using an MVCC
    4374             :  * snapshot uses one of these functions.  The underlying IsVisible functions
    4375             :  * always use an up-to-date snapshot and so might see the object as already
    4376             :  * gone when it's still visible to the transaction snapshot.  (There is no race
    4377             :  * condition in the current coding because we don't accept sinval messages
    4378             :  * between the SearchSysCacheExists test and the subsequent lookup.)
    4379             :  */
    4380             : 
    4381             : Datum
    4382        8272 : pg_table_is_visible(PG_FUNCTION_ARGS)
    4383             : {
    4384        8272 :     Oid         oid = PG_GETARG_OID(0);
    4385             : 
    4386        8272 :     if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(oid)))
    4387           0 :         PG_RETURN_NULL();
    4388             : 
    4389        8272 :     PG_RETURN_BOOL(RelationIsVisible(oid));
    4390             : }
    4391             : 
    4392             : Datum
    4393        2414 : pg_type_is_visible(PG_FUNCTION_ARGS)
    4394             : {
    4395        2414 :     Oid         oid = PG_GETARG_OID(0);
    4396             : 
    4397        2414 :     if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(oid)))
    4398           0 :         PG_RETURN_NULL();
    4399             : 
    4400        2414 :     PG_RETURN_BOOL(TypeIsVisible(oid));
    4401             : }
    4402             : 
    4403             : Datum
    4404        6120 : pg_function_is_visible(PG_FUNCTION_ARGS)
    4405             : {
    4406        6120 :     Oid         oid = PG_GETARG_OID(0);
    4407             : 
    4408        6120 :     if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(oid)))
    4409           0 :         PG_RETURN_NULL();
    4410             : 
    4411        6120 :     PG_RETURN_BOOL(FunctionIsVisible(oid));
    4412             : }
    4413             : 
    4414             : Datum
    4415        1556 : pg_operator_is_visible(PG_FUNCTION_ARGS)
    4416             : {
    4417        1556 :     Oid         oid = PG_GETARG_OID(0);
    4418             : 
    4419        1556 :     if (!SearchSysCacheExists1(OPEROID, ObjectIdGetDatum(oid)))
    4420           0 :         PG_RETURN_NULL();
    4421             : 
    4422        1556 :     PG_RETURN_BOOL(OperatorIsVisible(oid));
    4423             : }
    4424             : 
    4425             : Datum
    4426           0 : pg_opclass_is_visible(PG_FUNCTION_ARGS)
    4427             : {
    4428           0 :     Oid         oid = PG_GETARG_OID(0);
    4429             : 
    4430           0 :     if (!SearchSysCacheExists1(CLAOID, ObjectIdGetDatum(oid)))
    4431           0 :         PG_RETURN_NULL();
    4432             : 
    4433           0 :     PG_RETURN_BOOL(OpclassIsVisible(oid));
    4434             : }
    4435             : 
    4436             : Datum
    4437           0 : pg_opfamily_is_visible(PG_FUNCTION_ARGS)
    4438             : {
    4439           0 :     Oid         oid = PG_GETARG_OID(0);
    4440             : 
    4441           0 :     if (!SearchSysCacheExists1(OPFAMILYOID, ObjectIdGetDatum(oid)))
    4442           0 :         PG_RETURN_NULL();
    4443             : 
    4444           0 :     PG_RETURN_BOOL(OpfamilyIsVisible(oid));
    4445             : }
    4446             : 
    4447             : Datum
    4448           0 : pg_collation_is_visible(PG_FUNCTION_ARGS)
    4449             : {
    4450           0 :     Oid         oid = PG_GETARG_OID(0);
    4451             : 
    4452           0 :     if (!SearchSysCacheExists1(COLLOID, ObjectIdGetDatum(oid)))
    4453           0 :         PG_RETURN_NULL();
    4454             : 
    4455           0 :     PG_RETURN_BOOL(CollationIsVisible(oid));
    4456             : }
    4457             : 
    4458             : Datum
    4459           0 : pg_conversion_is_visible(PG_FUNCTION_ARGS)
    4460             : {
    4461           0 :     Oid         oid = PG_GETARG_OID(0);
    4462             : 
    4463           0 :     if (!SearchSysCacheExists1(CONVOID, ObjectIdGetDatum(oid)))
    4464           0 :         PG_RETURN_NULL();
    4465             : 
    4466           0 :     PG_RETURN_BOOL(ConversionIsVisible(oid));
    4467             : }
    4468             : 
    4469             : Datum
    4470           0 : pg_statistics_obj_is_visible(PG_FUNCTION_ARGS)
    4471             : {
    4472           0 :     Oid         oid = PG_GETARG_OID(0);
    4473             : 
    4474           0 :     if (!SearchSysCacheExists1(STATEXTOID, ObjectIdGetDatum(oid)))
    4475           0 :         PG_RETURN_NULL();
    4476             : 
    4477           0 :     PG_RETURN_BOOL(StatisticsObjIsVisible(oid));
    4478             : }
    4479             : 
    4480             : Datum
    4481           0 : pg_ts_parser_is_visible(PG_FUNCTION_ARGS)
    4482             : {
    4483           0 :     Oid         oid = PG_GETARG_OID(0);
    4484             : 
    4485           0 :     if (!SearchSysCacheExists1(TSPARSEROID, ObjectIdGetDatum(oid)))
    4486           0 :         PG_RETURN_NULL();
    4487             : 
    4488           0 :     PG_RETURN_BOOL(TSParserIsVisible(oid));
    4489             : }
    4490             : 
    4491             : Datum
    4492           0 : pg_ts_dict_is_visible(PG_FUNCTION_ARGS)
    4493             : {
    4494           0 :     Oid         oid = PG_GETARG_OID(0);
    4495             : 
    4496           0 :     if (!SearchSysCacheExists1(TSDICTOID, ObjectIdGetDatum(oid)))
    4497           0 :         PG_RETURN_NULL();
    4498             : 
    4499           0 :     PG_RETURN_BOOL(TSDictionaryIsVisible(oid));
    4500             : }
    4501             : 
    4502             : Datum
    4503           0 : pg_ts_template_is_visible(PG_FUNCTION_ARGS)
    4504             : {
    4505           0 :     Oid         oid = PG_GETARG_OID(0);
    4506             : 
    4507           0 :     if (!SearchSysCacheExists1(TSTEMPLATEOID, ObjectIdGetDatum(oid)))
    4508           0 :         PG_RETURN_NULL();
    4509             : 
    4510           0 :     PG_RETURN_BOOL(TSTemplateIsVisible(oid));
    4511             : }
    4512             : 
    4513             : Datum
    4514           0 : pg_ts_config_is_visible(PG_FUNCTION_ARGS)
    4515             : {
    4516           0 :     Oid         oid = PG_GETARG_OID(0);
    4517             : 
    4518           0 :     if (!SearchSysCacheExists1(TSCONFIGOID, ObjectIdGetDatum(oid)))
    4519           0 :         PG_RETURN_NULL();
    4520             : 
    4521           0 :     PG_RETURN_BOOL(TSConfigIsVisible(oid));
    4522             : }
    4523             : 
    4524             : Datum
    4525         222 : pg_my_temp_schema(PG_FUNCTION_ARGS)
    4526             : {
    4527         222 :     PG_RETURN_OID(myTempNamespace);
    4528             : }
    4529             : 
    4530             : Datum
    4531        3758 : pg_is_other_temp_schema(PG_FUNCTION_ARGS)
    4532             : {
    4533        3758 :     Oid         oid = PG_GETARG_OID(0);
    4534             : 
    4535        3758 :     PG_RETURN_BOOL(isOtherTempNamespace(oid));
    4536             : }

Generated by: LCOV version 1.13