]> granicus.if.org Git - postgresql/blob - src/backend/catalog/namespace.c
Allow CREATE TABLE IF EXIST so succeed if the schema is nonexistent
[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.  Raises ereport if any problem.
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 and
2694                  * give the "does not exist" error.
2695                  */
2696         }
2697
2698         namespaceId = get_namespace_oid(nspname, missing_ok);
2699         if (missing_ok && !OidIsValid(namespaceId))
2700                 return InvalidOid;
2701         
2702         aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
2703         if (aclresult != ACLCHECK_OK)
2704                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
2705                                            nspname);
2706
2707         return namespaceId;
2708 }
2709
2710 /*
2711  * LookupCreationNamespace
2712  *              Look up the schema and verify we have CREATE rights on it.
2713  *
2714  * This is just like LookupExplicitNamespace except for the different
2715  * permission check, and that we are willing to create pg_temp if needed.
2716  *
2717  * Note: calling this may result in a CommandCounterIncrement operation,
2718  * if we have to create or clean out the temp namespace.
2719  */
2720 Oid
2721 LookupCreationNamespace(const char *nspname)
2722 {
2723         Oid                     namespaceId;
2724         AclResult       aclresult;
2725
2726         /* check for pg_temp alias */
2727         if (strcmp(nspname, "pg_temp") == 0)
2728         {
2729                 /* Initialize temp namespace if first time through */
2730                 if (!OidIsValid(myTempNamespace))
2731                         InitTempTableNamespace();
2732                 return myTempNamespace;
2733         }
2734
2735         namespaceId = get_namespace_oid(nspname, false);
2736
2737         aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
2738         if (aclresult != ACLCHECK_OK)
2739                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
2740                                            nspname);
2741
2742         return namespaceId;
2743 }
2744
2745 /*
2746  * Common checks on switching namespaces.
2747  *
2748  * We complain if (1) the old and new namespaces are the same, (2) either the
2749  * old or new namespaces is a temporary schema (or temporary toast schema), or
2750  * (3) either the old or new namespaces is the TOAST schema.
2751  */
2752 void
2753 CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid, Oid objid)
2754 {
2755         if (oldNspOid == nspOid)
2756                 ereport(ERROR,
2757                                 (classid == RelationRelationId ?
2758                                  errcode(ERRCODE_DUPLICATE_TABLE) :
2759                                  classid == ProcedureRelationId ?
2760                                  errcode(ERRCODE_DUPLICATE_FUNCTION) :
2761                                  errcode(ERRCODE_DUPLICATE_OBJECT),
2762                                  errmsg("%s is already in schema \"%s\"",
2763                                                 getObjectDescriptionOids(classid, objid),
2764                                                 get_namespace_name(nspOid))));
2765
2766         /* disallow renaming into or out of temp schemas */
2767         if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
2768                 ereport(ERROR,
2769                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2770                         errmsg("cannot move objects into or out of temporary schemas")));
2771
2772         /* same for TOAST schema */
2773         if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
2774                 ereport(ERROR,
2775                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2776                                  errmsg("cannot move objects into or out of TOAST schema")));
2777 }
2778
2779 /*
2780  * QualifiedNameGetCreationNamespace
2781  *              Given a possibly-qualified name for an object (in List-of-Values
2782  *              format), determine what namespace the object should be created in.
2783  *              Also extract and return the object name (last component of list).
2784  *
2785  * Note: this does not apply any permissions check.  Callers must check
2786  * for CREATE rights on the selected namespace when appropriate.
2787  *
2788  * Note: calling this may result in a CommandCounterIncrement operation,
2789  * if we have to create or clean out the temp namespace.
2790  */
2791 Oid
2792 QualifiedNameGetCreationNamespace(List *names, char **objname_p)
2793 {
2794         char       *schemaname;
2795         Oid                     namespaceId;
2796
2797         /* deconstruct the name list */
2798         DeconstructQualifiedName(names, &schemaname, objname_p);
2799
2800         if (schemaname)
2801         {
2802                 /* check for pg_temp alias */
2803                 if (strcmp(schemaname, "pg_temp") == 0)
2804                 {
2805                         /* Initialize temp namespace if first time through */
2806                         if (!OidIsValid(myTempNamespace))
2807                                 InitTempTableNamespace();
2808                         return myTempNamespace;
2809                 }
2810                 /* use exact schema given */
2811                 namespaceId = get_namespace_oid(schemaname, false);
2812                 /* we do not check for USAGE rights here! */
2813         }
2814         else
2815         {
2816                 /* use the default creation namespace */
2817                 recomputeNamespacePath();
2818                 if (activeTempCreationPending)
2819                 {
2820                         /* Need to initialize temp namespace */
2821                         InitTempTableNamespace();
2822                         return myTempNamespace;
2823                 }
2824                 namespaceId = activeCreationNamespace;
2825                 if (!OidIsValid(namespaceId))
2826                         ereport(ERROR,
2827                                         (errcode(ERRCODE_UNDEFINED_SCHEMA),
2828                                          errmsg("no schema has been selected to create in")));
2829         }
2830
2831         return namespaceId;
2832 }
2833
2834 /*
2835  * get_namespace_oid - given a namespace name, look up the OID
2836  *
2837  * If missing_ok is false, throw an error if namespace name not found.  If
2838  * true, just return InvalidOid.
2839  */
2840 Oid
2841 get_namespace_oid(const char *nspname, bool missing_ok)
2842 {
2843         Oid                     oid;
2844
2845         oid = GetSysCacheOid1(NAMESPACENAME, CStringGetDatum(nspname));
2846         if (!OidIsValid(oid) && !missing_ok)
2847                 ereport(ERROR,
2848                                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
2849                                  errmsg("schema \"%s\" does not exist", nspname)));
2850
2851         return oid;
2852 }
2853
2854 /*
2855  * makeRangeVarFromNameList
2856  *              Utility routine to convert a qualified-name list into RangeVar form.
2857  */
2858 RangeVar *
2859 makeRangeVarFromNameList(List *names)
2860 {
2861         RangeVar   *rel = makeRangeVar(NULL, NULL, -1);
2862
2863         switch (list_length(names))
2864         {
2865                 case 1:
2866                         rel->relname = strVal(linitial(names));
2867                         break;
2868                 case 2:
2869                         rel->schemaname = strVal(linitial(names));
2870                         rel->relname = strVal(lsecond(names));
2871                         break;
2872                 case 3:
2873                         rel->catalogname = strVal(linitial(names));
2874                         rel->schemaname = strVal(lsecond(names));
2875                         rel->relname = strVal(lthird(names));
2876                         break;
2877                 default:
2878                         ereport(ERROR,
2879                                         (errcode(ERRCODE_SYNTAX_ERROR),
2880                                  errmsg("improper relation name (too many dotted names): %s",
2881                                                 NameListToString(names))));
2882                         break;
2883         }
2884
2885         return rel;
2886 }
2887
2888 /*
2889  * NameListToString
2890  *              Utility routine to convert a qualified-name list into a string.
2891  *
2892  * This is used primarily to form error messages, and so we do not quote
2893  * the list elements, for the sake of legibility.
2894  *
2895  * In most scenarios the list elements should always be Value strings,
2896  * but we also allow A_Star for the convenience of ColumnRef processing.
2897  */
2898 char *
2899 NameListToString(List *names)
2900 {
2901         StringInfoData string;
2902         ListCell   *l;
2903
2904         initStringInfo(&string);
2905
2906         foreach(l, names)
2907         {
2908                 Node       *name = (Node *) lfirst(l);
2909
2910                 if (l != list_head(names))
2911                         appendStringInfoChar(&string, '.');
2912
2913                 if (IsA(name, String))
2914                         appendStringInfoString(&string, strVal(name));
2915                 else if (IsA(name, A_Star))
2916                         appendStringInfoString(&string, "*");
2917                 else
2918                         elog(ERROR, "unexpected node type in name list: %d",
2919                                  (int) nodeTag(name));
2920         }
2921
2922         return string.data;
2923 }
2924
2925 /*
2926  * NameListToQuotedString
2927  *              Utility routine to convert a qualified-name list into a string.
2928  *
2929  * Same as above except that names will be double-quoted where necessary,
2930  * so the string could be re-parsed (eg, by textToQualifiedNameList).
2931  */
2932 char *
2933 NameListToQuotedString(List *names)
2934 {
2935         StringInfoData string;
2936         ListCell   *l;
2937
2938         initStringInfo(&string);
2939
2940         foreach(l, names)
2941         {
2942                 if (l != list_head(names))
2943                         appendStringInfoChar(&string, '.');
2944                 appendStringInfoString(&string, quote_identifier(strVal(lfirst(l))));
2945         }
2946
2947         return string.data;
2948 }
2949
2950 /*
2951  * isTempNamespace - is the given namespace my temporary-table namespace?
2952  */
2953 bool
2954 isTempNamespace(Oid namespaceId)
2955 {
2956         if (OidIsValid(myTempNamespace) && myTempNamespace == namespaceId)
2957                 return true;
2958         return false;
2959 }
2960
2961 /*
2962  * isTempToastNamespace - is the given namespace my temporary-toast-table
2963  *              namespace?
2964  */
2965 bool
2966 isTempToastNamespace(Oid namespaceId)
2967 {
2968         if (OidIsValid(myTempToastNamespace) && myTempToastNamespace == namespaceId)
2969                 return true;
2970         return false;
2971 }
2972
2973 /*
2974  * isTempOrToastNamespace - is the given namespace my temporary-table
2975  *              namespace or my temporary-toast-table namespace?
2976  */
2977 bool
2978 isTempOrToastNamespace(Oid namespaceId)
2979 {
2980         if (OidIsValid(myTempNamespace) &&
2981          (myTempNamespace == namespaceId || myTempToastNamespace == namespaceId))
2982                 return true;
2983         return false;
2984 }
2985
2986 /*
2987  * isAnyTempNamespace - is the given namespace a temporary-table namespace
2988  * (either my own, or another backend's)?  Temporary-toast-table namespaces
2989  * are included, too.
2990  */
2991 bool
2992 isAnyTempNamespace(Oid namespaceId)
2993 {
2994         bool            result;
2995         char       *nspname;
2996
2997         /* True if the namespace name starts with "pg_temp_" or "pg_toast_temp_" */
2998         nspname = get_namespace_name(namespaceId);
2999         if (!nspname)
3000                 return false;                   /* no such namespace? */
3001         result = (strncmp(nspname, "pg_temp_", 8) == 0) ||
3002                 (strncmp(nspname, "pg_toast_temp_", 14) == 0);
3003         pfree(nspname);
3004         return result;
3005 }
3006
3007 /*
3008  * isOtherTempNamespace - is the given namespace some other backend's
3009  * temporary-table namespace (including temporary-toast-table namespaces)?
3010  *
3011  * Note: for most purposes in the C code, this function is obsolete.  Use
3012  * RELATION_IS_OTHER_TEMP() instead to detect non-local temp relations.
3013  */
3014 bool
3015 isOtherTempNamespace(Oid namespaceId)
3016 {
3017         /* If it's my own temp namespace, say "false" */
3018         if (isTempOrToastNamespace(namespaceId))
3019                 return false;
3020         /* Else, if it's any temp namespace, say "true" */
3021         return isAnyTempNamespace(namespaceId);
3022 }
3023
3024 /*
3025  * GetTempNamespaceBackendId - if the given namespace is a temporary-table
3026  * namespace (either my own, or another backend's), return the BackendId
3027  * that owns it.  Temporary-toast-table namespaces are included, too.
3028  * If it isn't a temp namespace, return InvalidBackendId.
3029  */
3030 int
3031 GetTempNamespaceBackendId(Oid namespaceId)
3032 {
3033         int                     result;
3034         char       *nspname;
3035
3036         /* See if the namespace name starts with "pg_temp_" or "pg_toast_temp_" */
3037         nspname = get_namespace_name(namespaceId);
3038         if (!nspname)
3039                 return InvalidBackendId;        /* no such namespace? */
3040         if (strncmp(nspname, "pg_temp_", 8) == 0)
3041                 result = atoi(nspname + 8);
3042         else if (strncmp(nspname, "pg_toast_temp_", 14) == 0)
3043                 result = atoi(nspname + 14);
3044         else
3045                 result = InvalidBackendId;
3046         pfree(nspname);
3047         return result;
3048 }
3049
3050 /*
3051  * GetTempToastNamespace - get the OID of my temporary-toast-table namespace,
3052  * which must already be assigned.      (This is only used when creating a toast
3053  * table for a temp table, so we must have already done InitTempTableNamespace)
3054  */
3055 Oid
3056 GetTempToastNamespace(void)
3057 {
3058         Assert(OidIsValid(myTempToastNamespace));
3059         return myTempToastNamespace;
3060 }
3061
3062
3063 /*
3064  * GetOverrideSearchPath - fetch current search path definition in form
3065  * used by PushOverrideSearchPath.
3066  *
3067  * The result structure is allocated in the specified memory context
3068  * (which might or might not be equal to CurrentMemoryContext); but any
3069  * junk created by revalidation calculations will be in CurrentMemoryContext.
3070  */
3071 OverrideSearchPath *
3072 GetOverrideSearchPath(MemoryContext context)
3073 {
3074         OverrideSearchPath *result;
3075         List       *schemas;
3076         MemoryContext oldcxt;
3077
3078         recomputeNamespacePath();
3079
3080         oldcxt = MemoryContextSwitchTo(context);
3081
3082         result = (OverrideSearchPath *) palloc0(sizeof(OverrideSearchPath));
3083         schemas = list_copy(activeSearchPath);
3084         while (schemas && linitial_oid(schemas) != activeCreationNamespace)
3085         {
3086                 if (linitial_oid(schemas) == myTempNamespace)
3087                         result->addTemp = true;
3088                 else
3089                 {
3090                         Assert(linitial_oid(schemas) == PG_CATALOG_NAMESPACE);
3091                         result->addCatalog = true;
3092                 }
3093                 schemas = list_delete_first(schemas);
3094         }
3095         result->schemas = schemas;
3096
3097         MemoryContextSwitchTo(oldcxt);
3098
3099         return result;
3100 }
3101
3102 /*
3103  * CopyOverrideSearchPath - copy the specified OverrideSearchPath.
3104  *
3105  * The result structure is allocated in CurrentMemoryContext.
3106  */
3107 OverrideSearchPath *
3108 CopyOverrideSearchPath(OverrideSearchPath *path)
3109 {
3110         OverrideSearchPath *result;
3111
3112         result = (OverrideSearchPath *) palloc(sizeof(OverrideSearchPath));
3113         result->schemas = list_copy(path->schemas);
3114         result->addCatalog = path->addCatalog;
3115         result->addTemp = path->addTemp;
3116
3117         return result;
3118 }
3119
3120 /*
3121  * OverrideSearchPathMatchesCurrent - does path match current setting?
3122  */
3123 bool
3124 OverrideSearchPathMatchesCurrent(OverrideSearchPath *path)
3125 {
3126         /* Easiest way to do this is GetOverrideSearchPath() and compare */
3127         bool            result;
3128         OverrideSearchPath *cur;
3129
3130         cur = GetOverrideSearchPath(CurrentMemoryContext);
3131         if (path->addCatalog == cur->addCatalog &&
3132                 path->addTemp == cur->addTemp &&
3133                 equal(path->schemas, cur->schemas))
3134                 result = true;
3135         else
3136                 result = false;
3137         list_free(cur->schemas);
3138         pfree(cur);
3139         return result;
3140 }
3141
3142 /*
3143  * PushOverrideSearchPath - temporarily override the search path
3144  *
3145  * We allow nested overrides, hence the push/pop terminology.  The GUC
3146  * search_path variable is ignored while an override is active.
3147  *
3148  * It's possible that newpath->useTemp is set but there is no longer any
3149  * active temp namespace, if the path was saved during a transaction that
3150  * created a temp namespace and was later rolled back.  In that case we just
3151  * ignore useTemp.      A plausible alternative would be to create a new temp
3152  * namespace, but for existing callers that's not necessary because an empty
3153  * temp namespace wouldn't affect their results anyway.
3154  *
3155  * It's also worth noting that other schemas listed in newpath might not
3156  * exist anymore either.  We don't worry about this because OIDs that match
3157  * no existing namespace will simply not produce any hits during searches.
3158  */
3159 void
3160 PushOverrideSearchPath(OverrideSearchPath *newpath)
3161 {
3162         OverrideStackEntry *entry;
3163         List       *oidlist;
3164         Oid                     firstNS;
3165         MemoryContext oldcxt;
3166
3167         /*
3168          * Copy the list for safekeeping, and insert implicitly-searched
3169          * namespaces as needed.  This code should track recomputeNamespacePath.
3170          */
3171         oldcxt = MemoryContextSwitchTo(TopMemoryContext);
3172
3173         oidlist = list_copy(newpath->schemas);
3174
3175         /*
3176          * Remember the first member of the explicit list.
3177          */
3178         if (oidlist == NIL)
3179                 firstNS = InvalidOid;
3180         else
3181                 firstNS = linitial_oid(oidlist);
3182
3183         /*
3184          * Add any implicitly-searched namespaces to the list.  Note these go on
3185          * the front, not the back; also notice that we do not check USAGE
3186          * permissions for these.
3187          */
3188         if (newpath->addCatalog)
3189                 oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist);
3190
3191         if (newpath->addTemp && OidIsValid(myTempNamespace))
3192                 oidlist = lcons_oid(myTempNamespace, oidlist);
3193
3194         /*
3195          * Build the new stack entry, then insert it at the head of the list.
3196          */
3197         entry = (OverrideStackEntry *) palloc(sizeof(OverrideStackEntry));
3198         entry->searchPath = oidlist;
3199         entry->creationNamespace = firstNS;
3200         entry->nestLevel = GetCurrentTransactionNestLevel();
3201
3202         overrideStack = lcons(entry, overrideStack);
3203
3204         /* And make it active. */
3205         activeSearchPath = entry->searchPath;
3206         activeCreationNamespace = entry->creationNamespace;
3207         activeTempCreationPending = false;      /* XXX is this OK? */
3208
3209         MemoryContextSwitchTo(oldcxt);
3210 }
3211
3212 /*
3213  * PopOverrideSearchPath - undo a previous PushOverrideSearchPath
3214  *
3215  * Any push during a (sub)transaction will be popped automatically at abort.
3216  * But it's caller error if a push isn't popped in normal control flow.
3217  */
3218 void
3219 PopOverrideSearchPath(void)
3220 {
3221         OverrideStackEntry *entry;
3222
3223         /* Sanity checks. */
3224         if (overrideStack == NIL)
3225                 elog(ERROR, "bogus PopOverrideSearchPath call");
3226         entry = (OverrideStackEntry *) linitial(overrideStack);
3227         if (entry->nestLevel != GetCurrentTransactionNestLevel())
3228                 elog(ERROR, "bogus PopOverrideSearchPath call");
3229
3230         /* Pop the stack and free storage. */
3231         overrideStack = list_delete_first(overrideStack);
3232         list_free(entry->searchPath);
3233         pfree(entry);
3234
3235         /* Activate the next level down. */
3236         if (overrideStack)
3237         {
3238                 entry = (OverrideStackEntry *) linitial(overrideStack);
3239                 activeSearchPath = entry->searchPath;
3240                 activeCreationNamespace = entry->creationNamespace;
3241                 activeTempCreationPending = false;              /* XXX is this OK? */
3242         }
3243         else
3244         {
3245                 /* If not baseSearchPathValid, this is useless but harmless */
3246                 activeSearchPath = baseSearchPath;
3247                 activeCreationNamespace = baseCreationNamespace;
3248                 activeTempCreationPending = baseTempCreationPending;
3249         }
3250 }
3251
3252
3253 /*
3254  * get_collation_oid - find a collation by possibly qualified name
3255  */
3256 Oid
3257 get_collation_oid(List *name, bool missing_ok)
3258 {
3259         char       *schemaname;
3260         char       *collation_name;
3261         int32           dbencoding = GetDatabaseEncoding();
3262         Oid                     namespaceId;
3263         Oid                     colloid;
3264         ListCell   *l;
3265
3266         /* deconstruct the name list */
3267         DeconstructQualifiedName(name, &schemaname, &collation_name);
3268
3269         if (schemaname)
3270         {
3271                 /* use exact schema given */
3272                 namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
3273                 if (missing_ok && !OidIsValid(namespaceId))
3274                         return InvalidOid;
3275
3276                 /* first try for encoding-specific entry, then any-encoding */
3277                 colloid = GetSysCacheOid3(COLLNAMEENCNSP,
3278                                                                   PointerGetDatum(collation_name),
3279                                                                   Int32GetDatum(dbencoding),
3280                                                                   ObjectIdGetDatum(namespaceId));
3281                 if (OidIsValid(colloid))
3282                         return colloid;
3283                 colloid = GetSysCacheOid3(COLLNAMEENCNSP,
3284                                                                   PointerGetDatum(collation_name),
3285                                                                   Int32GetDatum(-1),
3286                                                                   ObjectIdGetDatum(namespaceId));
3287                 if (OidIsValid(colloid))
3288                         return colloid;
3289         }
3290         else
3291         {
3292                 /* search for it in search path */
3293                 recomputeNamespacePath();
3294
3295                 foreach(l, activeSearchPath)
3296                 {
3297                         namespaceId = lfirst_oid(l);
3298
3299                         if (namespaceId == myTempNamespace)
3300                                 continue;               /* do not look in temp namespace */
3301
3302                         colloid = GetSysCacheOid3(COLLNAMEENCNSP,
3303                                                                           PointerGetDatum(collation_name),
3304                                                                           Int32GetDatum(dbencoding),
3305                                                                           ObjectIdGetDatum(namespaceId));
3306                         if (OidIsValid(colloid))
3307                                 return colloid;
3308                         colloid = GetSysCacheOid3(COLLNAMEENCNSP,
3309                                                                           PointerGetDatum(collation_name),
3310                                                                           Int32GetDatum(-1),
3311                                                                           ObjectIdGetDatum(namespaceId));
3312                         if (OidIsValid(colloid))
3313                                 return colloid;
3314                 }
3315         }
3316
3317         /* Not found in path */
3318         if (!missing_ok)
3319                 ereport(ERROR,
3320                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
3321                                  errmsg("collation \"%s\" for encoding \"%s\" does not exist",
3322                                                 NameListToString(name), GetDatabaseEncodingName())));
3323         return InvalidOid;
3324 }
3325
3326 /*
3327  * get_conversion_oid - find a conversion by possibly qualified name
3328  */
3329 Oid
3330 get_conversion_oid(List *name, bool missing_ok)
3331 {
3332         char       *schemaname;
3333         char       *conversion_name;
3334         Oid                     namespaceId;
3335         Oid                     conoid = InvalidOid;
3336         ListCell   *l;
3337
3338         /* deconstruct the name list */
3339         DeconstructQualifiedName(name, &schemaname, &conversion_name);
3340
3341         if (schemaname)
3342         {
3343                 /* use exact schema given */
3344                 namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
3345                 if (missing_ok && !OidIsValid(namespaceId))
3346                         conoid = InvalidOid;
3347                 else
3348                         conoid = GetSysCacheOid2(CONNAMENSP,
3349                                                                          PointerGetDatum(conversion_name),
3350                                                                          ObjectIdGetDatum(namespaceId));
3351         }
3352         else
3353         {
3354                 /* search for it in search path */
3355                 recomputeNamespacePath();
3356
3357                 foreach(l, activeSearchPath)
3358                 {
3359                         namespaceId = lfirst_oid(l);
3360
3361                         if (namespaceId == myTempNamespace)
3362                                 continue;               /* do not look in temp namespace */
3363
3364                         conoid = GetSysCacheOid2(CONNAMENSP,
3365                                                                          PointerGetDatum(conversion_name),
3366                                                                          ObjectIdGetDatum(namespaceId));
3367                         if (OidIsValid(conoid))
3368                                 return conoid;
3369                 }
3370         }
3371
3372         /* Not found in path */
3373         if (!OidIsValid(conoid) && !missing_ok)
3374                 ereport(ERROR,
3375                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
3376                                  errmsg("conversion \"%s\" does not exist",
3377                                                 NameListToString(name))));
3378         return conoid;
3379 }
3380
3381 /*
3382  * FindDefaultConversionProc - find default encoding conversion proc
3383  */
3384 Oid
3385 FindDefaultConversionProc(int32 for_encoding, int32 to_encoding)
3386 {
3387         Oid                     proc;
3388         ListCell   *l;
3389
3390         recomputeNamespacePath();
3391
3392         foreach(l, activeSearchPath)
3393         {
3394                 Oid                     namespaceId = lfirst_oid(l);
3395
3396                 if (namespaceId == myTempNamespace)
3397                         continue;                       /* do not look in temp namespace */
3398
3399                 proc = FindDefaultConversion(namespaceId, for_encoding, to_encoding);
3400                 if (OidIsValid(proc))
3401                         return proc;
3402         }
3403
3404         /* Not found in path */
3405         return InvalidOid;
3406 }
3407
3408 /*
3409  * recomputeNamespacePath - recompute path derived variables if needed.
3410  */
3411 static void
3412 recomputeNamespacePath(void)
3413 {
3414         Oid                     roleid = GetUserId();
3415         char       *rawname;
3416         List       *namelist;
3417         List       *oidlist;
3418         List       *newpath;
3419         ListCell   *l;
3420         bool            temp_missing;
3421         Oid                     firstNS;
3422         MemoryContext oldcxt;
3423
3424         /* Do nothing if an override search spec is active. */
3425         if (overrideStack)
3426                 return;
3427
3428         /* Do nothing if path is already valid. */
3429         if (baseSearchPathValid && namespaceUser == roleid)
3430                 return;
3431
3432         /* Need a modifiable copy of namespace_search_path string */
3433         rawname = pstrdup(namespace_search_path);
3434
3435         /* Parse string into list of identifiers */
3436         if (!SplitIdentifierString(rawname, ',', &namelist))
3437         {
3438                 /* syntax error in name list */
3439                 /* this should not happen if GUC checked check_search_path */
3440                 elog(ERROR, "invalid list syntax");
3441         }
3442
3443         /*
3444          * Convert the list of names to a list of OIDs.  If any names are not
3445          * recognizable or we don't have read access, just leave them out of the
3446          * list.  (We can't raise an error, since the search_path setting has
3447          * already been accepted.)      Don't make duplicate entries, either.
3448          */
3449         oidlist = NIL;
3450         temp_missing = false;
3451         foreach(l, namelist)
3452         {
3453                 char       *curname = (char *) lfirst(l);
3454                 Oid                     namespaceId;
3455
3456                 if (strcmp(curname, "$user") == 0)
3457                 {
3458                         /* $user --- substitute namespace matching user name, if any */
3459                         HeapTuple       tuple;
3460
3461                         tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
3462                         if (HeapTupleIsValid(tuple))
3463                         {
3464                                 char       *rname;
3465
3466                                 rname = NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname);
3467                                 namespaceId = get_namespace_oid(rname, true);
3468                                 ReleaseSysCache(tuple);
3469                                 if (OidIsValid(namespaceId) &&
3470                                         !list_member_oid(oidlist, namespaceId) &&
3471                                         pg_namespace_aclcheck(namespaceId, roleid,
3472                                                                                   ACL_USAGE) == ACLCHECK_OK)
3473                                         oidlist = lappend_oid(oidlist, namespaceId);
3474                         }
3475                 }
3476                 else if (strcmp(curname, "pg_temp") == 0)
3477                 {
3478                         /* pg_temp --- substitute temp namespace, if any */
3479                         if (OidIsValid(myTempNamespace))
3480                         {
3481                                 if (!list_member_oid(oidlist, myTempNamespace))
3482                                         oidlist = lappend_oid(oidlist, myTempNamespace);
3483                         }
3484                         else
3485                         {
3486                                 /* If it ought to be the creation namespace, set flag */
3487                                 if (oidlist == NIL)
3488                                         temp_missing = true;
3489                         }
3490                 }
3491                 else
3492                 {
3493                         /* normal namespace reference */
3494                         namespaceId = get_namespace_oid(curname, true);
3495                         if (OidIsValid(namespaceId) &&
3496                                 !list_member_oid(oidlist, namespaceId) &&
3497                                 pg_namespace_aclcheck(namespaceId, roleid,
3498                                                                           ACL_USAGE) == ACLCHECK_OK)
3499                                 oidlist = lappend_oid(oidlist, namespaceId);
3500                 }
3501         }
3502
3503         /*
3504          * Remember the first member of the explicit list.      (Note: this is
3505          * nominally wrong if temp_missing, but we need it anyway to distinguish
3506          * explicit from implicit mention of pg_catalog.)
3507          */
3508         if (oidlist == NIL)
3509                 firstNS = InvalidOid;
3510         else
3511                 firstNS = linitial_oid(oidlist);
3512
3513         /*
3514          * Add any implicitly-searched namespaces to the list.  Note these go on
3515          * the front, not the back; also notice that we do not check USAGE
3516          * permissions for these.
3517          */
3518         if (!list_member_oid(oidlist, PG_CATALOG_NAMESPACE))
3519                 oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist);
3520
3521         if (OidIsValid(myTempNamespace) &&
3522                 !list_member_oid(oidlist, myTempNamespace))
3523                 oidlist = lcons_oid(myTempNamespace, oidlist);
3524
3525         /*
3526          * Now that we've successfully built the new list of namespace OIDs, save
3527          * it in permanent storage.
3528          */
3529         oldcxt = MemoryContextSwitchTo(TopMemoryContext);
3530         newpath = list_copy(oidlist);
3531         MemoryContextSwitchTo(oldcxt);
3532
3533         /* Now safe to assign to state variables. */
3534         list_free(baseSearchPath);
3535         baseSearchPath = newpath;
3536         baseCreationNamespace = firstNS;
3537         baseTempCreationPending = temp_missing;
3538
3539         /* Mark the path valid. */
3540         baseSearchPathValid = true;
3541         namespaceUser = roleid;
3542
3543         /* And make it active. */
3544         activeSearchPath = baseSearchPath;
3545         activeCreationNamespace = baseCreationNamespace;
3546         activeTempCreationPending = baseTempCreationPending;
3547
3548         /* Clean up. */
3549         pfree(rawname);
3550         list_free(namelist);
3551         list_free(oidlist);
3552 }
3553
3554 /*
3555  * InitTempTableNamespace
3556  *              Initialize temp table namespace on first use in a particular backend
3557  */
3558 static void
3559 InitTempTableNamespace(void)
3560 {
3561         char            namespaceName[NAMEDATALEN];
3562         Oid                     namespaceId;
3563         Oid                     toastspaceId;
3564
3565         Assert(!OidIsValid(myTempNamespace));
3566
3567         /*
3568          * First, do permission check to see if we are authorized to make temp
3569          * tables.      We use a nonstandard error message here since "databasename:
3570          * permission denied" might be a tad cryptic.
3571          *
3572          * Note that ACL_CREATE_TEMP rights are rechecked in pg_namespace_aclmask;
3573          * that's necessary since current user ID could change during the session.
3574          * But there's no need to make the namespace in the first place until a
3575          * temp table creation request is made by someone with appropriate rights.
3576          */
3577         if (pg_database_aclcheck(MyDatabaseId, GetUserId(),
3578                                                          ACL_CREATE_TEMP) != ACLCHECK_OK)
3579                 ereport(ERROR,
3580                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3581                                  errmsg("permission denied to create temporary tables in database \"%s\"",
3582                                                 get_database_name(MyDatabaseId))));
3583
3584         /*
3585          * Do not allow a Hot Standby slave session to make temp tables.  Aside
3586          * from problems with modifying the system catalogs, there is a naming
3587          * conflict: pg_temp_N belongs to the session with BackendId N on the
3588          * master, not to a slave session with the same BackendId.      We should not
3589          * be able to get here anyway due to XactReadOnly checks, but let's just
3590          * make real sure.      Note that this also backstops various operations that
3591          * allow XactReadOnly transactions to modify temp tables; they'd need
3592          * RecoveryInProgress checks if not for this.
3593          */
3594         if (RecoveryInProgress())
3595                 ereport(ERROR,
3596                                 (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
3597                                  errmsg("cannot create temporary tables during recovery")));
3598
3599         snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId);
3600
3601         namespaceId = get_namespace_oid(namespaceName, true);
3602         if (!OidIsValid(namespaceId))
3603         {
3604                 /*
3605                  * First use of this temp namespace in this database; create it. The
3606                  * temp namespaces are always owned by the superuser.  We leave their
3607                  * permissions at default --- i.e., no access except to superuser ---
3608                  * to ensure that unprivileged users can't peek at other backends'
3609                  * temp tables.  This works because the places that access the temp
3610                  * namespace for my own backend skip permissions checks on it.
3611                  */
3612                 namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID,
3613                                                                           true);
3614                 /* Advance command counter to make namespace visible */
3615                 CommandCounterIncrement();
3616         }
3617         else
3618         {
3619                 /*
3620                  * If the namespace already exists, clean it out (in case the former
3621                  * owner crashed without doing so).
3622                  */
3623                 RemoveTempRelations(namespaceId);
3624         }
3625
3626         /*
3627          * If the corresponding toast-table namespace doesn't exist yet, create
3628          * it. (We assume there is no need to clean it out if it does exist, since
3629          * dropping a parent table should make its toast table go away.)
3630          */
3631         snprintf(namespaceName, sizeof(namespaceName), "pg_toast_temp_%d",
3632                          MyBackendId);
3633
3634         toastspaceId = get_namespace_oid(namespaceName, true);
3635         if (!OidIsValid(toastspaceId))
3636         {
3637                 toastspaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID,
3638                                                                            true);
3639                 /* Advance command counter to make namespace visible */
3640                 CommandCounterIncrement();
3641         }
3642
3643         /*
3644          * Okay, we've prepared the temp namespace ... but it's not committed yet,
3645          * so all our work could be undone by transaction rollback.  Set flag for
3646          * AtEOXact_Namespace to know what to do.
3647          */
3648         myTempNamespace = namespaceId;
3649         myTempToastNamespace = toastspaceId;
3650
3651         /* It should not be done already. */
3652         AssertState(myTempNamespaceSubID == InvalidSubTransactionId);
3653         myTempNamespaceSubID = GetCurrentSubTransactionId();
3654
3655         baseSearchPathValid = false;    /* need to rebuild list */
3656 }
3657
3658 /*
3659  * End-of-transaction cleanup for namespaces.
3660  */
3661 void
3662 AtEOXact_Namespace(bool isCommit)
3663 {
3664         /*
3665          * If we abort the transaction in which a temp namespace was selected,
3666          * we'll have to do any creation or cleanout work over again.  So, just
3667          * forget the namespace entirely until next time.  On the other hand, if
3668          * we commit then register an exit callback to clean out the temp tables
3669          * at backend shutdown.  (We only want to register the callback once per
3670          * session, so this is a good place to do it.)
3671          */
3672         if (myTempNamespaceSubID != InvalidSubTransactionId)
3673         {
3674                 if (isCommit)
3675                         on_shmem_exit(RemoveTempRelationsCallback, 0);
3676                 else
3677                 {
3678                         myTempNamespace = InvalidOid;
3679                         myTempToastNamespace = InvalidOid;
3680                         baseSearchPathValid = false;            /* need to rebuild list */
3681                 }
3682                 myTempNamespaceSubID = InvalidSubTransactionId;
3683         }
3684
3685         /*
3686          * Clean up if someone failed to do PopOverrideSearchPath
3687          */
3688         if (overrideStack)
3689         {
3690                 if (isCommit)
3691                         elog(WARNING, "leaked override search path");
3692                 while (overrideStack)
3693                 {
3694                         OverrideStackEntry *entry;
3695
3696                         entry = (OverrideStackEntry *) linitial(overrideStack);
3697                         overrideStack = list_delete_first(overrideStack);
3698                         list_free(entry->searchPath);
3699                         pfree(entry);
3700                 }
3701                 /* If not baseSearchPathValid, this is useless but harmless */
3702                 activeSearchPath = baseSearchPath;
3703                 activeCreationNamespace = baseCreationNamespace;
3704                 activeTempCreationPending = baseTempCreationPending;
3705         }
3706 }
3707
3708 /*
3709  * AtEOSubXact_Namespace
3710  *
3711  * At subtransaction commit, propagate the temp-namespace-creation
3712  * flag to the parent subtransaction.
3713  *
3714  * At subtransaction abort, forget the flag if we set it up.
3715  */
3716 void
3717 AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid,
3718                                           SubTransactionId parentSubid)
3719 {
3720         OverrideStackEntry *entry;
3721
3722         if (myTempNamespaceSubID == mySubid)
3723         {
3724                 if (isCommit)
3725                         myTempNamespaceSubID = parentSubid;
3726                 else
3727                 {
3728                         myTempNamespaceSubID = InvalidSubTransactionId;
3729                         /* TEMP namespace creation failed, so reset state */
3730                         myTempNamespace = InvalidOid;
3731                         myTempToastNamespace = InvalidOid;
3732                         baseSearchPathValid = false;            /* need to rebuild list */
3733                 }
3734         }
3735
3736         /*
3737          * Clean up if someone failed to do PopOverrideSearchPath
3738          */
3739         while (overrideStack)
3740         {
3741                 entry = (OverrideStackEntry *) linitial(overrideStack);
3742                 if (entry->nestLevel < GetCurrentTransactionNestLevel())
3743                         break;
3744                 if (isCommit)
3745                         elog(WARNING, "leaked override search path");
3746                 overrideStack = list_delete_first(overrideStack);
3747                 list_free(entry->searchPath);
3748                 pfree(entry);
3749         }
3750
3751         /* Activate the next level down. */
3752         if (overrideStack)
3753         {
3754                 entry = (OverrideStackEntry *) linitial(overrideStack);
3755                 activeSearchPath = entry->searchPath;
3756                 activeCreationNamespace = entry->creationNamespace;
3757                 activeTempCreationPending = false;              /* XXX is this OK? */
3758         }
3759         else
3760         {
3761                 /* If not baseSearchPathValid, this is useless but harmless */
3762                 activeSearchPath = baseSearchPath;
3763                 activeCreationNamespace = baseCreationNamespace;
3764                 activeTempCreationPending = baseTempCreationPending;
3765         }
3766 }
3767
3768 /*
3769  * Remove all relations in the specified temp namespace.
3770  *
3771  * This is called at backend shutdown (if we made any temp relations).
3772  * It is also called when we begin using a pre-existing temp namespace,
3773  * in order to clean out any relations that might have been created by
3774  * a crashed backend.
3775  */
3776 static void
3777 RemoveTempRelations(Oid tempNamespaceId)
3778 {
3779         ObjectAddress object;
3780
3781         /*
3782          * We want to get rid of everything in the target namespace, but not the
3783          * namespace itself (deleting it only to recreate it later would be a
3784          * waste of cycles).  We do this by finding everything that has a
3785          * dependency on the namespace.
3786          */
3787         object.classId = NamespaceRelationId;
3788         object.objectId = tempNamespaceId;
3789         object.objectSubId = 0;
3790
3791         deleteWhatDependsOn(&object, false);
3792 }
3793
3794 /*
3795  * Callback to remove temp relations at backend exit.
3796  */
3797 static void
3798 RemoveTempRelationsCallback(int code, Datum arg)
3799 {
3800         if (OidIsValid(myTempNamespace))        /* should always be true */
3801         {
3802                 /* Need to ensure we have a usable transaction. */
3803                 AbortOutOfAnyTransaction();
3804                 StartTransactionCommand();
3805
3806                 RemoveTempRelations(myTempNamespace);
3807
3808                 CommitTransactionCommand();
3809         }
3810 }
3811
3812 /*
3813  * Remove all temp tables from the temporary namespace.
3814  */
3815 void
3816 ResetTempTableNamespace(void)
3817 {
3818         if (OidIsValid(myTempNamespace))
3819                 RemoveTempRelations(myTempNamespace);
3820 }
3821
3822
3823 /*
3824  * Routines for handling the GUC variable 'search_path'.
3825  */
3826
3827 /* check_hook: validate new search_path value */
3828 bool
3829 check_search_path(char **newval, void **extra, GucSource source)
3830 {
3831         char       *rawname;
3832         List       *namelist;
3833
3834         /* Need a modifiable copy of string */
3835         rawname = pstrdup(*newval);
3836
3837         /* Parse string into list of identifiers */
3838         if (!SplitIdentifierString(rawname, ',', &namelist))
3839         {
3840                 /* syntax error in name list */
3841                 GUC_check_errdetail("List syntax is invalid.");
3842                 pfree(rawname);
3843                 list_free(namelist);
3844                 return false;
3845         }
3846
3847         /*
3848          * We used to try to check that the named schemas exist, but there are
3849          * many valid use-cases for having search_path settings that include
3850          * schemas that don't exist; and often, we are not inside a transaction
3851          * here and so can't consult the system catalogs anyway.  So now, the only
3852          * requirement is syntactic validity of the identifier list.
3853          */
3854
3855         pfree(rawname);
3856         list_free(namelist);
3857
3858         return true;
3859 }
3860
3861 /* assign_hook: do extra actions as needed */
3862 void
3863 assign_search_path(const char *newval, void *extra)
3864 {
3865         /*
3866          * We mark the path as needing recomputation, but don't do anything until
3867          * it's needed.  This avoids trying to do database access during GUC
3868          * initialization, or outside a transaction.
3869          */
3870         baseSearchPathValid = false;
3871 }
3872
3873 /*
3874  * InitializeSearchPath: initialize module during InitPostgres.
3875  *
3876  * This is called after we are up enough to be able to do catalog lookups.
3877  */
3878 void
3879 InitializeSearchPath(void)
3880 {
3881         if (IsBootstrapProcessingMode())
3882         {
3883                 /*
3884                  * In bootstrap mode, the search path must be 'pg_catalog' so that
3885                  * tables are created in the proper namespace; ignore the GUC setting.
3886                  */
3887                 MemoryContext oldcxt;
3888
3889                 oldcxt = MemoryContextSwitchTo(TopMemoryContext);
3890                 baseSearchPath = list_make1_oid(PG_CATALOG_NAMESPACE);
3891                 MemoryContextSwitchTo(oldcxt);
3892                 baseCreationNamespace = PG_CATALOG_NAMESPACE;
3893                 baseTempCreationPending = false;
3894                 baseSearchPathValid = true;
3895                 namespaceUser = GetUserId();
3896                 activeSearchPath = baseSearchPath;
3897                 activeCreationNamespace = baseCreationNamespace;
3898                 activeTempCreationPending = baseTempCreationPending;
3899         }
3900         else
3901         {
3902                 /*
3903                  * In normal mode, arrange for a callback on any syscache invalidation
3904                  * of pg_namespace rows.
3905                  */
3906                 CacheRegisterSyscacheCallback(NAMESPACEOID,
3907                                                                           NamespaceCallback,
3908                                                                           (Datum) 0);
3909                 /* Force search path to be recomputed on next use */
3910                 baseSearchPathValid = false;
3911         }
3912 }
3913
3914 /*
3915  * NamespaceCallback
3916  *              Syscache inval callback function
3917  */
3918 static void
3919 NamespaceCallback(Datum arg, int cacheid, uint32 hashvalue)
3920 {
3921         /* Force search path to be recomputed on next use */
3922         baseSearchPathValid = false;
3923 }
3924
3925 /*
3926  * Fetch the active search path. The return value is a palloc'ed list
3927  * of OIDs; the caller is responsible for freeing this storage as
3928  * appropriate.
3929  *
3930  * The returned list includes the implicitly-prepended namespaces only if
3931  * includeImplicit is true.
3932  *
3933  * Note: calling this may result in a CommandCounterIncrement operation,
3934  * if we have to create or clean out the temp namespace.
3935  */
3936 List *
3937 fetch_search_path(bool includeImplicit)
3938 {
3939         List       *result;
3940
3941         recomputeNamespacePath();
3942
3943         /*
3944          * If the temp namespace should be first, force it to exist.  This is so
3945          * that callers can trust the result to reflect the actual default
3946          * creation namespace.  It's a bit bogus to do this here, since
3947          * current_schema() is supposedly a stable function without side-effects,
3948          * but the alternatives seem worse.
3949          */
3950         if (activeTempCreationPending)
3951         {
3952                 InitTempTableNamespace();
3953                 recomputeNamespacePath();
3954         }
3955
3956         result = list_copy(activeSearchPath);
3957         if (!includeImplicit)
3958         {
3959                 while (result && linitial_oid(result) != activeCreationNamespace)
3960                         result = list_delete_first(result);
3961         }
3962
3963         return result;
3964 }
3965
3966 /*
3967  * Fetch the active search path into a caller-allocated array of OIDs.
3968  * Returns the number of path entries.  (If this is more than sarray_len,
3969  * then the data didn't fit and is not all stored.)
3970  *
3971  * The returned list always includes the implicitly-prepended namespaces,
3972  * but never includes the temp namespace.  (This is suitable for existing
3973  * users, which would want to ignore the temp namespace anyway.)  This
3974  * definition allows us to not worry about initializing the temp namespace.
3975  */
3976 int
3977 fetch_search_path_array(Oid *sarray, int sarray_len)
3978 {
3979         int                     count = 0;
3980         ListCell   *l;
3981
3982         recomputeNamespacePath();
3983
3984         foreach(l, activeSearchPath)
3985         {
3986                 Oid                     namespaceId = lfirst_oid(l);
3987
3988                 if (namespaceId == myTempNamespace)
3989                         continue;                       /* do not include temp namespace */
3990
3991                 if (count < sarray_len)
3992                         sarray[count] = namespaceId;
3993                 count++;
3994         }
3995
3996         return count;
3997 }
3998
3999
4000 /*
4001  * Export the FooIsVisible functions as SQL-callable functions.
4002  *
4003  * Note: as of Postgres 8.4, these will silently return NULL if called on
4004  * a nonexistent object OID, rather than failing.  This is to avoid race
4005  * condition errors when a query that's scanning a catalog using an MVCC
4006  * snapshot uses one of these functions.  The underlying IsVisible functions
4007  * operate on SnapshotNow semantics and so might see the object as already
4008  * gone when it's still visible to the MVCC snapshot.  (There is no race
4009  * condition in the current coding because we don't accept sinval messages
4010  * between the SearchSysCacheExists test and the subsequent lookup.)
4011  */
4012
4013 Datum
4014 pg_table_is_visible(PG_FUNCTION_ARGS)
4015 {
4016         Oid                     oid = PG_GETARG_OID(0);
4017
4018         if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(oid)))
4019                 PG_RETURN_NULL();
4020
4021         PG_RETURN_BOOL(RelationIsVisible(oid));
4022 }
4023
4024 Datum
4025 pg_type_is_visible(PG_FUNCTION_ARGS)
4026 {
4027         Oid                     oid = PG_GETARG_OID(0);
4028
4029         if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(oid)))
4030                 PG_RETURN_NULL();
4031
4032         PG_RETURN_BOOL(TypeIsVisible(oid));
4033 }
4034
4035 Datum
4036 pg_function_is_visible(PG_FUNCTION_ARGS)
4037 {
4038         Oid                     oid = PG_GETARG_OID(0);
4039
4040         if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(oid)))
4041                 PG_RETURN_NULL();
4042
4043         PG_RETURN_BOOL(FunctionIsVisible(oid));
4044 }
4045
4046 Datum
4047 pg_operator_is_visible(PG_FUNCTION_ARGS)
4048 {
4049         Oid                     oid = PG_GETARG_OID(0);
4050
4051         if (!SearchSysCacheExists1(OPEROID, ObjectIdGetDatum(oid)))
4052                 PG_RETURN_NULL();
4053
4054         PG_RETURN_BOOL(OperatorIsVisible(oid));
4055 }
4056
4057 Datum
4058 pg_opclass_is_visible(PG_FUNCTION_ARGS)
4059 {
4060         Oid                     oid = PG_GETARG_OID(0);
4061
4062         if (!SearchSysCacheExists1(CLAOID, ObjectIdGetDatum(oid)))
4063                 PG_RETURN_NULL();
4064
4065         PG_RETURN_BOOL(OpclassIsVisible(oid));
4066 }
4067
4068 Datum
4069 pg_opfamily_is_visible(PG_FUNCTION_ARGS)
4070 {
4071         Oid                     oid = PG_GETARG_OID(0);
4072
4073         if (!SearchSysCacheExists1(OPFAMILYOID, ObjectIdGetDatum(oid)))
4074                 PG_RETURN_NULL();
4075
4076         PG_RETURN_BOOL(OpfamilyIsVisible(oid));
4077 }
4078
4079 Datum
4080 pg_collation_is_visible(PG_FUNCTION_ARGS)
4081 {
4082         Oid                     oid = PG_GETARG_OID(0);
4083
4084         if (!SearchSysCacheExists1(COLLOID, ObjectIdGetDatum(oid)))
4085                 PG_RETURN_NULL();
4086
4087         PG_RETURN_BOOL(CollationIsVisible(oid));
4088 }
4089
4090 Datum
4091 pg_conversion_is_visible(PG_FUNCTION_ARGS)
4092 {
4093         Oid                     oid = PG_GETARG_OID(0);
4094
4095         if (!SearchSysCacheExists1(CONVOID, ObjectIdGetDatum(oid)))
4096                 PG_RETURN_NULL();
4097
4098         PG_RETURN_BOOL(ConversionIsVisible(oid));
4099 }
4100
4101 Datum
4102 pg_ts_parser_is_visible(PG_FUNCTION_ARGS)
4103 {
4104         Oid                     oid = PG_GETARG_OID(0);
4105
4106         if (!SearchSysCacheExists1(TSPARSEROID, ObjectIdGetDatum(oid)))
4107                 PG_RETURN_NULL();
4108
4109         PG_RETURN_BOOL(TSParserIsVisible(oid));
4110 }
4111
4112 Datum
4113 pg_ts_dict_is_visible(PG_FUNCTION_ARGS)
4114 {
4115         Oid                     oid = PG_GETARG_OID(0);
4116
4117         if (!SearchSysCacheExists1(TSDICTOID, ObjectIdGetDatum(oid)))
4118                 PG_RETURN_NULL();
4119
4120         PG_RETURN_BOOL(TSDictionaryIsVisible(oid));
4121 }
4122
4123 Datum
4124 pg_ts_template_is_visible(PG_FUNCTION_ARGS)
4125 {
4126         Oid                     oid = PG_GETARG_OID(0);
4127
4128         if (!SearchSysCacheExists1(TSTEMPLATEOID, ObjectIdGetDatum(oid)))
4129                 PG_RETURN_NULL();
4130
4131         PG_RETURN_BOOL(TSTemplateIsVisible(oid));
4132 }
4133
4134 Datum
4135 pg_ts_config_is_visible(PG_FUNCTION_ARGS)
4136 {
4137         Oid                     oid = PG_GETARG_OID(0);
4138
4139         if (!SearchSysCacheExists1(TSCONFIGOID, ObjectIdGetDatum(oid)))
4140                 PG_RETURN_NULL();
4141
4142         PG_RETURN_BOOL(TSConfigIsVisible(oid));
4143 }
4144
4145 Datum
4146 pg_my_temp_schema(PG_FUNCTION_ARGS)
4147 {
4148         PG_RETURN_OID(myTempNamespace);
4149 }
4150
4151 Datum
4152 pg_is_other_temp_schema(PG_FUNCTION_ARGS)
4153 {
4154         Oid                     oid = PG_GETARG_OID(0);
4155
4156         PG_RETURN_BOOL(isOtherTempNamespace(oid));
4157 }