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

Generated by: LCOV version 1.11