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

Generated by: LCOV version 1.13