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