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