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