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

Generated by: LCOV version 1.14