]> granicus.if.org Git - postgresql/blob - src/backend/catalog/namespace.c
Support explicit placement of the temporary-table schema within search_path.
[postgresql] / src / backend / catalog / namespace.c
1 /*-------------------------------------------------------------------------
2  *
3  * namespace.c
4  *        code to support accessing and searching namespaces
5  *
6  * This is separate from pg_namespace.c, which contains the routines that
7  * directly manipulate the pg_namespace system catalog.  This module
8  * provides routines associated with defining a "namespace search path"
9  * and implementing search-path-controlled searches.
10  *
11  *
12  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
13  * Portions Copyright (c) 1994, Regents of the University of California
14  *
15  * IDENTIFICATION
16  *        $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.96 2007/04/20 02:37:37 tgl Exp $
17  *
18  *-------------------------------------------------------------------------
19  */
20 #include "postgres.h"
21
22 #include "access/xact.h"
23 #include "catalog/dependency.h"
24 #include "catalog/namespace.h"
25 #include "catalog/pg_authid.h"
26 #include "catalog/pg_conversion.h"
27 #include "catalog/pg_namespace.h"
28 #include "catalog/pg_opclass.h"
29 #include "catalog/pg_operator.h"
30 #include "catalog/pg_opfamily.h"
31 #include "catalog/pg_proc.h"
32 #include "catalog/pg_type.h"
33 #include "commands/dbcommands.h"
34 #include "miscadmin.h"
35 #include "nodes/makefuncs.h"
36 #include "storage/backendid.h"
37 #include "storage/ipc.h"
38 #include "utils/acl.h"
39 #include "utils/builtins.h"
40 #include "utils/guc.h"
41 #include "utils/inval.h"
42 #include "utils/lsyscache.h"
43 #include "utils/memutils.h"
44 #include "utils/syscache.h"
45
46
47 /*
48  * The namespace search path is a possibly-empty list of namespace OIDs.
49  * In addition to the explicit list, implicitly-searched namespaces
50  * may be included:
51  *
52  * 1. If a TEMP table namespace has been initialized in this session, it
53  * is implicitly searched first.  (The only time this doesn't happen is
54  * when we are obeying an override search path spec that says not to use the
55  * temp namespace, or the temp namespace is included in the explicit list.)
56  *
57  * 2. The system catalog namespace is always searched.  If the system
58  * namespace is present in the explicit path then it will be searched in
59  * the specified order; otherwise it will be searched after TEMP tables and
60  * *before* the explicit list.  (It might seem that the system namespace
61  * should be implicitly last, but this behavior appears to be required by
62  * SQL99.  Also, this provides a way to search the system namespace first
63  * without thereby making it the default creation target namespace.)
64  *
65  * For security reasons, searches using the search path will ignore the temp
66  * namespace when searching for any object type other than relations and
67  * types.  (We must allow types since temp tables have rowtypes.)
68  *
69  * The default creation target namespace is always the first element of the
70  * explicit list.  If the explicit list is empty, there is no default target.
71  *
72  * The textual specification of search_path can include "$user" to refer to
73  * the namespace named the same as the current user, if any.  (This is just
74  * ignored if there is no such namespace.)  Also, it can include "pg_temp"
75  * to refer to the current backend's temp namespace.  This is usually also
76  * ignorable if the temp namespace hasn't been set up, but there's a special
77  * case: if "pg_temp" appears first then it should be the default creation
78  * target.  We kluge this case a little bit so that the temp namespace isn't
79  * set up until the first attempt to create something in it.  (The reason for
80  * klugery is that we can't create the temp namespace outside a transaction,
81  * but initial GUC processing of search_path happens outside a transaction.)
82  * activeTempCreationPending is TRUE if "pg_temp" appears first in the string
83  * but is not reflected in activeCreationNamespace because the namespace isn't
84  * set up yet.
85  *
86  * In bootstrap mode, the search path is set equal to "pg_catalog", so that
87  * the system namespace is the only one searched or inserted into.
88  * initdb is also careful to set search_path to "pg_catalog" for its
89  * post-bootstrap standalone backend runs.      Otherwise the default search
90  * path is determined by GUC.  The factory default path contains the PUBLIC
91  * namespace (if it exists), preceded by the user's personal namespace
92  * (if one exists).
93  *
94  * We support a stack of "override" search path settings for use within
95  * specific sections of backend code.  namespace_search_path is ignored
96  * whenever the override stack is nonempty.  activeSearchPath is always
97  * the actually active path; it points either to the search list of the
98  * topmost stack entry, or to baseSearchPath which is the list derived
99  * from namespace_search_path.
100  *
101  * If baseSearchPathValid is false, then baseSearchPath (and other
102  * derived variables) need to be recomputed from namespace_search_path.
103  * We mark it invalid upon an assignment to namespace_search_path or receipt
104  * of a syscache invalidation event for pg_namespace.  The recomputation
105  * is done during the next non-overridden lookup attempt.  Note that an
106  * override spec is never subject to recomputation.
107  *
108  * Any namespaces mentioned in namespace_search_path that are not readable
109  * by the current user ID are simply left out of baseSearchPath; so
110  * we have to be willing to recompute the path when current userid changes.
111  * namespaceUser is the userid the path has been computed for.
112  *
113  * Note: all data pointed to by these List variables is in TopMemoryContext.
114  */
115
116 /* These variables define the actually active state: */
117
118 static List *activeSearchPath = NIL;
119
120 /* default place to create stuff; if InvalidOid, no default */
121 static Oid      activeCreationNamespace = InvalidOid;
122
123 /* if TRUE, activeCreationNamespace is wrong, it should be temp namespace */
124 static bool activeTempCreationPending = false;
125
126 /* These variables are the values last derived from namespace_search_path: */
127
128 static List *baseSearchPath = NIL;
129
130 static Oid      baseCreationNamespace = InvalidOid;
131
132 static bool baseTempCreationPending = false;
133
134 static Oid      namespaceUser = InvalidOid;
135
136 /* The above four values are valid only if baseSearchPathValid */
137 static bool baseSearchPathValid = true;
138
139 /* Override requests are remembered in a stack of OverrideStackEntry structs */
140
141 typedef struct
142 {
143         List       *searchPath;                         /* the desired search path */
144         Oid                     creationNamespace;              /* the desired creation namespace */
145         int                     nestLevel;                              /* subtransaction nesting level */
146 } OverrideStackEntry;
147
148 static List *overrideStack = NIL;
149
150 /*
151  * myTempNamespace is InvalidOid until and unless a TEMP namespace is set up
152  * in a particular backend session (this happens when a CREATE TEMP TABLE
153  * command is first executed).  Thereafter it's the OID of the temp namespace.
154  *
155  * myTempNamespaceSubID shows whether we've created the TEMP namespace in the
156  * current subtransaction.      The flag propagates up the subtransaction tree,
157  * so the main transaction will correctly recognize the flag if all
158  * intermediate subtransactions commit.  When it is InvalidSubTransactionId,
159  * we either haven't made the TEMP namespace yet, or have successfully
160  * committed its creation, depending on whether myTempNamespace is valid.
161  */
162 static Oid      myTempNamespace = InvalidOid;
163
164 static SubTransactionId myTempNamespaceSubID = InvalidSubTransactionId;
165
166 /*
167  * This is the user's textual search path specification --- it's the value
168  * of the GUC variable 'search_path'.
169  */
170 char       *namespace_search_path = NULL;
171
172
173 /* Local functions */
174 static void recomputeNamespacePath(void);
175 static void InitTempTableNamespace(void);
176 static void RemoveTempRelations(Oid tempNamespaceId);
177 static void RemoveTempRelationsCallback(int code, Datum arg);
178 static void NamespaceCallback(Datum arg, Oid relid);
179
180 /* These don't really need to appear in any header file */
181 Datum           pg_table_is_visible(PG_FUNCTION_ARGS);
182 Datum           pg_type_is_visible(PG_FUNCTION_ARGS);
183 Datum           pg_function_is_visible(PG_FUNCTION_ARGS);
184 Datum           pg_operator_is_visible(PG_FUNCTION_ARGS);
185 Datum           pg_opclass_is_visible(PG_FUNCTION_ARGS);
186 Datum           pg_conversion_is_visible(PG_FUNCTION_ARGS);
187 Datum           pg_my_temp_schema(PG_FUNCTION_ARGS);
188 Datum           pg_is_other_temp_schema(PG_FUNCTION_ARGS);
189
190
191 /*
192  * RangeVarGetRelid
193  *              Given a RangeVar describing an existing relation,
194  *              select the proper namespace and look up the relation OID.
195  *
196  * If the relation is not found, return InvalidOid if failOK = true,
197  * otherwise raise an error.
198  */
199 Oid
200 RangeVarGetRelid(const RangeVar *relation, bool failOK)
201 {
202         Oid                     namespaceId;
203         Oid                     relId;
204
205         /*
206          * We check the catalog name and then ignore it.
207          */
208         if (relation->catalogname)
209         {
210                 if (strcmp(relation->catalogname, get_database_name(MyDatabaseId)) != 0)
211                         ereport(ERROR,
212                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
213                                          errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
214                                                         relation->catalogname, relation->schemaname,
215                                                         relation->relname)));
216         }
217
218         if (relation->schemaname)
219         {
220                 /* use exact schema given */
221                 namespaceId = LookupExplicitNamespace(relation->schemaname);
222                 relId = get_relname_relid(relation->relname, namespaceId);
223         }
224         else
225         {
226                 /* search the namespace path */
227                 relId = RelnameGetRelid(relation->relname);
228         }
229
230         if (!OidIsValid(relId) && !failOK)
231         {
232                 if (relation->schemaname)
233                         ereport(ERROR,
234                                         (errcode(ERRCODE_UNDEFINED_TABLE),
235                                          errmsg("relation \"%s.%s\" does not exist",
236                                                         relation->schemaname, relation->relname)));
237                 else
238                         ereport(ERROR,
239                                         (errcode(ERRCODE_UNDEFINED_TABLE),
240                                          errmsg("relation \"%s\" does not exist",
241                                                         relation->relname)));
242         }
243         return relId;
244 }
245
246 /*
247  * RangeVarGetCreationNamespace
248  *              Given a RangeVar describing a to-be-created relation,
249  *              choose which namespace to create it in.
250  *
251  * Note: calling this may result in a CommandCounterIncrement operation.
252  * That will happen on the first request for a temp table in any particular
253  * backend run; we will need to either create or clean out the temp schema.
254  */
255 Oid
256 RangeVarGetCreationNamespace(const RangeVar *newRelation)
257 {
258         Oid                     namespaceId;
259
260         /*
261          * We check the catalog name and then ignore it.
262          */
263         if (newRelation->catalogname)
264         {
265                 if (strcmp(newRelation->catalogname, get_database_name(MyDatabaseId)) != 0)
266                         ereport(ERROR,
267                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
268                                          errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
269                                                         newRelation->catalogname, newRelation->schemaname,
270                                                         newRelation->relname)));
271         }
272
273         if (newRelation->istemp)
274         {
275                 /* TEMP tables are created in our backend-local temp namespace */
276                 if (newRelation->schemaname)
277                         ereport(ERROR,
278                                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
279                                   errmsg("temporary tables cannot specify a schema name")));
280                 /* Initialize temp namespace if first time through */
281                 if (!OidIsValid(myTempNamespace))
282                         InitTempTableNamespace();
283                 return myTempNamespace;
284         }
285
286         if (newRelation->schemaname)
287         {
288                 /* check for pg_temp alias */
289                 if (strcmp(newRelation->schemaname, "pg_temp") == 0)
290                 {
291                         /* Initialize temp namespace if first time through */
292                         if (!OidIsValid(myTempNamespace))
293                                 InitTempTableNamespace();
294                         return myTempNamespace;
295                 }
296                 /* use exact schema given */
297                 namespaceId = GetSysCacheOid(NAMESPACENAME,
298                                                                          CStringGetDatum(newRelation->schemaname),
299                                                                          0, 0, 0);
300                 if (!OidIsValid(namespaceId))
301                         ereport(ERROR,
302                                         (errcode(ERRCODE_UNDEFINED_SCHEMA),
303                                          errmsg("schema \"%s\" does not exist",
304                                                         newRelation->schemaname)));
305                 /* we do not check for USAGE rights here! */
306         }
307         else
308         {
309                 /* use the default creation namespace */
310                 recomputeNamespacePath();
311                 if (activeTempCreationPending)
312                 {
313                         /* Need to initialize temp namespace */
314                         InitTempTableNamespace();
315                         return myTempNamespace;
316                 }
317                 namespaceId = activeCreationNamespace;
318                 if (!OidIsValid(namespaceId))
319                         ereport(ERROR,
320                                         (errcode(ERRCODE_UNDEFINED_SCHEMA),
321                                          errmsg("no schema has been selected to create in")));
322         }
323
324         /* Note: callers will check for CREATE rights when appropriate */
325
326         return namespaceId;
327 }
328
329 /*
330  * RelnameGetRelid
331  *              Try to resolve an unqualified relation name.
332  *              Returns OID if relation found in search path, else InvalidOid.
333  */
334 Oid
335 RelnameGetRelid(const char *relname)
336 {
337         Oid                     relid;
338         ListCell   *l;
339
340         recomputeNamespacePath();
341
342         foreach(l, activeSearchPath)
343         {
344                 Oid                     namespaceId = lfirst_oid(l);
345
346                 relid = get_relname_relid(relname, namespaceId);
347                 if (OidIsValid(relid))
348                         return relid;
349         }
350
351         /* Not found in path */
352         return InvalidOid;
353 }
354
355
356 /*
357  * RelationIsVisible
358  *              Determine whether a relation (identified by OID) is visible in the
359  *              current search path.  Visible means "would be found by searching
360  *              for the unqualified relation name".
361  */
362 bool
363 RelationIsVisible(Oid relid)
364 {
365         HeapTuple       reltup;
366         Form_pg_class relform;
367         Oid                     relnamespace;
368         bool            visible;
369
370         reltup = SearchSysCache(RELOID,
371                                                         ObjectIdGetDatum(relid),
372                                                         0, 0, 0);
373         if (!HeapTupleIsValid(reltup))
374                 elog(ERROR, "cache lookup failed for relation %u", relid);
375         relform = (Form_pg_class) GETSTRUCT(reltup);
376
377         recomputeNamespacePath();
378
379         /*
380          * Quick check: if it ain't in the path at all, it ain't visible. Items in
381          * the system namespace are surely in the path and so we needn't even do
382          * list_member_oid() for them.
383          */
384         relnamespace = relform->relnamespace;
385         if (relnamespace != PG_CATALOG_NAMESPACE &&
386                 !list_member_oid(activeSearchPath, relnamespace))
387                 visible = false;
388         else
389         {
390                 /*
391                  * If it is in the path, it might still not be visible; it could be
392                  * hidden by another relation of the same name earlier in the path. So
393                  * we must do a slow check for conflicting relations.
394                  */
395                 char       *relname = NameStr(relform->relname);
396                 ListCell   *l;
397
398                 visible = false;
399                 foreach(l, activeSearchPath)
400                 {
401                         Oid                     namespaceId = lfirst_oid(l);
402
403                         if (namespaceId == relnamespace)
404                         {
405                                 /* Found it first in path */
406                                 visible = true;
407                                 break;
408                         }
409                         if (OidIsValid(get_relname_relid(relname, namespaceId)))
410                         {
411                                 /* Found something else first in path */
412                                 break;
413                         }
414                 }
415         }
416
417         ReleaseSysCache(reltup);
418
419         return visible;
420 }
421
422
423 /*
424  * TypenameGetTypid
425  *              Try to resolve an unqualified datatype name.
426  *              Returns OID if type found in search path, else InvalidOid.
427  *
428  * This is essentially the same as RelnameGetRelid.
429  */
430 Oid
431 TypenameGetTypid(const char *typname)
432 {
433         Oid                     typid;
434         ListCell   *l;
435
436         recomputeNamespacePath();
437
438         foreach(l, activeSearchPath)
439         {
440                 Oid                     namespaceId = lfirst_oid(l);
441
442                 typid = GetSysCacheOid(TYPENAMENSP,
443                                                            PointerGetDatum(typname),
444                                                            ObjectIdGetDatum(namespaceId),
445                                                            0, 0);
446                 if (OidIsValid(typid))
447                         return typid;
448         }
449
450         /* Not found in path */
451         return InvalidOid;
452 }
453
454 /*
455  * TypeIsVisible
456  *              Determine whether a type (identified by OID) is visible in the
457  *              current search path.  Visible means "would be found by searching
458  *              for the unqualified type name".
459  */
460 bool
461 TypeIsVisible(Oid typid)
462 {
463         HeapTuple       typtup;
464         Form_pg_type typform;
465         Oid                     typnamespace;
466         bool            visible;
467
468         typtup = SearchSysCache(TYPEOID,
469                                                         ObjectIdGetDatum(typid),
470                                                         0, 0, 0);
471         if (!HeapTupleIsValid(typtup))
472                 elog(ERROR, "cache lookup failed for type %u", typid);
473         typform = (Form_pg_type) GETSTRUCT(typtup);
474
475         recomputeNamespacePath();
476
477         /*
478          * Quick check: if it ain't in the path at all, it ain't visible. Items in
479          * the system namespace are surely in the path and so we needn't even do
480          * list_member_oid() for them.
481          */
482         typnamespace = typform->typnamespace;
483         if (typnamespace != PG_CATALOG_NAMESPACE &&
484                 !list_member_oid(activeSearchPath, typnamespace))
485                 visible = false;
486         else
487         {
488                 /*
489                  * If it is in the path, it might still not be visible; it could be
490                  * hidden by another type of the same name earlier in the path. So we
491                  * must do a slow check for conflicting types.
492                  */
493                 char       *typname = NameStr(typform->typname);
494                 ListCell   *l;
495
496                 visible = false;
497                 foreach(l, activeSearchPath)
498                 {
499                         Oid                     namespaceId = lfirst_oid(l);
500
501                         if (namespaceId == typnamespace)
502                         {
503                                 /* Found it first in path */
504                                 visible = true;
505                                 break;
506                         }
507                         if (SearchSysCacheExists(TYPENAMENSP,
508                                                                          PointerGetDatum(typname),
509                                                                          ObjectIdGetDatum(namespaceId),
510                                                                          0, 0))
511                         {
512                                 /* Found something else first in path */
513                                 break;
514                         }
515                 }
516         }
517
518         ReleaseSysCache(typtup);
519
520         return visible;
521 }
522
523
524 /*
525  * FuncnameGetCandidates
526  *              Given a possibly-qualified function name and argument count,
527  *              retrieve a list of the possible matches.
528  *
529  * If nargs is -1, we return all functions matching the given name,
530  * regardless of argument count.
531  *
532  * We search a single namespace if the function name is qualified, else
533  * all namespaces in the search path.  The return list will never contain
534  * multiple entries with identical argument lists --- in the multiple-
535  * namespace case, we arrange for entries in earlier namespaces to mask
536  * identical entries in later namespaces.
537  */
538 FuncCandidateList
539 FuncnameGetCandidates(List *names, int nargs)
540 {
541         FuncCandidateList resultList = NULL;
542         char       *schemaname;
543         char       *funcname;
544         Oid                     namespaceId;
545         CatCList   *catlist;
546         int                     i;
547
548         /* deconstruct the name list */
549         DeconstructQualifiedName(names, &schemaname, &funcname);
550
551         if (schemaname)
552         {
553                 /* use exact schema given */
554                 namespaceId = LookupExplicitNamespace(schemaname);
555         }
556         else
557         {
558                 /* flag to indicate we need namespace search */
559                 namespaceId = InvalidOid;
560                 recomputeNamespacePath();
561         }
562
563         /* Search syscache by name only */
564         catlist = SearchSysCacheList(PROCNAMEARGSNSP, 1,
565                                                                  CStringGetDatum(funcname),
566                                                                  0, 0, 0);
567
568         for (i = 0; i < catlist->n_members; i++)
569         {
570                 HeapTuple       proctup = &catlist->members[i]->tuple;
571                 Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
572                 int                     pronargs = procform->pronargs;
573                 int                     pathpos = 0;
574                 FuncCandidateList newResult;
575
576                 /* Ignore if it doesn't match requested argument count */
577                 if (nargs >= 0 && pronargs != nargs)
578                         continue;
579
580                 if (OidIsValid(namespaceId))
581                 {
582                         /* Consider only procs in specified namespace */
583                         if (procform->pronamespace != namespaceId)
584                                 continue;
585                         /* No need to check args, they must all be different */
586                 }
587                 else
588                 {
589                         /*
590                          * Consider only procs that are in the search path and are not
591                          * in the temp namespace.
592                          */
593                         ListCell   *nsp;
594
595                         foreach(nsp, activeSearchPath)
596                         {
597                                 if (procform->pronamespace == lfirst_oid(nsp) &&
598                                         procform->pronamespace != myTempNamespace)
599                                         break;
600                                 pathpos++;
601                         }
602                         if (nsp == NULL)
603                                 continue;               /* proc is not in search path */
604
605                         /*
606                          * Okay, it's in the search path, but does it have the same
607                          * arguments as something we already accepted?  If so, keep only
608                          * the one that appears earlier in the search path.
609                          *
610                          * If we have an ordered list from SearchSysCacheList (the normal
611                          * case), then any conflicting proc must immediately adjoin this
612                          * one in the list, so we only need to look at the newest result
613                          * item.  If we have an unordered list, we have to scan the whole
614                          * result list.
615                          */
616                         if (resultList)
617                         {
618                                 FuncCandidateList prevResult;
619
620                                 if (catlist->ordered)
621                                 {
622                                         if (pronargs == resultList->nargs &&
623                                                 memcmp(procform->proargtypes.values,
624                                                            resultList->args,
625                                                            pronargs * sizeof(Oid)) == 0)
626                                                 prevResult = resultList;
627                                         else
628                                                 prevResult = NULL;
629                                 }
630                                 else
631                                 {
632                                         for (prevResult = resultList;
633                                                  prevResult;
634                                                  prevResult = prevResult->next)
635                                         {
636                                                 if (pronargs == prevResult->nargs &&
637                                                         memcmp(procform->proargtypes.values,
638                                                                    prevResult->args,
639                                                                    pronargs * sizeof(Oid)) == 0)
640                                                         break;
641                                         }
642                                 }
643                                 if (prevResult)
644                                 {
645                                         /* We have a match with a previous result */
646                                         Assert(pathpos != prevResult->pathpos);
647                                         if (pathpos > prevResult->pathpos)
648                                                 continue;               /* keep previous result */
649                                         /* replace previous result */
650                                         prevResult->pathpos = pathpos;
651                                         prevResult->oid = HeapTupleGetOid(proctup);
652                                         continue;       /* args are same, of course */
653                                 }
654                         }
655                 }
656
657                 /*
658                  * Okay to add it to result list
659                  */
660                 newResult = (FuncCandidateList)
661                         palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid)
662                                    + pronargs * sizeof(Oid));
663                 newResult->pathpos = pathpos;
664                 newResult->oid = HeapTupleGetOid(proctup);
665                 newResult->nargs = pronargs;
666                 memcpy(newResult->args, procform->proargtypes.values,
667                            pronargs * sizeof(Oid));
668
669                 newResult->next = resultList;
670                 resultList = newResult;
671         }
672
673         ReleaseSysCacheList(catlist);
674
675         return resultList;
676 }
677
678 /*
679  * FunctionIsVisible
680  *              Determine whether a function (identified by OID) is visible in the
681  *              current search path.  Visible means "would be found by searching
682  *              for the unqualified function name with exact argument matches".
683  */
684 bool
685 FunctionIsVisible(Oid funcid)
686 {
687         HeapTuple       proctup;
688         Form_pg_proc procform;
689         Oid                     pronamespace;
690         bool            visible;
691
692         proctup = SearchSysCache(PROCOID,
693                                                          ObjectIdGetDatum(funcid),
694                                                          0, 0, 0);
695         if (!HeapTupleIsValid(proctup))
696                 elog(ERROR, "cache lookup failed for function %u", funcid);
697         procform = (Form_pg_proc) GETSTRUCT(proctup);
698
699         recomputeNamespacePath();
700
701         /*
702          * Quick check: if it ain't in the path at all, it ain't visible. Items in
703          * the system namespace are surely in the path and so we needn't even do
704          * list_member_oid() for them.
705          */
706         pronamespace = procform->pronamespace;
707         if (pronamespace != PG_CATALOG_NAMESPACE &&
708                 !list_member_oid(activeSearchPath, pronamespace))
709                 visible = false;
710         else
711         {
712                 /*
713                  * If it is in the path, it might still not be visible; it could be
714                  * hidden by another proc of the same name and arguments earlier in
715                  * the path.  So we must do a slow check to see if this is the same
716                  * proc that would be found by FuncnameGetCandidates.
717                  */
718                 char       *proname = NameStr(procform->proname);
719                 int                     nargs = procform->pronargs;
720                 FuncCandidateList clist;
721
722                 visible = false;
723
724                 clist = FuncnameGetCandidates(list_make1(makeString(proname)), nargs);
725
726                 for (; clist; clist = clist->next)
727                 {
728                         if (memcmp(clist->args, procform->proargtypes.values,
729                                            nargs * sizeof(Oid)) == 0)
730                         {
731                                 /* Found the expected entry; is it the right proc? */
732                                 visible = (clist->oid == funcid);
733                                 break;
734                         }
735                 }
736         }
737
738         ReleaseSysCache(proctup);
739
740         return visible;
741 }
742
743
744 /*
745  * OpernameGetOprid
746  *              Given a possibly-qualified operator name and exact input datatypes,
747  *              look up the operator.  Returns InvalidOid if not found.
748  *
749  * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
750  * a postfix op.
751  *
752  * If the operator name is not schema-qualified, it is sought in the current
753  * namespace search path.
754  */
755 Oid
756 OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
757 {
758         char       *schemaname;
759         char       *opername;
760         CatCList   *catlist;
761         ListCell   *l;
762
763         /* deconstruct the name list */
764         DeconstructQualifiedName(names, &schemaname, &opername);
765
766         if (schemaname)
767         {
768                 /* search only in exact schema given */
769                 Oid                     namespaceId;
770                 HeapTuple       opertup;
771
772                 namespaceId = LookupExplicitNamespace(schemaname);
773                 opertup = SearchSysCache(OPERNAMENSP,
774                                                                  CStringGetDatum(opername),
775                                                                  ObjectIdGetDatum(oprleft),
776                                                                  ObjectIdGetDatum(oprright),
777                                                                  ObjectIdGetDatum(namespaceId));
778                 if (HeapTupleIsValid(opertup))
779                 {
780                         Oid                     result = HeapTupleGetOid(opertup);
781
782                         ReleaseSysCache(opertup);
783                         return result;
784                 }
785                 return InvalidOid;
786         }
787
788         /* Search syscache by name and argument types */
789         catlist = SearchSysCacheList(OPERNAMENSP, 3,
790                                                                  CStringGetDatum(opername),
791                                                                  ObjectIdGetDatum(oprleft),
792                                                                  ObjectIdGetDatum(oprright),
793                                                                  0);
794
795         if (catlist->n_members == 0)
796         {
797                 /* no hope, fall out early */
798                 ReleaseSysCacheList(catlist);
799                 return InvalidOid;
800         }
801
802         /*
803          * We have to find the list member that is first in the search path, if
804          * there's more than one.  This doubly-nested loop looks ugly, but in
805          * practice there should usually be few catlist members.
806          */
807         recomputeNamespacePath();
808
809         foreach(l, activeSearchPath)
810         {
811                 Oid                     namespaceId = lfirst_oid(l);
812                 int                     i;
813
814                 if (namespaceId == myTempNamespace)
815                         continue;                       /* do not look in temp namespace */
816
817                 for (i = 0; i < catlist->n_members; i++)
818                 {
819                         HeapTuple       opertup = &catlist->members[i]->tuple;
820                         Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
821
822                         if (operform->oprnamespace == namespaceId)
823                         {
824                                 Oid                     result = HeapTupleGetOid(opertup);
825
826                                 ReleaseSysCacheList(catlist);
827                                 return result;
828                         }
829                 }
830         }
831
832         ReleaseSysCacheList(catlist);
833         return InvalidOid;
834 }
835
836 /*
837  * OpernameGetCandidates
838  *              Given a possibly-qualified operator name and operator kind,
839  *              retrieve a list of the possible matches.
840  *
841  * If oprkind is '\0', we return all operators matching the given name,
842  * regardless of arguments.
843  *
844  * We search a single namespace if the operator name is qualified, else
845  * all namespaces in the search path.  The return list will never contain
846  * multiple entries with identical argument lists --- in the multiple-
847  * namespace case, we arrange for entries in earlier namespaces to mask
848  * identical entries in later namespaces.
849  *
850  * The returned items always have two args[] entries --- one or the other
851  * will be InvalidOid for a prefix or postfix oprkind.  nargs is 2, too.
852  */
853 FuncCandidateList
854 OpernameGetCandidates(List *names, char oprkind)
855 {
856         FuncCandidateList resultList = NULL;
857         char       *resultSpace = NULL;
858         int                     nextResult = 0;
859         char       *schemaname;
860         char       *opername;
861         Oid                     namespaceId;
862         CatCList   *catlist;
863         int                     i;
864
865         /* deconstruct the name list */
866         DeconstructQualifiedName(names, &schemaname, &opername);
867
868         if (schemaname)
869         {
870                 /* use exact schema given */
871                 namespaceId = LookupExplicitNamespace(schemaname);
872         }
873         else
874         {
875                 /* flag to indicate we need namespace search */
876                 namespaceId = InvalidOid;
877                 recomputeNamespacePath();
878         }
879
880         /* Search syscache by name only */
881         catlist = SearchSysCacheList(OPERNAMENSP, 1,
882                                                                  CStringGetDatum(opername),
883                                                                  0, 0, 0);
884
885         /*
886          * In typical scenarios, most if not all of the operators found by the
887          * catcache search will end up getting returned; and there can be quite a
888          * few, for common operator names such as '=' or '+'.  To reduce the time
889          * spent in palloc, we allocate the result space as an array large enough
890          * to hold all the operators.  The original coding of this routine did a
891          * separate palloc for each operator, but profiling revealed that the
892          * pallocs used an unreasonably large fraction of parsing time.
893          */
894 #define SPACE_PER_OP MAXALIGN(sizeof(struct _FuncCandidateList) + sizeof(Oid))
895
896         if (catlist->n_members > 0)
897                 resultSpace = palloc(catlist->n_members * SPACE_PER_OP);
898
899         for (i = 0; i < catlist->n_members; i++)
900         {
901                 HeapTuple       opertup = &catlist->members[i]->tuple;
902                 Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
903                 int                     pathpos = 0;
904                 FuncCandidateList newResult;
905
906                 /* Ignore operators of wrong kind, if specific kind requested */
907                 if (oprkind && operform->oprkind != oprkind)
908                         continue;
909
910                 if (OidIsValid(namespaceId))
911                 {
912                         /* Consider only opers in specified namespace */
913                         if (operform->oprnamespace != namespaceId)
914                                 continue;
915                         /* No need to check args, they must all be different */
916                 }
917                 else
918                 {
919                         /*
920                          * Consider only opers that are in the search path and are not
921                          * in the temp namespace.
922                          */
923                         ListCell   *nsp;
924
925                         foreach(nsp, activeSearchPath)
926                         {
927                                 if (operform->oprnamespace == lfirst_oid(nsp) &&
928                                         operform->oprnamespace != myTempNamespace)
929                                         break;
930                                 pathpos++;
931                         }
932                         if (nsp == NULL)
933                                 continue;               /* oper is not in search path */
934
935                         /*
936                          * Okay, it's in the search path, but does it have the same
937                          * arguments as something we already accepted?  If so, keep only
938                          * the one that appears earlier in the search path.
939                          *
940                          * If we have an ordered list from SearchSysCacheList (the normal
941                          * case), then any conflicting oper must immediately adjoin this
942                          * one in the list, so we only need to look at the newest result
943                          * item.  If we have an unordered list, we have to scan the whole
944                          * result list.
945                          */
946                         if (resultList)
947                         {
948                                 FuncCandidateList prevResult;
949
950                                 if (catlist->ordered)
951                                 {
952                                         if (operform->oprleft == resultList->args[0] &&
953                                                 operform->oprright == resultList->args[1])
954                                                 prevResult = resultList;
955                                         else
956                                                 prevResult = NULL;
957                                 }
958                                 else
959                                 {
960                                         for (prevResult = resultList;
961                                                  prevResult;
962                                                  prevResult = prevResult->next)
963                                         {
964                                                 if (operform->oprleft == prevResult->args[0] &&
965                                                         operform->oprright == prevResult->args[1])
966                                                         break;
967                                         }
968                                 }
969                                 if (prevResult)
970                                 {
971                                         /* We have a match with a previous result */
972                                         Assert(pathpos != prevResult->pathpos);
973                                         if (pathpos > prevResult->pathpos)
974                                                 continue;               /* keep previous result */
975                                         /* replace previous result */
976                                         prevResult->pathpos = pathpos;
977                                         prevResult->oid = HeapTupleGetOid(opertup);
978                                         continue;       /* args are same, of course */
979                                 }
980                         }
981                 }
982
983                 /*
984                  * Okay to add it to result list
985                  */
986                 newResult = (FuncCandidateList) (resultSpace + nextResult);
987                 nextResult += SPACE_PER_OP;
988
989                 newResult->pathpos = pathpos;
990                 newResult->oid = HeapTupleGetOid(opertup);
991                 newResult->nargs = 2;
992                 newResult->args[0] = operform->oprleft;
993                 newResult->args[1] = operform->oprright;
994                 newResult->next = resultList;
995                 resultList = newResult;
996         }
997
998         ReleaseSysCacheList(catlist);
999
1000         return resultList;
1001 }
1002
1003 /*
1004  * OperatorIsVisible
1005  *              Determine whether an operator (identified by OID) is visible in the
1006  *              current search path.  Visible means "would be found by searching
1007  *              for the unqualified operator name with exact argument matches".
1008  */
1009 bool
1010 OperatorIsVisible(Oid oprid)
1011 {
1012         HeapTuple       oprtup;
1013         Form_pg_operator oprform;
1014         Oid                     oprnamespace;
1015         bool            visible;
1016
1017         oprtup = SearchSysCache(OPEROID,
1018                                                         ObjectIdGetDatum(oprid),
1019                                                         0, 0, 0);
1020         if (!HeapTupleIsValid(oprtup))
1021                 elog(ERROR, "cache lookup failed for operator %u", oprid);
1022         oprform = (Form_pg_operator) GETSTRUCT(oprtup);
1023
1024         recomputeNamespacePath();
1025
1026         /*
1027          * Quick check: if it ain't in the path at all, it ain't visible. Items in
1028          * the system namespace are surely in the path and so we needn't even do
1029          * list_member_oid() for them.
1030          */
1031         oprnamespace = oprform->oprnamespace;
1032         if (oprnamespace != PG_CATALOG_NAMESPACE &&
1033                 !list_member_oid(activeSearchPath, oprnamespace))
1034                 visible = false;
1035         else
1036         {
1037                 /*
1038                  * If it is in the path, it might still not be visible; it could be
1039                  * hidden by another operator of the same name and arguments earlier
1040                  * in the path.  So we must do a slow check to see if this is the same
1041                  * operator that would be found by OpernameGetOprId.
1042                  */
1043                 char       *oprname = NameStr(oprform->oprname);
1044
1045                 visible = (OpernameGetOprid(list_make1(makeString(oprname)),
1046                                                                         oprform->oprleft, oprform->oprright)
1047                                    == oprid);
1048         }
1049
1050         ReleaseSysCache(oprtup);
1051
1052         return visible;
1053 }
1054
1055
1056 /*
1057  * OpclassnameGetOpcid
1058  *              Try to resolve an unqualified index opclass name.
1059  *              Returns OID if opclass found in search path, else InvalidOid.
1060  *
1061  * This is essentially the same as TypenameGetTypid, but we have to have
1062  * an extra argument for the index AM OID.
1063  */
1064 Oid
1065 OpclassnameGetOpcid(Oid amid, const char *opcname)
1066 {
1067         Oid                     opcid;
1068         ListCell   *l;
1069
1070         recomputeNamespacePath();
1071
1072         foreach(l, activeSearchPath)
1073         {
1074                 Oid                     namespaceId = lfirst_oid(l);
1075
1076                 if (namespaceId == myTempNamespace)
1077                         continue;                       /* do not look in temp namespace */
1078
1079                 opcid = GetSysCacheOid(CLAAMNAMENSP,
1080                                                            ObjectIdGetDatum(amid),
1081                                                            PointerGetDatum(opcname),
1082                                                            ObjectIdGetDatum(namespaceId),
1083                                                            0);
1084                 if (OidIsValid(opcid))
1085                         return opcid;
1086         }
1087
1088         /* Not found in path */
1089         return InvalidOid;
1090 }
1091
1092 /*
1093  * OpclassIsVisible
1094  *              Determine whether an opclass (identified by OID) is visible in the
1095  *              current search path.  Visible means "would be found by searching
1096  *              for the unqualified opclass name".
1097  */
1098 bool
1099 OpclassIsVisible(Oid opcid)
1100 {
1101         HeapTuple       opctup;
1102         Form_pg_opclass opcform;
1103         Oid                     opcnamespace;
1104         bool            visible;
1105
1106         opctup = SearchSysCache(CLAOID,
1107                                                         ObjectIdGetDatum(opcid),
1108                                                         0, 0, 0);
1109         if (!HeapTupleIsValid(opctup))
1110                 elog(ERROR, "cache lookup failed for opclass %u", opcid);
1111         opcform = (Form_pg_opclass) GETSTRUCT(opctup);
1112
1113         recomputeNamespacePath();
1114
1115         /*
1116          * Quick check: if it ain't in the path at all, it ain't visible. Items in
1117          * the system namespace are surely in the path and so we needn't even do
1118          * list_member_oid() for them.
1119          */
1120         opcnamespace = opcform->opcnamespace;
1121         if (opcnamespace != PG_CATALOG_NAMESPACE &&
1122                 !list_member_oid(activeSearchPath, opcnamespace))
1123                 visible = false;
1124         else
1125         {
1126                 /*
1127                  * If it is in the path, it might still not be visible; it could be
1128                  * hidden by another opclass of the same name earlier in the path. So
1129                  * we must do a slow check to see if this opclass would be found by
1130                  * OpclassnameGetOpcid.
1131                  */
1132                 char       *opcname = NameStr(opcform->opcname);
1133
1134                 visible = (OpclassnameGetOpcid(opcform->opcmethod, opcname) == opcid);
1135         }
1136
1137         ReleaseSysCache(opctup);
1138
1139         return visible;
1140 }
1141
1142 /*
1143  * OpfamilynameGetOpfid
1144  *              Try to resolve an unqualified index opfamily name.
1145  *              Returns OID if opfamily found in search path, else InvalidOid.
1146  *
1147  * This is essentially the same as TypenameGetTypid, but we have to have
1148  * an extra argument for the index AM OID.
1149  */
1150 Oid
1151 OpfamilynameGetOpfid(Oid amid, const char *opfname)
1152 {
1153         Oid                     opfid;
1154         ListCell   *l;
1155
1156         recomputeNamespacePath();
1157
1158         foreach(l, activeSearchPath)
1159         {
1160                 Oid                     namespaceId = lfirst_oid(l);
1161
1162                 if (namespaceId == myTempNamespace)
1163                         continue;                       /* do not look in temp namespace */
1164
1165                 opfid = GetSysCacheOid(OPFAMILYAMNAMENSP,
1166                                                            ObjectIdGetDatum(amid),
1167                                                            PointerGetDatum(opfname),
1168                                                            ObjectIdGetDatum(namespaceId),
1169                                                            0);
1170                 if (OidIsValid(opfid))
1171                         return opfid;
1172         }
1173
1174         /* Not found in path */
1175         return InvalidOid;
1176 }
1177
1178 /*
1179  * OpfamilyIsVisible
1180  *              Determine whether an opfamily (identified by OID) is visible in the
1181  *              current search path.  Visible means "would be found by searching
1182  *              for the unqualified opfamily name".
1183  */
1184 bool
1185 OpfamilyIsVisible(Oid opfid)
1186 {
1187         HeapTuple       opftup;
1188         Form_pg_opfamily opfform;
1189         Oid                     opfnamespace;
1190         bool            visible;
1191
1192         opftup = SearchSysCache(OPFAMILYOID,
1193                                                         ObjectIdGetDatum(opfid),
1194                                                         0, 0, 0);
1195         if (!HeapTupleIsValid(opftup))
1196                 elog(ERROR, "cache lookup failed for opfamily %u", opfid);
1197         opfform = (Form_pg_opfamily) GETSTRUCT(opftup);
1198
1199         recomputeNamespacePath();
1200
1201         /*
1202          * Quick check: if it ain't in the path at all, it ain't visible. Items in
1203          * the system namespace are surely in the path and so we needn't even do
1204          * list_member_oid() for them.
1205          */
1206         opfnamespace = opfform->opfnamespace;
1207         if (opfnamespace != PG_CATALOG_NAMESPACE &&
1208                 !list_member_oid(activeSearchPath, opfnamespace))
1209                 visible = false;
1210         else
1211         {
1212                 /*
1213                  * If it is in the path, it might still not be visible; it could be
1214                  * hidden by another opfamily of the same name earlier in the path. So
1215                  * we must do a slow check to see if this opfamily would be found by
1216                  * OpfamilynameGetOpfid.
1217                  */
1218                 char       *opfname = NameStr(opfform->opfname);
1219
1220                 visible = (OpfamilynameGetOpfid(opfform->opfmethod, opfname) == opfid);
1221         }
1222
1223         ReleaseSysCache(opftup);
1224
1225         return visible;
1226 }
1227
1228 /*
1229  * ConversionGetConid
1230  *              Try to resolve an unqualified conversion name.
1231  *              Returns OID if conversion found in search path, else InvalidOid.
1232  *
1233  * This is essentially the same as RelnameGetRelid.
1234  */
1235 Oid
1236 ConversionGetConid(const char *conname)
1237 {
1238         Oid                     conid;
1239         ListCell   *l;
1240
1241         recomputeNamespacePath();
1242
1243         foreach(l, activeSearchPath)
1244         {
1245                 Oid                     namespaceId = lfirst_oid(l);
1246
1247                 if (namespaceId == myTempNamespace)
1248                         continue;                       /* do not look in temp namespace */
1249
1250                 conid = GetSysCacheOid(CONNAMENSP,
1251                                                            PointerGetDatum(conname),
1252                                                            ObjectIdGetDatum(namespaceId),
1253                                                            0, 0);
1254                 if (OidIsValid(conid))
1255                         return conid;
1256         }
1257
1258         /* Not found in path */
1259         return InvalidOid;
1260 }
1261
1262 /*
1263  * ConversionIsVisible
1264  *              Determine whether a conversion (identified by OID) is visible in the
1265  *              current search path.  Visible means "would be found by searching
1266  *              for the unqualified conversion name".
1267  */
1268 bool
1269 ConversionIsVisible(Oid conid)
1270 {
1271         HeapTuple       contup;
1272         Form_pg_conversion conform;
1273         Oid                     connamespace;
1274         bool            visible;
1275
1276         contup = SearchSysCache(CONVOID,
1277                                                         ObjectIdGetDatum(conid),
1278                                                         0, 0, 0);
1279         if (!HeapTupleIsValid(contup))
1280                 elog(ERROR, "cache lookup failed for conversion %u", conid);
1281         conform = (Form_pg_conversion) GETSTRUCT(contup);
1282
1283         recomputeNamespacePath();
1284
1285         /*
1286          * Quick check: if it ain't in the path at all, it ain't visible. Items in
1287          * the system namespace are surely in the path and so we needn't even do
1288          * list_member_oid() for them.
1289          */
1290         connamespace = conform->connamespace;
1291         if (connamespace != PG_CATALOG_NAMESPACE &&
1292                 !list_member_oid(activeSearchPath, connamespace))
1293                 visible = false;
1294         else
1295         {
1296                 /*
1297                  * If it is in the path, it might still not be visible; it could be
1298                  * hidden by another conversion of the same name earlier in the path.
1299                  * So we must do a slow check to see if this conversion would be found
1300                  * by ConversionGetConid.
1301                  */
1302                 char       *conname = NameStr(conform->conname);
1303
1304                 visible = (ConversionGetConid(conname) == conid);
1305         }
1306
1307         ReleaseSysCache(contup);
1308
1309         return visible;
1310 }
1311
1312 /*
1313  * DeconstructQualifiedName
1314  *              Given a possibly-qualified name expressed as a list of String nodes,
1315  *              extract the schema name and object name.
1316  *
1317  * *nspname_p is set to NULL if there is no explicit schema name.
1318  */
1319 void
1320 DeconstructQualifiedName(List *names,
1321                                                  char **nspname_p,
1322                                                  char **objname_p)
1323 {
1324         char       *catalogname;
1325         char       *schemaname = NULL;
1326         char       *objname = NULL;
1327
1328         switch (list_length(names))
1329         {
1330                 case 1:
1331                         objname = strVal(linitial(names));
1332                         break;
1333                 case 2:
1334                         schemaname = strVal(linitial(names));
1335                         objname = strVal(lsecond(names));
1336                         break;
1337                 case 3:
1338                         catalogname = strVal(linitial(names));
1339                         schemaname = strVal(lsecond(names));
1340                         objname = strVal(lthird(names));
1341
1342                         /*
1343                          * We check the catalog name and then ignore it.
1344                          */
1345                         if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0)
1346                                 ereport(ERROR,
1347                                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1348                                   errmsg("cross-database references are not implemented: %s",
1349                                                  NameListToString(names))));
1350                         break;
1351                 default:
1352                         ereport(ERROR,
1353                                         (errcode(ERRCODE_SYNTAX_ERROR),
1354                                 errmsg("improper qualified name (too many dotted names): %s",
1355                                            NameListToString(names))));
1356                         break;
1357         }
1358
1359         *nspname_p = schemaname;
1360         *objname_p = objname;
1361 }
1362
1363 /*
1364  * LookupExplicitNamespace
1365  *              Process an explicitly-specified schema name: look up the schema
1366  *              and verify we have USAGE (lookup) rights in it.
1367  *
1368  * Returns the namespace OID.  Raises ereport if any problem.
1369  */
1370 Oid
1371 LookupExplicitNamespace(const char *nspname)
1372 {
1373         Oid                     namespaceId;
1374         AclResult       aclresult;
1375
1376         /* check for pg_temp alias */
1377         if (strcmp(nspname, "pg_temp") == 0)
1378         {
1379                 if (OidIsValid(myTempNamespace))
1380                         return myTempNamespace;
1381                 /*
1382                  * Since this is used only for looking up existing objects, there
1383                  * is no point in trying to initialize the temp namespace here;
1384                  * and doing so might create problems for some callers.
1385                  * Just fall through and give the "does not exist" error.
1386                  */
1387         }
1388
1389         namespaceId = GetSysCacheOid(NAMESPACENAME,
1390                                                                  CStringGetDatum(nspname),
1391                                                                  0, 0, 0);
1392         if (!OidIsValid(namespaceId))
1393                 ereport(ERROR,
1394                                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1395                                  errmsg("schema \"%s\" does not exist", nspname)));
1396
1397         aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
1398         if (aclresult != ACLCHECK_OK)
1399                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1400                                            nspname);
1401
1402         return namespaceId;
1403 }
1404
1405 /*
1406  * LookupCreationNamespace
1407  *              Look up the schema and verify we have CREATE rights on it.
1408  *
1409  * This is just like LookupExplicitNamespace except for the permission check,
1410  * and that we are willing to create pg_temp if needed.
1411  *
1412  * Note: calling this may result in a CommandCounterIncrement operation,
1413  * if we have to create or clean out the temp namespace.
1414  */
1415 Oid
1416 LookupCreationNamespace(const char *nspname)
1417 {
1418         Oid                     namespaceId;
1419         AclResult       aclresult;
1420
1421         /* check for pg_temp alias */
1422         if (strcmp(nspname, "pg_temp") == 0)
1423         {
1424                 /* Initialize temp namespace if first time through */
1425                 if (!OidIsValid(myTempNamespace))
1426                         InitTempTableNamespace();
1427                 return myTempNamespace;
1428         }
1429
1430         namespaceId = GetSysCacheOid(NAMESPACENAME,
1431                                                                  CStringGetDatum(nspname),
1432                                                                  0, 0, 0);
1433         if (!OidIsValid(namespaceId))
1434                 ereport(ERROR,
1435                                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1436                                  errmsg("schema \"%s\" does not exist", nspname)));
1437
1438         aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
1439         if (aclresult != ACLCHECK_OK)
1440                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1441                                            nspname);
1442
1443         return namespaceId;
1444 }
1445
1446 /*
1447  * QualifiedNameGetCreationNamespace
1448  *              Given a possibly-qualified name for an object (in List-of-Values
1449  *              format), determine what namespace the object should be created in.
1450  *              Also extract and return the object name (last component of list).
1451  *
1452  * Note: this does not apply any permissions check.  Callers must check
1453  * for CREATE rights on the selected namespace when appropriate.
1454  *
1455  * Note: calling this may result in a CommandCounterIncrement operation,
1456  * if we have to create or clean out the temp namespace.
1457  */
1458 Oid
1459 QualifiedNameGetCreationNamespace(List *names, char **objname_p)
1460 {
1461         char       *schemaname;
1462         Oid                     namespaceId;
1463
1464         /* deconstruct the name list */
1465         DeconstructQualifiedName(names, &schemaname, objname_p);
1466
1467         if (schemaname)
1468         {
1469                 /* check for pg_temp alias */
1470                 if (strcmp(schemaname, "pg_temp") == 0)
1471                 {
1472                         /* Initialize temp namespace if first time through */
1473                         if (!OidIsValid(myTempNamespace))
1474                                 InitTempTableNamespace();
1475                         return myTempNamespace;
1476                 }
1477                 /* use exact schema given */
1478                 namespaceId = GetSysCacheOid(NAMESPACENAME,
1479                                                                          CStringGetDatum(schemaname),
1480                                                                          0, 0, 0);
1481                 if (!OidIsValid(namespaceId))
1482                         ereport(ERROR,
1483                                         (errcode(ERRCODE_UNDEFINED_SCHEMA),
1484                                          errmsg("schema \"%s\" does not exist", schemaname)));
1485                 /* we do not check for USAGE rights here! */
1486         }
1487         else
1488         {
1489                 /* use the default creation namespace */
1490                 recomputeNamespacePath();
1491                 if (activeTempCreationPending)
1492                 {
1493                         /* Need to initialize temp namespace */
1494                         InitTempTableNamespace();
1495                         return myTempNamespace;
1496                 }
1497                 namespaceId = activeCreationNamespace;
1498                 if (!OidIsValid(namespaceId))
1499                         ereport(ERROR,
1500                                         (errcode(ERRCODE_UNDEFINED_SCHEMA),
1501                                          errmsg("no schema has been selected to create in")));
1502         }
1503
1504         return namespaceId;
1505 }
1506
1507 /*
1508  * makeRangeVarFromNameList
1509  *              Utility routine to convert a qualified-name list into RangeVar form.
1510  */
1511 RangeVar *
1512 makeRangeVarFromNameList(List *names)
1513 {
1514         RangeVar   *rel = makeRangeVar(NULL, NULL);
1515
1516         switch (list_length(names))
1517         {
1518                 case 1:
1519                         rel->relname = strVal(linitial(names));
1520                         break;
1521                 case 2:
1522                         rel->schemaname = strVal(linitial(names));
1523                         rel->relname = strVal(lsecond(names));
1524                         break;
1525                 case 3:
1526                         rel->catalogname = strVal(linitial(names));
1527                         rel->schemaname = strVal(lsecond(names));
1528                         rel->relname = strVal(lthird(names));
1529                         break;
1530                 default:
1531                         ereport(ERROR,
1532                                         (errcode(ERRCODE_SYNTAX_ERROR),
1533                                  errmsg("improper relation name (too many dotted names): %s",
1534                                                 NameListToString(names))));
1535                         break;
1536         }
1537
1538         return rel;
1539 }
1540
1541 /*
1542  * NameListToString
1543  *              Utility routine to convert a qualified-name list into a string.
1544  *
1545  * This is used primarily to form error messages, and so we do not quote
1546  * the list elements, for the sake of legibility.
1547  */
1548 char *
1549 NameListToString(List *names)
1550 {
1551         StringInfoData string;
1552         ListCell   *l;
1553
1554         initStringInfo(&string);
1555
1556         foreach(l, names)
1557         {
1558                 if (l != list_head(names))
1559                         appendStringInfoChar(&string, '.');
1560                 appendStringInfoString(&string, strVal(lfirst(l)));
1561         }
1562
1563         return string.data;
1564 }
1565
1566 /*
1567  * NameListToQuotedString
1568  *              Utility routine to convert a qualified-name list into a string.
1569  *
1570  * Same as above except that names will be double-quoted where necessary,
1571  * so the string could be re-parsed (eg, by textToQualifiedNameList).
1572  */
1573 char *
1574 NameListToQuotedString(List *names)
1575 {
1576         StringInfoData string;
1577         ListCell   *l;
1578
1579         initStringInfo(&string);
1580
1581         foreach(l, names)
1582         {
1583                 if (l != list_head(names))
1584                         appendStringInfoChar(&string, '.');
1585                 appendStringInfoString(&string, quote_identifier(strVal(lfirst(l))));
1586         }
1587
1588         return string.data;
1589 }
1590
1591 /*
1592  * isTempNamespace - is the given namespace my temporary-table namespace?
1593  */
1594 bool
1595 isTempNamespace(Oid namespaceId)
1596 {
1597         if (OidIsValid(myTempNamespace) && myTempNamespace == namespaceId)
1598                 return true;
1599         return false;
1600 }
1601
1602 /*
1603  * isAnyTempNamespace - is the given namespace a temporary-table namespace
1604  * (either my own, or another backend's)?
1605  */
1606 bool
1607 isAnyTempNamespace(Oid namespaceId)
1608 {
1609         bool            result;
1610         char       *nspname;
1611
1612         /* If the namespace name starts with "pg_temp_", say "true" */
1613         nspname = get_namespace_name(namespaceId);
1614         if (!nspname)
1615                 return false;                   /* no such namespace? */
1616         result = (strncmp(nspname, "pg_temp_", 8) == 0);
1617         pfree(nspname);
1618         return result;
1619 }
1620
1621 /*
1622  * isOtherTempNamespace - is the given namespace some other backend's
1623  * temporary-table namespace?
1624  */
1625 bool
1626 isOtherTempNamespace(Oid namespaceId)
1627 {
1628         /* If it's my own temp namespace, say "false" */
1629         if (isTempNamespace(namespaceId))
1630                 return false;
1631         /* Else, if the namespace name starts with "pg_temp_", say "true" */
1632         return isAnyTempNamespace(namespaceId);
1633 }
1634
1635
1636 /*
1637  * GetOverrideSearchPath - fetch current search path definition in form
1638  * used by PushOverrideSearchPath.
1639  *
1640  * The result structure is allocated in the specified memory context
1641  * (which might or might not be equal to CurrentMemoryContext); but any
1642  * junk created by revalidation calculations will be in CurrentMemoryContext.
1643  */
1644 OverrideSearchPath *
1645 GetOverrideSearchPath(MemoryContext context)
1646 {
1647         OverrideSearchPath *result;
1648         List       *schemas;
1649         MemoryContext oldcxt;
1650
1651         recomputeNamespacePath();
1652
1653         oldcxt = MemoryContextSwitchTo(context);
1654
1655         result = (OverrideSearchPath *) palloc0(sizeof(OverrideSearchPath));
1656         schemas = list_copy(activeSearchPath);
1657         while (schemas && linitial_oid(schemas) != activeCreationNamespace)
1658         {
1659                 if (linitial_oid(schemas) == myTempNamespace)
1660                         result->addTemp = true;
1661                 else
1662                 {
1663                         Assert(linitial_oid(schemas) == PG_CATALOG_NAMESPACE);
1664                         result->addCatalog = true;
1665                 }
1666                 schemas = list_delete_first(schemas);
1667         }
1668         result->schemas = schemas;
1669
1670         MemoryContextSwitchTo(oldcxt);
1671
1672         return result;
1673 }
1674
1675 /*
1676  * PushOverrideSearchPath - temporarily override the search path
1677  *
1678  * We allow nested overrides, hence the push/pop terminology.  The GUC
1679  * search_path variable is ignored while an override is active.
1680  */
1681 void
1682 PushOverrideSearchPath(OverrideSearchPath *newpath)
1683 {
1684         OverrideStackEntry *entry;
1685         List       *oidlist;
1686         Oid                     firstNS;
1687         MemoryContext oldcxt;
1688
1689         /*
1690          * Copy the list for safekeeping, and insert implicitly-searched
1691          * namespaces as needed.  This code should track recomputeNamespacePath.
1692          */
1693         oldcxt = MemoryContextSwitchTo(TopMemoryContext);
1694
1695         oidlist = list_copy(newpath->schemas);
1696
1697         /*
1698          * Remember the first member of the explicit list.
1699          */
1700         if (oidlist == NIL)
1701                 firstNS = InvalidOid;
1702         else
1703                 firstNS = linitial_oid(oidlist);
1704
1705         /*
1706          * Add any implicitly-searched namespaces to the list.  Note these go on
1707          * the front, not the back; also notice that we do not check USAGE
1708          * permissions for these.
1709          */
1710         if (newpath->addCatalog)
1711                 oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist);
1712
1713         if (newpath->addTemp)
1714         {
1715                 Assert(OidIsValid(myTempNamespace));
1716                 oidlist = lcons_oid(myTempNamespace, oidlist);
1717         }
1718
1719         /*
1720          * Build the new stack entry, then insert it at the head of the list.
1721          */
1722         entry = (OverrideStackEntry *) palloc(sizeof(OverrideStackEntry));
1723         entry->searchPath = oidlist;
1724         entry->creationNamespace = firstNS;
1725         entry->nestLevel = GetCurrentTransactionNestLevel();
1726
1727         overrideStack = lcons(entry, overrideStack);
1728
1729         /* And make it active. */
1730         activeSearchPath = entry->searchPath;
1731         activeCreationNamespace = entry->creationNamespace;
1732         activeTempCreationPending = false;                      /* XXX is this OK? */
1733
1734         MemoryContextSwitchTo(oldcxt);
1735 }
1736
1737 /*
1738  * PopOverrideSearchPath - undo a previous PushOverrideSearchPath
1739  *
1740  * Any push during a (sub)transaction will be popped automatically at abort.
1741  * But it's caller error if a push isn't popped in normal control flow.
1742  */
1743 void
1744 PopOverrideSearchPath(void)
1745 {
1746         OverrideStackEntry *entry;
1747
1748         /* Sanity checks. */
1749         if (overrideStack == NIL)
1750                 elog(ERROR, "bogus PopOverrideSearchPath call");
1751         entry = (OverrideStackEntry *) linitial(overrideStack);
1752         if (entry->nestLevel != GetCurrentTransactionNestLevel())
1753                 elog(ERROR, "bogus PopOverrideSearchPath call");
1754
1755         /* Pop the stack and free storage. */
1756         overrideStack = list_delete_first(overrideStack);
1757         list_free(entry->searchPath);
1758         pfree(entry);
1759
1760         /* Activate the next level down. */
1761         if (overrideStack)
1762         {
1763                 entry = (OverrideStackEntry *) linitial(overrideStack);
1764                 activeSearchPath = entry->searchPath;
1765                 activeCreationNamespace = entry->creationNamespace;
1766                 activeTempCreationPending = false;                      /* XXX is this OK? */
1767         }
1768         else
1769         {
1770                 /* If not baseSearchPathValid, this is useless but harmless */
1771                 activeSearchPath = baseSearchPath;
1772                 activeCreationNamespace = baseCreationNamespace;
1773                 activeTempCreationPending = baseTempCreationPending;
1774         }
1775 }
1776
1777
1778 /*
1779  * FindConversionByName - find a conversion by possibly qualified name
1780  */
1781 Oid
1782 FindConversionByName(List *name)
1783 {
1784         char       *schemaname;
1785         char       *conversion_name;
1786         Oid                     namespaceId;
1787         Oid                     conoid;
1788         ListCell   *l;
1789
1790         /* deconstruct the name list */
1791         DeconstructQualifiedName(name, &schemaname, &conversion_name);
1792
1793         if (schemaname)
1794         {
1795                 /* use exact schema given */
1796                 namespaceId = LookupExplicitNamespace(schemaname);
1797                 return FindConversion(conversion_name, namespaceId);
1798         }
1799         else
1800         {
1801                 /* search for it in search path */
1802                 recomputeNamespacePath();
1803
1804                 foreach(l, activeSearchPath)
1805                 {
1806                         namespaceId = lfirst_oid(l);
1807
1808                         if (namespaceId == myTempNamespace)
1809                                 continue;                       /* do not look in temp namespace */
1810
1811                         conoid = FindConversion(conversion_name, namespaceId);
1812                         if (OidIsValid(conoid))
1813                                 return conoid;
1814                 }
1815         }
1816
1817         /* Not found in path */
1818         return InvalidOid;
1819 }
1820
1821 /*
1822  * FindDefaultConversionProc - find default encoding conversion proc
1823  */
1824 Oid
1825 FindDefaultConversionProc(int4 for_encoding, int4 to_encoding)
1826 {
1827         Oid                     proc;
1828         ListCell   *l;
1829
1830         recomputeNamespacePath();
1831
1832         foreach(l, activeSearchPath)
1833         {
1834                 Oid                     namespaceId = lfirst_oid(l);
1835
1836                 if (namespaceId == myTempNamespace)
1837                         continue;                       /* do not look in temp namespace */
1838
1839                 proc = FindDefaultConversion(namespaceId, for_encoding, to_encoding);
1840                 if (OidIsValid(proc))
1841                         return proc;
1842         }
1843
1844         /* Not found in path */
1845         return InvalidOid;
1846 }
1847
1848 /*
1849  * recomputeNamespacePath - recompute path derived variables if needed.
1850  */
1851 static void
1852 recomputeNamespacePath(void)
1853 {
1854         Oid                     roleid = GetUserId();
1855         char       *rawname;
1856         List       *namelist;
1857         List       *oidlist;
1858         List       *newpath;
1859         ListCell   *l;
1860         bool            temp_missing;
1861         Oid                     firstNS;
1862         MemoryContext oldcxt;
1863
1864         /* Do nothing if an override search spec is active. */
1865         if (overrideStack)
1866                 return;
1867
1868         /* Do nothing if path is already valid. */
1869         if (baseSearchPathValid && namespaceUser == roleid)
1870                 return;
1871
1872         /* Need a modifiable copy of namespace_search_path string */
1873         rawname = pstrdup(namespace_search_path);
1874
1875         /* Parse string into list of identifiers */
1876         if (!SplitIdentifierString(rawname, ',', &namelist))
1877         {
1878                 /* syntax error in name list */
1879                 /* this should not happen if GUC checked check_search_path */
1880                 elog(ERROR, "invalid list syntax");
1881         }
1882
1883         /*
1884          * Convert the list of names to a list of OIDs.  If any names are not
1885          * recognizable or we don't have read access, just leave them out of the
1886          * list.  (We can't raise an error, since the search_path setting has
1887          * already been accepted.)      Don't make duplicate entries, either.
1888          */
1889         oidlist = NIL;
1890         temp_missing = false;
1891         foreach(l, namelist)
1892         {
1893                 char       *curname = (char *) lfirst(l);
1894                 Oid                     namespaceId;
1895
1896                 if (strcmp(curname, "$user") == 0)
1897                 {
1898                         /* $user --- substitute namespace matching user name, if any */
1899                         HeapTuple       tuple;
1900
1901                         tuple = SearchSysCache(AUTHOID,
1902                                                                    ObjectIdGetDatum(roleid),
1903                                                                    0, 0, 0);
1904                         if (HeapTupleIsValid(tuple))
1905                         {
1906                                 char       *rname;
1907
1908                                 rname = NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname);
1909                                 namespaceId = GetSysCacheOid(NAMESPACENAME,
1910                                                                                          CStringGetDatum(rname),
1911                                                                                          0, 0, 0);
1912                                 ReleaseSysCache(tuple);
1913                                 if (OidIsValid(namespaceId) &&
1914                                         !list_member_oid(oidlist, namespaceId) &&
1915                                         pg_namespace_aclcheck(namespaceId, roleid,
1916                                                                                   ACL_USAGE) == ACLCHECK_OK)
1917                                         oidlist = lappend_oid(oidlist, namespaceId);
1918                         }
1919                 }
1920                 else if (strcmp(curname, "pg_temp") == 0)
1921                 {
1922                         /* pg_temp --- substitute temp namespace, if any */
1923                         if (OidIsValid(myTempNamespace))
1924                         {
1925                                 if (!list_member_oid(oidlist, myTempNamespace))
1926                                         oidlist = lappend_oid(oidlist, myTempNamespace);
1927                         }
1928                         else
1929                         {
1930                                 /* If it ought to be the creation namespace, set flag */
1931                                 if (oidlist == NIL)
1932                                         temp_missing = true;
1933                         }
1934                 }
1935                 else
1936                 {
1937                         /* normal namespace reference */
1938                         namespaceId = GetSysCacheOid(NAMESPACENAME,
1939                                                                                  CStringGetDatum(curname),
1940                                                                                  0, 0, 0);
1941                         if (OidIsValid(namespaceId) &&
1942                                 !list_member_oid(oidlist, namespaceId) &&
1943                                 pg_namespace_aclcheck(namespaceId, roleid,
1944                                                                           ACL_USAGE) == ACLCHECK_OK)
1945                                 oidlist = lappend_oid(oidlist, namespaceId);
1946                 }
1947         }
1948
1949         /*
1950          * Remember the first member of the explicit list.  (Note: this is
1951          * nominally wrong if temp_missing, but we need it anyway to distinguish
1952          * explicit from implicit mention of pg_catalog.)
1953          */
1954         if (oidlist == NIL)
1955                 firstNS = InvalidOid;
1956         else
1957                 firstNS = linitial_oid(oidlist);
1958
1959         /*
1960          * Add any implicitly-searched namespaces to the list.  Note these go on
1961          * the front, not the back; also notice that we do not check USAGE
1962          * permissions for these.
1963          */
1964         if (!list_member_oid(oidlist, PG_CATALOG_NAMESPACE))
1965                 oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist);
1966
1967         if (OidIsValid(myTempNamespace) &&
1968                 !list_member_oid(oidlist, myTempNamespace))
1969                 oidlist = lcons_oid(myTempNamespace, oidlist);
1970
1971         /*
1972          * Now that we've successfully built the new list of namespace OIDs, save
1973          * it in permanent storage.
1974          */
1975         oldcxt = MemoryContextSwitchTo(TopMemoryContext);
1976         newpath = list_copy(oidlist);
1977         MemoryContextSwitchTo(oldcxt);
1978
1979         /* Now safe to assign to state variables. */
1980         list_free(baseSearchPath);
1981         baseSearchPath = newpath;
1982         baseCreationNamespace = firstNS;
1983         baseTempCreationPending = temp_missing;
1984
1985         /* Mark the path valid. */
1986         baseSearchPathValid = true;
1987         namespaceUser = roleid;
1988
1989         /* And make it active. */
1990         activeSearchPath = baseSearchPath;
1991         activeCreationNamespace = baseCreationNamespace;
1992         activeTempCreationPending = baseTempCreationPending;
1993
1994         /* Clean up. */
1995         pfree(rawname);
1996         list_free(namelist);
1997         list_free(oidlist);
1998 }
1999
2000 /*
2001  * InitTempTableNamespace
2002  *              Initialize temp table namespace on first use in a particular backend
2003  */
2004 static void
2005 InitTempTableNamespace(void)
2006 {
2007         char            namespaceName[NAMEDATALEN];
2008         Oid                     namespaceId;
2009
2010         Assert(!OidIsValid(myTempNamespace));
2011
2012         /*
2013          * First, do permission check to see if we are authorized to make temp
2014          * tables.      We use a nonstandard error message here since "databasename:
2015          * permission denied" might be a tad cryptic.
2016          *
2017          * Note that ACL_CREATE_TEMP rights are rechecked in pg_namespace_aclmask;
2018          * that's necessary since current user ID could change during the session.
2019          * But there's no need to make the namespace in the first place until a
2020          * temp table creation request is made by someone with appropriate rights.
2021          */
2022         if (pg_database_aclcheck(MyDatabaseId, GetUserId(),
2023                                                          ACL_CREATE_TEMP) != ACLCHECK_OK)
2024                 ereport(ERROR,
2025                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2026                                  errmsg("permission denied to create temporary tables in database \"%s\"",
2027                                                 get_database_name(MyDatabaseId))));
2028
2029         snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId);
2030
2031         namespaceId = GetSysCacheOid(NAMESPACENAME,
2032                                                                  CStringGetDatum(namespaceName),
2033                                                                  0, 0, 0);
2034         if (!OidIsValid(namespaceId))
2035         {
2036                 /*
2037                  * First use of this temp namespace in this database; create it. The
2038                  * temp namespaces are always owned by the superuser.  We leave their
2039                  * permissions at default --- i.e., no access except to superuser ---
2040                  * to ensure that unprivileged users can't peek at other backends'
2041                  * temp tables.  This works because the places that access the temp
2042                  * namespace for my own backend skip permissions checks on it.
2043                  */
2044                 namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID);
2045                 /* Advance command counter to make namespace visible */
2046                 CommandCounterIncrement();
2047         }
2048         else
2049         {
2050                 /*
2051                  * If the namespace already exists, clean it out (in case the former
2052                  * owner crashed without doing so).
2053                  */
2054                 RemoveTempRelations(namespaceId);
2055         }
2056
2057         /*
2058          * Okay, we've prepared the temp namespace ... but it's not committed yet,
2059          * so all our work could be undone by transaction rollback.  Set flag for
2060          * AtEOXact_Namespace to know what to do.
2061          */
2062         myTempNamespace = namespaceId;
2063
2064         /* It should not be done already. */
2065         AssertState(myTempNamespaceSubID == InvalidSubTransactionId);
2066         myTempNamespaceSubID = GetCurrentSubTransactionId();
2067
2068         baseSearchPathValid = false;    /* need to rebuild list */
2069 }
2070
2071 /*
2072  * End-of-transaction cleanup for namespaces.
2073  */
2074 void
2075 AtEOXact_Namespace(bool isCommit)
2076 {
2077         /*
2078          * If we abort the transaction in which a temp namespace was selected,
2079          * we'll have to do any creation or cleanout work over again.  So, just
2080          * forget the namespace entirely until next time.  On the other hand, if
2081          * we commit then register an exit callback to clean out the temp tables
2082          * at backend shutdown.  (We only want to register the callback once per
2083          * session, so this is a good place to do it.)
2084          */
2085         if (myTempNamespaceSubID != InvalidSubTransactionId)
2086         {
2087                 if (isCommit)
2088                         on_shmem_exit(RemoveTempRelationsCallback, 0);
2089                 else
2090                 {
2091                         myTempNamespace = InvalidOid;
2092                         baseSearchPathValid = false;    /* need to rebuild list */
2093                 }
2094                 myTempNamespaceSubID = InvalidSubTransactionId;
2095         }
2096
2097         /*
2098          * Clean up if someone failed to do PopOverrideSearchPath
2099          */
2100         if (overrideStack)
2101         {
2102                 if (isCommit)
2103                         elog(WARNING, "leaked override search path");
2104                 while (overrideStack)
2105                 {
2106                         OverrideStackEntry *entry;
2107
2108                         entry = (OverrideStackEntry *) linitial(overrideStack);
2109                         overrideStack = list_delete_first(overrideStack);
2110                         list_free(entry->searchPath);
2111                         pfree(entry);
2112                 }
2113                 /* If not baseSearchPathValid, this is useless but harmless */
2114                 activeSearchPath = baseSearchPath;
2115                 activeCreationNamespace = baseCreationNamespace;
2116                 activeTempCreationPending = baseTempCreationPending;
2117         }
2118 }
2119
2120 /*
2121  * AtEOSubXact_Namespace
2122  *
2123  * At subtransaction commit, propagate the temp-namespace-creation
2124  * flag to the parent subtransaction.
2125  *
2126  * At subtransaction abort, forget the flag if we set it up.
2127  */
2128 void
2129 AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid,
2130                                           SubTransactionId parentSubid)
2131 {
2132         OverrideStackEntry *entry;
2133
2134         if (myTempNamespaceSubID == mySubid)
2135         {
2136                 if (isCommit)
2137                         myTempNamespaceSubID = parentSubid;
2138                 else
2139                 {
2140                         myTempNamespaceSubID = InvalidSubTransactionId;
2141                         /* TEMP namespace creation failed, so reset state */
2142                         myTempNamespace = InvalidOid;
2143                         baseSearchPathValid = false;    /* need to rebuild list */
2144                 }
2145         }
2146
2147         /*
2148          * Clean up if someone failed to do PopOverrideSearchPath
2149          */
2150         while (overrideStack)
2151         {
2152                 entry = (OverrideStackEntry *) linitial(overrideStack);
2153                 if (entry->nestLevel < GetCurrentTransactionNestLevel())
2154                         break;
2155                 if (isCommit)
2156                         elog(WARNING, "leaked override search path");
2157                 overrideStack = list_delete_first(overrideStack);
2158                 list_free(entry->searchPath);
2159                 pfree(entry);
2160         }
2161
2162         /* Activate the next level down. */
2163         if (overrideStack)
2164         {
2165                 entry = (OverrideStackEntry *) linitial(overrideStack);
2166                 activeSearchPath = entry->searchPath;
2167                 activeCreationNamespace = entry->creationNamespace;
2168                 activeTempCreationPending = false;                      /* XXX is this OK? */
2169         }
2170         else
2171         {
2172                 /* If not baseSearchPathValid, this is useless but harmless */
2173                 activeSearchPath = baseSearchPath;
2174                 activeCreationNamespace = baseCreationNamespace;
2175                 activeTempCreationPending = baseTempCreationPending;
2176         }
2177 }
2178
2179 /*
2180  * Remove all relations in the specified temp namespace.
2181  *
2182  * This is called at backend shutdown (if we made any temp relations).
2183  * It is also called when we begin using a pre-existing temp namespace,
2184  * in order to clean out any relations that might have been created by
2185  * a crashed backend.
2186  */
2187 static void
2188 RemoveTempRelations(Oid tempNamespaceId)
2189 {
2190         ObjectAddress object;
2191
2192         /*
2193          * We want to get rid of everything in the target namespace, but not the
2194          * namespace itself (deleting it only to recreate it later would be a
2195          * waste of cycles).  We do this by finding everything that has a
2196          * dependency on the namespace.
2197          */
2198         object.classId = NamespaceRelationId;
2199         object.objectId = tempNamespaceId;
2200         object.objectSubId = 0;
2201
2202         deleteWhatDependsOn(&object, false);
2203 }
2204
2205 /*
2206  * Callback to remove temp relations at backend exit.
2207  */
2208 static void
2209 RemoveTempRelationsCallback(int code, Datum arg)
2210 {
2211         if (OidIsValid(myTempNamespace))        /* should always be true */
2212         {
2213                 /* Need to ensure we have a usable transaction. */
2214                 AbortOutOfAnyTransaction();
2215                 StartTransactionCommand();
2216
2217                 RemoveTempRelations(myTempNamespace);
2218
2219                 CommitTransactionCommand();
2220         }
2221 }
2222
2223 /*
2224  * Remove all temp tables from the temporary namespace.
2225  */
2226 void
2227 ResetTempTableNamespace(void)
2228 {
2229         if (OidIsValid(myTempNamespace))
2230                 RemoveTempRelations(myTempNamespace);
2231 }
2232
2233
2234 /*
2235  * Routines for handling the GUC variable 'search_path'.
2236  */
2237
2238 /* assign_hook: validate new search_path, do extra actions as needed */
2239 const char *
2240 assign_search_path(const char *newval, bool doit, GucSource source)
2241 {
2242         char       *rawname;
2243         List       *namelist;
2244         ListCell   *l;
2245
2246         /* Need a modifiable copy of string */
2247         rawname = pstrdup(newval);
2248
2249         /* Parse string into list of identifiers */
2250         if (!SplitIdentifierString(rawname, ',', &namelist))
2251         {
2252                 /* syntax error in name list */
2253                 pfree(rawname);
2254                 list_free(namelist);
2255                 return NULL;
2256         }
2257
2258         /*
2259          * If we aren't inside a transaction, we cannot do database access so
2260          * cannot verify the individual names.  Must accept the list on faith.
2261          */
2262         if (source >= PGC_S_INTERACTIVE && IsTransactionState())
2263         {
2264                 /*
2265                  * Verify that all the names are either valid namespace names or
2266                  * "$user" or "pg_temp".  We do not require $user to correspond to a
2267                  * valid namespace, and pg_temp might not exist yet.  We do not check
2268                  * for USAGE rights, either; should we?
2269                  *
2270                  * When source == PGC_S_TEST, we are checking the argument of an ALTER
2271                  * DATABASE SET or ALTER USER SET command.      It could be that the
2272                  * intended use of the search path is for some other database, so we
2273                  * should not error out if it mentions schemas not present in the
2274                  * current database.  We reduce the message to NOTICE instead.
2275                  */
2276                 foreach(l, namelist)
2277                 {
2278                         char       *curname = (char *) lfirst(l);
2279
2280                         if (strcmp(curname, "$user") == 0)
2281                                 continue;
2282                         if (strcmp(curname, "pg_temp") == 0)
2283                                 continue;
2284                         if (!SearchSysCacheExists(NAMESPACENAME,
2285                                                                           CStringGetDatum(curname),
2286                                                                           0, 0, 0))
2287                                 ereport((source == PGC_S_TEST) ? NOTICE : ERROR,
2288                                                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
2289                                                  errmsg("schema \"%s\" does not exist", curname)));
2290                 }
2291         }
2292
2293         pfree(rawname);
2294         list_free(namelist);
2295
2296         /*
2297          * We mark the path as needing recomputation, but don't do anything until
2298          * it's needed.  This avoids trying to do database access during GUC
2299          * initialization.
2300          */
2301         if (doit)
2302                 baseSearchPathValid = false;
2303
2304         return newval;
2305 }
2306
2307 /*
2308  * InitializeSearchPath: initialize module during InitPostgres.
2309  *
2310  * This is called after we are up enough to be able to do catalog lookups.
2311  */
2312 void
2313 InitializeSearchPath(void)
2314 {
2315         if (IsBootstrapProcessingMode())
2316         {
2317                 /*
2318                  * In bootstrap mode, the search path must be 'pg_catalog' so that
2319                  * tables are created in the proper namespace; ignore the GUC setting.
2320                  */
2321                 MemoryContext oldcxt;
2322
2323                 oldcxt = MemoryContextSwitchTo(TopMemoryContext);
2324                 baseSearchPath = list_make1_oid(PG_CATALOG_NAMESPACE);
2325                 MemoryContextSwitchTo(oldcxt);
2326                 baseCreationNamespace = PG_CATALOG_NAMESPACE;
2327                 baseTempCreationPending = false;
2328                 baseSearchPathValid = true;
2329                 namespaceUser = GetUserId();
2330                 activeSearchPath = baseSearchPath;
2331                 activeCreationNamespace = baseCreationNamespace;
2332                 activeTempCreationPending = baseTempCreationPending;
2333         }
2334         else
2335         {
2336                 /*
2337                  * In normal mode, arrange for a callback on any syscache invalidation
2338                  * of pg_namespace rows.
2339                  */
2340                 CacheRegisterSyscacheCallback(NAMESPACEOID,
2341                                                                           NamespaceCallback,
2342                                                                           (Datum) 0);
2343                 /* Force search path to be recomputed on next use */
2344                 baseSearchPathValid = false;
2345         }
2346 }
2347
2348 /*
2349  * NamespaceCallback
2350  *              Syscache inval callback function
2351  */
2352 static void
2353 NamespaceCallback(Datum arg, Oid relid)
2354 {
2355         /* Force search path to be recomputed on next use */
2356         baseSearchPathValid = false;
2357 }
2358
2359 /*
2360  * Fetch the active search path. The return value is a palloc'ed list
2361  * of OIDs; the caller is responsible for freeing this storage as
2362  * appropriate.
2363  *
2364  * The returned list includes the implicitly-prepended namespaces only if
2365  * includeImplicit is true.
2366  *
2367  * Note: calling this may result in a CommandCounterIncrement operation,
2368  * if we have to create or clean out the temp namespace.
2369  */
2370 List *
2371 fetch_search_path(bool includeImplicit)
2372 {
2373         List       *result;
2374
2375         recomputeNamespacePath();
2376
2377         /*
2378          * If the temp namespace should be first, force it to exist.  This is
2379          * so that callers can trust the result to reflect the actual default
2380          * creation namespace.  It's a bit bogus to do this here, since
2381          * current_schema() is supposedly a stable function without side-effects,
2382          * but the alternatives seem worse.
2383          */
2384         if (activeTempCreationPending)
2385         {
2386                 InitTempTableNamespace();
2387                 recomputeNamespacePath();
2388         }
2389
2390         result = list_copy(activeSearchPath);
2391         if (!includeImplicit)
2392         {
2393                 while (result && linitial_oid(result) != activeCreationNamespace)
2394                         result = list_delete_first(result);
2395         }
2396
2397         return result;
2398 }
2399
2400 /*
2401  * Export the FooIsVisible functions as SQL-callable functions.
2402  */
2403
2404 Datum
2405 pg_table_is_visible(PG_FUNCTION_ARGS)
2406 {
2407         Oid                     oid = PG_GETARG_OID(0);
2408
2409         PG_RETURN_BOOL(RelationIsVisible(oid));
2410 }
2411
2412 Datum
2413 pg_type_is_visible(PG_FUNCTION_ARGS)
2414 {
2415         Oid                     oid = PG_GETARG_OID(0);
2416
2417         PG_RETURN_BOOL(TypeIsVisible(oid));
2418 }
2419
2420 Datum
2421 pg_function_is_visible(PG_FUNCTION_ARGS)
2422 {
2423         Oid                     oid = PG_GETARG_OID(0);
2424
2425         PG_RETURN_BOOL(FunctionIsVisible(oid));
2426 }
2427
2428 Datum
2429 pg_operator_is_visible(PG_FUNCTION_ARGS)
2430 {
2431         Oid                     oid = PG_GETARG_OID(0);
2432
2433         PG_RETURN_BOOL(OperatorIsVisible(oid));
2434 }
2435
2436 Datum
2437 pg_opclass_is_visible(PG_FUNCTION_ARGS)
2438 {
2439         Oid                     oid = PG_GETARG_OID(0);
2440
2441         PG_RETURN_BOOL(OpclassIsVisible(oid));
2442 }
2443
2444 Datum
2445 pg_conversion_is_visible(PG_FUNCTION_ARGS)
2446 {
2447         Oid                     oid = PG_GETARG_OID(0);
2448
2449         PG_RETURN_BOOL(ConversionIsVisible(oid));
2450 }
2451
2452 Datum
2453 pg_my_temp_schema(PG_FUNCTION_ARGS)
2454 {
2455         PG_RETURN_OID(myTempNamespace);
2456 }
2457
2458 Datum
2459 pg_is_other_temp_schema(PG_FUNCTION_ARGS)
2460 {
2461         Oid                     oid = PG_GETARG_OID(0);
2462
2463         PG_RETURN_BOOL(isOtherTempNamespace(oid));
2464 }