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